iwmc3200wifi: check for iwm_priv_init error
We need to check for iwm_priv_init() errors and do proper cleanups. Otherwise we may fail to catch the create_singlethread_workqueue() error which will cause a kernel oops when destroy_workqueue() later. Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
@@ -317,6 +317,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||||||
void iwm_if_free(struct iwm_priv *iwm);
|
void iwm_if_free(struct iwm_priv *iwm);
|
||||||
int iwm_mode_to_nl80211_iftype(int mode);
|
int iwm_mode_to_nl80211_iftype(int mode);
|
||||||
int iwm_priv_init(struct iwm_priv *iwm);
|
int iwm_priv_init(struct iwm_priv *iwm);
|
||||||
|
void iwm_priv_deinit(struct iwm_priv *iwm);
|
||||||
void iwm_reset(struct iwm_priv *iwm);
|
void iwm_reset(struct iwm_priv *iwm);
|
||||||
void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
|
void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
|
||||||
struct iwm_umac_notif_alive *alive);
|
struct iwm_umac_notif_alive *alive);
|
||||||
|
@@ -219,6 +219,16 @@ int iwm_priv_init(struct iwm_priv *iwm)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iwm_priv_deinit(struct iwm_priv *iwm)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < IWM_TX_QUEUES; i++)
|
||||||
|
destroy_workqueue(iwm->txq[i].wq);
|
||||||
|
|
||||||
|
destroy_workqueue(iwm->rx_wq);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We reset all the structures, and we reset the UMAC.
|
* We reset all the structures, and we reset the UMAC.
|
||||||
* After calling this routine, you're expected to reload
|
* After calling this routine, you're expected to reload
|
||||||
|
@@ -114,14 +114,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||||||
iwm = wdev_to_iwm(wdev);
|
iwm = wdev_to_iwm(wdev);
|
||||||
iwm->bus_ops = if_ops;
|
iwm->bus_ops = if_ops;
|
||||||
iwm->wdev = wdev;
|
iwm->wdev = wdev;
|
||||||
iwm_priv_init(iwm);
|
|
||||||
|
ret = iwm_priv_init(iwm);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to init iwm_priv\n");
|
||||||
|
goto out_wdev;
|
||||||
|
}
|
||||||
|
|
||||||
wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
|
wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
|
||||||
|
|
||||||
ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
|
ndev = alloc_netdev_mq(0, "wlan%d", ether_setup,
|
||||||
IWM_TX_QUEUES);
|
IWM_TX_QUEUES);
|
||||||
if (!ndev) {
|
if (!ndev) {
|
||||||
dev_err(dev, "no memory for network device instance\n");
|
dev_err(dev, "no memory for network device instance\n");
|
||||||
goto out_wdev;
|
goto out_priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
ndev->netdev_ops = &iwm_netdev_ops;
|
ndev->netdev_ops = &iwm_netdev_ops;
|
||||||
@@ -141,6 +147,9 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||||||
out_ndev:
|
out_ndev:
|
||||||
free_netdev(ndev);
|
free_netdev(ndev);
|
||||||
|
|
||||||
|
out_priv:
|
||||||
|
iwm_priv_deinit(iwm);
|
||||||
|
|
||||||
out_wdev:
|
out_wdev:
|
||||||
iwm_wdev_free(iwm);
|
iwm_wdev_free(iwm);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
@@ -148,15 +157,11 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||||||
|
|
||||||
void iwm_if_free(struct iwm_priv *iwm)
|
void iwm_if_free(struct iwm_priv *iwm)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!iwm_to_ndev(iwm))
|
if (!iwm_to_ndev(iwm))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unregister_netdev(iwm_to_ndev(iwm));
|
unregister_netdev(iwm_to_ndev(iwm));
|
||||||
free_netdev(iwm_to_ndev(iwm));
|
free_netdev(iwm_to_ndev(iwm));
|
||||||
iwm_wdev_free(iwm);
|
iwm_wdev_free(iwm);
|
||||||
destroy_workqueue(iwm->rx_wq);
|
iwm_priv_deinit(iwm);
|
||||||
for (i = 0; i < IWM_TX_QUEUES; i++)
|
|
||||||
destroy_workqueue(iwm->txq[i].wq);
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user