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
|
@ -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…
Reference in New Issue