diff options
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 18 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/netdev.c | 49 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/sdio.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/zd1211rw/zd_usb.c | 1 |
9 files changed, 136 insertions, 31 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 55f7de09d134..ea045151f953 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -538,6 +538,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
538 | sc->iobase = mem; /* So we can unmap it on detach */ | 538 | sc->iobase = mem; /* So we can unmap it on detach */ |
539 | sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ | 539 | sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ |
540 | sc->opmode = NL80211_IFTYPE_STATION; | 540 | sc->opmode = NL80211_IFTYPE_STATION; |
541 | sc->bintval = 1000; | ||
541 | mutex_init(&sc->lock); | 542 | mutex_init(&sc->lock); |
542 | spin_lock_init(&sc->rxbuflock); | 543 | spin_lock_init(&sc->rxbuflock); |
543 | spin_lock_init(&sc->txbuflock); | 544 | spin_lock_init(&sc->txbuflock); |
@@ -686,6 +687,13 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
686 | if (err) | 687 | if (err) |
687 | return err; | 688 | return err; |
688 | 689 | ||
690 | /* | ||
691 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
692 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
693 | * PCI Tx retries from interfering with C3 CPU state | ||
694 | */ | ||
695 | pci_write_config_byte(pdev, 0x41, 0); | ||
696 | |||
689 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | 697 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); |
690 | if (err) { | 698 | if (err) { |
691 | ATH5K_ERR(sc, "request_irq failed\n"); | 699 | ATH5K_ERR(sc, "request_irq failed\n"); |
@@ -2748,9 +2756,6 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | |||
2748 | goto end; | 2756 | goto end; |
2749 | } | 2757 | } |
2750 | 2758 | ||
2751 | /* Set to a reasonable value. Note that this will | ||
2752 | * be set to mac80211's value at ath5k_config(). */ | ||
2753 | sc->bintval = 1000; | ||
2754 | ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); | 2759 | ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); |
2755 | 2760 | ||
2756 | ret = 0; | 2761 | ret = 0; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 9f49a3251d4d..66a6c1f5022a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1196,8 +1196,8 @@ void ath_radio_disable(struct ath_softc *sc) | |||
1196 | 1196 | ||
1197 | ath9k_hw_phy_disable(ah); | 1197 | ath9k_hw_phy_disable(ah); |
1198 | ath9k_hw_configpcipowersave(ah, 1); | 1198 | ath9k_hw_configpcipowersave(ah, 1); |
1199 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | ||
1200 | ath9k_ps_restore(sc); | 1199 | ath9k_ps_restore(sc); |
1200 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | ||
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | /*******************/ | 1203 | /*******************/ |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index ccdf20a2e9be..170c5b32e49b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -87,6 +87,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
87 | struct ath_softc *sc; | 87 | struct ath_softc *sc; |
88 | struct ieee80211_hw *hw; | 88 | struct ieee80211_hw *hw; |
89 | u8 csz; | 89 | u8 csz; |
90 | u32 val; | ||
90 | int ret = 0; | 91 | int ret = 0; |
91 | struct ath_hw *ah; | 92 | struct ath_hw *ah; |
92 | 93 | ||
@@ -133,6 +134,14 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
133 | 134 | ||
134 | pci_set_master(pdev); | 135 | pci_set_master(pdev); |
135 | 136 | ||
137 | /* | ||
138 | * Disable the RETRY_TIMEOUT register (0x41) to keep | ||
139 | * PCI Tx retries from interfering with C3 CPU state. | ||
140 | */ | ||
141 | pci_read_config_dword(pdev, 0x40, &val); | ||
142 | if ((val & 0x0000ff00) != 0) | ||
143 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
144 | |||
136 | ret = pci_request_region(pdev, 0, "ath9k"); | 145 | ret = pci_request_region(pdev, 0, "ath9k"); |
137 | if (ret) { | 146 | if (ret) { |
138 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | 147 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); |
@@ -239,12 +248,21 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
239 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 248 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
240 | struct ath_wiphy *aphy = hw->priv; | 249 | struct ath_wiphy *aphy = hw->priv; |
241 | struct ath_softc *sc = aphy->sc; | 250 | struct ath_softc *sc = aphy->sc; |
251 | u32 val; | ||
242 | int err; | 252 | int err; |
243 | 253 | ||
244 | err = pci_enable_device(pdev); | 254 | err = pci_enable_device(pdev); |
245 | if (err) | 255 | if (err) |
246 | return err; | 256 | return err; |
247 | pci_restore_state(pdev); | 257 | pci_restore_state(pdev); |
258 | /* | ||
259 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
260 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
261 | * PCI Tx retries from interfering with C3 CPU state | ||
262 | */ | ||
263 | pci_read_config_dword(pdev, 0x40, &val); | ||
264 | if ((val & 0x0000ff00) != 0) | ||
265 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
248 | 266 | ||
249 | /* Enable LED */ | 267 | /* Enable LED */ |
250 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | 268 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f99f3a76df3f..cece1c4c6bda 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -539,11 +539,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
539 | if (ath_beacon_dtim_pending_cab(skb)) { | 539 | if (ath_beacon_dtim_pending_cab(skb)) { |
540 | /* | 540 | /* |
541 | * Remain awake waiting for buffered broadcast/multicast | 541 | * Remain awake waiting for buffered broadcast/multicast |
542 | * frames. | 542 | * frames. If the last broadcast/multicast frame is not |
543 | * received properly, the next beacon frame will work as | ||
544 | * a backup trigger for returning into NETWORK SLEEP state, | ||
545 | * so we are waiting for it as well. | ||
543 | */ | 546 | */ |
544 | DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " | 547 | DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " |
545 | "buffered broadcast/multicast frame(s)\n"); | 548 | "buffered broadcast/multicast frame(s)\n"); |
546 | sc->sc_flags |= SC_OP_WAIT_FOR_CAB; | 549 | sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; |
547 | return; | 550 | return; |
548 | } | 551 | } |
549 | 552 | ||
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; | |||
315 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, | 316 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, |
316 | struct iwm_if_ops *if_ops); | 317 | struct iwm_if_ops *if_ops); |
317 | void iwm_if_free(struct iwm_priv *iwm); | 318 | void iwm_if_free(struct iwm_priv *iwm); |
319 | int iwm_if_add(struct iwm_priv *iwm); | ||
320 | void iwm_if_remove(struct iwm_priv *iwm); | ||
318 | int iwm_mode_to_nl80211_iftype(int mode); | 321 | int iwm_mode_to_nl80211_iftype(int mode); |
319 | int iwm_priv_init(struct iwm_priv *iwm); | 322 | int iwm_priv_init(struct iwm_priv *iwm); |
323 | void iwm_priv_deinit(struct iwm_priv *iwm); | ||
320 | void iwm_reset(struct iwm_priv *iwm); | 324 | void iwm_reset(struct iwm_priv *iwm); |
321 | void iwm_tx_credit_init_pools(struct iwm_priv *iwm, | 325 | void 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 | ||
115 | int __iwm_up(struct iwm_priv *iwm); | ||
116 | int __iwm_down(struct iwm_priv *iwm); | ||
117 | |||
115 | static void iwm_reset_worker(struct work_struct *work) | 118 | static 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 | ||
156 | static void iwm_watchdog(unsigned long data) | 175 | static 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 | ||
242 | void 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 | ||
514 | int iwm_up(struct iwm_priv *iwm) | 544 | int __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 | ||
650 | int iwm_down(struct iwm_priv *iwm) | 680 | int 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 | |||
691 | int __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 | |||
723 | int 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 | ||
149 | void iwm_if_free(struct iwm_priv *iwm) | 148 | void 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 | |
158 | int 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 | |||
172 | void 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 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index f0e5e943f6e3..14a19baff214 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -67,6 +67,7 @@ static struct usb_device_id usb_ids[] = { | |||
67 | { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, | 67 | { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, |
68 | { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, | 68 | { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, |
69 | { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, | 69 | { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, |
70 | { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, | ||
70 | { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, | 71 | { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, |
71 | { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, | 72 | { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, |
72 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, | 73 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, |