Commit 6b41f941 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by John W. Linville

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: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarBing Zhao <bzhao@marvell.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 9d55911e
...@@ -389,6 +389,17 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) ...@@ -389,6 +389,17 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
pr_debug("info: %s: free adapter\n", __func__); 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. * This function gets firmware and initializes it.
* *
...@@ -398,7 +409,7 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) ...@@ -398,7 +409,7 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
*/ */
static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
{ {
int ret; int ret, i;
char fmt[64]; char fmt[64];
struct mwifiex_private *priv; struct mwifiex_private *priv;
struct mwifiex_adapter *adapter = context; struct mwifiex_adapter *adapter = context;
...@@ -407,7 +418,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -407,7 +418,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (!firmware) { if (!firmware) {
dev_err(adapter->dev, dev_err(adapter->dev,
"Failed to get firmware %s\n", adapter->fw_name); "Failed to get firmware %s\n", adapter->fw_name);
goto done; goto err_dnld_fw;
} }
memset(&fw, 0, sizeof(struct mwifiex_fw_image)); memset(&fw, 0, sizeof(struct mwifiex_fw_image));
...@@ -420,7 +431,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -420,7 +431,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
else else
ret = mwifiex_dnld_fw(adapter, &fw); ret = mwifiex_dnld_fw(adapter, &fw);
if (ret == -1) if (ret == -1)
goto done; goto err_dnld_fw;
dev_notice(adapter->dev, "WLAN FW is active\n"); dev_notice(adapter->dev, "WLAN FW is active\n");
...@@ -432,13 +443,15 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -432,13 +443,15 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
} }
/* enable host interrupt after fw dnld is successful */ /* enable host interrupt after fw dnld is successful */
if (adapter->if_ops.enable_int) if (adapter->if_ops.enable_int) {
adapter->if_ops.enable_int(adapter); if (adapter->if_ops.enable_int(adapter))
goto err_dnld_fw;
}
adapter->init_wait_q_woken = false; adapter->init_wait_q_woken = false;
ret = mwifiex_init_fw(adapter); ret = mwifiex_init_fw(adapter);
if (ret == -1) { if (ret == -1) {
goto done; goto err_init_fw;
} else if (!ret) { } else if (!ret) {
adapter->hw_status = MWIFIEX_HW_STATUS_READY; adapter->hw_status = MWIFIEX_HW_STATUS_READY;
goto done; goto done;
...@@ -447,12 +460,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -447,12 +460,12 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
wait_event_interruptible(adapter->init_wait_q, wait_event_interruptible(adapter->init_wait_q,
adapter->init_wait_q_woken); adapter->init_wait_q_woken);
if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
goto done; goto err_init_fw;
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) { if (mwifiex_register_cfg80211(adapter)) {
dev_err(adapter->dev, "cannot register with cfg80211\n"); dev_err(adapter->dev, "cannot register with cfg80211\n");
goto err_init_fw; goto err_register_cfg80211;
} }
rtnl_lock(); rtnl_lock();
...@@ -483,13 +496,39 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -483,13 +496,39 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done; goto done;
err_add_intf: 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(); rtnl_unlock();
err_register_cfg80211:
wiphy_unregister(adapter->wiphy);
wiphy_free(adapter->wiphy);
err_init_fw: err_init_fw:
if (adapter->if_ops.disable_int) if (adapter->if_ops.disable_int)
adapter->if_ops.disable_int(adapter); adapter->if_ops.disable_int(adapter);
err_dnld_fw:
pr_debug("info: %s: unregister device\n", __func__); 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: done:
if (adapter->cal_data) { if (adapter->cal_data) {
release_firmware(adapter->cal_data); release_firmware(adapter->cal_data);
...@@ -497,6 +536,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) ...@@ -497,6 +536,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
} }
release_firmware(adapter->firmware); release_firmware(adapter->firmware);
complete(&adapter->fw_load); complete(&adapter->fw_load);
up(adapter->card_sem);
return; return;
} }
...@@ -806,18 +846,6 @@ static void mwifiex_main_work_queue(struct work_struct *work) ...@@ -806,18 +846,6 @@ static void mwifiex_main_work_queue(struct work_struct *work)
mwifiex_main_process(adapter); 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. * This function adds the card.
* *
...@@ -846,6 +874,7 @@ mwifiex_add_card(void *card, struct semaphore *sem, ...@@ -846,6 +874,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
} }
adapter->iface_type = iface_type; adapter->iface_type = iface_type;
adapter->card_sem = sem;
adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
adapter->surprise_removed = false; adapter->surprise_removed = false;
...@@ -876,17 +905,12 @@ mwifiex_add_card(void *card, struct semaphore *sem, ...@@ -876,17 +905,12 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_fw; goto err_init_fw;
} }
up(sem);
return 0; return 0;
err_init_fw: err_init_fw:
pr_debug("info: %s: unregister device\n", __func__); pr_debug("info: %s: unregister device\n", __func__);
if (adapter->if_ops.unregister_dev) if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter); 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) || if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
(adapter->hw_status == MWIFIEX_HW_STATUS_READY)) { (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
pr_debug("info: %s: shutdown mwifiex\n", __func__); pr_debug("info: %s: shutdown mwifiex\n", __func__);
...@@ -896,7 +920,10 @@ mwifiex_add_card(void *card, struct semaphore *sem, ...@@ -896,7 +920,10 @@ mwifiex_add_card(void *card, struct semaphore *sem,
wait_event_interruptible(adapter->init_wait_q, wait_event_interruptible(adapter->init_wait_q,
adapter->init_wait_q_woken); adapter->init_wait_q_woken);
} }
err_registerdev:
adapter->surprise_removed = true;
mwifiex_terminate_workqueue(adapter);
err_kmalloc:
mwifiex_free_adapter(adapter); mwifiex_free_adapter(adapter);
err_init_sw: err_init_sw:
......
...@@ -749,6 +749,7 @@ struct mwifiex_adapter { ...@@ -749,6 +749,7 @@ struct mwifiex_adapter {
atomic_t is_tx_received; atomic_t is_tx_received;
atomic_t pending_bridged_pkts; atomic_t pending_bridged_pkts;
struct semaphore *card_sem;
}; };
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment