diff options
| author | John W. Linville <linville@tuxdriver.com> | 2011-01-05 16:06:25 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2011-01-05 16:06:25 -0500 |
| commit | c96e96354a6c9456cdf1f150eca504e2ea35301e (patch) | |
| tree | 751bec601fb8152116b8e31e0f1f83d687a37d6f /drivers/net/wireless/ath/ath9k | |
| parent | dbbe68bb12b34f3e450da7a73c20e6fa1f85d63a (diff) | |
| parent | 33af88138b859f515b365a074e0a014d7cdbf846 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
net/bluetooth/Makefile
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
24 files changed, 623 insertions, 420 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index fdb5a835fdcf..f8a7771faee2 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | int modparam_force_new_ani; | 23 | int modparam_force_new_ani; |
| 24 | module_param_named(force_new_ani, modparam_force_new_ani, int, 0444); | 24 | module_param_named(force_new_ani, modparam_force_new_ani, int, 0444); |
| 25 | MODULE_PARM_DESC(nohwcrypt, "Force new ANI for AR5008, AR9001, AR9002"); | 25 | MODULE_PARM_DESC(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002"); |
| 26 | 26 | ||
| 27 | /* General hardware code for the A5008/AR9001/AR9002 hadware families */ | 27 | /* General hardware code for the A5008/AR9001/AR9002 hadware families */ |
| 28 | 28 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 7ae66a889f5a..7d68d61e406b 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c | |||
| @@ -203,13 +203,14 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, | |||
| 203 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { | 203 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { |
| 204 | cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); | 204 | cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); |
| 205 | 205 | ||
| 206 | if (AR_NO_SPUR == cur_bb_spur) | ||
| 207 | break; | ||
| 208 | |||
| 206 | if (is2GHz) | 209 | if (is2GHz) |
| 207 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; | 210 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; |
| 208 | else | 211 | else |
| 209 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; | 212 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; |
| 210 | 213 | ||
| 211 | if (AR_NO_SPUR == cur_bb_spur) | ||
| 212 | break; | ||
| 213 | cur_bb_spur = cur_bb_spur - freq; | 214 | cur_bb_spur = cur_bb_spur - freq; |
| 214 | 215 | ||
| 215 | if (IS_CHAN_HT40(chan)) { | 216 | if (IS_CHAN_HT40(chan)) { |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 466d2bf02eab..4819747fa4c3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | |||
| @@ -59,6 +59,8 @@ | |||
| 59 | 59 | ||
| 60 | #define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6)) | 60 | #define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6)) |
| 61 | 61 | ||
| 62 | #define EEPROM_DATA_LEN_9485 1088 | ||
| 63 | |||
| 62 | static int ar9003_hw_power_interpolate(int32_t x, | 64 | static int ar9003_hw_power_interpolate(int32_t x, |
| 63 | int32_t *px, int32_t *py, u_int16_t np); | 65 | int32_t *px, int32_t *py, u_int16_t np); |
| 64 | 66 | ||
| @@ -3368,7 +3370,7 @@ found: | |||
| 3368 | "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", | 3370 | "Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n", |
| 3369 | cptr, code, reference, length, major, minor); | 3371 | cptr, code, reference, length, major, minor); |
| 3370 | if ((!AR_SREV_9485(ah) && length >= 1024) || | 3372 | if ((!AR_SREV_9485(ah) && length >= 1024) || |
| 3371 | (AR_SREV_9485(ah) && length >= (4 * 1024))) { | 3373 | (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) { |
| 3372 | ath_dbg(common, ATH_DBG_EEPROM, | 3374 | ath_dbg(common, ATH_DBG_EEPROM, |
| 3373 | "Skipping bad header\n"); | 3375 | "Skipping bad header\n"); |
| 3374 | cptr -= COMP_HDR_LEN; | 3376 | cptr -= COMP_HDR_LEN; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index b6e4ee48ef78..4ceddbbdfcee 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
| @@ -613,9 +613,9 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |||
| 613 | * possibly be reviewing the last subframe. AR_CRCErr | 613 | * possibly be reviewing the last subframe. AR_CRCErr |
| 614 | * is the CRC of the actual data. | 614 | * is the CRC of the actual data. |
| 615 | */ | 615 | */ |
| 616 | if (rxsp->status11 & AR_CRCErr) { | 616 | if (rxsp->status11 & AR_CRCErr) |
| 617 | rxs->rs_status |= ATH9K_RXERR_CRC; | 617 | rxs->rs_status |= ATH9K_RXERR_CRC; |
| 618 | } else if (rxsp->status11 & AR_PHYErr) { | 618 | if (rxsp->status11 & AR_PHYErr) { |
| 619 | phyerr = MS(rxsp->status11, AR_PHYErrCode); | 619 | phyerr = MS(rxsp->status11, AR_PHYErrCode); |
| 620 | /* | 620 | /* |
| 621 | * If we reach a point here where AR_PostDelimCRCErr is | 621 | * If we reach a point here where AR_PostDelimCRCErr is |
| @@ -638,11 +638,12 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |||
| 638 | rxs->rs_phyerr = phyerr; | 638 | rxs->rs_phyerr = phyerr; |
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | } else if (rxsp->status11 & AR_DecryptCRCErr) { | 641 | } |
| 642 | if (rxsp->status11 & AR_DecryptCRCErr) | ||
| 642 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; | 643 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; |
| 643 | } else if (rxsp->status11 & AR_MichaelErr) { | 644 | if (rxsp->status11 & AR_MichaelErr) |
| 644 | rxs->rs_status |= ATH9K_RXERR_MIC; | 645 | rxs->rs_status |= ATH9K_RXERR_MIC; |
| 645 | } else if (rxsp->status11 & AR_KeyMiss) | 646 | if (rxsp->status11 & AR_KeyMiss) |
| 646 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; | 647 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; |
| 647 | } | 648 | } |
| 648 | 649 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 2c31f5142eda..3681caf54282 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
| @@ -664,11 +664,13 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) | |||
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | extern struct ieee80211_ops ath9k_ops; | 666 | extern struct ieee80211_ops ath9k_ops; |
| 667 | extern int modparam_nohwcrypt; | 667 | extern int ath9k_modparam_nohwcrypt; |
| 668 | extern int led_blink; | 668 | extern int led_blink; |
| 669 | extern int ath9k_pm_qos_value; | 669 | extern int ath9k_pm_qos_value; |
| 670 | extern bool is_ath9k_unloaded; | ||
| 670 | 671 | ||
| 671 | irqreturn_t ath_isr(int irq, void *dev); | 672 | irqreturn_t ath_isr(int irq, void *dev); |
| 673 | void ath9k_init_crypto(struct ath_softc *sc); | ||
| 672 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | 674 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, |
| 673 | const struct ath_bus_ops *bus_ops); | 675 | const struct ath_bus_ops *bus_ops); |
| 674 | void ath9k_deinit_device(struct ath_softc *sc); | 676 | void ath9k_deinit_device(struct ath_softc *sc); |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 5e108c086904..385ba03134ba 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
| @@ -566,8 +566,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
| 566 | * last beacon we received (which may be none). | 566 | * last beacon we received (which may be none). |
| 567 | */ | 567 | */ |
| 568 | dtimperiod = conf->dtim_period; | 568 | dtimperiod = conf->dtim_period; |
| 569 | if (dtimperiod <= 0) /* NB: 0 if not known */ | ||
| 570 | dtimperiod = 1; | ||
| 571 | dtimcount = conf->dtim_count; | 569 | dtimcount = conf->dtim_count; |
| 572 | if (dtimcount >= dtimperiod) /* NB: sanity check */ | 570 | if (dtimcount >= dtimperiod) /* NB: sanity check */ |
| 573 | dtimcount = 0; | 571 | dtimcount = 0; |
| @@ -575,8 +573,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
| 575 | cfpcount = 0; | 573 | cfpcount = 0; |
| 576 | 574 | ||
| 577 | sleepduration = conf->listen_interval * intval; | 575 | sleepduration = conf->listen_interval * intval; |
| 578 | if (sleepduration <= 0) | ||
| 579 | sleepduration = intval; | ||
| 580 | 576 | ||
| 581 | /* | 577 | /* |
| 582 | * Pull nexttbtt forward to reflect the current | 578 | * Pull nexttbtt forward to reflect the current |
| @@ -662,8 +658,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
| 662 | } | 658 | } |
| 663 | 659 | ||
| 664 | static void ath_beacon_config_adhoc(struct ath_softc *sc, | 660 | static void ath_beacon_config_adhoc(struct ath_softc *sc, |
| 665 | struct ath_beacon_config *conf, | 661 | struct ath_beacon_config *conf) |
| 666 | struct ieee80211_vif *vif) | ||
| 667 | { | 662 | { |
| 668 | struct ath_hw *ah = sc->sc_ah; | 663 | struct ath_hw *ah = sc->sc_ah; |
| 669 | struct ath_common *common = ath9k_hw_common(ah); | 664 | struct ath_common *common = ath9k_hw_common(ah); |
| @@ -718,18 +713,17 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
| 718 | /* Setup the beacon configuration parameters */ | 713 | /* Setup the beacon configuration parameters */ |
| 719 | if (vif) { | 714 | if (vif) { |
| 720 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 715 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
| 721 | |||
| 722 | iftype = vif->type; | 716 | iftype = vif->type; |
| 723 | |||
| 724 | cur_conf->beacon_interval = bss_conf->beacon_int; | 717 | cur_conf->beacon_interval = bss_conf->beacon_int; |
| 725 | cur_conf->dtim_period = bss_conf->dtim_period; | 718 | cur_conf->dtim_period = bss_conf->dtim_period; |
| 719 | } else { | ||
| 720 | iftype = sc->sc_ah->opmode; | ||
| 721 | } | ||
| 722 | |||
| 726 | cur_conf->listen_interval = 1; | 723 | cur_conf->listen_interval = 1; |
| 727 | cur_conf->dtim_count = 1; | 724 | cur_conf->dtim_count = 1; |
| 728 | cur_conf->bmiss_timeout = | 725 | cur_conf->bmiss_timeout = |
| 729 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | 726 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; |
| 730 | } else { | ||
| 731 | iftype = sc->sc_ah->opmode; | ||
| 732 | } | ||
| 733 | 727 | ||
| 734 | /* | 728 | /* |
| 735 | * It looks like mac80211 may end up using beacon interval of zero in | 729 | * It looks like mac80211 may end up using beacon interval of zero in |
| @@ -740,13 +734,20 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
| 740 | if (cur_conf->beacon_interval == 0) | 734 | if (cur_conf->beacon_interval == 0) |
| 741 | cur_conf->beacon_interval = 100; | 735 | cur_conf->beacon_interval = 100; |
| 742 | 736 | ||
| 737 | /* | ||
| 738 | * Some times we dont parse dtim period from mac80211, in that case | ||
| 739 | * use a default value | ||
| 740 | */ | ||
| 741 | if (cur_conf->dtim_period == 0) | ||
| 742 | cur_conf->dtim_period = 1; | ||
| 743 | |||
| 743 | switch (iftype) { | 744 | switch (iftype) { |
| 744 | case NL80211_IFTYPE_AP: | 745 | case NL80211_IFTYPE_AP: |
| 745 | ath_beacon_config_ap(sc, cur_conf); | 746 | ath_beacon_config_ap(sc, cur_conf); |
| 746 | break; | 747 | break; |
| 747 | case NL80211_IFTYPE_ADHOC: | 748 | case NL80211_IFTYPE_ADHOC: |
| 748 | case NL80211_IFTYPE_MESH_POINT: | 749 | case NL80211_IFTYPE_MESH_POINT: |
| 749 | ath_beacon_config_adhoc(sc, cur_conf, vif); | 750 | ath_beacon_config_adhoc(sc, cur_conf); |
| 750 | break; | 751 | break; |
| 751 | case NL80211_IFTYPE_STATION: | 752 | case NL80211_IFTYPE_STATION: |
| 752 | ath_beacon_config_sta(sc, cur_conf); | 753 | ath_beacon_config_sta(sc, cur_conf); |
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index f6f09d1378f4..58e2ddc927a9 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | #include <net/cfg80211.h> | 23 | #include <net/cfg80211.h> |
| 24 | #include "ar9003_eeprom.h" | 24 | #include "ar9003_eeprom.h" |
| 25 | 25 | ||
| 26 | #define AH_USE_EEPROM 0x1 | ||
| 27 | |||
| 28 | #ifdef __BIG_ENDIAN | 26 | #ifdef __BIG_ENDIAN |
| 29 | #define AR5416_EEPROM_MAGIC 0x5aa5 | 27 | #define AR5416_EEPROM_MAGIC 0x5aa5 |
| 30 | #else | 28 | #else |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 22b68b3c8566..5ab3084eb9cb 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
| @@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb) | |||
| 153 | case -ENODEV: | 153 | case -ENODEV: |
| 154 | case -ESHUTDOWN: | 154 | case -ESHUTDOWN: |
| 155 | /* | 155 | /* |
| 156 | * The URB has been killed, free the SKBs | 156 | * The URB has been killed, free the SKBs. |
| 157 | * and return. | ||
| 158 | */ | 157 | */ |
| 159 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | 158 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); |
| 160 | return; | 159 | |
| 160 | /* | ||
| 161 | * If the URBs are being flushed, no need to add this | ||
| 162 | * URB to the free list. | ||
| 163 | */ | ||
| 164 | spin_lock(&hif_dev->tx.tx_lock); | ||
| 165 | if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { | ||
| 166 | spin_unlock(&hif_dev->tx.tx_lock); | ||
| 167 | return; | ||
| 168 | } | ||
| 169 | spin_unlock(&hif_dev->tx.tx_lock); | ||
| 170 | |||
| 171 | /* | ||
| 172 | * In the stop() case, this URB has to be added to | ||
| 173 | * the free list. | ||
| 174 | */ | ||
| 175 | goto add_free; | ||
| 161 | default: | 176 | default: |
| 162 | break; | 177 | break; |
| 163 | } | 178 | } |
| 164 | 179 | ||
| 165 | /* Check if TX has been stopped */ | 180 | /* |
| 181 | * Check if TX has been stopped, this is needed because | ||
| 182 | * this CB could have been invoked just after the TX lock | ||
| 183 | * was released in hif_stop() and kill_urb() hasn't been | ||
| 184 | * called yet. | ||
| 185 | */ | ||
| 166 | spin_lock(&hif_dev->tx.tx_lock); | 186 | spin_lock(&hif_dev->tx.tx_lock); |
| 167 | if (hif_dev->tx.flags & HIF_USB_TX_STOP) { | 187 | if (hif_dev->tx.flags & HIF_USB_TX_STOP) { |
| 168 | spin_unlock(&hif_dev->tx.tx_lock); | 188 | spin_unlock(&hif_dev->tx.tx_lock); |
| @@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id) | |||
| 314 | static void hif_usb_stop(void *hif_handle, u8 pipe_id) | 334 | static void hif_usb_stop(void *hif_handle, u8 pipe_id) |
| 315 | { | 335 | { |
| 316 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; | 336 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; |
| 337 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; | ||
| 317 | unsigned long flags; | 338 | unsigned long flags; |
| 318 | 339 | ||
| 319 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | 340 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); |
| @@ -321,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) | |||
| 321 | hif_dev->tx.tx_skb_cnt = 0; | 342 | hif_dev->tx.tx_skb_cnt = 0; |
| 322 | hif_dev->tx.flags |= HIF_USB_TX_STOP; | 343 | hif_dev->tx.flags |= HIF_USB_TX_STOP; |
| 323 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | 344 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); |
| 345 | |||
| 346 | /* The pending URBs have to be canceled. */ | ||
| 347 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, | ||
| 348 | &hif_dev->tx.tx_pending, list) { | ||
| 349 | usb_kill_urb(tx_buf->urb); | ||
| 350 | } | ||
| 324 | } | 351 | } |
| 325 | 352 | ||
| 326 | static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, | 353 | static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, |
| @@ -587,6 +614,7 @@ free: | |||
| 587 | static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) | 614 | static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) |
| 588 | { | 615 | { |
| 589 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; | 616 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; |
| 617 | unsigned long flags; | ||
| 590 | 618 | ||
| 591 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, | 619 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, |
| 592 | &hif_dev->tx.tx_buf, list) { | 620 | &hif_dev->tx.tx_buf, list) { |
| @@ -597,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) | |||
| 597 | kfree(tx_buf); | 625 | kfree(tx_buf); |
| 598 | } | 626 | } |
| 599 | 627 | ||
| 628 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
| 629 | hif_dev->tx.flags |= HIF_USB_TX_FLUSH; | ||
| 630 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
| 631 | |||
| 600 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, | 632 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, |
| 601 | &hif_dev->tx.tx_pending, list) { | 633 | &hif_dev->tx.tx_pending, list) { |
| 602 | usb_kill_urb(tx_buf->urb); | 634 | usb_kill_urb(tx_buf->urb); |
| @@ -993,16 +1025,16 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface) | |||
| 993 | { | 1025 | { |
| 994 | struct usb_device *udev = interface_to_usbdev(interface); | 1026 | struct usb_device *udev = interface_to_usbdev(interface); |
| 995 | struct hif_device_usb *hif_dev = usb_get_intfdata(interface); | 1027 | struct hif_device_usb *hif_dev = usb_get_intfdata(interface); |
| 1028 | bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false; | ||
| 996 | 1029 | ||
| 997 | if (hif_dev) { | 1030 | if (hif_dev) { |
| 998 | ath9k_htc_hw_deinit(hif_dev->htc_handle, | 1031 | ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged); |
| 999 | (udev->state == USB_STATE_NOTATTACHED) ? true : false); | ||
| 1000 | ath9k_htc_hw_free(hif_dev->htc_handle); | 1032 | ath9k_htc_hw_free(hif_dev->htc_handle); |
| 1001 | ath9k_hif_usb_dev_deinit(hif_dev); | 1033 | ath9k_hif_usb_dev_deinit(hif_dev); |
| 1002 | usb_set_intfdata(interface, NULL); | 1034 | usb_set_intfdata(interface, NULL); |
| 1003 | } | 1035 | } |
| 1004 | 1036 | ||
| 1005 | if (hif_dev->flags & HIF_USB_START) | 1037 | if (!unplugged && (hif_dev->flags & HIF_USB_START)) |
| 1006 | ath9k_hif_usb_reboot(udev); | 1038 | ath9k_hif_usb_reboot(udev); |
| 1007 | 1039 | ||
| 1008 | kfree(hif_dev); | 1040 | kfree(hif_dev); |
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index e4a5e2e79541..7b9d863d4035 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h | |||
| @@ -64,6 +64,7 @@ struct tx_buf { | |||
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | #define HIF_USB_TX_STOP BIT(0) | 66 | #define HIF_USB_TX_STOP BIT(0) |
| 67 | #define HIF_USB_TX_FLUSH BIT(1) | ||
| 67 | 68 | ||
| 68 | struct hif_usb_tx { | 69 | struct hif_usb_tx { |
| 69 | u8 flags; | 70 | u8 flags; |
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index fdf9d5fe8cc0..a099b3e87ed3 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
| @@ -331,17 +331,15 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); | |||
| 331 | 331 | ||
| 332 | #define OP_INVALID BIT(0) | 332 | #define OP_INVALID BIT(0) |
| 333 | #define OP_SCANNING BIT(1) | 333 | #define OP_SCANNING BIT(1) |
| 334 | #define OP_FULL_RESET BIT(2) | 334 | #define OP_LED_ASSOCIATED BIT(2) |
| 335 | #define OP_LED_ASSOCIATED BIT(3) | 335 | #define OP_LED_ON BIT(3) |
| 336 | #define OP_LED_ON BIT(4) | 336 | #define OP_PREAMBLE_SHORT BIT(4) |
| 337 | #define OP_PREAMBLE_SHORT BIT(5) | 337 | #define OP_PROTECT_ENABLE BIT(5) |
| 338 | #define OP_PROTECT_ENABLE BIT(6) | 338 | #define OP_ASSOCIATED BIT(6) |
| 339 | #define OP_ASSOCIATED BIT(7) | 339 | #define OP_ENABLE_BEACON BIT(7) |
| 340 | #define OP_ENABLE_BEACON BIT(8) | 340 | #define OP_LED_DEINIT BIT(8) |
| 341 | #define OP_LED_DEINIT BIT(9) | 341 | #define OP_BT_PRIORITY_DETECTED BIT(9) |
| 342 | #define OP_UNPLUGGED BIT(10) | 342 | #define OP_BT_SCAN BIT(10) |
| 343 | #define OP_BT_PRIORITY_DETECTED BIT(11) | ||
| 344 | #define OP_BT_SCAN BIT(12) | ||
| 345 | 343 | ||
| 346 | struct ath9k_htc_priv { | 344 | struct ath9k_htc_priv { |
| 347 | struct device *dev; | 345 | struct device *dev; |
| @@ -378,7 +376,7 @@ struct ath9k_htc_priv { | |||
| 378 | struct ieee80211_vif *vif; | 376 | struct ieee80211_vif *vif; |
| 379 | struct htc_beacon_config cur_beacon_conf; | 377 | struct htc_beacon_config cur_beacon_conf; |
| 380 | unsigned int rxfilter; | 378 | unsigned int rxfilter; |
| 381 | struct tasklet_struct wmi_tasklet; | 379 | struct tasklet_struct swba_tasklet; |
| 382 | struct tasklet_struct rx_tasklet; | 380 | struct tasklet_struct rx_tasklet; |
| 383 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | 381 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; |
| 384 | struct ath9k_htc_rx rx; | 382 | struct ath9k_htc_rx rx; |
| @@ -386,6 +384,7 @@ struct ath9k_htc_priv { | |||
| 386 | struct sk_buff_head tx_queue; | 384 | struct sk_buff_head tx_queue; |
| 387 | struct delayed_work ath9k_ani_work; | 385 | struct delayed_work ath9k_ani_work; |
| 388 | struct work_struct ps_work; | 386 | struct work_struct ps_work; |
| 387 | struct work_struct fatal_work; | ||
| 389 | 388 | ||
| 390 | struct mutex htc_pm_lock; | 389 | struct mutex htc_pm_lock; |
| 391 | unsigned long ps_usecount; | 390 | unsigned long ps_usecount; |
| @@ -420,6 +419,8 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz) | |||
| 420 | common->bus_ops->read_cachesize(common, csz); | 419 | common->bus_ops->read_cachesize(common, csz); |
| 421 | } | 420 | } |
| 422 | 421 | ||
| 422 | void ath9k_htc_reset(struct ath9k_htc_priv *priv); | ||
| 423 | |||
| 423 | void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); | 424 | void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv); |
| 424 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | 425 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, |
| 425 | struct ieee80211_vif *vif); | 426 | struct ieee80211_vif *vif); |
| @@ -435,6 +436,7 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, | |||
| 435 | void ath9k_htc_station_work(struct work_struct *work); | 436 | void ath9k_htc_station_work(struct work_struct *work); |
| 436 | void ath9k_htc_aggr_work(struct work_struct *work); | 437 | void ath9k_htc_aggr_work(struct work_struct *work); |
| 437 | void ath9k_ani_work(struct work_struct *work);; | 438 | void ath9k_ani_work(struct work_struct *work);; |
| 439 | void ath_start_ani(struct ath9k_htc_priv *priv); | ||
| 438 | 440 | ||
| 439 | int ath9k_tx_init(struct ath9k_htc_priv *priv); | 441 | int ath9k_tx_init(struct ath9k_htc_priv *priv); |
| 440 | void ath9k_tx_tasklet(unsigned long data); | 442 | void ath9k_tx_tasklet(unsigned long data); |
| @@ -457,8 +459,13 @@ void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv); | |||
| 457 | void ath9k_ps_work(struct work_struct *work); | 459 | void ath9k_ps_work(struct work_struct *work); |
| 458 | bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, | 460 | bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, |
| 459 | enum ath9k_power_mode mode); | 461 | enum ath9k_power_mode mode); |
| 462 | void ath_update_txpow(struct ath9k_htc_priv *priv); | ||
| 460 | 463 | ||
| 461 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); | 464 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); |
| 465 | void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); | ||
| 466 | void ath9k_htc_radio_enable(struct ieee80211_hw *hw); | ||
| 467 | void ath9k_htc_radio_disable(struct ieee80211_hw *hw); | ||
| 468 | void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); | ||
| 462 | void ath9k_init_leds(struct ath9k_htc_priv *priv); | 469 | void ath9k_init_leds(struct ath9k_htc_priv *priv); |
| 463 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv); | 470 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv); |
| 464 | 471 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 283ff97ed446..fe70f67aa088 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
| 3 | * | ||
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 5 | * purpose with or without fee is hereby granted, provided that the above | ||
| 6 | * copyright notice and this permission notice appear in all copies. | ||
| 7 | * | ||
| 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 15 | */ | ||
| 16 | |||
| 1 | #include "htc.h" | 17 | #include "htc.h" |
| 2 | 18 | ||
| 3 | /******************/ | 19 | /******************/ |
| @@ -131,3 +147,314 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) | |||
| 131 | cancel_delayed_work_sync(&priv->coex_period_work); | 147 | cancel_delayed_work_sync(&priv->coex_period_work); |
| 132 | cancel_delayed_work_sync(&priv->duty_cycle_work); | 148 | cancel_delayed_work_sync(&priv->duty_cycle_work); |
| 133 | } | 149 | } |
| 150 | |||
| 151 | /*******/ | ||
| 152 | /* LED */ | ||
| 153 | /*******/ | ||
| 154 | |||
| 155 | static void ath9k_led_blink_work(struct work_struct *work) | ||
| 156 | { | ||
| 157 | struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, | ||
| 158 | ath9k_led_blink_work.work); | ||
| 159 | |||
| 160 | if (!(priv->op_flags & OP_LED_ASSOCIATED)) | ||
| 161 | return; | ||
| 162 | |||
| 163 | if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
| 164 | (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
| 165 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 166 | else | ||
| 167 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 168 | (priv->op_flags & OP_LED_ON) ? 1 : 0); | ||
| 169 | |||
| 170 | ieee80211_queue_delayed_work(priv->hw, | ||
| 171 | &priv->ath9k_led_blink_work, | ||
| 172 | (priv->op_flags & OP_LED_ON) ? | ||
| 173 | msecs_to_jiffies(priv->led_off_duration) : | ||
| 174 | msecs_to_jiffies(priv->led_on_duration)); | ||
| 175 | |||
| 176 | priv->led_on_duration = priv->led_on_cnt ? | ||
| 177 | max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : | ||
| 178 | ATH_LED_ON_DURATION_IDLE; | ||
| 179 | priv->led_off_duration = priv->led_off_cnt ? | ||
| 180 | max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : | ||
| 181 | ATH_LED_OFF_DURATION_IDLE; | ||
| 182 | priv->led_on_cnt = priv->led_off_cnt = 0; | ||
| 183 | |||
| 184 | if (priv->op_flags & OP_LED_ON) | ||
| 185 | priv->op_flags &= ~OP_LED_ON; | ||
| 186 | else | ||
| 187 | priv->op_flags |= OP_LED_ON; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void ath9k_led_brightness_work(struct work_struct *work) | ||
| 191 | { | ||
| 192 | struct ath_led *led = container_of(work, struct ath_led, | ||
| 193 | brightness_work.work); | ||
| 194 | struct ath9k_htc_priv *priv = led->priv; | ||
| 195 | |||
| 196 | switch (led->brightness) { | ||
| 197 | case LED_OFF: | ||
| 198 | if (led->led_type == ATH_LED_ASSOC || | ||
| 199 | led->led_type == ATH_LED_RADIO) { | ||
| 200 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 201 | (led->led_type == ATH_LED_RADIO)); | ||
| 202 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 203 | if (led->led_type == ATH_LED_RADIO) | ||
| 204 | priv->op_flags &= ~OP_LED_ON; | ||
| 205 | } else { | ||
| 206 | priv->led_off_cnt++; | ||
| 207 | } | ||
| 208 | break; | ||
| 209 | case LED_FULL: | ||
| 210 | if (led->led_type == ATH_LED_ASSOC) { | ||
| 211 | priv->op_flags |= OP_LED_ASSOCIATED; | ||
| 212 | ieee80211_queue_delayed_work(priv->hw, | ||
| 213 | &priv->ath9k_led_blink_work, 0); | ||
| 214 | } else if (led->led_type == ATH_LED_RADIO) { | ||
| 215 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 216 | priv->op_flags |= OP_LED_ON; | ||
| 217 | } else { | ||
| 218 | priv->led_on_cnt++; | ||
| 219 | } | ||
| 220 | break; | ||
| 221 | default: | ||
| 222 | break; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | static void ath9k_led_brightness(struct led_classdev *led_cdev, | ||
| 227 | enum led_brightness brightness) | ||
| 228 | { | ||
| 229 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
| 230 | struct ath9k_htc_priv *priv = led->priv; | ||
| 231 | |||
| 232 | led->brightness = brightness; | ||
| 233 | if (!(priv->op_flags & OP_LED_DEINIT)) | ||
| 234 | ieee80211_queue_delayed_work(priv->hw, | ||
| 235 | &led->brightness_work, 0); | ||
| 236 | } | ||
| 237 | |||
| 238 | void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) | ||
| 239 | { | ||
| 240 | cancel_delayed_work_sync(&priv->radio_led.brightness_work); | ||
| 241 | cancel_delayed_work_sync(&priv->assoc_led.brightness_work); | ||
| 242 | cancel_delayed_work_sync(&priv->tx_led.brightness_work); | ||
| 243 | cancel_delayed_work_sync(&priv->rx_led.brightness_work); | ||
| 244 | } | ||
| 245 | |||
| 246 | static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, | ||
| 247 | char *trigger) | ||
| 248 | { | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | led->priv = priv; | ||
| 252 | led->led_cdev.name = led->name; | ||
| 253 | led->led_cdev.default_trigger = trigger; | ||
| 254 | led->led_cdev.brightness_set = ath9k_led_brightness; | ||
| 255 | |||
| 256 | ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); | ||
| 257 | if (ret) | ||
| 258 | ath_err(ath9k_hw_common(priv->ah), | ||
| 259 | "Failed to register led:%s", led->name); | ||
| 260 | else | ||
| 261 | led->registered = 1; | ||
| 262 | |||
| 263 | INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); | ||
| 264 | |||
| 265 | return ret; | ||
| 266 | } | ||
| 267 | |||
| 268 | static void ath9k_unregister_led(struct ath_led *led) | ||
| 269 | { | ||
| 270 | if (led->registered) { | ||
| 271 | led_classdev_unregister(&led->led_cdev); | ||
| 272 | led->registered = 0; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv) | ||
| 277 | { | ||
| 278 | priv->op_flags |= OP_LED_DEINIT; | ||
| 279 | ath9k_unregister_led(&priv->assoc_led); | ||
| 280 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 281 | ath9k_unregister_led(&priv->tx_led); | ||
| 282 | ath9k_unregister_led(&priv->rx_led); | ||
| 283 | ath9k_unregister_led(&priv->radio_led); | ||
| 284 | } | ||
| 285 | |||
| 286 | void ath9k_init_leds(struct ath9k_htc_priv *priv) | ||
| 287 | { | ||
| 288 | char *trigger; | ||
| 289 | int ret; | ||
| 290 | |||
| 291 | if (AR_SREV_9287(priv->ah)) | ||
| 292 | priv->ah->led_pin = ATH_LED_PIN_9287; | ||
| 293 | else if (AR_SREV_9271(priv->ah)) | ||
| 294 | priv->ah->led_pin = ATH_LED_PIN_9271; | ||
| 295 | else if (AR_DEVID_7010(priv->ah)) | ||
| 296 | priv->ah->led_pin = ATH_LED_PIN_7010; | ||
| 297 | else | ||
| 298 | priv->ah->led_pin = ATH_LED_PIN_DEF; | ||
| 299 | |||
| 300 | /* Configure gpio 1 for output */ | ||
| 301 | ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, | ||
| 302 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 303 | /* LED off, active low */ | ||
| 304 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); | ||
| 305 | |||
| 306 | INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); | ||
| 307 | |||
| 308 | trigger = ieee80211_get_radio_led_name(priv->hw); | ||
| 309 | snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), | ||
| 310 | "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); | ||
| 311 | ret = ath9k_register_led(priv, &priv->radio_led, trigger); | ||
| 312 | priv->radio_led.led_type = ATH_LED_RADIO; | ||
| 313 | if (ret) | ||
| 314 | goto fail; | ||
| 315 | |||
| 316 | trigger = ieee80211_get_assoc_led_name(priv->hw); | ||
| 317 | snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), | ||
| 318 | "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); | ||
| 319 | ret = ath9k_register_led(priv, &priv->assoc_led, trigger); | ||
| 320 | priv->assoc_led.led_type = ATH_LED_ASSOC; | ||
| 321 | if (ret) | ||
| 322 | goto fail; | ||
| 323 | |||
| 324 | trigger = ieee80211_get_tx_led_name(priv->hw); | ||
| 325 | snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), | ||
| 326 | "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); | ||
| 327 | ret = ath9k_register_led(priv, &priv->tx_led, trigger); | ||
| 328 | priv->tx_led.led_type = ATH_LED_TX; | ||
| 329 | if (ret) | ||
| 330 | goto fail; | ||
| 331 | |||
| 332 | trigger = ieee80211_get_rx_led_name(priv->hw); | ||
| 333 | snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), | ||
| 334 | "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); | ||
| 335 | ret = ath9k_register_led(priv, &priv->rx_led, trigger); | ||
| 336 | priv->rx_led.led_type = ATH_LED_RX; | ||
| 337 | if (ret) | ||
| 338 | goto fail; | ||
| 339 | |||
| 340 | priv->op_flags &= ~OP_LED_DEINIT; | ||
| 341 | |||
| 342 | return; | ||
| 343 | |||
| 344 | fail: | ||
| 345 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 346 | ath9k_deinit_leds(priv); | ||
| 347 | } | ||
| 348 | |||
| 349 | /*******************/ | ||
| 350 | /* Rfkill */ | ||
| 351 | /*******************/ | ||
| 352 | |||
| 353 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) | ||
| 354 | { | ||
| 355 | return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | ||
| 356 | priv->ah->rfkill_polarity; | ||
| 357 | } | ||
| 358 | |||
| 359 | void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) | ||
| 360 | { | ||
| 361 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 362 | bool blocked = !!ath_is_rfkill_set(priv); | ||
| 363 | |||
| 364 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
| 365 | } | ||
| 366 | |||
| 367 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | ||
| 368 | { | ||
| 369 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
| 370 | wiphy_rfkill_start_polling(priv->hw->wiphy); | ||
| 371 | } | ||
| 372 | |||
| 373 | void ath9k_htc_radio_enable(struct ieee80211_hw *hw) | ||
| 374 | { | ||
| 375 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 376 | struct ath_hw *ah = priv->ah; | ||
| 377 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 378 | int ret; | ||
| 379 | u8 cmd_rsp; | ||
| 380 | |||
| 381 | if (!ah->curchan) | ||
| 382 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 383 | |||
| 384 | /* Reset the HW */ | ||
| 385 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 386 | if (ret) { | ||
| 387 | ath_err(common, | ||
| 388 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 389 | ret, ah->curchan->channel); | ||
| 390 | } | ||
| 391 | |||
| 392 | ath_update_txpow(priv); | ||
| 393 | |||
| 394 | /* Start RX */ | ||
| 395 | WMI_CMD(WMI_START_RECV_CMDID); | ||
| 396 | ath9k_host_rx_init(priv); | ||
| 397 | |||
| 398 | /* Start TX */ | ||
| 399 | htc_start(priv->htc); | ||
| 400 | spin_lock_bh(&priv->tx_lock); | ||
| 401 | priv->tx_queues_stop = false; | ||
| 402 | spin_unlock_bh(&priv->tx_lock); | ||
| 403 | ieee80211_wake_queues(hw); | ||
| 404 | |||
| 405 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
| 406 | |||
| 407 | /* Enable LED */ | ||
| 408 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
| 409 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 410 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
| 411 | } | ||
| 412 | |||
| 413 | void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | ||
| 414 | { | ||
| 415 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 416 | struct ath_hw *ah = priv->ah; | ||
| 417 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 418 | int ret; | ||
| 419 | u8 cmd_rsp; | ||
| 420 | |||
| 421 | ath9k_htc_ps_wakeup(priv); | ||
| 422 | |||
| 423 | /* Disable LED */ | ||
| 424 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
| 425 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
| 426 | |||
| 427 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
| 428 | |||
| 429 | /* Stop TX */ | ||
| 430 | ieee80211_stop_queues(hw); | ||
| 431 | htc_stop(priv->htc); | ||
| 432 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
| 433 | skb_queue_purge(&priv->tx_queue); | ||
| 434 | |||
| 435 | /* Stop RX */ | ||
| 436 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
| 437 | |||
| 438 | /* | ||
| 439 | * The MIB counters have to be disabled here, | ||
| 440 | * since the target doesn't do it. | ||
| 441 | */ | ||
| 442 | ath9k_hw_disable_mib_counters(ah); | ||
| 443 | |||
| 444 | if (!ah->curchan) | ||
| 445 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 446 | |||
| 447 | /* Reset the HW */ | ||
| 448 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 449 | if (ret) { | ||
| 450 | ath_err(common, | ||
| 451 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 452 | ret, ah->curchan->channel); | ||
| 453 | } | ||
| 454 | |||
| 455 | /* Disable the PHY */ | ||
| 456 | ath9k_hw_phy_disable(ah); | ||
| 457 | |||
| 458 | ath9k_htc_ps_restore(priv); | ||
| 459 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
| 460 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 0f6be350fd3c..38433f9bfe59 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
| @@ -142,7 +142,7 @@ static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) | |||
| 142 | { | 142 | { |
| 143 | ath9k_htc_exit_debug(priv->ah); | 143 | ath9k_htc_exit_debug(priv->ah); |
| 144 | ath9k_hw_deinit(priv->ah); | 144 | ath9k_hw_deinit(priv->ah); |
| 145 | tasklet_kill(&priv->wmi_tasklet); | 145 | tasklet_kill(&priv->swba_tasklet); |
| 146 | tasklet_kill(&priv->rx_tasklet); | 146 | tasklet_kill(&priv->rx_tasklet); |
| 147 | tasklet_kill(&priv->tx_tasklet); | 147 | tasklet_kill(&priv->tx_tasklet); |
| 148 | kfree(priv->ah); | 148 | kfree(priv->ah); |
| @@ -647,13 +647,15 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, | |||
| 647 | spin_lock_init(&priv->tx_lock); | 647 | spin_lock_init(&priv->tx_lock); |
| 648 | mutex_init(&priv->mutex); | 648 | mutex_init(&priv->mutex); |
| 649 | mutex_init(&priv->htc_pm_lock); | 649 | mutex_init(&priv->htc_pm_lock); |
| 650 | tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, | 650 | tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet, |
| 651 | (unsigned long)priv); | 651 | (unsigned long)priv); |
| 652 | tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, | 652 | tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, |
| 653 | (unsigned long)priv); | 653 | (unsigned long)priv); |
| 654 | tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); | 654 | tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, |
| 655 | (unsigned long)priv); | ||
| 655 | INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); | 656 | INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); |
| 656 | INIT_WORK(&priv->ps_work, ath9k_ps_work); | 657 | INIT_WORK(&priv->ps_work, ath9k_ps_work); |
| 658 | INIT_WORK(&priv->fatal_work, ath9k_fatal_work); | ||
| 657 | 659 | ||
| 658 | /* | 660 | /* |
| 659 | * Cache line size is used to size and align various | 661 | * Cache line size is used to size and align various |
| @@ -714,8 +716,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, | |||
| 714 | IEEE80211_HW_HAS_RATE_CONTROL | | 716 | IEEE80211_HW_HAS_RATE_CONTROL | |
| 715 | IEEE80211_HW_RX_INCLUDES_FCS | | 717 | IEEE80211_HW_RX_INCLUDES_FCS | |
| 716 | IEEE80211_HW_SUPPORTS_PS | | 718 | IEEE80211_HW_SUPPORTS_PS | |
| 717 | IEEE80211_HW_PS_NULLFUNC_STACK | | 719 | IEEE80211_HW_PS_NULLFUNC_STACK; |
| 718 | IEEE80211_HW_NEED_DTIM_PERIOD; | ||
| 719 | 720 | ||
| 720 | hw->wiphy->interface_modes = | 721 | hw->wiphy->interface_modes = |
| 721 | BIT(NL80211_IFTYPE_STATION) | | 722 | BIT(NL80211_IFTYPE_STATION) | |
| @@ -851,9 +852,6 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, | |||
| 851 | if (ret) | 852 | if (ret) |
| 852 | goto err_init; | 853 | goto err_init; |
| 853 | 854 | ||
| 854 | /* The device may have been unplugged earlier. */ | ||
| 855 | priv->op_flags &= ~OP_UNPLUGGED; | ||
| 856 | |||
| 857 | ret = ath9k_init_device(priv, devid, product, drv_info); | 855 | ret = ath9k_init_device(priv, devid, product, drv_info); |
| 858 | if (ret) | 856 | if (ret) |
| 859 | goto err_init; | 857 | goto err_init; |
| @@ -873,7 +871,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) | |||
| 873 | 871 | ||
| 874 | /* Check if the device has been yanked out. */ | 872 | /* Check if the device has been yanked out. */ |
| 875 | if (hotunplug) | 873 | if (hotunplug) |
| 876 | htc_handle->drv_priv->op_flags |= OP_UNPLUGGED; | 874 | htc_handle->drv_priv->ah->ah_flags |= AH_UNPLUGGED; |
| 877 | 875 | ||
| 878 | ath9k_deinit_device(htc_handle->drv_priv); | 876 | ath9k_deinit_device(htc_handle->drv_priv); |
| 879 | ath9k_deinit_wmi(htc_handle->drv_priv); | 877 | ath9k_deinit_wmi(htc_handle->drv_priv); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index dd17909bd903..845b4c938d16 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
| @@ -24,7 +24,7 @@ static struct dentry *ath9k_debugfs_root; | |||
| 24 | /* Utilities */ | 24 | /* Utilities */ |
| 25 | /*************/ | 25 | /*************/ |
| 26 | 26 | ||
| 27 | static void ath_update_txpow(struct ath9k_htc_priv *priv) | 27 | void ath_update_txpow(struct ath9k_htc_priv *priv) |
| 28 | { | 28 | { |
| 29 | struct ath_hw *ah = priv->ah; | 29 | struct ath_hw *ah = priv->ah; |
| 30 | 30 | ||
| @@ -116,6 +116,60 @@ void ath9k_ps_work(struct work_struct *work) | |||
| 116 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); | 116 | ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void ath9k_htc_reset(struct ath9k_htc_priv *priv) | ||
| 120 | { | ||
| 121 | struct ath_hw *ah = priv->ah; | ||
| 122 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 123 | struct ieee80211_channel *channel = priv->hw->conf.channel; | ||
| 124 | struct ath9k_hw_cal_data *caldata; | ||
| 125 | enum htc_phymode mode; | ||
| 126 | __be16 htc_mode; | ||
| 127 | u8 cmd_rsp; | ||
| 128 | int ret; | ||
| 129 | |||
| 130 | mutex_lock(&priv->mutex); | ||
| 131 | ath9k_htc_ps_wakeup(priv); | ||
| 132 | |||
| 133 | if (priv->op_flags & OP_ASSOCIATED) | ||
| 134 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
| 135 | |||
| 136 | ieee80211_stop_queues(priv->hw); | ||
| 137 | htc_stop(priv->htc); | ||
| 138 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
| 139 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
| 140 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
| 141 | |||
| 142 | caldata = &priv->caldata[channel->hw_value]; | ||
| 143 | ret = ath9k_hw_reset(ah, ah->curchan, caldata, false); | ||
| 144 | if (ret) { | ||
| 145 | ath_err(common, | ||
| 146 | "Unable to reset device (%u Mhz) reset status %d\n", | ||
| 147 | channel->center_freq, ret); | ||
| 148 | } | ||
| 149 | |||
| 150 | ath_update_txpow(priv); | ||
| 151 | |||
| 152 | WMI_CMD(WMI_START_RECV_CMDID); | ||
| 153 | ath9k_host_rx_init(priv); | ||
| 154 | |||
| 155 | mode = ath9k_htc_get_curmode(priv, ah->curchan); | ||
| 156 | htc_mode = cpu_to_be16(mode); | ||
| 157 | WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); | ||
| 158 | |||
| 159 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
| 160 | htc_start(priv->htc); | ||
| 161 | |||
| 162 | if (priv->op_flags & OP_ASSOCIATED) { | ||
| 163 | ath9k_htc_beacon_config(priv, priv->vif); | ||
| 164 | ath_start_ani(priv); | ||
| 165 | } | ||
| 166 | |||
| 167 | ieee80211_wake_queues(priv->hw); | ||
| 168 | |||
| 169 | ath9k_htc_ps_restore(priv); | ||
| 170 | mutex_unlock(&priv->mutex); | ||
| 171 | } | ||
| 172 | |||
| 119 | static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | 173 | static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, |
| 120 | struct ieee80211_hw *hw, | 174 | struct ieee80211_hw *hw, |
| 121 | struct ath9k_channel *hchan) | 175 | struct ath9k_channel *hchan) |
| @@ -123,7 +177,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 123 | struct ath_hw *ah = priv->ah; | 177 | struct ath_hw *ah = priv->ah; |
| 124 | struct ath_common *common = ath9k_hw_common(ah); | 178 | struct ath_common *common = ath9k_hw_common(ah); |
| 125 | struct ieee80211_conf *conf = &common->hw->conf; | 179 | struct ieee80211_conf *conf = &common->hw->conf; |
| 126 | bool fastcc = true; | 180 | bool fastcc; |
| 127 | struct ieee80211_channel *channel = hw->conf.channel; | 181 | struct ieee80211_channel *channel = hw->conf.channel; |
| 128 | struct ath9k_hw_cal_data *caldata; | 182 | struct ath9k_hw_cal_data *caldata; |
| 129 | enum htc_phymode mode; | 183 | enum htc_phymode mode; |
| @@ -134,8 +188,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 134 | if (priv->op_flags & OP_INVALID) | 188 | if (priv->op_flags & OP_INVALID) |
| 135 | return -EIO; | 189 | return -EIO; |
| 136 | 190 | ||
| 137 | if (priv->op_flags & OP_FULL_RESET) | 191 | fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); |
| 138 | fastcc = false; | ||
| 139 | 192 | ||
| 140 | ath9k_htc_ps_wakeup(priv); | 193 | ath9k_htc_ps_wakeup(priv); |
| 141 | htc_stop(priv->htc); | 194 | htc_stop(priv->htc); |
| @@ -177,23 +230,43 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
| 177 | goto err; | 230 | goto err; |
| 178 | 231 | ||
| 179 | htc_start(priv->htc); | 232 | htc_start(priv->htc); |
| 180 | |||
| 181 | priv->op_flags &= ~OP_FULL_RESET; | ||
| 182 | err: | 233 | err: |
| 183 | ath9k_htc_ps_restore(priv); | 234 | ath9k_htc_ps_restore(priv); |
| 184 | return ret; | 235 | return ret; |
| 185 | } | 236 | } |
| 186 | 237 | ||
| 238 | static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | ||
| 239 | { | ||
| 240 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
| 241 | struct ath9k_htc_target_vif hvif; | ||
| 242 | int ret = 0; | ||
| 243 | u8 cmd_rsp; | ||
| 244 | |||
| 245 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
| 246 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
| 247 | hvif.index = 0; /* Should do for now */ | ||
| 248 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
| 249 | priv->nvifs--; | ||
| 250 | } | ||
| 251 | |||
| 187 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | 252 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) |
| 188 | { | 253 | { |
| 189 | struct ath_common *common = ath9k_hw_common(priv->ah); | 254 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 190 | struct ath9k_htc_target_vif hvif; | 255 | struct ath9k_htc_target_vif hvif; |
| 256 | struct ath9k_htc_target_sta tsta; | ||
| 191 | int ret = 0; | 257 | int ret = 0; |
| 192 | u8 cmd_rsp; | 258 | u8 cmd_rsp; |
| 193 | 259 | ||
| 194 | if (priv->nvifs > 0) | 260 | if (priv->nvifs > 0) |
| 195 | return -ENOBUFS; | 261 | return -ENOBUFS; |
| 196 | 262 | ||
| 263 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | ||
| 264 | return -ENOBUFS; | ||
| 265 | |||
| 266 | /* | ||
| 267 | * Add an interface. | ||
| 268 | */ | ||
| 269 | |||
| 197 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 270 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); |
| 198 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | 271 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); |
| 199 | 272 | ||
| @@ -206,23 +279,57 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | |||
| 206 | return ret; | 279 | return ret; |
| 207 | 280 | ||
| 208 | priv->nvifs++; | 281 | priv->nvifs++; |
| 282 | |||
| 283 | /* | ||
| 284 | * Associate a station with the interface for packet injection. | ||
| 285 | */ | ||
| 286 | |||
| 287 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | ||
| 288 | |||
| 289 | memcpy(&tsta.macaddr, common->macaddr, ETH_ALEN); | ||
| 290 | |||
| 291 | tsta.is_vif_sta = 1; | ||
| 292 | tsta.sta_index = priv->nstations; | ||
| 293 | tsta.vif_index = hvif.index; | ||
| 294 | tsta.maxampdu = 0xffff; | ||
| 295 | |||
| 296 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | ||
| 297 | if (ret) { | ||
| 298 | ath_err(common, "Unable to add station entry for monitor mode\n"); | ||
| 299 | goto err_vif; | ||
| 300 | } | ||
| 301 | |||
| 302 | priv->nstations++; | ||
| 303 | |||
| 209 | return 0; | 304 | return 0; |
| 305 | |||
| 306 | err_vif: | ||
| 307 | /* | ||
| 308 | * Remove the interface from the target. | ||
| 309 | */ | ||
| 310 | __ath9k_htc_remove_monitor_interface(priv); | ||
| 311 | return ret; | ||
| 210 | } | 312 | } |
| 211 | 313 | ||
| 212 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | 314 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) |
| 213 | { | 315 | { |
| 214 | struct ath_common *common = ath9k_hw_common(priv->ah); | 316 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 215 | struct ath9k_htc_target_vif hvif; | ||
| 216 | int ret = 0; | 317 | int ret = 0; |
| 217 | u8 cmd_rsp; | 318 | u8 cmd_rsp, sta_idx; |
| 218 | 319 | ||
| 219 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | 320 | __ath9k_htc_remove_monitor_interface(priv); |
| 220 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
| 221 | hvif.index = 0; /* Should do for now */ | ||
| 222 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
| 223 | priv->nvifs--; | ||
| 224 | 321 | ||
| 225 | return ret; | 322 | sta_idx = 0; /* Only single interface, for now */ |
| 323 | |||
| 324 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | ||
| 325 | if (ret) { | ||
| 326 | ath_err(common, "Unable to remove station entry for monitor mode\n"); | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | |||
| 330 | priv->nstations--; | ||
| 331 | |||
| 332 | return 0; | ||
| 226 | } | 333 | } |
| 227 | 334 | ||
| 228 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | 335 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, |
| @@ -690,7 +797,7 @@ void ath9k_htc_debug_remove_root(void) | |||
| 690 | /* ANI */ | 797 | /* ANI */ |
| 691 | /*******/ | 798 | /*******/ |
| 692 | 799 | ||
| 693 | static void ath_start_ani(struct ath9k_htc_priv *priv) | 800 | void ath_start_ani(struct ath9k_htc_priv *priv) |
| 694 | { | 801 | { |
| 695 | struct ath_common *common = ath9k_hw_common(priv->ah); | 802 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| 696 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 803 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
| @@ -789,317 +896,6 @@ set_timer: | |||
| 789 | msecs_to_jiffies(cal_interval)); | 896 | msecs_to_jiffies(cal_interval)); |
| 790 | } | 897 | } |
| 791 | 898 | ||
| 792 | /*******/ | ||
| 793 | /* LED */ | ||
| 794 | /*******/ | ||
| 795 | |||
| 796 | static void ath9k_led_blink_work(struct work_struct *work) | ||
| 797 | { | ||
| 798 | struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, | ||
| 799 | ath9k_led_blink_work.work); | ||
| 800 | |||
| 801 | if (!(priv->op_flags & OP_LED_ASSOCIATED)) | ||
| 802 | return; | ||
| 803 | |||
| 804 | if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
| 805 | (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
| 806 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 807 | else | ||
| 808 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 809 | (priv->op_flags & OP_LED_ON) ? 1 : 0); | ||
| 810 | |||
| 811 | ieee80211_queue_delayed_work(priv->hw, | ||
| 812 | &priv->ath9k_led_blink_work, | ||
| 813 | (priv->op_flags & OP_LED_ON) ? | ||
| 814 | msecs_to_jiffies(priv->led_off_duration) : | ||
| 815 | msecs_to_jiffies(priv->led_on_duration)); | ||
| 816 | |||
| 817 | priv->led_on_duration = priv->led_on_cnt ? | ||
| 818 | max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : | ||
| 819 | ATH_LED_ON_DURATION_IDLE; | ||
| 820 | priv->led_off_duration = priv->led_off_cnt ? | ||
| 821 | max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : | ||
| 822 | ATH_LED_OFF_DURATION_IDLE; | ||
| 823 | priv->led_on_cnt = priv->led_off_cnt = 0; | ||
| 824 | |||
| 825 | if (priv->op_flags & OP_LED_ON) | ||
| 826 | priv->op_flags &= ~OP_LED_ON; | ||
| 827 | else | ||
| 828 | priv->op_flags |= OP_LED_ON; | ||
| 829 | } | ||
| 830 | |||
| 831 | static void ath9k_led_brightness_work(struct work_struct *work) | ||
| 832 | { | ||
| 833 | struct ath_led *led = container_of(work, struct ath_led, | ||
| 834 | brightness_work.work); | ||
| 835 | struct ath9k_htc_priv *priv = led->priv; | ||
| 836 | |||
| 837 | switch (led->brightness) { | ||
| 838 | case LED_OFF: | ||
| 839 | if (led->led_type == ATH_LED_ASSOC || | ||
| 840 | led->led_type == ATH_LED_RADIO) { | ||
| 841 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
| 842 | (led->led_type == ATH_LED_RADIO)); | ||
| 843 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 844 | if (led->led_type == ATH_LED_RADIO) | ||
| 845 | priv->op_flags &= ~OP_LED_ON; | ||
| 846 | } else { | ||
| 847 | priv->led_off_cnt++; | ||
| 848 | } | ||
| 849 | break; | ||
| 850 | case LED_FULL: | ||
| 851 | if (led->led_type == ATH_LED_ASSOC) { | ||
| 852 | priv->op_flags |= OP_LED_ASSOCIATED; | ||
| 853 | ieee80211_queue_delayed_work(priv->hw, | ||
| 854 | &priv->ath9k_led_blink_work, 0); | ||
| 855 | } else if (led->led_type == ATH_LED_RADIO) { | ||
| 856 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
| 857 | priv->op_flags |= OP_LED_ON; | ||
| 858 | } else { | ||
| 859 | priv->led_on_cnt++; | ||
| 860 | } | ||
| 861 | break; | ||
| 862 | default: | ||
| 863 | break; | ||
| 864 | } | ||
| 865 | } | ||
| 866 | |||
| 867 | static void ath9k_led_brightness(struct led_classdev *led_cdev, | ||
| 868 | enum led_brightness brightness) | ||
| 869 | { | ||
| 870 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
| 871 | struct ath9k_htc_priv *priv = led->priv; | ||
| 872 | |||
| 873 | led->brightness = brightness; | ||
| 874 | if (!(priv->op_flags & OP_LED_DEINIT)) | ||
| 875 | ieee80211_queue_delayed_work(priv->hw, | ||
| 876 | &led->brightness_work, 0); | ||
| 877 | } | ||
| 878 | |||
| 879 | static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) | ||
| 880 | { | ||
| 881 | cancel_delayed_work_sync(&priv->radio_led.brightness_work); | ||
| 882 | cancel_delayed_work_sync(&priv->assoc_led.brightness_work); | ||
| 883 | cancel_delayed_work_sync(&priv->tx_led.brightness_work); | ||
| 884 | cancel_delayed_work_sync(&priv->rx_led.brightness_work); | ||
| 885 | } | ||
| 886 | |||
| 887 | static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, | ||
| 888 | char *trigger) | ||
| 889 | { | ||
| 890 | int ret; | ||
| 891 | |||
| 892 | led->priv = priv; | ||
| 893 | led->led_cdev.name = led->name; | ||
| 894 | led->led_cdev.default_trigger = trigger; | ||
| 895 | led->led_cdev.brightness_set = ath9k_led_brightness; | ||
| 896 | |||
| 897 | ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); | ||
| 898 | if (ret) | ||
| 899 | ath_err(ath9k_hw_common(priv->ah), | ||
| 900 | "Failed to register led:%s", led->name); | ||
| 901 | else | ||
| 902 | led->registered = 1; | ||
| 903 | |||
| 904 | INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); | ||
| 905 | |||
| 906 | return ret; | ||
| 907 | } | ||
| 908 | |||
| 909 | static void ath9k_unregister_led(struct ath_led *led) | ||
| 910 | { | ||
| 911 | if (led->registered) { | ||
| 912 | led_classdev_unregister(&led->led_cdev); | ||
| 913 | led->registered = 0; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | |||
| 917 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv) | ||
| 918 | { | ||
| 919 | priv->op_flags |= OP_LED_DEINIT; | ||
| 920 | ath9k_unregister_led(&priv->assoc_led); | ||
| 921 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
| 922 | ath9k_unregister_led(&priv->tx_led); | ||
| 923 | ath9k_unregister_led(&priv->rx_led); | ||
| 924 | ath9k_unregister_led(&priv->radio_led); | ||
| 925 | } | ||
| 926 | |||
| 927 | void ath9k_init_leds(struct ath9k_htc_priv *priv) | ||
| 928 | { | ||
| 929 | char *trigger; | ||
| 930 | int ret; | ||
| 931 | |||
| 932 | if (AR_SREV_9287(priv->ah)) | ||
| 933 | priv->ah->led_pin = ATH_LED_PIN_9287; | ||
| 934 | else if (AR_SREV_9271(priv->ah)) | ||
| 935 | priv->ah->led_pin = ATH_LED_PIN_9271; | ||
| 936 | else if (AR_DEVID_7010(priv->ah)) | ||
| 937 | priv->ah->led_pin = ATH_LED_PIN_7010; | ||
| 938 | else | ||
| 939 | priv->ah->led_pin = ATH_LED_PIN_DEF; | ||
| 940 | |||
| 941 | /* Configure gpio 1 for output */ | ||
| 942 | ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, | ||
| 943 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 944 | /* LED off, active low */ | ||
| 945 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); | ||
| 946 | |||
| 947 | INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); | ||
| 948 | |||
| 949 | trigger = ieee80211_get_radio_led_name(priv->hw); | ||
| 950 | snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), | ||
| 951 | "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); | ||
| 952 | ret = ath9k_register_led(priv, &priv->radio_led, trigger); | ||
| 953 | priv->radio_led.led_type = ATH_LED_RADIO; | ||
| 954 | if (ret) | ||
| 955 | goto fail; | ||
| 956 | |||
| 957 | trigger = ieee80211_get_assoc_led_name(priv->hw); | ||
| 958 | snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), | ||
| 959 | "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); | ||
| 960 | ret = ath9k_register_led(priv, &priv->assoc_led, trigger); | ||
| 961 | priv->assoc_led.led_type = ATH_LED_ASSOC; | ||
| 962 | if (ret) | ||
| 963 | goto fail; | ||
| 964 | |||
| 965 | trigger = ieee80211_get_tx_led_name(priv->hw); | ||
| 966 | snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), | ||
| 967 | "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); | ||
| 968 | ret = ath9k_register_led(priv, &priv->tx_led, trigger); | ||
| 969 | priv->tx_led.led_type = ATH_LED_TX; | ||
| 970 | if (ret) | ||
| 971 | goto fail; | ||
| 972 | |||
| 973 | trigger = ieee80211_get_rx_led_name(priv->hw); | ||
| 974 | snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), | ||
| 975 | "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); | ||
| 976 | ret = ath9k_register_led(priv, &priv->rx_led, trigger); | ||
| 977 | priv->rx_led.led_type = ATH_LED_RX; | ||
| 978 | if (ret) | ||
| 979 | goto fail; | ||
| 980 | |||
| 981 | priv->op_flags &= ~OP_LED_DEINIT; | ||
| 982 | |||
| 983 | return; | ||
| 984 | |||
| 985 | fail: | ||
| 986 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 987 | ath9k_deinit_leds(priv); | ||
| 988 | } | ||
| 989 | |||
| 990 | /*******************/ | ||
| 991 | /* Rfkill */ | ||
| 992 | /*******************/ | ||
| 993 | |||
| 994 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) | ||
| 995 | { | ||
| 996 | return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | ||
| 997 | priv->ah->rfkill_polarity; | ||
| 998 | } | ||
| 999 | |||
| 1000 | static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) | ||
| 1001 | { | ||
| 1002 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1003 | bool blocked = !!ath_is_rfkill_set(priv); | ||
| 1004 | |||
| 1005 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | ||
| 1009 | { | ||
| 1010 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
| 1011 | wiphy_rfkill_start_polling(priv->hw->wiphy); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | static void ath9k_htc_radio_enable(struct ieee80211_hw *hw) | ||
| 1015 | { | ||
| 1016 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1017 | struct ath_hw *ah = priv->ah; | ||
| 1018 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 1019 | int ret; | ||
| 1020 | u8 cmd_rsp; | ||
| 1021 | |||
| 1022 | if (!ah->curchan) | ||
| 1023 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 1024 | |||
| 1025 | /* Reset the HW */ | ||
| 1026 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 1027 | if (ret) { | ||
| 1028 | ath_err(common, | ||
| 1029 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 1030 | ret, ah->curchan->channel); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | ath_update_txpow(priv); | ||
| 1034 | |||
| 1035 | /* Start RX */ | ||
| 1036 | WMI_CMD(WMI_START_RECV_CMDID); | ||
| 1037 | ath9k_host_rx_init(priv); | ||
| 1038 | |||
| 1039 | /* Start TX */ | ||
| 1040 | htc_start(priv->htc); | ||
| 1041 | spin_lock_bh(&priv->tx_lock); | ||
| 1042 | priv->tx_queues_stop = false; | ||
| 1043 | spin_unlock_bh(&priv->tx_lock); | ||
| 1044 | ieee80211_wake_queues(hw); | ||
| 1045 | |||
| 1046 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
| 1047 | |||
| 1048 | /* Enable LED */ | ||
| 1049 | ath9k_hw_cfg_output(ah, ah->led_pin, | ||
| 1050 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
| 1051 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | static void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | ||
| 1055 | { | ||
| 1056 | struct ath9k_htc_priv *priv = hw->priv; | ||
| 1057 | struct ath_hw *ah = priv->ah; | ||
| 1058 | struct ath_common *common = ath9k_hw_common(ah); | ||
| 1059 | int ret; | ||
| 1060 | u8 cmd_rsp; | ||
| 1061 | |||
| 1062 | ath9k_htc_ps_wakeup(priv); | ||
| 1063 | |||
| 1064 | /* Disable LED */ | ||
| 1065 | ath9k_hw_set_gpio(ah, ah->led_pin, 1); | ||
| 1066 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | ||
| 1067 | |||
| 1068 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
| 1069 | |||
| 1070 | /* Stop TX */ | ||
| 1071 | ieee80211_stop_queues(hw); | ||
| 1072 | htc_stop(priv->htc); | ||
| 1073 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
| 1074 | skb_queue_purge(&priv->tx_queue); | ||
| 1075 | |||
| 1076 | /* Stop RX */ | ||
| 1077 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * The MIB counters have to be disabled here, | ||
| 1081 | * since the target doesn't do it. | ||
| 1082 | */ | ||
| 1083 | ath9k_hw_disable_mib_counters(ah); | ||
| 1084 | |||
| 1085 | if (!ah->curchan) | ||
| 1086 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | ||
| 1087 | |||
| 1088 | /* Reset the HW */ | ||
| 1089 | ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | ||
| 1090 | if (ret) { | ||
| 1091 | ath_err(common, | ||
| 1092 | "Unable to reset hardware; reset status %d (freq %u MHz)\n", | ||
| 1093 | ret, ah->curchan->channel); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | /* Disable the PHY */ | ||
| 1097 | ath9k_hw_phy_disable(ah); | ||
| 1098 | |||
| 1099 | ath9k_htc_ps_restore(priv); | ||
| 1100 | ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | /**********************/ | 899 | /**********************/ |
| 1104 | /* mac80211 Callbacks */ | 900 | /* mac80211 Callbacks */ |
| 1105 | /**********************/ | 901 | /**********************/ |
| @@ -1218,6 +1014,12 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
| 1218 | int ret = 0; | 1014 | int ret = 0; |
| 1219 | u8 cmd_rsp; | 1015 | u8 cmd_rsp; |
| 1220 | 1016 | ||
| 1017 | /* Cancel all the running timers/work .. */ | ||
| 1018 | cancel_work_sync(&priv->fatal_work); | ||
| 1019 | cancel_work_sync(&priv->ps_work); | ||
| 1020 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 1021 | ath9k_led_stop_brightness(priv); | ||
| 1022 | |||
| 1221 | mutex_lock(&priv->mutex); | 1023 | mutex_lock(&priv->mutex); |
| 1222 | 1024 | ||
| 1223 | if (priv->op_flags & OP_INVALID) { | 1025 | if (priv->op_flags & OP_INVALID) { |
| @@ -1226,11 +1028,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
| 1226 | return; | 1028 | return; |
| 1227 | } | 1029 | } |
| 1228 | 1030 | ||
| 1229 | /* Cancel all the running timers/work .. */ | ||
| 1230 | cancel_work_sync(&priv->ps_work); | ||
| 1231 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
| 1232 | ath9k_led_stop_brightness(priv); | ||
| 1233 | |||
| 1234 | ath9k_htc_ps_wakeup(priv); | 1031 | ath9k_htc_ps_wakeup(priv); |
| 1235 | htc_stop(priv->htc); | 1032 | htc_stop(priv->htc); |
| 1236 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 1033 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
| @@ -1792,7 +1589,6 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | |||
| 1792 | spin_lock_bh(&priv->beacon_lock); | 1589 | spin_lock_bh(&priv->beacon_lock); |
| 1793 | priv->op_flags &= ~OP_SCANNING; | 1590 | priv->op_flags &= ~OP_SCANNING; |
| 1794 | spin_unlock_bh(&priv->beacon_lock); | 1591 | spin_unlock_bh(&priv->beacon_lock); |
| 1795 | priv->op_flags |= OP_FULL_RESET; | ||
| 1796 | if (priv->op_flags & OP_ASSOCIATED) { | 1592 | if (priv->op_flags & OP_ASSOCIATED) { |
| 1797 | ath9k_htc_beacon_config(priv, priv->vif); | 1593 | ath9k_htc_beacon_config(priv, priv->vif); |
| 1798 | ath_start_ani(priv); | 1594 | ath_start_ani(priv); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4b51ed47fe69..fde978665e07 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
| @@ -1615,7 +1615,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode) | |||
| 1615 | * simply keep the ATH_DBG_WARN_ON_ONCE() but make | 1615 | * simply keep the ATH_DBG_WARN_ON_ONCE() but make |
| 1616 | * ath9k_hw_setpower() return type void. | 1616 | * ath9k_hw_setpower() return type void. |
| 1617 | */ | 1617 | */ |
| 1618 | ATH_DBG_WARN_ON_ONCE(!status); | 1618 | |
| 1619 | if (!(ah->ah_flags & AH_UNPLUGGED)) | ||
| 1620 | ATH_DBG_WARN_ON_ONCE(!status); | ||
| 1619 | 1621 | ||
| 1620 | return status; | 1622 | return status; |
| 1621 | } | 1623 | } |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index b8ffaa5dc650..5a3dfec45e96 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
| @@ -646,6 +646,10 @@ struct ath_nf_limits { | |||
| 646 | s16 nominal; | 646 | s16 nominal; |
| 647 | }; | 647 | }; |
| 648 | 648 | ||
| 649 | /* ah_flags */ | ||
| 650 | #define AH_USE_EEPROM 0x1 | ||
| 651 | #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ | ||
| 652 | |||
| 649 | struct ath_hw { | 653 | struct ath_hw { |
| 650 | struct ieee80211_hw *hw; | 654 | struct ieee80211_hw *hw; |
| 651 | struct ath_common common; | 655 | struct ath_common common; |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index b0e5e716b167..767d8b86f1e1 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
| @@ -29,8 +29,8 @@ static unsigned int ath9k_debug = ATH_DBG_DEFAULT; | |||
| 29 | module_param_named(debug, ath9k_debug, uint, 0); | 29 | module_param_named(debug, ath9k_debug, uint, 0); |
| 30 | MODULE_PARM_DESC(debug, "Debugging mask"); | 30 | MODULE_PARM_DESC(debug, "Debugging mask"); |
| 31 | 31 | ||
| 32 | int modparam_nohwcrypt; | 32 | int ath9k_modparam_nohwcrypt; |
| 33 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 33 | module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); |
| 34 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | 34 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); |
| 35 | 35 | ||
| 36 | int led_blink; | 36 | int led_blink; |
| @@ -45,6 +45,7 @@ int ath9k_pm_qos_value = ATH9K_PM_QOS_DEFAULT_VALUE; | |||
| 45 | module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH); | 45 | module_param_named(pmqos, ath9k_pm_qos_value, int, S_IRUSR | S_IRGRP | S_IROTH); |
| 46 | MODULE_PARM_DESC(pmqos, "User specified PM-QOS value"); | 46 | MODULE_PARM_DESC(pmqos, "User specified PM-QOS value"); |
| 47 | 47 | ||
| 48 | bool is_ath9k_unloaded; | ||
| 48 | /* We use the hw_value as an index into our private channel structure */ | 49 | /* We use the hw_value as an index into our private channel structure */ |
| 49 | 50 | ||
| 50 | #define CHAN2G(_freq, _idx) { \ | 51 | #define CHAN2G(_freq, _idx) { \ |
| @@ -372,7 +373,7 @@ fail: | |||
| 372 | #undef DS2PHYS | 373 | #undef DS2PHYS |
| 373 | } | 374 | } |
| 374 | 375 | ||
| 375 | static void ath9k_init_crypto(struct ath_softc *sc) | 376 | void ath9k_init_crypto(struct ath_softc *sc) |
| 376 | { | 377 | { |
| 377 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 378 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 378 | int i = 0; | 379 | int i = 0; |
| @@ -647,13 +648,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
| 647 | IEEE80211_HW_SUPPORTS_PS | | 648 | IEEE80211_HW_SUPPORTS_PS | |
| 648 | IEEE80211_HW_PS_NULLFUNC_STACK | | 649 | IEEE80211_HW_PS_NULLFUNC_STACK | |
| 649 | IEEE80211_HW_SPECTRUM_MGMT | | 650 | IEEE80211_HW_SPECTRUM_MGMT | |
| 650 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 651 | IEEE80211_HW_REPORTS_TX_ACK_STATUS; |
| 651 | IEEE80211_HW_NEED_DTIM_PERIOD; | ||
| 652 | 652 | ||
| 653 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 653 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) |
| 654 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | 654 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; |
| 655 | 655 | ||
| 656 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) | 656 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) |
| 657 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 657 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
| 658 | 658 | ||
| 659 | hw->wiphy->interface_modes = | 659 | hw->wiphy->interface_modes = |
| @@ -899,6 +899,7 @@ module_init(ath9k_init); | |||
| 899 | 899 | ||
| 900 | static void __exit ath9k_exit(void) | 900 | static void __exit ath9k_exit(void) |
| 901 | { | 901 | { |
| 902 | is_ath9k_unloaded = true; | ||
| 902 | ath_ahb_exit(); | 903 | ath_ahb_exit(); |
| 903 | ath_pci_exit(); | 904 | ath_pci_exit(); |
| 904 | ath_rate_control_unregister(); | 905 | ath_rate_control_unregister(); |
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index e3d2ebf00e2e..180170d3ce25 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
| @@ -692,15 +692,16 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
| 692 | if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { | 692 | if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { |
| 693 | if (ads.ds_rxstatus8 & AR_CRCErr) | 693 | if (ads.ds_rxstatus8 & AR_CRCErr) |
| 694 | rs->rs_status |= ATH9K_RXERR_CRC; | 694 | rs->rs_status |= ATH9K_RXERR_CRC; |
| 695 | else if (ads.ds_rxstatus8 & AR_PHYErr) { | 695 | if (ads.ds_rxstatus8 & AR_PHYErr) { |
| 696 | rs->rs_status |= ATH9K_RXERR_PHY; | 696 | rs->rs_status |= ATH9K_RXERR_PHY; |
| 697 | phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); | 697 | phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); |
| 698 | rs->rs_phyerr = phyerr; | 698 | rs->rs_phyerr = phyerr; |
| 699 | } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) | 699 | } |
| 700 | if (ads.ds_rxstatus8 & AR_DecryptCRCErr) | ||
| 700 | rs->rs_status |= ATH9K_RXERR_DECRYPT; | 701 | rs->rs_status |= ATH9K_RXERR_DECRYPT; |
| 701 | else if (ads.ds_rxstatus8 & AR_MichaelErr) | 702 | if (ads.ds_rxstatus8 & AR_MichaelErr) |
| 702 | rs->rs_status |= ATH9K_RXERR_MIC; | 703 | rs->rs_status |= ATH9K_RXERR_MIC; |
| 703 | else if (ads.ds_rxstatus8 & AR_KeyMiss) | 704 | if (ads.ds_rxstatus8 & AR_KeyMiss) |
| 704 | rs->rs_status |= ATH9K_RXERR_DECRYPT; | 705 | rs->rs_status |= ATH9K_RXERR_DECRYPT; |
| 705 | } | 706 | } |
| 706 | 707 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8a1691db166d..f90a6ca94a76 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
| @@ -285,7 +285,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
| 285 | ath9k_hw_set_interrupts(ah, ah->imask); | 285 | ath9k_hw_set_interrupts(ah, ah->imask); |
| 286 | 286 | ||
| 287 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { | 287 | if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { |
| 288 | ath_beacon_config(sc, NULL); | 288 | if (sc->sc_flags & SC_OP_BEACONS) |
| 289 | ath_beacon_config(sc, NULL); | ||
| 289 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 290 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
| 290 | ath_start_ani(common); | 291 | ath_start_ani(common); |
| 291 | } | 292 | } |
| @@ -599,7 +600,7 @@ void ath9k_tasklet(unsigned long data) | |||
| 599 | return; | 600 | return; |
| 600 | } | 601 | } |
| 601 | 602 | ||
| 602 | spin_lock_bh(&sc->sc_pcu_lock); | 603 | spin_lock(&sc->sc_pcu_lock); |
| 603 | 604 | ||
| 604 | if (!ath9k_hw_check_alive(ah)) | 605 | if (!ath9k_hw_check_alive(ah)) |
| 605 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); | 606 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); |
| @@ -643,7 +644,7 @@ void ath9k_tasklet(unsigned long data) | |||
| 643 | /* re-enable hardware interrupt */ | 644 | /* re-enable hardware interrupt */ |
| 644 | ath9k_hw_enable_interrupts(ah); | 645 | ath9k_hw_enable_interrupts(ah); |
| 645 | 646 | ||
| 646 | spin_unlock_bh(&sc->sc_pcu_lock); | 647 | spin_unlock(&sc->sc_pcu_lock); |
| 647 | ath9k_ps_restore(sc); | 648 | ath9k_ps_restore(sc); |
| 648 | } | 649 | } |
| 649 | 650 | ||
| @@ -1328,6 +1329,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
| 1328 | ath9k_ps_restore(sc); | 1329 | ath9k_ps_restore(sc); |
| 1329 | 1330 | ||
| 1330 | sc->ps_idle = true; | 1331 | sc->ps_idle = true; |
| 1332 | ath9k_set_wiphy_idle(aphy, true); | ||
| 1331 | ath_radio_disable(sc, hw); | 1333 | ath_radio_disable(sc, hw); |
| 1332 | 1334 | ||
| 1333 | sc->sc_flags |= SC_OP_INVALID; | 1335 | sc->sc_flags |= SC_OP_INVALID; |
| @@ -1455,6 +1457,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
| 1455 | struct ath_wiphy *aphy = hw->priv; | 1457 | struct ath_wiphy *aphy = hw->priv; |
| 1456 | struct ath_softc *sc = aphy->sc; | 1458 | struct ath_softc *sc = aphy->sc; |
| 1457 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1459 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1460 | int ret = 0; | ||
| 1458 | 1461 | ||
| 1459 | ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); | 1462 | ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); |
| 1460 | mutex_lock(&sc->mutex); | 1463 | mutex_lock(&sc->mutex); |
| @@ -1464,7 +1467,8 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
| 1464 | case NL80211_IFTYPE_ADHOC: | 1467 | case NL80211_IFTYPE_ADHOC: |
| 1465 | if (sc->nbcnvifs >= ATH_BCBUF) { | 1468 | if (sc->nbcnvifs >= ATH_BCBUF) { |
| 1466 | ath_err(common, "No beacon slot available\n"); | 1469 | ath_err(common, "No beacon slot available\n"); |
| 1467 | return -ENOBUFS; | 1470 | ret = -ENOBUFS; |
| 1471 | goto out; | ||
| 1468 | } | 1472 | } |
| 1469 | break; | 1473 | break; |
| 1470 | case NL80211_IFTYPE_STATION: | 1474 | case NL80211_IFTYPE_STATION: |
| @@ -1478,14 +1482,15 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
| 1478 | default: | 1482 | default: |
| 1479 | ath_err(common, "Interface type %d not yet supported\n", | 1483 | ath_err(common, "Interface type %d not yet supported\n", |
| 1480 | vif->type); | 1484 | vif->type); |
| 1481 | mutex_unlock(&sc->mutex); | 1485 | ret = -ENOTSUPP; |
| 1482 | return -ENOTSUPP; | 1486 | goto out; |
| 1483 | } | 1487 | } |
| 1484 | vif->type = new_type; | 1488 | vif->type = new_type; |
| 1485 | vif->p2p = p2p; | 1489 | vif->p2p = p2p; |
| 1486 | 1490 | ||
| 1491 | out: | ||
| 1487 | mutex_unlock(&sc->mutex); | 1492 | mutex_unlock(&sc->mutex); |
| 1488 | return 0; | 1493 | return ret; |
| 1489 | } | 1494 | } |
| 1490 | 1495 | ||
| 1491 | static void ath9k_remove_interface(struct ieee80211_hw *hw, | 1496 | static void ath9k_remove_interface(struct ieee80211_hw *hw, |
| @@ -1824,7 +1829,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
| 1824 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1829 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
| 1825 | int ret = 0; | 1830 | int ret = 0; |
| 1826 | 1831 | ||
| 1827 | if (modparam_nohwcrypt) | 1832 | if (ath9k_modparam_nohwcrypt) |
| 1828 | return -ENOSPC; | 1833 | return -ENOSPC; |
| 1829 | 1834 | ||
| 1830 | mutex_lock(&sc->mutex); | 1835 | mutex_lock(&sc->mutex); |
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 7ca8499249ec..78ef1f13386f 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
| @@ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) | |||
| 96 | struct pci_dev *pdev = to_pci_dev(sc->dev); | 96 | struct pci_dev *pdev = to_pci_dev(sc->dev); |
| 97 | u8 aspm; | 97 | u8 aspm; |
| 98 | 98 | ||
| 99 | if (!pdev->is_pcie) | 99 | if (!pci_is_pcie(pdev)) |
| 100 | return; | 100 | return; |
| 101 | 101 | ||
| 102 | pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); | 102 | pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); |
| @@ -264,6 +264,8 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
| 264 | struct ath_softc *sc = aphy->sc; | 264 | struct ath_softc *sc = aphy->sc; |
| 265 | void __iomem *mem = sc->mem; | 265 | void __iomem *mem = sc->mem; |
| 266 | 266 | ||
| 267 | if (!is_ath9k_unloaded) | ||
| 268 | sc->sc_ah->ah_flags |= AH_UNPLUGGED; | ||
| 267 | ath9k_deinit_device(sc); | 269 | ath9k_deinit_device(sc); |
| 268 | free_irq(sc->irq, sc); | 270 | free_irq(sc->irq, sc); |
| 269 | ieee80211_free_hw(sc->hw); | 271 | ieee80211_free_hw(sc->hw); |
| @@ -309,7 +311,16 @@ static int ath_pci_resume(struct device *device) | |||
| 309 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 311 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
| 310 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | 312 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); |
| 311 | 313 | ||
| 314 | /* | ||
| 315 | * Reset key cache to sane defaults (all entries cleared) instead of | ||
| 316 | * semi-random values after suspend/resume. | ||
| 317 | */ | ||
| 318 | ath9k_ps_wakeup(sc); | ||
| 319 | ath9k_init_crypto(sc); | ||
| 320 | ath9k_ps_restore(sc); | ||
| 321 | |||
| 312 | sc->ps_idle = true; | 322 | sc->ps_idle = true; |
| 323 | ath9k_set_wiphy_idle(aphy, true); | ||
| 313 | ath_radio_disable(sc, hw); | 324 | ath_radio_disable(sc, hw); |
| 314 | 325 | ||
| 315 | return 0; | 326 | return 0; |
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 896d12986b1e..e45147820eae 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
| @@ -400,7 +400,7 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, | |||
| 400 | } | 400 | } |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) | 403 | static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv) |
| 404 | { | 404 | { |
| 405 | u8 i; | 405 | u8 i; |
| 406 | 406 | ||
| @@ -408,7 +408,7 @@ static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) | |||
| 408 | ath_rc_priv->valid_rate_index[i] = 0; | 408 | ath_rc_priv->valid_rate_index[i] = 0; |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, | 411 | static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv, |
| 412 | u8 index, int valid_tx_rate) | 412 | u8 index, int valid_tx_rate) |
| 413 | { | 413 | { |
| 414 | BUG_ON(index > ath_rc_priv->rate_table_size); | 414 | BUG_ON(index > ath_rc_priv->rate_table_size); |
| @@ -489,7 +489,7 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, | |||
| 489 | 489 | ||
| 490 | ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; | 490 | ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; |
| 491 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 491 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
| 492 | ath_rc_set_valid_txmask(ath_rc_priv, i, 1); | 492 | ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1); |
| 493 | hi = i; | 493 | hi = i; |
| 494 | } | 494 | } |
| 495 | } | 495 | } |
| @@ -532,7 +532,7 @@ static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, | |||
| 532 | ath_rc_priv->valid_phy_rateidx[phy] | 532 | ath_rc_priv->valid_phy_rateidx[phy] |
| 533 | [valid_rate_count] = j; | 533 | [valid_rate_count] = j; |
| 534 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 534 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
| 535 | ath_rc_set_valid_txmask(ath_rc_priv, j, 1); | 535 | ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1); |
| 536 | hi = A_MAX(hi, j); | 536 | hi = A_MAX(hi, j); |
| 537 | } | 537 | } |
| 538 | } | 538 | } |
| @@ -568,7 +568,7 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, | |||
| 568 | ath_rc_priv->valid_phy_rateidx[phy] | 568 | ath_rc_priv->valid_phy_rateidx[phy] |
| 569 | [ath_rc_priv->valid_phy_ratecnt[phy]] = j; | 569 | [ath_rc_priv->valid_phy_ratecnt[phy]] = j; |
| 570 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; | 570 | ath_rc_priv->valid_phy_ratecnt[phy] += 1; |
| 571 | ath_rc_set_valid_txmask(ath_rc_priv, j, 1); | 571 | ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1); |
| 572 | hi = A_MAX(hi, j); | 572 | hi = A_MAX(hi, j); |
| 573 | } | 573 | } |
| 574 | } | 574 | } |
| @@ -1210,7 +1210,7 @@ static void ath_rc_init(struct ath_softc *sc, | |||
| 1210 | } | 1210 | } |
| 1211 | 1211 | ||
| 1212 | /* Determine the valid rates */ | 1212 | /* Determine the valid rates */ |
| 1213 | ath_rc_init_valid_txmask(ath_rc_priv); | 1213 | ath_rc_init_valid_rate_idx(ath_rc_priv); |
| 1214 | 1214 | ||
| 1215 | for (i = 0; i < WLAN_RC_PHY_MAX; i++) { | 1215 | for (i = 0; i < WLAN_RC_PHY_MAX; i++) { |
| 1216 | for (j = 0; j < MAX_TX_RATE_PHY; j++) | 1216 | for (j = 0; j < MAX_TX_RATE_PHY; j++) |
| @@ -1321,7 +1321,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 1321 | struct ath_rate_priv *ath_rc_priv = priv_sta; | 1321 | struct ath_rate_priv *ath_rc_priv = priv_sta; |
| 1322 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1322 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
| 1323 | struct ieee80211_hdr *hdr; | 1323 | struct ieee80211_hdr *hdr; |
| 1324 | int final_ts_idx = 0, tx_status = 0, is_underrun = 0; | 1324 | int final_ts_idx = 0, tx_status = 0; |
| 1325 | int long_retry = 0; | 1325 | int long_retry = 0; |
| 1326 | __le16 fc; | 1326 | __le16 fc; |
| 1327 | int i; | 1327 | int i; |
| @@ -1358,7 +1358,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
| 1358 | tx_status = 1; | 1358 | tx_status = 1; |
| 1359 | 1359 | ||
| 1360 | ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, | 1360 | ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, |
| 1361 | (is_underrun) ? sc->hw->max_rate_tries : long_retry); | 1361 | long_retry); |
| 1362 | 1362 | ||
| 1363 | /* Check if aggregation has to be enabled for this tid */ | 1363 | /* Check if aggregation has to be enabled for this tid */ |
| 1364 | if (conf_is_ht(&sc->hw->conf) && | 1364 | if (conf_is_ht(&sc->hw->conf) && |
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index 31a004cb60ac..5d984b8acdb1 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h | |||
| @@ -195,7 +195,6 @@ struct ath_rc_stats { | |||
| 195 | * @rate_max_phy: phy index for the max rate | 195 | * @rate_max_phy: phy index for the max rate |
| 196 | * @per: PER for every valid rate in % | 196 | * @per: PER for every valid rate in % |
| 197 | * @probe_interval: interval for ratectrl to probe for other rates | 197 | * @probe_interval: interval for ratectrl to probe for other rates |
| 198 | * @prev_data_rix: rate idx of last data frame | ||
| 199 | * @ht_cap: HT capabilities | 198 | * @ht_cap: HT capabilities |
| 200 | * @neg_rates: Negotatied rates | 199 | * @neg_rates: Negotatied rates |
| 201 | * @neg_ht_rates: Negotiated HT rates | 200 | * @neg_ht_rates: Negotiated HT rates |
| @@ -214,10 +213,8 @@ struct ath_rate_priv { | |||
| 214 | u32 probe_time; | 213 | u32 probe_time; |
| 215 | u32 per_down_time; | 214 | u32 per_down_time; |
| 216 | u32 probe_interval; | 215 | u32 probe_interval; |
| 217 | u32 prev_data_rix; | ||
| 218 | struct ath_rateset neg_rates; | 216 | struct ath_rateset neg_rates; |
| 219 | struct ath_rateset neg_ht_rates; | 217 | struct ath_rateset neg_ht_rates; |
| 220 | struct ath_rate_softc *asc; | ||
| 221 | const struct ath_rate_table *rate_table; | 218 | const struct ath_rate_table *rate_table; |
| 222 | 219 | ||
| 223 | struct dentry *debugfs_rcstats; | 220 | struct dentry *debugfs_rcstats; |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 00ebed3f9158..b2497b8601e5 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
| @@ -528,7 +528,8 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
| 528 | sc->rx.rxlink = NULL; | 528 | sc->rx.rxlink = NULL; |
| 529 | spin_unlock_bh(&sc->rx.rxbuflock); | 529 | spin_unlock_bh(&sc->rx.rxbuflock); |
| 530 | 530 | ||
| 531 | if (unlikely(!stopped)) { | 531 | if (!(ah->ah_flags & AH_UNPLUGGED) && |
| 532 | unlikely(!stopped)) { | ||
| 532 | ath_err(ath9k_hw_common(sc->sc_ah), | 533 | ath_err(ath9k_hw_common(sc->sc_ah), |
| 533 | "Could not stop RX, we could be " | 534 | "Could not stop RX, we could be " |
| 534 | "confusing the DMA engine when we start RX up\n"); | 535 | "confusing the DMA engine when we start RX up\n"); |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 8f42ea78198c..dc862f5e1162 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c | |||
| @@ -120,7 +120,7 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) | |||
| 120 | kfree(priv->wmi); | 120 | kfree(priv->wmi); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | void ath9k_wmi_tasklet(unsigned long data) | 123 | void ath9k_swba_tasklet(unsigned long data) |
| 124 | { | 124 | { |
| 125 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | 125 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; |
| 126 | struct ath_common *common = ath9k_hw_common(priv->ah); | 126 | struct ath_common *common = ath9k_hw_common(priv->ah); |
| @@ -131,6 +131,16 @@ void ath9k_wmi_tasklet(unsigned long data) | |||
| 131 | 131 | ||
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | void ath9k_fatal_work(struct work_struct *work) | ||
| 135 | { | ||
| 136 | struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, | ||
| 137 | fatal_work); | ||
| 138 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
| 139 | |||
| 140 | ath_dbg(common, ATH_DBG_FATAL, "FATAL Event received, resetting device\n"); | ||
| 141 | ath9k_htc_reset(priv); | ||
| 142 | } | ||
| 143 | |||
| 134 | static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) | 144 | static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) |
| 135 | { | 145 | { |
| 136 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); | 146 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); |
| @@ -163,7 +173,11 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, | |||
| 163 | switch (cmd_id) { | 173 | switch (cmd_id) { |
| 164 | case WMI_SWBA_EVENTID: | 174 | case WMI_SWBA_EVENTID: |
| 165 | wmi->beacon_pending = *(u8 *)wmi_event; | 175 | wmi->beacon_pending = *(u8 *)wmi_event; |
| 166 | tasklet_schedule(&wmi->drv_priv->wmi_tasklet); | 176 | tasklet_schedule(&wmi->drv_priv->swba_tasklet); |
| 177 | break; | ||
| 178 | case WMI_FATAL_EVENTID: | ||
| 179 | ieee80211_queue_work(wmi->drv_priv->hw, | ||
| 180 | &wmi->drv_priv->fatal_work); | ||
| 167 | break; | 181 | break; |
| 168 | case WMI_TXRATE_EVENTID: | 182 | case WMI_TXRATE_EVENTID: |
| 169 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | 183 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS |
| @@ -250,7 +264,7 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, | |||
| 250 | int time_left, ret = 0; | 264 | int time_left, ret = 0; |
| 251 | unsigned long flags; | 265 | unsigned long flags; |
| 252 | 266 | ||
| 253 | if (wmi->drv_priv->op_flags & OP_UNPLUGGED) | 267 | if (ah->ah_flags & AH_UNPLUGGED) |
| 254 | return 0; | 268 | return 0; |
| 255 | 269 | ||
| 256 | skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC); | 270 | skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC); |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index ac61074af8ac..42084277522d 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h | |||
| @@ -117,7 +117,8 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, | |||
| 117 | u8 *cmd_buf, u32 cmd_len, | 117 | u8 *cmd_buf, u32 cmd_len, |
| 118 | u8 *rsp_buf, u32 rsp_len, | 118 | u8 *rsp_buf, u32 rsp_len, |
| 119 | u32 timeout); | 119 | u32 timeout); |
| 120 | void ath9k_wmi_tasklet(unsigned long data); | 120 | void ath9k_swba_tasklet(unsigned long data); |
| 121 | void ath9k_fatal_work(struct work_struct *work); | ||
| 121 | 122 | ||
| 122 | #define WMI_CMD(_wmi_cmd) \ | 123 | #define WMI_CMD(_wmi_cmd) \ |
| 123 | do { \ | 124 | do { \ |
