mwifiex: handle driver initialization error paths
mwifiex_fw_dpc() asynchronously takes care of firmware download and initialization. Currently the error paths in mwifiex_fw_dpc() are not handled. So if wrong firmware is downloaded, required cleanup work is not performed. memory is leaked and workqueue remains unterminated in this case. mwifiex_terminate_workqueue() is moved to avoid forward declaration. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
					parent
					
						
							
								9d55911e8f
							
						
					
				
			
			
				commit
				
					
						6b41f941d7
					
				
			
		
					 2 changed files with 56 additions and 28 deletions
				
			
		|  | @ -389,6 +389,17 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) | |||
| 	pr_debug("info: %s: free adapter\n", __func__); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function cancels all works in the queue and destroys | ||||
|  * the main workqueue. | ||||
|  */ | ||||
| static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) | ||||
| { | ||||
| 	flush_workqueue(adapter->workqueue); | ||||
| 	destroy_workqueue(adapter->workqueue); | ||||
| 	adapter->workqueue = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function gets firmware and initializes it. | ||||
|  * | ||||
|  | @ -398,7 +409,7 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) | |||
|  */ | ||||
| static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | ||||
| { | ||||
| 	int ret; | ||||
| 	int ret, i; | ||||
| 	char fmt[64]; | ||||
| 	struct mwifiex_private *priv; | ||||
| 	struct mwifiex_adapter *adapter = context; | ||||
|  | @ -407,7 +418,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
| 	if (!firmware) { | ||||
| 		dev_err(adapter->dev, | ||||
| 			"Failed to get firmware %s\n", adapter->fw_name); | ||||
| 		goto done; | ||||
| 		goto err_dnld_fw; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&fw, 0, sizeof(struct mwifiex_fw_image)); | ||||
|  | @ -420,7 +431,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
| 	else | ||||
| 		ret = mwifiex_dnld_fw(adapter, &fw); | ||||
| 	if (ret == -1) | ||||
| 		goto done; | ||||
| 		goto err_dnld_fw; | ||||
| 
 | ||||
| 	dev_notice(adapter->dev, "WLAN FW is active\n"); | ||||
| 
 | ||||
|  | @ -432,13 +443,15 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
| 	} | ||||
| 
 | ||||
| 	/* enable host interrupt after fw dnld is successful */ | ||||
| 	if (adapter->if_ops.enable_int) | ||||
| 		adapter->if_ops.enable_int(adapter); | ||||
| 	if (adapter->if_ops.enable_int) { | ||||
| 		if (adapter->if_ops.enable_int(adapter)) | ||||
| 			goto err_dnld_fw; | ||||
| 	} | ||||
| 
 | ||||
| 	adapter->init_wait_q_woken = false; | ||||
| 	ret = mwifiex_init_fw(adapter); | ||||
| 	if (ret == -1) { | ||||
| 		goto done; | ||||
| 		goto err_init_fw; | ||||
| 	} else if (!ret) { | ||||
| 		adapter->hw_status = MWIFIEX_HW_STATUS_READY; | ||||
| 		goto done; | ||||
|  | @ -447,12 +460,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
| 	wait_event_interruptible(adapter->init_wait_q, | ||||
| 				 adapter->init_wait_q_woken); | ||||
| 	if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) | ||||
| 		goto done; | ||||
| 		goto err_init_fw; | ||||
| 
 | ||||
| 	priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; | ||||
| 	if (mwifiex_register_cfg80211(adapter)) { | ||||
| 		dev_err(adapter->dev, "cannot register with cfg80211\n"); | ||||
| 		goto err_init_fw; | ||||
| 		goto err_register_cfg80211; | ||||
| 	} | ||||
| 
 | ||||
| 	rtnl_lock(); | ||||
|  | @ -483,13 +496,39 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
| 	goto done; | ||||
| 
 | ||||
| err_add_intf: | ||||
| 	mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); | ||||
| 	for (i = 0; i < adapter->priv_num; i++) { | ||||
| 		priv = adapter->priv[i]; | ||||
| 
 | ||||
| 		if (!priv) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (priv->wdev && priv->netdev) | ||||
| 			mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); | ||||
| 	} | ||||
| 	rtnl_unlock(); | ||||
| err_register_cfg80211: | ||||
| 	wiphy_unregister(adapter->wiphy); | ||||
| 	wiphy_free(adapter->wiphy); | ||||
| err_init_fw: | ||||
| 	if (adapter->if_ops.disable_int) | ||||
| 		adapter->if_ops.disable_int(adapter); | ||||
| err_dnld_fw: | ||||
| 	pr_debug("info: %s: unregister device\n", __func__); | ||||
| 	adapter->if_ops.unregister_dev(adapter); | ||||
| 	if (adapter->if_ops.unregister_dev) | ||||
| 		adapter->if_ops.unregister_dev(adapter); | ||||
| 
 | ||||
| 	if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || | ||||
| 	    (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { | ||||
| 		pr_debug("info: %s: shutdown mwifiex\n", __func__); | ||||
| 		adapter->init_wait_q_woken = false; | ||||
| 
 | ||||
| 		if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS) | ||||
| 			wait_event_interruptible(adapter->init_wait_q, | ||||
| 						 adapter->init_wait_q_woken); | ||||
| 	} | ||||
| 	adapter->surprise_removed = true; | ||||
| 	mwifiex_terminate_workqueue(adapter); | ||||
| 	mwifiex_free_adapter(adapter); | ||||
| done: | ||||
| 	if (adapter->cal_data) { | ||||
| 		release_firmware(adapter->cal_data); | ||||
|  | @ -497,6 +536,7 @@ done: | |||
| 	} | ||||
| 	release_firmware(adapter->firmware); | ||||
| 	complete(&adapter->fw_load); | ||||
| 	up(adapter->card_sem); | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
|  | @ -806,18 +846,6 @@ static void mwifiex_main_work_queue(struct work_struct *work) | |||
| 	mwifiex_main_process(adapter); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function cancels all works in the queue and destroys | ||||
|  * the main workqueue. | ||||
|  */ | ||||
| static void | ||||
| mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) | ||||
| { | ||||
| 	flush_workqueue(adapter->workqueue); | ||||
| 	destroy_workqueue(adapter->workqueue); | ||||
| 	adapter->workqueue = NULL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This function adds the card. | ||||
|  * | ||||
|  | @ -846,6 +874,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
| 	} | ||||
| 
 | ||||
| 	adapter->iface_type = iface_type; | ||||
| 	adapter->card_sem = sem; | ||||
| 
 | ||||
| 	adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; | ||||
| 	adapter->surprise_removed = false; | ||||
|  | @ -876,17 +905,12 @@ mwifiex_add_card(void *card, struct semaphore *sem, | |||
| 		goto err_init_fw; | ||||
| 	} | ||||
| 
 | ||||
| 	up(sem); | ||||
| 	return 0; | ||||
| 
 | ||||
| err_init_fw: | ||||
| 	pr_debug("info: %s: unregister device\n", __func__); | ||||
| 	if (adapter->if_ops.unregister_dev) | ||||
| 		adapter->if_ops.unregister_dev(adapter); | ||||
| err_registerdev: | ||||
| 	adapter->surprise_removed = true; | ||||
| 	mwifiex_terminate_workqueue(adapter); | ||||
| err_kmalloc: | ||||
| 	if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) || | ||||
| 	    (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { | ||||
| 		pr_debug("info: %s: shutdown mwifiex\n", __func__); | ||||
|  | @ -896,7 +920,10 @@ err_kmalloc: | |||
| 			wait_event_interruptible(adapter->init_wait_q, | ||||
| 						 adapter->init_wait_q_woken); | ||||
| 	} | ||||
| 
 | ||||
| err_registerdev: | ||||
| 	adapter->surprise_removed = true; | ||||
| 	mwifiex_terminate_workqueue(adapter); | ||||
| err_kmalloc: | ||||
| 	mwifiex_free_adapter(adapter); | ||||
| 
 | ||||
| err_init_sw: | ||||
|  |  | |||
|  | @ -749,6 +749,7 @@ struct mwifiex_adapter { | |||
| 
 | ||||
| 	atomic_t is_tx_received; | ||||
| 	atomic_t pending_bridged_pkts; | ||||
| 	struct semaphore *card_sem; | ||||
| }; | ||||
| 
 | ||||
| int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Amitkumar Karwar
				Amitkumar Karwar