diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2008-10-29 00:47:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:16:06 -0500 |
commit | 9c84b7978f1b99048bf31be5a0218cd509e74148 (patch) | |
tree | 91f60b0986c75c6536c467a475568e33ff757245 /drivers | |
parent | 50fdae2c7bcb6417997f90c3d9853a59a9ed06ce (diff) |
ath9k: Streamline attach/detach
Simplify attach and detach routines by consolidating
the stop and suspend functions.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath9k/core.c | 218 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 185 |
3 files changed, 158 insertions, 248 deletions
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index b45953f35417..1826818c7b45 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c | |||
@@ -186,17 +186,10 @@ static int ath_setup_channels(struct ath_softc *sc) | |||
186 | struct ath9k_channel *c; | 186 | struct ath9k_channel *c; |
187 | 187 | ||
188 | /* Fill in ah->ah_channels */ | 188 | /* Fill in ah->ah_channels */ |
189 | if (!ath9k_regd_init_channels(ah, | 189 | if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, |
190 | ATH_CHAN_MAX, | 190 | regclassids, ATH_REGCLASSIDS_MAX, |
191 | (u32 *)&nchan, | 191 | &nregclass, CTRY_DEFAULT, false, 1)) { |
192 | regclassids, | ||
193 | ATH_REGCLASSIDS_MAX, | ||
194 | &nregclass, | ||
195 | CTRY_DEFAULT, | ||
196 | false, | ||
197 | 1)) { | ||
198 | u32 rd = ah->ah_currentRD; | 192 | u32 rd = ah->ah_currentRD; |
199 | |||
200 | DPRINTF(sc, ATH_DBG_FATAL, | 193 | DPRINTF(sc, ATH_DBG_FATAL, |
201 | "%s: unable to collect channel list; " | 194 | "%s: unable to collect channel list; " |
202 | "regdomain likely %u country code %u\n", | 195 | "regdomain likely %u country code %u\n", |
@@ -217,40 +210,32 @@ static int ath_setup_channels(struct ath_softc *sc) | |||
217 | chan_2ghz[a].max_power = c->maxTxPower; | 210 | chan_2ghz[a].max_power = c->maxTxPower; |
218 | 211 | ||
219 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) | 212 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) |
220 | chan_2ghz[a].flags |= | 213 | chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; |
221 | IEEE80211_CHAN_NO_IBSS; | ||
222 | if (c->channelFlags & CHANNEL_PASSIVE) | 214 | if (c->channelFlags & CHANNEL_PASSIVE) |
223 | chan_2ghz[a].flags |= | 215 | chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; |
224 | IEEE80211_CHAN_PASSIVE_SCAN; | ||
225 | 216 | ||
226 | band_2ghz->n_channels = ++a; | 217 | band_2ghz->n_channels = ++a; |
227 | 218 | ||
228 | DPRINTF(sc, ATH_DBG_CONFIG, | 219 | DPRINTF(sc, ATH_DBG_CONFIG, |
229 | "%s: 2MHz channel: %d, " | 220 | "%s: 2MHz channel: %d, " |
230 | "channelFlags: 0x%x\n", | 221 | "channelFlags: 0x%x\n", |
231 | __func__, | 222 | __func__, c->channel, c->channelFlags); |
232 | c->channel, | ||
233 | c->channelFlags); | ||
234 | } else if (IS_CHAN_5GHZ(c)) { | 223 | } else if (IS_CHAN_5GHZ(c)) { |
235 | chan_5ghz[b].band = IEEE80211_BAND_5GHZ; | 224 | chan_5ghz[b].band = IEEE80211_BAND_5GHZ; |
236 | chan_5ghz[b].center_freq = c->channel; | 225 | chan_5ghz[b].center_freq = c->channel; |
237 | chan_5ghz[b].max_power = c->maxTxPower; | 226 | chan_5ghz[b].max_power = c->maxTxPower; |
238 | 227 | ||
239 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) | 228 | if (c->privFlags & CHANNEL_DISALLOW_ADHOC) |
240 | chan_5ghz[b].flags |= | 229 | chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; |
241 | IEEE80211_CHAN_NO_IBSS; | ||
242 | if (c->channelFlags & CHANNEL_PASSIVE) | 230 | if (c->channelFlags & CHANNEL_PASSIVE) |
243 | chan_5ghz[b].flags |= | 231 | chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; |
244 | IEEE80211_CHAN_PASSIVE_SCAN; | ||
245 | 232 | ||
246 | band_5ghz->n_channels = ++b; | 233 | band_5ghz->n_channels = ++b; |
247 | 234 | ||
248 | DPRINTF(sc, ATH_DBG_CONFIG, | 235 | DPRINTF(sc, ATH_DBG_CONFIG, |
249 | "%s: 5MHz channel: %d, " | 236 | "%s: 5MHz channel: %d, " |
250 | "channelFlags: 0x%x\n", | 237 | "channelFlags: 0x%x\n", |
251 | __func__, | 238 | __func__, c->channel, c->channelFlags); |
252 | c->channel, | ||
253 | c->channelFlags); | ||
254 | } | 239 | } |
255 | } | 240 | } |
256 | 241 | ||
@@ -292,44 +277,6 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) | |||
292 | } | 277 | } |
293 | 278 | ||
294 | /* | 279 | /* |
295 | * Stop the device, grabbing the top-level lock to protect | ||
296 | * against concurrent entry through ath_init (which can happen | ||
297 | * if another thread does a system call and the thread doing the | ||
298 | * stop is preempted). | ||
299 | */ | ||
300 | |||
301 | static int ath_stop(struct ath_softc *sc) | ||
302 | { | ||
303 | struct ath_hal *ah = sc->sc_ah; | ||
304 | |||
305 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", | ||
306 | __func__, sc->sc_flags & SC_OP_INVALID); | ||
307 | |||
308 | /* | ||
309 | * Shutdown the hardware and driver: | ||
310 | * stop output from above | ||
311 | * turn off timers | ||
312 | * disable interrupts | ||
313 | * clear transmit machinery | ||
314 | * clear receive machinery | ||
315 | * turn off the radio | ||
316 | * reclaim beacon resources | ||
317 | * | ||
318 | * Note that some of this work is not possible if the | ||
319 | * hardware is gone (invalid). | ||
320 | */ | ||
321 | |||
322 | ath_draintxq(sc, false); | ||
323 | if (!(sc->sc_flags & SC_OP_INVALID)) { | ||
324 | ath_stoprecv(sc); | ||
325 | ath9k_hw_phy_disable(ah); | ||
326 | } else | ||
327 | sc->sc_rxlink = NULL; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Set the current channel | 280 | * Set the current channel |
334 | * | 281 | * |
335 | * Set/change channels. If the channel is really being changed, it's done | 282 | * Set/change channels. If the channel is really being changed, it's done |
@@ -650,16 +597,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
650 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", | 597 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", |
651 | __func__, sc->sc_ah->ah_opmode); | 598 | __func__, sc->sc_ah->ah_opmode); |
652 | 599 | ||
653 | /* | ||
654 | * Stop anything previously setup. This is safe | ||
655 | * whether this is the first time through or not. | ||
656 | */ | ||
657 | ath_stop(sc); | ||
658 | |||
659 | /* Initialize chanmask selection */ | ||
660 | sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; | ||
661 | sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; | ||
662 | |||
663 | /* Reset SERDES registers */ | 600 | /* Reset SERDES registers */ |
664 | ath9k_hw_configpcipowersave(ah, 0); | 601 | ath9k_hw_configpcipowersave(ah, 0); |
665 | 602 | ||
@@ -685,6 +622,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
685 | goto done; | 622 | goto done; |
686 | } | 623 | } |
687 | spin_unlock_bh(&sc->sc_resetlock); | 624 | spin_unlock_bh(&sc->sc_resetlock); |
625 | |||
688 | /* | 626 | /* |
689 | * This is needed only to setup initial state | 627 | * This is needed only to setup initial state |
690 | * but it's best done after a reset. | 628 | * but it's best done after a reset. |
@@ -704,6 +642,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
704 | error = -EIO; | 642 | error = -EIO; |
705 | goto done; | 643 | goto done; |
706 | } | 644 | } |
645 | |||
707 | /* Setup our intr mask. */ | 646 | /* Setup our intr mask. */ |
708 | sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX | 647 | sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX |
709 | | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | 648 | | ATH9K_INT_RXEOL | ATH9K_INT_RXORN |
@@ -733,30 +672,61 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
733 | (sc->sc_ah->ah_opmode == ATH9K_M_STA) && | 672 | (sc->sc_ah->ah_opmode == ATH9K_M_STA) && |
734 | !sc->sc_config.swBeaconProcess) | 673 | !sc->sc_config.swBeaconProcess) |
735 | sc->sc_imask |= ATH9K_INT_TIM; | 674 | sc->sc_imask |= ATH9K_INT_TIM; |
675 | |||
676 | ath_setcurmode(sc, ath_chan2mode(initial_chan)); | ||
677 | |||
736 | /* | 678 | /* |
737 | * Don't enable interrupts here as we've not yet built our | 679 | * Don't enable interrupts here as we've not yet built our |
738 | * vap and node data structures, which will be needed as soon | 680 | * vap and node data structures, which will be needed as soon |
739 | * as we start receiving. | 681 | * as we start receiving. |
740 | */ | 682 | */ |
741 | ath_setcurmode(sc, ath_chan2mode(initial_chan)); | ||
742 | |||
743 | /* XXX: we must make sure h/w is ready and clear invalid flag | ||
744 | * before turning on interrupt. */ | ||
745 | sc->sc_flags &= ~SC_OP_INVALID; | 683 | sc->sc_flags &= ~SC_OP_INVALID; |
684 | |||
685 | ieee80211_wake_queues(sc->hw); | ||
746 | done: | 686 | done: |
747 | return error; | 687 | return error; |
748 | } | 688 | } |
749 | 689 | ||
690 | void ath_stop(struct ath_softc *sc) | ||
691 | { | ||
692 | struct ath_hal *ah = sc->sc_ah; | ||
693 | |||
694 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Cleaning up\n", __func__); | ||
695 | |||
696 | ieee80211_stop_queues(sc->hw); | ||
697 | |||
698 | /* make sure h/w will not generate any interrupt | ||
699 | * before setting the invalid flag. */ | ||
700 | ath9k_hw_set_interrupts(ah, 0); | ||
701 | |||
702 | if (!(sc->sc_flags & SC_OP_INVALID)) { | ||
703 | ath_draintxq(sc, false); | ||
704 | ath_stoprecv(sc); | ||
705 | ath9k_hw_phy_disable(ah); | ||
706 | } else | ||
707 | sc->sc_rxlink = NULL; | ||
708 | |||
709 | #ifdef CONFIG_RFKILL | ||
710 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
711 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
712 | #endif | ||
713 | /* disable HAL and put h/w to sleep */ | ||
714 | ath9k_hw_disable(sc->sc_ah); | ||
715 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | ||
716 | |||
717 | sc->sc_flags |= SC_OP_INVALID; | ||
718 | } | ||
719 | |||
750 | int ath_reset(struct ath_softc *sc, bool retry_tx) | 720 | int ath_reset(struct ath_softc *sc, bool retry_tx) |
751 | { | 721 | { |
752 | struct ath_hal *ah = sc->sc_ah; | 722 | struct ath_hal *ah = sc->sc_ah; |
753 | int status; | 723 | int status; |
754 | int error = 0; | 724 | int error = 0; |
755 | 725 | ||
756 | ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ | 726 | ath9k_hw_set_interrupts(ah, 0); |
757 | ath_draintxq(sc, retry_tx); /* stop xmit */ | 727 | ath_draintxq(sc, retry_tx); |
758 | ath_stoprecv(sc); /* stop recv */ | 728 | ath_stoprecv(sc); |
759 | ath_flushrecv(sc); /* flush recv queue */ | 729 | ath_flushrecv(sc); |
760 | 730 | ||
761 | /* Reset chip */ | 731 | /* Reset chip */ |
762 | spin_lock_bh(&sc->sc_resetlock); | 732 | spin_lock_bh(&sc->sc_resetlock); |
@@ -771,7 +741,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
771 | } | 741 | } |
772 | spin_unlock_bh(&sc->sc_resetlock); | 742 | spin_unlock_bh(&sc->sc_resetlock); |
773 | 743 | ||
774 | if (ath_startrecv(sc) != 0) /* restart recv */ | 744 | if (ath_startrecv(sc) != 0) |
775 | DPRINTF(sc, ATH_DBG_FATAL, | 745 | DPRINTF(sc, ATH_DBG_FATAL, |
776 | "%s: unable to start recv logic\n", __func__); | 746 | "%s: unable to start recv logic\n", __func__); |
777 | 747 | ||
@@ -804,29 +774,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
804 | return error; | 774 | return error; |
805 | } | 775 | } |
806 | 776 | ||
807 | int ath_suspend(struct ath_softc *sc) | ||
808 | { | ||
809 | struct ath_hal *ah = sc->sc_ah; | ||
810 | |||
811 | /* No I/O if device has been surprise removed */ | ||
812 | if (sc->sc_flags & SC_OP_INVALID) | ||
813 | return -EIO; | ||
814 | |||
815 | /* Shut off the interrupt before setting sc->sc_invalid to '1' */ | ||
816 | ath9k_hw_set_interrupts(ah, 0); | ||
817 | |||
818 | /* XXX: we must make sure h/w will not generate any interrupt | ||
819 | * before setting the invalid flag. */ | ||
820 | sc->sc_flags |= SC_OP_INVALID; | ||
821 | |||
822 | /* disable HAL and put h/w to sleep */ | ||
823 | ath9k_hw_disable(sc->sc_ah); | ||
824 | |||
825 | ath9k_hw_configpcipowersave(sc->sc_ah, 1); | ||
826 | |||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | /* Interrupt handler. Most of the actual processing is deferred. | 777 | /* Interrupt handler. Most of the actual processing is deferred. |
831 | * It's the caller's responsibility to ensure the chip is awake. */ | 778 | * It's the caller's responsibility to ensure the chip is awake. */ |
832 | 779 | ||
@@ -994,11 +941,9 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
994 | 941 | ||
995 | /* XXX: hardware will not be ready until ath_open() being called */ | 942 | /* XXX: hardware will not be ready until ath_open() being called */ |
996 | sc->sc_flags |= SC_OP_INVALID; | 943 | sc->sc_flags |= SC_OP_INVALID; |
997 | |||
998 | sc->sc_debug = DBG_DEFAULT; | 944 | sc->sc_debug = DBG_DEFAULT; |
999 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); | ||
1000 | 945 | ||
1001 | /* Initialize tasklet */ | 946 | spin_lock_init(&sc->sc_resetlock); |
1002 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 947 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
1003 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, | 948 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, |
1004 | (unsigned long)sc); | 949 | (unsigned long)sc); |
@@ -1011,8 +956,6 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1011 | /* XXX assert csz is non-zero */ | 956 | /* XXX assert csz is non-zero */ |
1012 | sc->sc_cachelsz = csz << 2; /* convert to bytes */ | 957 | sc->sc_cachelsz = csz << 2; /* convert to bytes */ |
1013 | 958 | ||
1014 | spin_lock_init(&sc->sc_resetlock); | ||
1015 | |||
1016 | ah = ath9k_hw_attach(devid, sc, sc->mem, &status); | 959 | ah = ath9k_hw_attach(devid, sc, sc->mem, &status); |
1017 | if (ah == NULL) { | 960 | if (ah == NULL) { |
1018 | DPRINTF(sc, ATH_DBG_FATAL, | 961 | DPRINTF(sc, ATH_DBG_FATAL, |
@@ -1023,10 +966,6 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1023 | } | 966 | } |
1024 | sc->sc_ah = ah; | 967 | sc->sc_ah = ah; |
1025 | 968 | ||
1026 | /* Initializes the noise floor to a reasonable default value. | ||
1027 | * Later on this will be updated during ANI processing. */ | ||
1028 | sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; | ||
1029 | |||
1030 | /* Get the hardware key cache size. */ | 969 | /* Get the hardware key cache size. */ |
1031 | sc->sc_keymax = ah->ah_caps.keycache_size; | 970 | sc->sc_keymax = ah->ah_caps.keycache_size; |
1032 | if (sc->sc_keymax > ATH_KEYMAX) { | 971 | if (sc->sc_keymax > ATH_KEYMAX) { |
@@ -1054,17 +993,14 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1054 | set_bit(i + 64, sc->sc_keymap); | 993 | set_bit(i + 64, sc->sc_keymap); |
1055 | set_bit(i + 32 + 64, sc->sc_keymap); | 994 | set_bit(i + 32 + 64, sc->sc_keymap); |
1056 | } | 995 | } |
1057 | /* | 996 | |
1058 | * Collect the channel list using the default country | 997 | /* Collect the channel list using the default country code */ |
1059 | * code and including outdoor channels. The 802.11 layer | 998 | |
1060 | * is resposible for filtering this list based on settings | ||
1061 | * like the phy mode. | ||
1062 | */ | ||
1063 | error = ath_setup_channels(sc); | 999 | error = ath_setup_channels(sc); |
1064 | if (error) | 1000 | if (error) |
1065 | goto bad; | 1001 | goto bad; |
1066 | 1002 | ||
1067 | /* default to STA mode */ | 1003 | /* default to MONITOR mode */ |
1068 | sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; | 1004 | sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; |
1069 | 1005 | ||
1070 | /* Setup rate tables */ | 1006 | /* Setup rate tables */ |
@@ -1134,6 +1070,10 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1134 | goto bad2; | 1070 | goto bad2; |
1135 | } | 1071 | } |
1136 | 1072 | ||
1073 | /* Initializes the noise floor to a reasonable default value. | ||
1074 | * Later on this will be updated during ANI processing. */ | ||
1075 | |||
1076 | sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; | ||
1137 | setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); | 1077 | setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); |
1138 | 1078 | ||
1139 | sc->sc_rc = ath_rate_attach(ah); | 1079 | sc->sc_rc = ath_rate_attach(ah); |
@@ -1194,6 +1134,7 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1194 | ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); | 1134 | ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); |
1195 | ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); | 1135 | ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); |
1196 | } | 1136 | } |
1137 | |||
1197 | sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ | 1138 | sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ |
1198 | 1139 | ||
1199 | /* initialize beacon slots */ | 1140 | /* initialize beacon slots */ |
@@ -1208,6 +1149,22 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1208 | ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); | 1149 | ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); |
1209 | #endif | 1150 | #endif |
1210 | 1151 | ||
1152 | /* setup channels and rates */ | ||
1153 | |||
1154 | sc->sbands[IEEE80211_BAND_2GHZ].channels = | ||
1155 | sc->channels[IEEE80211_BAND_2GHZ]; | ||
1156 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = | ||
1157 | sc->rates[IEEE80211_BAND_2GHZ]; | ||
1158 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
1159 | |||
1160 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { | ||
1161 | sc->sbands[IEEE80211_BAND_5GHZ].channels = | ||
1162 | sc->channels[IEEE80211_BAND_5GHZ]; | ||
1163 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
1164 | sc->rates[IEEE80211_BAND_5GHZ]; | ||
1165 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; | ||
1166 | } | ||
1167 | |||
1211 | return 0; | 1168 | return 0; |
1212 | bad2: | 1169 | bad2: |
1213 | /* cleanup tx queues */ | 1170 | /* cleanup tx queues */ |
@@ -1217,27 +1174,8 @@ bad2: | |||
1217 | bad: | 1174 | bad: |
1218 | if (ah) | 1175 | if (ah) |
1219 | ath9k_hw_detach(ah); | 1176 | ath9k_hw_detach(ah); |
1220 | return error; | ||
1221 | } | ||
1222 | |||
1223 | void ath_deinit(struct ath_softc *sc) | ||
1224 | { | ||
1225 | struct ath_hal *ah = sc->sc_ah; | ||
1226 | int i; | ||
1227 | 1177 | ||
1228 | DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); | 1178 | return error; |
1229 | |||
1230 | tasklet_kill(&sc->intr_tq); | ||
1231 | tasklet_kill(&sc->bcon_tasklet); | ||
1232 | ath_stop(sc); | ||
1233 | if (!(sc->sc_flags & SC_OP_INVALID)) | ||
1234 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | ||
1235 | ath_rate_detach(sc->sc_rc); | ||
1236 | /* cleanup tx queues */ | ||
1237 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
1238 | if (ATH_TXQ_SETUP(sc, i)) | ||
1239 | ath_tx_cleanupq(sc, &sc->sc_txq[i]); | ||
1240 | ath9k_hw_detach(ah); | ||
1241 | } | 1179 | } |
1242 | 1180 | ||
1243 | /*******************/ | 1181 | /*******************/ |
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index fdaecb1e326b..49d2f894b9dc 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h | |||
@@ -997,9 +997,8 @@ struct ath_softc { | |||
997 | }; | 997 | }; |
998 | 998 | ||
999 | int ath_init(u16 devid, struct ath_softc *sc); | 999 | int ath_init(u16 devid, struct ath_softc *sc); |
1000 | void ath_deinit(struct ath_softc *sc); | ||
1001 | int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); | 1000 | int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); |
1002 | int ath_suspend(struct ath_softc *sc); | 1001 | void ath_stop(struct ath_softc *sc); |
1003 | irqreturn_t ath_isr(int irq, void *dev); | 1002 | irqreturn_t ath_isr(int irq, void *dev); |
1004 | int ath_reset(struct ath_softc *sc, bool retry_tx); | 1003 | int ath_reset(struct ath_softc *sc, bool retry_tx); |
1005 | int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); | 1004 | int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 0194e44034e0..0d6000205548 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -616,6 +616,7 @@ fail: | |||
616 | } | 616 | } |
617 | 617 | ||
618 | #ifdef CONFIG_RFKILL | 618 | #ifdef CONFIG_RFKILL |
619 | |||
619 | /*******************/ | 620 | /*******************/ |
620 | /* Rfkill */ | 621 | /* Rfkill */ |
621 | /*******************/ | 622 | /*******************/ |
@@ -816,43 +817,72 @@ static void ath_deinit_rfkill(struct ath_softc *sc) | |||
816 | sc->rf_kill.rfkill = NULL; | 817 | sc->rf_kill.rfkill = NULL; |
817 | } | 818 | } |
818 | } | 819 | } |
820 | |||
821 | static int ath_start_rfkill_poll(struct ath_softc *sc) | ||
822 | { | ||
823 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
824 | queue_delayed_work(sc->hw->workqueue, | ||
825 | &sc->rf_kill.rfkill_poll, 0); | ||
826 | |||
827 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | ||
828 | if (rfkill_register(sc->rf_kill.rfkill)) { | ||
829 | DPRINTF(sc, ATH_DBG_FATAL, | ||
830 | "Unable to register rfkill\n"); | ||
831 | rfkill_free(sc->rf_kill.rfkill); | ||
832 | |||
833 | /* Deinitialize the device */ | ||
834 | if (sc->pdev->irq) | ||
835 | free_irq(sc->pdev->irq, sc); | ||
836 | ath_detach(sc); | ||
837 | pci_iounmap(sc->pdev, sc->mem); | ||
838 | pci_release_region(sc->pdev, 0); | ||
839 | pci_disable_device(sc->pdev); | ||
840 | ieee80211_free_hw(hw); | ||
841 | return -EIO; | ||
842 | } else { | ||
843 | sc->sc_flags |= SC_OP_RFKILL_REGISTERED; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | return 0; | ||
848 | } | ||
819 | #endif /* CONFIG_RFKILL */ | 849 | #endif /* CONFIG_RFKILL */ |
820 | 850 | ||
821 | static int ath_detach(struct ath_softc *sc) | 851 | static void ath_detach(struct ath_softc *sc) |
822 | { | 852 | { |
823 | struct ieee80211_hw *hw = sc->hw; | 853 | struct ieee80211_hw *hw = sc->hw; |
854 | int i = 0; | ||
824 | 855 | ||
825 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); | 856 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); |
826 | 857 | ||
827 | /* Deinit LED control */ | 858 | ieee80211_unregister_hw(hw); |
859 | |||
828 | ath_deinit_leds(sc); | 860 | ath_deinit_leds(sc); |
829 | 861 | ||
830 | #ifdef CONFIG_RFKILL | 862 | #ifdef CONFIG_RFKILL |
831 | /* deinit rfkill */ | ||
832 | ath_deinit_rfkill(sc); | 863 | ath_deinit_rfkill(sc); |
833 | #endif | 864 | #endif |
834 | |||
835 | /* Unregister hw */ | ||
836 | |||
837 | ieee80211_unregister_hw(hw); | ||
838 | |||
839 | /* unregister Rate control */ | ||
840 | ath_rate_control_unregister(); | 865 | ath_rate_control_unregister(); |
841 | 866 | ath_rate_detach(sc->sc_rc); | |
842 | /* tx/rx cleanup */ | ||
843 | 867 | ||
844 | ath_rx_cleanup(sc); | 868 | ath_rx_cleanup(sc); |
845 | ath_tx_cleanup(sc); | 869 | ath_tx_cleanup(sc); |
846 | 870 | ||
847 | /* Deinit */ | 871 | tasklet_kill(&sc->intr_tq); |
872 | tasklet_kill(&sc->bcon_tasklet); | ||
848 | 873 | ||
849 | ath_deinit(sc); | 874 | if (!(sc->sc_flags & SC_OP_INVALID)) |
875 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); | ||
850 | 876 | ||
851 | return 0; | 877 | /* cleanup tx queues */ |
878 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
879 | if (ATH_TXQ_SETUP(sc, i)) | ||
880 | ath_tx_cleanupq(sc, &sc->sc_txq[i]); | ||
881 | |||
882 | ath9k_hw_detach(sc->sc_ah); | ||
852 | } | 883 | } |
853 | 884 | ||
854 | static int ath_attach(u16 devid, | 885 | static int ath_attach(u16 devid, struct ath_softc *sc) |
855 | struct ath_softc *sc) | ||
856 | { | 886 | { |
857 | struct ieee80211_hw *hw = sc->hw; | 887 | struct ieee80211_hw *hw = sc->hw; |
858 | int error = 0; | 888 | int error = 0; |
@@ -867,36 +897,15 @@ static int ath_attach(u16 devid, | |||
867 | 897 | ||
868 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); | 898 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); |
869 | 899 | ||
870 | /* setup channels and rates */ | 900 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | |
871 | 901 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | |
872 | sc->sbands[IEEE80211_BAND_2GHZ].channels = | 902 | IEEE80211_HW_SIGNAL_DBM | |
873 | sc->channels[IEEE80211_BAND_2GHZ]; | 903 | IEEE80211_HW_AMPDU_AGGREGATION; |
874 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = | ||
875 | sc->rates[IEEE80211_BAND_2GHZ]; | ||
876 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
877 | |||
878 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
879 | /* Setup HT capabilities for 2.4Ghz*/ | ||
880 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||
881 | |||
882 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
883 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
884 | |||
885 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { | ||
886 | sc->sbands[IEEE80211_BAND_5GHZ].channels = | ||
887 | sc->channels[IEEE80211_BAND_5GHZ]; | ||
888 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
889 | sc->rates[IEEE80211_BAND_5GHZ]; | ||
890 | sc->sbands[IEEE80211_BAND_5GHZ].band = | ||
891 | IEEE80211_BAND_5GHZ; | ||
892 | |||
893 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | ||
894 | /* Setup HT capabilities for 5Ghz*/ | ||
895 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | ||
896 | 904 | ||
897 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | 905 | hw->wiphy->interface_modes = |
898 | &sc->sbands[IEEE80211_BAND_5GHZ]; | 906 | BIT(NL80211_IFTYPE_AP) | |
899 | } | 907 | BIT(NL80211_IFTYPE_STATION) | |
908 | BIT(NL80211_IFTYPE_ADHOC); | ||
900 | 909 | ||
901 | hw->queues = 4; | 910 | hw->queues = 4; |
902 | hw->sta_data_size = sizeof(struct ath_node); | 911 | hw->sta_data_size = sizeof(struct ath_node); |
@@ -913,6 +922,17 @@ static int ath_attach(u16 devid, | |||
913 | goto bad; | 922 | goto bad; |
914 | } | 923 | } |
915 | 924 | ||
925 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
926 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||
927 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) | ||
928 | setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | ||
929 | } | ||
930 | |||
931 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
932 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) | ||
933 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
934 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
935 | |||
916 | error = ieee80211_register_hw(hw); | 936 | error = ieee80211_register_hw(hw); |
917 | if (error != 0) { | 937 | if (error != 0) { |
918 | ath_rate_control_unregister(); | 938 | ath_rate_control_unregister(); |
@@ -963,49 +983,26 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
963 | pos = ath_get_channel(sc, curchan); | 983 | pos = ath_get_channel(sc, curchan); |
964 | if (pos == -1) { | 984 | if (pos == -1) { |
965 | DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); | 985 | DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); |
966 | return -EINVAL; | 986 | error = -EINVAL; |
987 | goto exit; | ||
967 | } | 988 | } |
968 | 989 | ||
969 | sc->sc_ah->ah_channels[pos].chanmode = | 990 | sc->sc_ah->ah_channels[pos].chanmode = |
970 | (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; | 991 | (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; |
971 | 992 | ||
972 | /* open ath_dev */ | ||
973 | error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); | 993 | error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); |
974 | if (error) { | 994 | if (error) { |
975 | DPRINTF(sc, ATH_DBG_FATAL, | 995 | DPRINTF(sc, ATH_DBG_FATAL, |
976 | "%s: Unable to complete ath_open\n", __func__); | 996 | "%s: Unable to complete ath_open\n", __func__); |
977 | return error; | 997 | goto exit; |
978 | } | 998 | } |
979 | 999 | ||
980 | #ifdef CONFIG_RFKILL | 1000 | #ifdef CONFIG_RFKILL |
981 | /* Start rfkill polling */ | 1001 | error = ath_start_rfkill_poll(sc); |
982 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
983 | queue_delayed_work(sc->hw->workqueue, | ||
984 | &sc->rf_kill.rfkill_poll, 0); | ||
985 | |||
986 | if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { | ||
987 | if (rfkill_register(sc->rf_kill.rfkill)) { | ||
988 | DPRINTF(sc, ATH_DBG_FATAL, | ||
989 | "Unable to register rfkill\n"); | ||
990 | rfkill_free(sc->rf_kill.rfkill); | ||
991 | |||
992 | /* Deinitialize the device */ | ||
993 | if (sc->pdev->irq) | ||
994 | free_irq(sc->pdev->irq, sc); | ||
995 | ath_detach(sc); | ||
996 | pci_iounmap(sc->pdev, sc->mem); | ||
997 | pci_release_region(sc->pdev, 0); | ||
998 | pci_disable_device(sc->pdev); | ||
999 | ieee80211_free_hw(hw); | ||
1000 | return -EIO; | ||
1001 | } else { | ||
1002 | sc->sc_flags |= SC_OP_RFKILL_REGISTERED; | ||
1003 | } | ||
1004 | } | ||
1005 | #endif | 1002 | #endif |
1006 | 1003 | ||
1007 | ieee80211_wake_queues(hw); | 1004 | exit: |
1008 | return 0; | 1005 | return error; |
1009 | } | 1006 | } |
1010 | 1007 | ||
1011 | static int ath9k_tx(struct ieee80211_hw *hw, | 1008 | static int ath9k_tx(struct ieee80211_hw *hw, |
@@ -1065,21 +1062,15 @@ exit: | |||
1065 | static void ath9k_stop(struct ieee80211_hw *hw) | 1062 | static void ath9k_stop(struct ieee80211_hw *hw) |
1066 | { | 1063 | { |
1067 | struct ath_softc *sc = hw->priv; | 1064 | struct ath_softc *sc = hw->priv; |
1068 | int error; | ||
1069 | 1065 | ||
1070 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); | 1066 | if (sc->sc_flags & SC_OP_INVALID) { |
1071 | 1067 | DPRINTF(sc, ATH_DBG_ANY, "%s: Device not present\n", __func__); | |
1072 | error = ath_suspend(sc); | 1068 | return; |
1073 | if (error) | 1069 | } |
1074 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
1075 | "%s: Device is no longer present\n", __func__); | ||
1076 | 1070 | ||
1077 | ieee80211_stop_queues(hw); | 1071 | ath_stop(sc); |
1078 | 1072 | ||
1079 | #ifdef CONFIG_RFKILL | 1073 | DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); |
1080 | if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1081 | cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); | ||
1082 | #endif | ||
1083 | } | 1074 | } |
1084 | 1075 | ||
1085 | static int ath9k_add_interface(struct ieee80211_hw *hw, | 1076 | static int ath9k_add_interface(struct ieee80211_hw *hw, |
@@ -1643,17 +1634,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1643 | goto bad2; | 1634 | goto bad2; |
1644 | } | 1635 | } |
1645 | 1636 | ||
1646 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | ||
1647 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
1648 | IEEE80211_HW_SIGNAL_DBM | | ||
1649 | IEEE80211_HW_NOISE_DBM | | ||
1650 | IEEE80211_HW_AMPDU_AGGREGATION; | ||
1651 | |||
1652 | hw->wiphy->interface_modes = | ||
1653 | BIT(NL80211_IFTYPE_AP) | | ||
1654 | BIT(NL80211_IFTYPE_STATION) | | ||
1655 | BIT(NL80211_IFTYPE_ADHOC); | ||
1656 | |||
1657 | SET_IEEE80211_DEV(hw, &pdev->dev); | 1637 | SET_IEEE80211_DEV(hw, &pdev->dev); |
1658 | pci_set_drvdata(pdev, hw); | 1638 | pci_set_drvdata(pdev, hw); |
1659 | 1639 | ||
@@ -1701,17 +1681,10 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
1701 | { | 1681 | { |
1702 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 1682 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
1703 | struct ath_softc *sc = hw->priv; | 1683 | struct ath_softc *sc = hw->priv; |
1704 | enum ath9k_int status; | ||
1705 | 1684 | ||
1706 | if (pdev->irq) { | ||
1707 | ath9k_hw_set_interrupts(sc->sc_ah, 0); | ||
1708 | /* clear the ISR */ | ||
1709 | ath9k_hw_getisr(sc->sc_ah, &status); | ||
1710 | sc->sc_flags |= SC_OP_INVALID; | ||
1711 | free_irq(pdev->irq, sc); | ||
1712 | } | ||
1713 | ath_detach(sc); | 1685 | ath_detach(sc); |
1714 | 1686 | if (pdev->irq) | |
1687 | free_irq(pdev->irq, sc); | ||
1715 | pci_iounmap(pdev, sc->mem); | 1688 | pci_iounmap(pdev, sc->mem); |
1716 | pci_release_region(pdev, 0); | 1689 | pci_release_region(pdev, 0); |
1717 | pci_disable_device(pdev); | 1690 | pci_disable_device(pdev); |