aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c64
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c49
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c11
4 files changed, 103 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 635c16ee6186..77c339f8516c 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -288,6 +288,7 @@ struct iwm_priv {
288 u8 *eeprom; 288 u8 *eeprom;
289 struct timer_list watchdog; 289 struct timer_list watchdog;
290 struct work_struct reset_worker; 290 struct work_struct reset_worker;
291 struct mutex mutex;
291 struct rfkill *rfkill; 292 struct rfkill *rfkill;
292 293
293 char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); 294 char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -315,8 +316,11 @@ extern const struct iw_handler_def iwm_iw_handler_def;
315void *iwm_if_alloc(int sizeof_bus, struct device *dev, 316void *iwm_if_alloc(int sizeof_bus, struct device *dev,
316 struct iwm_if_ops *if_ops); 317 struct iwm_if_ops *if_ops);
317void iwm_if_free(struct iwm_priv *iwm); 318void iwm_if_free(struct iwm_priv *iwm);
319int iwm_if_add(struct iwm_priv *iwm);
320void iwm_if_remove(struct iwm_priv *iwm);
318int iwm_mode_to_nl80211_iftype(int mode); 321int iwm_mode_to_nl80211_iftype(int mode);
319int iwm_priv_init(struct iwm_priv *iwm); 322int iwm_priv_init(struct iwm_priv *iwm);
323void iwm_priv_deinit(struct iwm_priv *iwm);
320void iwm_reset(struct iwm_priv *iwm); 324void iwm_reset(struct iwm_priv *iwm);
321void iwm_tx_credit_init_pools(struct iwm_priv *iwm, 325void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
322 struct iwm_umac_notif_alive *alive); 326 struct iwm_umac_notif_alive *alive);
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 6a2640f16b6d..8be206d58222 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -112,6 +112,9 @@ static void iwm_statistics_request(struct work_struct *work)
112 iwm_send_umac_stats_req(iwm, 0); 112 iwm_send_umac_stats_req(iwm, 0);
113} 113}
114 114
115int __iwm_up(struct iwm_priv *iwm);
116int __iwm_down(struct iwm_priv *iwm);
117
115static void iwm_reset_worker(struct work_struct *work) 118static void iwm_reset_worker(struct work_struct *work)
116{ 119{
117 struct iwm_priv *iwm; 120 struct iwm_priv *iwm;
@@ -120,6 +123,19 @@ static void iwm_reset_worker(struct work_struct *work)
120 123
121 iwm = container_of(work, struct iwm_priv, reset_worker); 124 iwm = container_of(work, struct iwm_priv, reset_worker);
122 125
126 /*
127 * XXX: The iwm->mutex is introduced purely for this reset work,
128 * because the other users for iwm_up and iwm_down are only netdev
129 * ndo_open and ndo_stop which are already protected by rtnl.
130 * Please remove iwm->mutex together if iwm_reset_worker() is not
131 * required in the future.
132 */
133 if (!mutex_trylock(&iwm->mutex)) {
134 IWM_WARN(iwm, "We are in the middle of interface bringing "
135 "UP/DOWN. Skip driver resetting.\n");
136 return;
137 }
138
123 if (iwm->umac_profile_active) { 139 if (iwm->umac_profile_active) {
124 profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); 140 profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL);
125 if (profile) 141 if (profile)
@@ -128,10 +144,10 @@ static void iwm_reset_worker(struct work_struct *work)
128 IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); 144 IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
129 } 145 }
130 146
131 iwm_down(iwm); 147 __iwm_down(iwm);
132 148
133 while (retry++ < 3) { 149 while (retry++ < 3) {
134 ret = iwm_up(iwm); 150 ret = __iwm_up(iwm);
135 if (!ret) 151 if (!ret)
136 break; 152 break;
137 153
@@ -142,7 +158,7 @@ static void iwm_reset_worker(struct work_struct *work)
142 IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); 158 IWM_WARN(iwm, "iwm_up() failed: %d\n", ret);
143 159
144 kfree(profile); 160 kfree(profile);
145 return; 161 goto out;
146 } 162 }
147 163
148 if (profile) { 164 if (profile) {
@@ -151,6 +167,9 @@ static void iwm_reset_worker(struct work_struct *work)
151 iwm_send_mlme_profile(iwm); 167 iwm_send_mlme_profile(iwm);
152 kfree(profile); 168 kfree(profile);
153 } 169 }
170
171 out:
172 mutex_unlock(&iwm->mutex);
154} 173}
155 174
156static void iwm_watchdog(unsigned long data) 175static void iwm_watchdog(unsigned long data)
@@ -215,10 +234,21 @@ int iwm_priv_init(struct iwm_priv *iwm)
215 init_timer(&iwm->watchdog); 234 init_timer(&iwm->watchdog);
216 iwm->watchdog.function = iwm_watchdog; 235 iwm->watchdog.function = iwm_watchdog;
217 iwm->watchdog.data = (unsigned long)iwm; 236 iwm->watchdog.data = (unsigned long)iwm;
237 mutex_init(&iwm->mutex);
218 238
219 return 0; 239 return 0;
220} 240}
221 241
242void iwm_priv_deinit(struct iwm_priv *iwm)
243{
244 int i;
245
246 for (i = 0; i < IWM_TX_QUEUES; i++)
247 destroy_workqueue(iwm->txq[i].wq);
248
249 destroy_workqueue(iwm->rx_wq);
250}
251
222/* 252/*
223 * We reset all the structures, and we reset the UMAC. 253 * We reset all the structures, and we reset the UMAC.
224 * After calling this routine, you're expected to reload 254 * After calling this routine, you're expected to reload
@@ -466,7 +496,7 @@ void iwm_link_off(struct iwm_priv *iwm)
466 496
467 iwm_rx_free(iwm); 497 iwm_rx_free(iwm);
468 498
469 cancel_delayed_work(&iwm->stats_request); 499 cancel_delayed_work_sync(&iwm->stats_request);
470 memset(wstats, 0, sizeof(struct iw_statistics)); 500 memset(wstats, 0, sizeof(struct iw_statistics));
471 wstats->qual.updated = IW_QUAL_ALL_INVALID; 501 wstats->qual.updated = IW_QUAL_ALL_INVALID;
472 502
@@ -511,7 +541,7 @@ static int iwm_channels_init(struct iwm_priv *iwm)
511 return 0; 541 return 0;
512} 542}
513 543
514int iwm_up(struct iwm_priv *iwm) 544int __iwm_up(struct iwm_priv *iwm)
515{ 545{
516 int ret; 546 int ret;
517 struct iwm_notif *notif_reboot, *notif_ack = NULL; 547 struct iwm_notif *notif_reboot, *notif_ack = NULL;
@@ -647,7 +677,18 @@ int iwm_up(struct iwm_priv *iwm)
647 return -EIO; 677 return -EIO;
648} 678}
649 679
650int iwm_down(struct iwm_priv *iwm) 680int iwm_up(struct iwm_priv *iwm)
681{
682 int ret;
683
684 mutex_lock(&iwm->mutex);
685 ret = __iwm_up(iwm);
686 mutex_unlock(&iwm->mutex);
687
688 return ret;
689}
690
691int __iwm_down(struct iwm_priv *iwm)
651{ 692{
652 int ret; 693 int ret;
653 694
@@ -678,3 +719,14 @@ int iwm_down(struct iwm_priv *iwm)
678 719
679 return 0; 720 return 0;
680} 721}
722
723int iwm_down(struct iwm_priv *iwm)
724{
725 int ret;
726
727 mutex_lock(&iwm->mutex);
728 ret = __iwm_down(iwm);
729 mutex_unlock(&iwm->mutex);
730
731 return ret;
732}
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 68e2c3b6c7a1..aaa20c6885c8 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -114,32 +114,31 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
114 iwm = wdev_to_iwm(wdev); 114 iwm = wdev_to_iwm(wdev);
115 iwm->bus_ops = if_ops; 115 iwm->bus_ops = if_ops;
116 iwm->wdev = wdev; 116 iwm->wdev = wdev;
117 iwm_priv_init(iwm); 117
118 ret = iwm_priv_init(iwm);
119 if (ret) {
120 dev_err(dev, "failed to init iwm_priv\n");
121 goto out_wdev;
122 }
123
118 wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); 124 wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode);
119 125
120 ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, 126 ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
121 IWM_TX_QUEUES);
122 if (!ndev) { 127 if (!ndev) {
123 dev_err(dev, "no memory for network device instance\n"); 128 dev_err(dev, "no memory for network device instance\n");
124 goto out_wdev; 129 goto out_priv;
125 } 130 }
126 131
127 ndev->netdev_ops = &iwm_netdev_ops; 132 ndev->netdev_ops = &iwm_netdev_ops;
128 ndev->wireless_handlers = &iwm_iw_handler_def; 133 ndev->wireless_handlers = &iwm_iw_handler_def;
129 ndev->ieee80211_ptr = wdev; 134 ndev->ieee80211_ptr = wdev;
130 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); 135 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
131 ret = register_netdev(ndev);
132 if (ret < 0) {
133 dev_err(dev, "Failed to register netdev: %d\n", ret);
134 goto out_ndev;
135 }
136
137 wdev->netdev = ndev; 136 wdev->netdev = ndev;
138 137
139 return iwm; 138 return iwm;
140 139
141 out_ndev: 140 out_priv:
142 free_netdev(ndev); 141 iwm_priv_deinit(iwm);
143 142
144 out_wdev: 143 out_wdev:
145 iwm_wdev_free(iwm); 144 iwm_wdev_free(iwm);
@@ -148,15 +147,29 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
148 147
149void iwm_if_free(struct iwm_priv *iwm) 148void iwm_if_free(struct iwm_priv *iwm)
150{ 149{
151 int i;
152
153 if (!iwm_to_ndev(iwm)) 150 if (!iwm_to_ndev(iwm))
154 return; 151 return;
155 152
156 unregister_netdev(iwm_to_ndev(iwm));
157 free_netdev(iwm_to_ndev(iwm)); 153 free_netdev(iwm_to_ndev(iwm));
158 iwm_wdev_free(iwm); 154 iwm_wdev_free(iwm);
159 destroy_workqueue(iwm->rx_wq); 155 iwm_priv_deinit(iwm);
160 for (i = 0; i < IWM_TX_QUEUES; i++) 156}
161 destroy_workqueue(iwm->txq[i].wq); 157
158int iwm_if_add(struct iwm_priv *iwm)
159{
160 struct net_device *ndev = iwm_to_ndev(iwm);
161 int ret;
162
163 ret = register_netdev(ndev);
164 if (ret < 0) {
165 dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret);
166 return ret;
167 }
168
169 return 0;
170}
171
172void iwm_if_remove(struct iwm_priv *iwm)
173{
174 unregister_netdev(iwm_to_ndev(iwm));
162} 175}
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index b54da677b371..916681837fd2 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -454,10 +454,18 @@ static int iwm_sdio_probe(struct sdio_func *func,
454 454
455 INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); 455 INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker);
456 456
457 ret = iwm_if_add(iwm);
458 if (ret) {
459 dev_err(dev, "add SDIO interface failed\n");
460 goto destroy_wq;
461 }
462
457 dev_info(dev, "IWM SDIO probe\n"); 463 dev_info(dev, "IWM SDIO probe\n");
458 464
459 return 0; 465 return 0;
460 466
467 destroy_wq:
468 destroy_workqueue(hw->isr_wq);
461 debugfs_exit: 469 debugfs_exit:
462 iwm_debugfs_exit(iwm); 470 iwm_debugfs_exit(iwm);
463 if_free: 471 if_free:
@@ -471,9 +479,10 @@ static void iwm_sdio_remove(struct sdio_func *func)
471 struct iwm_priv *iwm = hw_to_iwm(hw); 479 struct iwm_priv *iwm = hw_to_iwm(hw);
472 struct device *dev = &func->dev; 480 struct device *dev = &func->dev;
473 481
482 iwm_if_remove(iwm);
483 destroy_workqueue(hw->isr_wq);
474 iwm_debugfs_exit(iwm); 484 iwm_debugfs_exit(iwm);
475 iwm_if_free(iwm); 485 iwm_if_free(iwm);
476 destroy_workqueue(hw->isr_wq);
477 486
478 sdio_set_drvdata(func, NULL); 487 sdio_set_drvdata(func, NULL);
479 488