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__);
|
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
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 @@ done:
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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 @@ err_kmalloc:
|
|||||||
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 {
|
|||||||
|
|
||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user