diff options
author | David S. Miller <davem@davemloft.net> | 2009-05-25 03:38:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-25 03:38:24 -0400 |
commit | 45ea4ea2af358fe316c918381c7868f9418cad09 (patch) | |
tree | 4deb3d87b26e884b06929fe33740d45e78fbdcab | |
parent | dddc045e2fdd4eb8d7dfac29bff191d639fff8c3 (diff) | |
parent | a2e2322d83df82a57ba456cfa604c8b8f7b04670 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
124 files changed, 13213 insertions, 1745 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index fbeaffc1dcc3..e36986663570 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -145,7 +145,6 @@ usage should require reading the full document. | |||
145 | interface in STA mode at first! | 145 | interface in STA mode at first! |
146 | </para> | 146 | </para> |
147 | !Finclude/net/mac80211.h ieee80211_if_init_conf | 147 | !Finclude/net/mac80211.h ieee80211_if_init_conf |
148 | !Finclude/net/mac80211.h ieee80211_if_conf | ||
149 | </chapter> | 148 | </chapter> |
150 | 149 | ||
151 | <chapter id="rx-tx"> | 150 | <chapter id="rx-tx"> |
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 91be3e7bf133..a67d29290ba0 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -501,5 +501,6 @@ source "drivers/net/wireless/zd1211rw/Kconfig" | |||
501 | source "drivers/net/wireless/rt2x00/Kconfig" | 501 | source "drivers/net/wireless/rt2x00/Kconfig" |
502 | source "drivers/net/wireless/orinoco/Kconfig" | 502 | source "drivers/net/wireless/orinoco/Kconfig" |
503 | source "drivers/net/wireless/wl12xx/Kconfig" | 503 | source "drivers/net/wireless/wl12xx/Kconfig" |
504 | source "drivers/net/wireless/iwmc3200wifi/Kconfig" | ||
504 | 505 | ||
505 | endmenu | 506 | endmenu |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index f2b1861e6bcb..7a4647e78fd3 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -60,3 +60,5 @@ obj-$(CONFIG_ATH_COMMON) += ath/ | |||
60 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o | 60 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o |
61 | 61 | ||
62 | obj-$(CONFIG_WL12XX) += wl12xx/ | 62 | obj-$(CONFIG_WL12XX) += wl12xx/ |
63 | |||
64 | obj-$(CONFIG_IWM) += iwmc3200wifi/ | ||
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index 4ef1d2fc859c..99df9ddae9cb 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c | |||
@@ -1555,7 +1555,7 @@ static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
1555 | 1555 | ||
1556 | switch (key->alg) { | 1556 | switch (key->alg) { |
1557 | case ALG_WEP: | 1557 | case ALG_WEP: |
1558 | if (key->keylen == LEN_WEP40) | 1558 | if (key->keylen == WLAN_KEY_LEN_WEP40) |
1559 | ktype = AR9170_ENC_ALG_WEP64; | 1559 | ktype = AR9170_ENC_ALG_WEP64; |
1560 | else | 1560 | else |
1561 | ktype = AR9170_ENC_ALG_WEP128; | 1561 | ktype = AR9170_ENC_ALG_WEP128; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index dbfe9f45050e..fb5193764afa 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -242,8 +242,8 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, | |||
242 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); | 242 | static u64 ath5k_get_tsf(struct ieee80211_hw *hw); |
243 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); | 243 | static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf); |
244 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); | 244 | static void ath5k_reset_tsf(struct ieee80211_hw *hw); |
245 | static int ath5k_beacon_update(struct ath5k_softc *sc, | 245 | static int ath5k_beacon_update(struct ieee80211_hw *hw, |
246 | struct sk_buff *skb); | 246 | struct ieee80211_vif *vif); |
247 | static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | 247 | static void ath5k_bss_info_changed(struct ieee80211_hw *hw, |
248 | struct ieee80211_vif *vif, | 248 | struct ieee80211_vif *vif, |
249 | struct ieee80211_bss_conf *bss_conf, | 249 | struct ieee80211_bss_conf *bss_conf, |
@@ -2127,8 +2127,10 @@ ath5k_beacon_send(struct ath5k_softc *sc) | |||
2127 | /* NB: hw still stops DMA, so proceed */ | 2127 | /* NB: hw still stops DMA, so proceed */ |
2128 | } | 2128 | } |
2129 | 2129 | ||
2130 | /* Note: Beacon buffer is updated on beacon_update when mac80211 | 2130 | /* refresh the beacon for AP mode */ |
2131 | * calls config_interface */ | 2131 | if (sc->opmode == NL80211_IFTYPE_AP) |
2132 | ath5k_beacon_update(sc->hw, sc->vif); | ||
2133 | |||
2132 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); | 2134 | ath5k_hw_set_txdp(ah, sc->bhalq, bf->daddr); |
2133 | ath5k_hw_start_tx_dma(ah, sc->bhalq); | 2135 | ath5k_hw_start_tx_dma(ah, sc->bhalq); |
2134 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", | 2136 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n", |
@@ -3047,28 +3049,55 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) | |||
3047 | ath5k_hw_reset_tsf(sc->ah); | 3049 | ath5k_hw_reset_tsf(sc->ah); |
3048 | } | 3050 | } |
3049 | 3051 | ||
3052 | /* | ||
3053 | * Updates the beacon that is sent by ath5k_beacon_send. For adhoc, | ||
3054 | * this is called only once at config_bss time, for AP we do it every | ||
3055 | * SWBA interrupt so that the TIM will reflect buffered frames. | ||
3056 | * | ||
3057 | * Called with the beacon lock. | ||
3058 | */ | ||
3050 | static int | 3059 | static int |
3051 | ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) | 3060 | ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
3052 | { | 3061 | { |
3053 | unsigned long flags; | ||
3054 | int ret; | 3062 | int ret; |
3063 | struct ath5k_softc *sc = hw->priv; | ||
3064 | struct sk_buff *skb = ieee80211_beacon_get(hw, vif); | ||
3065 | |||
3066 | if (!skb) { | ||
3067 | ret = -ENOMEM; | ||
3068 | goto out; | ||
3069 | } | ||
3055 | 3070 | ||
3056 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 3071 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
3057 | 3072 | ||
3058 | spin_lock_irqsave(&sc->block, flags); | ||
3059 | ath5k_txbuf_free(sc, sc->bbuf); | 3073 | ath5k_txbuf_free(sc, sc->bbuf); |
3060 | sc->bbuf->skb = skb; | 3074 | sc->bbuf->skb = skb; |
3061 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 3075 | ret = ath5k_beacon_setup(sc, sc->bbuf); |
3062 | if (ret) | 3076 | if (ret) |
3063 | sc->bbuf->skb = NULL; | 3077 | sc->bbuf->skb = NULL; |
3078 | out: | ||
3079 | return ret; | ||
3080 | } | ||
3081 | |||
3082 | /* | ||
3083 | * Update the beacon and reconfigure the beacon queues. | ||
3084 | */ | ||
3085 | static void | ||
3086 | ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||
3087 | { | ||
3088 | int ret; | ||
3089 | unsigned long flags; | ||
3090 | struct ath5k_softc *sc = hw->priv; | ||
3091 | |||
3092 | spin_lock_irqsave(&sc->block, flags); | ||
3093 | ret = ath5k_beacon_update(hw, vif); | ||
3064 | spin_unlock_irqrestore(&sc->block, flags); | 3094 | spin_unlock_irqrestore(&sc->block, flags); |
3065 | if (!ret) { | 3095 | if (ret == 0) { |
3066 | ath5k_beacon_config(sc); | 3096 | ath5k_beacon_config(sc); |
3067 | mmiowb(); | 3097 | mmiowb(); |
3068 | } | 3098 | } |
3069 | |||
3070 | return ret; | ||
3071 | } | 3099 | } |
3100 | |||
3072 | static void | 3101 | static void |
3073 | set_beacon_filter(struct ieee80211_hw *hw, bool enable) | 3102 | set_beacon_filter(struct ieee80211_hw *hw, bool enable) |
3074 | { | 3103 | { |
@@ -3118,10 +3147,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
3118 | (vif->type == NL80211_IFTYPE_ADHOC || | 3147 | (vif->type == NL80211_IFTYPE_ADHOC || |
3119 | vif->type == NL80211_IFTYPE_MESH_POINT || | 3148 | vif->type == NL80211_IFTYPE_MESH_POINT || |
3120 | vif->type == NL80211_IFTYPE_AP)) { | 3149 | vif->type == NL80211_IFTYPE_AP)) { |
3121 | struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | 3150 | ath5k_beacon_reconfig(hw, vif); |
3122 | |||
3123 | if (beacon) | ||
3124 | ath5k_beacon_update(sc, beacon); | ||
3125 | } | 3151 | } |
3126 | 3152 | ||
3127 | unlock: | 3153 | unlock: |
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 579aa0a96ab8..ec35503f6a40 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -1038,9 +1038,9 @@ int ath5k_keycache_type(const struct ieee80211_key_conf *key) | |||
1038 | case ALG_CCMP: | 1038 | case ALG_CCMP: |
1039 | return AR5K_KEYTABLE_TYPE_CCM; | 1039 | return AR5K_KEYTABLE_TYPE_CCM; |
1040 | case ALG_WEP: | 1040 | case ALG_WEP: |
1041 | if (key->keylen == LEN_WEP40) | 1041 | if (key->keylen == WLAN_KEY_LEN_WEP40) |
1042 | return AR5K_KEYTABLE_TYPE_40; | 1042 | return AR5K_KEYTABLE_TYPE_40; |
1043 | else if (key->keylen == LEN_WEP104) | 1043 | else if (key->keylen == WLAN_KEY_LEN_WEP104) |
1044 | return AR5K_KEYTABLE_TYPE_104; | 1044 | return AR5K_KEYTABLE_TYPE_104; |
1045 | return -EINVAL; | 1045 | return -EINVAL; |
1046 | default: | 1046 | default: |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index d0d1c350025a..a876ca8d69ef 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c | |||
@@ -1897,6 +1897,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, | |||
1897 | s16 min_pwrL, min_pwrR; | 1897 | s16 min_pwrL, min_pwrR; |
1898 | s16 pwr_i; | 1898 | s16 pwr_i; |
1899 | 1899 | ||
1900 | if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1])) | ||
1901 | return 0; | ||
1902 | |||
1900 | if (pwrL[0] == pwrL[1]) | 1903 | if (pwrL[0] == pwrL[1]) |
1901 | min_pwrL = pwrL[0]; | 1904 | min_pwrL = pwrL[0]; |
1902 | else { | 1905 | else { |
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 10ffc9442859..796a3adffea0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -515,6 +515,10 @@ struct ath_rfkill { | |||
515 | #define SC_OP_LED_ON BIT(13) | 515 | #define SC_OP_LED_ON BIT(13) |
516 | #define SC_OP_SCANNING BIT(14) | 516 | #define SC_OP_SCANNING BIT(14) |
517 | #define SC_OP_TSF_RESET BIT(15) | 517 | #define SC_OP_TSF_RESET BIT(15) |
518 | #define SC_OP_WAIT_FOR_CAB BIT(16) | ||
519 | #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) | ||
520 | #define SC_OP_WAIT_FOR_TX_ACK BIT(18) | ||
521 | #define SC_OP_BEACON_SYNC BIT(19) | ||
518 | 522 | ||
519 | struct ath_bus_ops { | 523 | struct ath_bus_ops { |
520 | void (*read_cachesize)(struct ath_softc *sc, int *csz); | 524 | void (*read_cachesize)(struct ath_softc *sc, int *csz); |
@@ -599,6 +603,7 @@ struct ath_softc { | |||
599 | struct ath9k_debug debug; | 603 | struct ath9k_debug debug; |
600 | #endif | 604 | #endif |
601 | struct ath_bus_ops *bus_ops; | 605 | struct ath_bus_ops *bus_ops; |
606 | struct ath_beacon_config cur_beacon_conf; | ||
602 | }; | 607 | }; |
603 | 608 | ||
604 | struct ath_wiphy { | 609 | struct ath_wiphy { |
@@ -676,7 +681,9 @@ static inline void ath9k_ps_restore(struct ath_softc *sc) | |||
676 | { | 681 | { |
677 | if (atomic_dec_and_test(&sc->ps_usecount)) | 682 | if (atomic_dec_and_test(&sc->ps_usecount)) |
678 | if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && | 683 | if ((sc->hw->conf.flags & IEEE80211_CONF_PS) && |
679 | !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) | 684 | !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | |
685 | SC_OP_WAIT_FOR_PSPOLL_DATA | | ||
686 | SC_OP_WAIT_FOR_TX_ACK))) | ||
680 | ath9k_hw_setpower(sc->sc_ah, | 687 | ath9k_hw_setpower(sc->sc_ah, |
681 | sc->sc_ah->restore_mode); | 688 | sc->sc_ah->restore_mode); |
682 | } | 689 | } |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 3a7154beeae1..a21b21339fbc 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -507,8 +507,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
507 | * slot. Slots that are not occupied will generate nothing. | 507 | * slot. Slots that are not occupied will generate nothing. |
508 | */ | 508 | */ |
509 | static void ath_beacon_config_ap(struct ath_softc *sc, | 509 | static void ath_beacon_config_ap(struct ath_softc *sc, |
510 | struct ath_beacon_config *conf, | 510 | struct ath_beacon_config *conf) |
511 | struct ath_vif *avp) | ||
512 | { | 511 | { |
513 | u32 nexttbtt, intval; | 512 | u32 nexttbtt, intval; |
514 | 513 | ||
@@ -553,14 +552,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
553 | * we've associated with. | 552 | * we've associated with. |
554 | */ | 553 | */ |
555 | static void ath_beacon_config_sta(struct ath_softc *sc, | 554 | static void ath_beacon_config_sta(struct ath_softc *sc, |
556 | struct ath_beacon_config *conf, | 555 | struct ath_beacon_config *conf) |
557 | struct ath_vif *avp) | ||
558 | { | 556 | { |
559 | struct ath9k_beacon_state bs; | 557 | struct ath9k_beacon_state bs; |
560 | int dtimperiod, dtimcount, sleepduration; | 558 | int dtimperiod, dtimcount, sleepduration; |
561 | int cfpperiod, cfpcount; | 559 | int cfpperiod, cfpcount; |
562 | u32 nexttbtt = 0, intval, tsftu; | 560 | u32 nexttbtt = 0, intval, tsftu; |
563 | u64 tsf; | 561 | u64 tsf; |
562 | int num_beacons, offset, dtim_dec_count, cfp_dec_count; | ||
564 | 563 | ||
565 | memset(&bs, 0, sizeof(bs)); | 564 | memset(&bs, 0, sizeof(bs)); |
566 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 565 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; |
@@ -588,14 +587,27 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
588 | */ | 587 | */ |
589 | tsf = ath9k_hw_gettsf64(sc->sc_ah); | 588 | tsf = ath9k_hw_gettsf64(sc->sc_ah); |
590 | tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; | 589 | tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; |
591 | do { | 590 | |
591 | num_beacons = tsftu / intval + 1; | ||
592 | offset = tsftu % intval; | ||
593 | nexttbtt = tsftu - offset; | ||
594 | if (offset) | ||
592 | nexttbtt += intval; | 595 | nexttbtt += intval; |
593 | if (--dtimcount < 0) { | 596 | |
594 | dtimcount = dtimperiod - 1; | 597 | /* DTIM Beacon every dtimperiod Beacon */ |
595 | if (--cfpcount < 0) | 598 | dtim_dec_count = num_beacons % dtimperiod; |
596 | cfpcount = cfpperiod - 1; | 599 | /* CFP every cfpperiod DTIM Beacon */ |
597 | } | 600 | cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; |
598 | } while (nexttbtt < tsftu); | 601 | if (dtim_dec_count) |
602 | cfp_dec_count++; | ||
603 | |||
604 | dtimcount -= dtim_dec_count; | ||
605 | if (dtimcount < 0) | ||
606 | dtimcount += dtimperiod; | ||
607 | |||
608 | cfpcount -= cfp_dec_count; | ||
609 | if (cfpcount < 0) | ||
610 | cfpcount += cfpperiod; | ||
599 | 611 | ||
600 | bs.bs_intval = intval; | 612 | bs.bs_intval = intval; |
601 | bs.bs_nexttbtt = nexttbtt; | 613 | bs.bs_nexttbtt = nexttbtt; |
@@ -654,7 +666,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
654 | 666 | ||
655 | static void ath_beacon_config_adhoc(struct ath_softc *sc, | 667 | static void ath_beacon_config_adhoc(struct ath_softc *sc, |
656 | struct ath_beacon_config *conf, | 668 | struct ath_beacon_config *conf, |
657 | struct ath_vif *avp, | ||
658 | struct ieee80211_vif *vif) | 669 | struct ieee80211_vif *vif) |
659 | { | 670 | { |
660 | u64 tsf; | 671 | u64 tsf; |
@@ -698,43 +709,50 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, | |||
698 | sc->beacon.bmisscnt = 0; | 709 | sc->beacon.bmisscnt = 0; |
699 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); | 710 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); |
700 | 711 | ||
701 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) | 712 | /* FIXME: Handle properly when vif is NULL */ |
713 | if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) | ||
702 | ath_beacon_start_adhoc(sc, vif); | 714 | ath_beacon_start_adhoc(sc, vif); |
703 | } | 715 | } |
704 | 716 | ||
705 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | 717 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) |
706 | { | 718 | { |
707 | struct ath_beacon_config conf; | 719 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; |
720 | enum nl80211_iftype iftype; | ||
708 | 721 | ||
709 | /* Setup the beacon configuration parameters */ | 722 | /* Setup the beacon configuration parameters */ |
710 | 723 | ||
711 | memset(&conf, 0, sizeof(struct ath_beacon_config)); | ||
712 | conf.beacon_interval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; | ||
713 | conf.listen_interval = 1; | ||
714 | conf.dtim_period = conf.beacon_interval; | ||
715 | conf.dtim_count = 1; | ||
716 | conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; | ||
717 | |||
718 | if (vif) { | 724 | if (vif) { |
719 | struct ath_vif *avp = (struct ath_vif *)vif->drv_priv; | 725 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
720 | 726 | ||
721 | switch(avp->av_opmode) { | 727 | iftype = vif->type; |
722 | case NL80211_IFTYPE_AP: | 728 | |
723 | ath_beacon_config_ap(sc, &conf, avp); | 729 | cur_conf->beacon_interval = bss_conf->beacon_int; |
724 | break; | 730 | cur_conf->dtim_period = bss_conf->dtim_period; |
725 | case NL80211_IFTYPE_ADHOC: | 731 | cur_conf->listen_interval = 1; |
726 | case NL80211_IFTYPE_MESH_POINT: | 732 | cur_conf->dtim_count = 1; |
727 | ath_beacon_config_adhoc(sc, &conf, avp, vif); | 733 | cur_conf->bmiss_timeout = |
728 | break; | 734 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; |
729 | case NL80211_IFTYPE_STATION: | 735 | } else { |
730 | ath_beacon_config_sta(sc, &conf, avp); | 736 | iftype = sc->sc_ah->opmode; |
731 | break; | 737 | } |
732 | default: | 738 | |
733 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
734 | "Unsupported beaconing mode\n"); | ||
735 | return; | ||
736 | } | ||
737 | 739 | ||
738 | sc->sc_flags |= SC_OP_BEACONS; | 740 | switch (iftype) { |
741 | case NL80211_IFTYPE_AP: | ||
742 | ath_beacon_config_ap(sc, cur_conf); | ||
743 | break; | ||
744 | case NL80211_IFTYPE_ADHOC: | ||
745 | case NL80211_IFTYPE_MESH_POINT: | ||
746 | ath_beacon_config_adhoc(sc, cur_conf, vif); | ||
747 | break; | ||
748 | case NL80211_IFTYPE_STATION: | ||
749 | ath_beacon_config_sta(sc, cur_conf); | ||
750 | break; | ||
751 | default: | ||
752 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
753 | "Unsupported beaconing mode\n"); | ||
754 | return; | ||
739 | } | 755 | } |
756 | |||
757 | sc->sc_flags |= SC_OP_BEACONS; | ||
740 | } | 758 | } |
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 23298b90b52b..db845cf960c9 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
@@ -29,6 +29,7 @@ enum ATH_DEBUG { | |||
29 | ATH_DBG_BEACON = 0x00000100, | 29 | ATH_DBG_BEACON = 0x00000100, |
30 | ATH_DBG_CONFIG = 0x00000200, | 30 | ATH_DBG_CONFIG = 0x00000200, |
31 | ATH_DBG_FATAL = 0x00000400, | 31 | ATH_DBG_FATAL = 0x00000400, |
32 | ATH_DBG_PS = 0x00000800, | ||
32 | ATH_DBG_ANY = 0xffffffff | 33 | ATH_DBG_ANY = 0xffffffff |
33 | }; | 34 | }; |
34 | 35 | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4acfab514916..1579c9407ed5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -2472,14 +2472,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | |||
2472 | } | 2472 | } |
2473 | break; | 2473 | break; |
2474 | case ATH9K_CIPHER_WEP: | 2474 | case ATH9K_CIPHER_WEP: |
2475 | if (k->kv_len < LEN_WEP40) { | 2475 | if (k->kv_len < WLAN_KEY_LEN_WEP40) { |
2476 | DPRINTF(ah->ah_sc, ATH_DBG_ANY, | 2476 | DPRINTF(ah->ah_sc, ATH_DBG_ANY, |
2477 | "WEP key length %u too small\n", k->kv_len); | 2477 | "WEP key length %u too small\n", k->kv_len); |
2478 | return false; | 2478 | return false; |
2479 | } | 2479 | } |
2480 | if (k->kv_len <= LEN_WEP40) | 2480 | if (k->kv_len <= WLAN_KEY_LEN_WEP40) |
2481 | keyType = AR_KEYTABLE_TYPE_40; | 2481 | keyType = AR_KEYTABLE_TYPE_40; |
2482 | else if (k->kv_len <= LEN_WEP104) | 2482 | else if (k->kv_len <= WLAN_KEY_LEN_WEP104) |
2483 | keyType = AR_KEYTABLE_TYPE_104; | 2483 | keyType = AR_KEYTABLE_TYPE_104; |
2484 | else | 2484 | else |
2485 | keyType = AR_KEYTABLE_TYPE_128; | 2485 | keyType = AR_KEYTABLE_TYPE_128; |
@@ -2498,7 +2498,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry, | |||
2498 | key2 = get_unaligned_le32(k->kv_val + 6); | 2498 | key2 = get_unaligned_le32(k->kv_val + 6); |
2499 | key3 = get_unaligned_le16(k->kv_val + 10); | 2499 | key3 = get_unaligned_le16(k->kv_val + 10); |
2500 | key4 = get_unaligned_le32(k->kv_val + 12); | 2500 | key4 = get_unaligned_le32(k->kv_val + 12); |
2501 | if (k->kv_len <= LEN_WEP104) | 2501 | if (k->kv_len <= WLAN_KEY_LEN_WEP104) |
2502 | key4 &= 0xff; | 2502 | key4 &= 0xff; |
2503 | 2503 | ||
2504 | /* | 2504 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index bbbfdcde2727..61da08a1648c 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -35,14 +35,14 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | |||
35 | #define CHAN2G(_freq, _idx) { \ | 35 | #define CHAN2G(_freq, _idx) { \ |
36 | .center_freq = (_freq), \ | 36 | .center_freq = (_freq), \ |
37 | .hw_value = (_idx), \ | 37 | .hw_value = (_idx), \ |
38 | .max_power = 30, \ | 38 | .max_power = 20, \ |
39 | } | 39 | } |
40 | 40 | ||
41 | #define CHAN5G(_freq, _idx) { \ | 41 | #define CHAN5G(_freq, _idx) { \ |
42 | .band = IEEE80211_BAND_5GHZ, \ | 42 | .band = IEEE80211_BAND_5GHZ, \ |
43 | .center_freq = (_freq), \ | 43 | .center_freq = (_freq), \ |
44 | .hw_value = (_idx), \ | 44 | .hw_value = (_idx), \ |
45 | .max_power = 30, \ | 45 | .max_power = 20, \ |
46 | } | 46 | } |
47 | 47 | ||
48 | /* Some 2 GHz radios are actually tunable on 2312-2732 | 48 | /* Some 2 GHz radios are actually tunable on 2312-2732 |
@@ -280,7 +280,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
280 | if (r) { | 280 | if (r) { |
281 | DPRINTF(sc, ATH_DBG_FATAL, | 281 | DPRINTF(sc, ATH_DBG_FATAL, |
282 | "Unable to reset channel (%u Mhz) " | 282 | "Unable to reset channel (%u Mhz) " |
283 | "reset status %u\n", | 283 | "reset status %d\n", |
284 | channel->center_freq, r); | 284 | channel->center_freq, r); |
285 | spin_unlock_bh(&sc->sc_resetlock); | 285 | spin_unlock_bh(&sc->sc_resetlock); |
286 | return r; | 286 | return r; |
@@ -329,6 +329,12 @@ static void ath_ani_calibrate(unsigned long data) | |||
329 | if (sc->sc_flags & SC_OP_SCANNING) | 329 | if (sc->sc_flags & SC_OP_SCANNING) |
330 | goto set_timer; | 330 | goto set_timer; |
331 | 331 | ||
332 | /* Only calibrate if awake */ | ||
333 | if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) | ||
334 | goto set_timer; | ||
335 | |||
336 | ath9k_ps_wakeup(sc); | ||
337 | |||
332 | /* Long calibration runs independently of short calibration. */ | 338 | /* Long calibration runs independently of short calibration. */ |
333 | if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { | 339 | if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { |
334 | longcal = true; | 340 | longcal = true; |
@@ -380,6 +386,8 @@ static void ath_ani_calibrate(unsigned long data) | |||
380 | } | 386 | } |
381 | } | 387 | } |
382 | 388 | ||
389 | ath9k_ps_restore(sc); | ||
390 | |||
383 | set_timer: | 391 | set_timer: |
384 | /* | 392 | /* |
385 | * Set timer interval based on previous results. | 393 | * Set timer interval based on previous results. |
@@ -455,8 +463,11 @@ static void ath9k_tasklet(unsigned long data) | |||
455 | struct ath_softc *sc = (struct ath_softc *)data; | 463 | struct ath_softc *sc = (struct ath_softc *)data; |
456 | u32 status = sc->intrstatus; | 464 | u32 status = sc->intrstatus; |
457 | 465 | ||
466 | ath9k_ps_wakeup(sc); | ||
467 | |||
458 | if (status & ATH9K_INT_FATAL) { | 468 | if (status & ATH9K_INT_FATAL) { |
459 | ath_reset(sc, false); | 469 | ath_reset(sc, false); |
470 | ath9k_ps_restore(sc); | ||
460 | return; | 471 | return; |
461 | } | 472 | } |
462 | 473 | ||
@@ -469,8 +480,19 @@ static void ath9k_tasklet(unsigned long data) | |||
469 | if (status & ATH9K_INT_TX) | 480 | if (status & ATH9K_INT_TX) |
470 | ath_tx_tasklet(sc); | 481 | ath_tx_tasklet(sc); |
471 | 482 | ||
483 | if ((status & ATH9K_INT_TSFOOR) && | ||
484 | (sc->hw->conf.flags & IEEE80211_CONF_PS)) { | ||
485 | /* | ||
486 | * TSF sync does not look correct; remain awake to sync with | ||
487 | * the next Beacon. | ||
488 | */ | ||
489 | DPRINTF(sc, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); | ||
490 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; | ||
491 | } | ||
492 | |||
472 | /* re-enable hardware interrupt */ | 493 | /* re-enable hardware interrupt */ |
473 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); | 494 | ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); |
495 | ath9k_ps_restore(sc); | ||
474 | } | 496 | } |
475 | 497 | ||
476 | irqreturn_t ath_isr(int irq, void *dev) | 498 | irqreturn_t ath_isr(int irq, void *dev) |
@@ -498,14 +520,11 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
498 | if (sc->sc_flags & SC_OP_INVALID) | 520 | if (sc->sc_flags & SC_OP_INVALID) |
499 | return IRQ_NONE; | 521 | return IRQ_NONE; |
500 | 522 | ||
501 | ath9k_ps_wakeup(sc); | ||
502 | 523 | ||
503 | /* shared irq, not for us */ | 524 | /* shared irq, not for us */ |
504 | 525 | ||
505 | if (!ath9k_hw_intrpend(ah)) { | 526 | if (!ath9k_hw_intrpend(ah)) |
506 | ath9k_ps_restore(sc); | ||
507 | return IRQ_NONE; | 527 | return IRQ_NONE; |
508 | } | ||
509 | 528 | ||
510 | /* | 529 | /* |
511 | * Figure out the reason(s) for the interrupt. Note | 530 | * Figure out the reason(s) for the interrupt. Note |
@@ -520,10 +539,8 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
520 | * If there are no status bits set, then this interrupt was not | 539 | * If there are no status bits set, then this interrupt was not |
521 | * for me (should have been caught above). | 540 | * for me (should have been caught above). |
522 | */ | 541 | */ |
523 | if (!status) { | 542 | if (!status) |
524 | ath9k_ps_restore(sc); | ||
525 | return IRQ_NONE; | 543 | return IRQ_NONE; |
526 | } | ||
527 | 544 | ||
528 | /* Cache the status */ | 545 | /* Cache the status */ |
529 | sc->intrstatus = status; | 546 | sc->intrstatus = status; |
@@ -560,20 +577,17 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
560 | ath9k_hw_set_interrupts(ah, sc->imask); | 577 | ath9k_hw_set_interrupts(ah, sc->imask); |
561 | } | 578 | } |
562 | 579 | ||
563 | if (status & ATH9K_INT_TIM_TIMER) { | 580 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) |
564 | if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { | 581 | if (status & ATH9K_INT_TIM_TIMER) { |
565 | /* Clear RxAbort bit so that we can | 582 | /* Clear RxAbort bit so that we can |
566 | * receive frames */ | 583 | * receive frames */ |
567 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); | 584 | ath9k_hw_setpower(ah, ATH9K_PM_AWAKE); |
568 | ath9k_hw_setrxabort(ah, 0); | 585 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
569 | sched = true; | ||
570 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; | 586 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; |
571 | } | 587 | } |
572 | } | ||
573 | 588 | ||
574 | chip_reset: | 589 | chip_reset: |
575 | 590 | ||
576 | ath9k_ps_restore(sc); | ||
577 | ath_debug_stat_interrupt(sc, status); | 591 | ath_debug_stat_interrupt(sc, status); |
578 | 592 | ||
579 | if (sched) { | 593 | if (sched) { |
@@ -900,6 +914,13 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
900 | if (avp->av_opmode == NL80211_IFTYPE_STATION) { | 914 | if (avp->av_opmode == NL80211_IFTYPE_STATION) { |
901 | sc->curaid = bss_conf->aid; | 915 | sc->curaid = bss_conf->aid; |
902 | ath9k_hw_write_associd(sc); | 916 | ath9k_hw_write_associd(sc); |
917 | |||
918 | /* | ||
919 | * Request a re-configuration of Beacon related timers | ||
920 | * on the receipt of the first Beacon frame (i.e., | ||
921 | * after time sync with the AP). | ||
922 | */ | ||
923 | sc->sc_flags |= SC_OP_BEACON_SYNC; | ||
903 | } | 924 | } |
904 | 925 | ||
905 | /* Configure the beacon */ | 926 | /* Configure the beacon */ |
@@ -1094,7 +1115,7 @@ void ath_radio_enable(struct ath_softc *sc) | |||
1094 | if (r) { | 1115 | if (r) { |
1095 | DPRINTF(sc, ATH_DBG_FATAL, | 1116 | DPRINTF(sc, ATH_DBG_FATAL, |
1096 | "Unable to reset channel %u (%uMhz) ", | 1117 | "Unable to reset channel %u (%uMhz) ", |
1097 | "reset status %u\n", | 1118 | "reset status %d\n", |
1098 | channel->center_freq, r); | 1119 | channel->center_freq, r); |
1099 | } | 1120 | } |
1100 | spin_unlock_bh(&sc->sc_resetlock); | 1121 | spin_unlock_bh(&sc->sc_resetlock); |
@@ -1146,7 +1167,7 @@ void ath_radio_disable(struct ath_softc *sc) | |||
1146 | if (r) { | 1167 | if (r) { |
1147 | DPRINTF(sc, ATH_DBG_FATAL, | 1168 | DPRINTF(sc, ATH_DBG_FATAL, |
1148 | "Unable to reset channel %u (%uMhz) " | 1169 | "Unable to reset channel %u (%uMhz) " |
1149 | "reset status %u\n", | 1170 | "reset status %d\n", |
1150 | channel->center_freq, r); | 1171 | channel->center_freq, r); |
1151 | } | 1172 | } |
1152 | spin_unlock_bh(&sc->sc_resetlock); | 1173 | spin_unlock_bh(&sc->sc_resetlock); |
@@ -1416,8 +1437,6 @@ static int ath_init(u16 devid, struct ath_softc *sc) | |||
1416 | for (i = 0; i < sc->keymax; i++) | 1437 | for (i = 0; i < sc->keymax; i++) |
1417 | ath9k_hw_keyreset(ah, (u16) i); | 1438 | ath9k_hw_keyreset(ah, (u16) i); |
1418 | 1439 | ||
1419 | error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, | ||
1420 | ath9k_reg_notifier); | ||
1421 | if (error) | 1440 | if (error) |
1422 | goto bad; | 1441 | goto bad; |
1423 | 1442 | ||
@@ -1630,14 +1649,19 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1630 | if (error != 0) | 1649 | if (error != 0) |
1631 | return error; | 1650 | return error; |
1632 | 1651 | ||
1633 | reg = &sc->sc_ah->regulatory; | ||
1634 | |||
1635 | /* get mac address from hardware and set in mac80211 */ | 1652 | /* get mac address from hardware and set in mac80211 */ |
1636 | 1653 | ||
1637 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); | 1654 | SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr); |
1638 | 1655 | ||
1639 | ath_set_hw_capab(sc, hw); | 1656 | ath_set_hw_capab(sc, hw); |
1640 | 1657 | ||
1658 | error = ath_regd_init(&sc->sc_ah->regulatory, sc->hw->wiphy, | ||
1659 | ath9k_reg_notifier); | ||
1660 | if (error) | ||
1661 | return error; | ||
1662 | |||
1663 | reg = &sc->sc_ah->regulatory; | ||
1664 | |||
1641 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | 1665 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { |
1642 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | 1666 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); |
1643 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | 1667 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) |
@@ -1709,7 +1733,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
1709 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); | 1733 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false); |
1710 | if (r) | 1734 | if (r) |
1711 | DPRINTF(sc, ATH_DBG_FATAL, | 1735 | DPRINTF(sc, ATH_DBG_FATAL, |
1712 | "Unable to reset hardware; reset status %u\n", r); | 1736 | "Unable to reset hardware; reset status %d\n", r); |
1713 | spin_unlock_bh(&sc->sc_resetlock); | 1737 | spin_unlock_bh(&sc->sc_resetlock); |
1714 | 1738 | ||
1715 | if (ath_startrecv(sc) != 0) | 1739 | if (ath_startrecv(sc) != 0) |
@@ -2001,7 +2025,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
2001 | r = ath9k_hw_reset(sc->sc_ah, init_channel, false); | 2025 | r = ath9k_hw_reset(sc->sc_ah, init_channel, false); |
2002 | if (r) { | 2026 | if (r) { |
2003 | DPRINTF(sc, ATH_DBG_FATAL, | 2027 | DPRINTF(sc, ATH_DBG_FATAL, |
2004 | "Unable to reset hardware; reset status %u " | 2028 | "Unable to reset hardware; reset status %d " |
2005 | "(freq %u MHz)\n", r, | 2029 | "(freq %u MHz)\n", r, |
2006 | curchan->center_freq); | 2030 | curchan->center_freq); |
2007 | spin_unlock_bh(&sc->sc_resetlock); | 2031 | spin_unlock_bh(&sc->sc_resetlock); |
@@ -2074,6 +2098,46 @@ static int ath9k_tx(struct ieee80211_hw *hw, | |||
2074 | goto exit; | 2098 | goto exit; |
2075 | } | 2099 | } |
2076 | 2100 | ||
2101 | if (sc->hw->conf.flags & IEEE80211_CONF_PS) { | ||
2102 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
2103 | /* | ||
2104 | * mac80211 does not set PM field for normal data frames, so we | ||
2105 | * need to update that based on the current PS mode. | ||
2106 | */ | ||
2107 | if (ieee80211_is_data(hdr->frame_control) && | ||
2108 | !ieee80211_is_nullfunc(hdr->frame_control) && | ||
2109 | !ieee80211_has_pm(hdr->frame_control)) { | ||
2110 | DPRINTF(sc, ATH_DBG_PS, "Add PM=1 for a TX frame " | ||
2111 | "while in PS mode\n"); | ||
2112 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
2113 | } | ||
2114 | } | ||
2115 | |||
2116 | if (unlikely(sc->sc_ah->power_mode != ATH9K_PM_AWAKE)) { | ||
2117 | /* | ||
2118 | * We are using PS-Poll and mac80211 can request TX while in | ||
2119 | * power save mode. Need to wake up hardware for the TX to be | ||
2120 | * completed and if needed, also for RX of buffered frames. | ||
2121 | */ | ||
2122 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
2123 | ath9k_ps_wakeup(sc); | ||
2124 | ath9k_hw_setrxabort(sc->sc_ah, 0); | ||
2125 | if (ieee80211_is_pspoll(hdr->frame_control)) { | ||
2126 | DPRINTF(sc, ATH_DBG_PS, "Sending PS-Poll to pick a " | ||
2127 | "buffered frame\n"); | ||
2128 | sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; | ||
2129 | } else { | ||
2130 | DPRINTF(sc, ATH_DBG_PS, "Wake up to complete TX\n"); | ||
2131 | sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; | ||
2132 | } | ||
2133 | /* | ||
2134 | * The actual restore operation will happen only after | ||
2135 | * the sc_flags bit is cleared. We are just dropping | ||
2136 | * the ps_usecount here. | ||
2137 | */ | ||
2138 | ath9k_ps_restore(sc); | ||
2139 | } | ||
2140 | |||
2077 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | 2141 | memset(&txctl, 0, sizeof(struct ath_tx_control)); |
2078 | 2142 | ||
2079 | /* | 2143 | /* |
@@ -2311,7 +2375,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2311 | if (!(ah->caps.hw_caps & | 2375 | if (!(ah->caps.hw_caps & |
2312 | ATH9K_HW_CAP_AUTOSLEEP)) { | 2376 | ATH9K_HW_CAP_AUTOSLEEP)) { |
2313 | ath9k_hw_setrxabort(sc->sc_ah, 0); | 2377 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
2314 | sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; | 2378 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | |
2379 | SC_OP_WAIT_FOR_CAB | | ||
2380 | SC_OP_WAIT_FOR_PSPOLL_DATA | | ||
2381 | SC_OP_WAIT_FOR_TX_ACK); | ||
2315 | if (sc->imask & ATH9K_INT_TIM_TIMER) { | 2382 | if (sc->imask & ATH9K_INT_TIM_TIMER) { |
2316 | sc->imask &= ~ATH9K_INT_TIM_TIMER; | 2383 | sc->imask &= ~ATH9K_INT_TIM_TIMER; |
2317 | ath9k_hw_set_interrupts(sc->sc_ah, | 2384 | ath9k_hw_set_interrupts(sc->sc_ah, |
@@ -2386,8 +2453,10 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, | |||
2386 | *total_flags &= SUPPORTED_FILTERS; | 2453 | *total_flags &= SUPPORTED_FILTERS; |
2387 | 2454 | ||
2388 | sc->rx.rxfilter = *total_flags; | 2455 | sc->rx.rxfilter = *total_flags; |
2456 | ath9k_ps_wakeup(sc); | ||
2389 | rfilt = ath_calcrxfilter(sc); | 2457 | rfilt = ath_calcrxfilter(sc); |
2390 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); | 2458 | ath9k_hw_setrxfilter(sc->sc_ah, rfilt); |
2459 | ath9k_ps_restore(sc); | ||
2391 | 2460 | ||
2392 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); | 2461 | DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); |
2393 | } | 2462 | } |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b46badd21f73..5014a19b0f75 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -473,6 +473,159 @@ void ath_flushrecv(struct ath_softc *sc) | |||
473 | spin_unlock_bh(&sc->rx.rxflushlock); | 473 | spin_unlock_bh(&sc->rx.rxflushlock); |
474 | } | 474 | } |
475 | 475 | ||
476 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | ||
477 | { | ||
478 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ | ||
479 | struct ieee80211_mgmt *mgmt; | ||
480 | u8 *pos, *end, id, elen; | ||
481 | struct ieee80211_tim_ie *tim; | ||
482 | |||
483 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
484 | pos = mgmt->u.beacon.variable; | ||
485 | end = skb->data + skb->len; | ||
486 | |||
487 | while (pos + 2 < end) { | ||
488 | id = *pos++; | ||
489 | elen = *pos++; | ||
490 | if (pos + elen > end) | ||
491 | break; | ||
492 | |||
493 | if (id == WLAN_EID_TIM) { | ||
494 | if (elen < sizeof(*tim)) | ||
495 | break; | ||
496 | tim = (struct ieee80211_tim_ie *) pos; | ||
497 | if (tim->dtim_count != 0) | ||
498 | break; | ||
499 | return tim->bitmap_ctrl & 0x01; | ||
500 | } | ||
501 | |||
502 | pos += elen; | ||
503 | } | ||
504 | |||
505 | return false; | ||
506 | } | ||
507 | |||
508 | static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) | ||
509 | { | ||
510 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); | ||
511 | } | ||
512 | |||
513 | static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | ||
514 | { | ||
515 | struct ieee80211_mgmt *mgmt; | ||
516 | |||
517 | if (skb->len < 24 + 8 + 2 + 2) | ||
518 | return; | ||
519 | |||
520 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
521 | if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) | ||
522 | return; /* not from our current AP */ | ||
523 | |||
524 | if (sc->sc_flags & SC_OP_BEACON_SYNC) { | ||
525 | sc->sc_flags &= ~SC_OP_BEACON_SYNC; | ||
526 | DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " | ||
527 | "timestamp from the AP\n"); | ||
528 | ath_beacon_config(sc, NULL); | ||
529 | } | ||
530 | |||
531 | if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { | ||
532 | /* We are not in PS mode anymore; remain awake */ | ||
533 | DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " | ||
534 | "awake\n"); | ||
535 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | if (ath_beacon_dtim_pending_cab(skb)) { | ||
540 | /* | ||
541 | * Remain awake waiting for buffered broadcast/multicast | ||
542 | * frames. | ||
543 | */ | ||
544 | DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " | ||
545 | "buffered broadcast/multicast frame(s)\n"); | ||
546 | sc->sc_flags |= SC_OP_WAIT_FOR_CAB; | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { | ||
551 | /* | ||
552 | * This can happen if a broadcast frame is dropped or the AP | ||
553 | * fails to send a frame indicating that all CAB frames have | ||
554 | * been delivered. | ||
555 | */ | ||
556 | DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); | ||
557 | } | ||
558 | |||
559 | /* No more broadcast/multicast frames to be received at this point. */ | ||
560 | ath_rx_ps_back_to_sleep(sc); | ||
561 | } | ||
562 | |||
563 | static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | ||
564 | { | ||
565 | struct ieee80211_hdr *hdr; | ||
566 | |||
567 | hdr = (struct ieee80211_hdr *)skb->data; | ||
568 | |||
569 | /* Process Beacon and CAB receive in PS state */ | ||
570 | if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && | ||
571 | ieee80211_is_beacon(hdr->frame_control)) | ||
572 | ath_rx_ps_beacon(sc, skb); | ||
573 | else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && | ||
574 | (ieee80211_is_data(hdr->frame_control) || | ||
575 | ieee80211_is_action(hdr->frame_control)) && | ||
576 | is_multicast_ether_addr(hdr->addr1) && | ||
577 | !ieee80211_has_moredata(hdr->frame_control)) { | ||
578 | DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " | ||
579 | "sleep\n"); | ||
580 | /* | ||
581 | * No more broadcast/multicast frames to be received at this | ||
582 | * point. | ||
583 | */ | ||
584 | ath_rx_ps_back_to_sleep(sc); | ||
585 | } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && | ||
586 | !is_multicast_ether_addr(hdr->addr1) && | ||
587 | !ieee80211_has_morefrags(hdr->frame_control)) { | ||
588 | sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; | ||
589 | DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " | ||
590 | "received PS-Poll data (0x%x)\n", | ||
591 | sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | ||
592 | SC_OP_WAIT_FOR_CAB | | ||
593 | SC_OP_WAIT_FOR_PSPOLL_DATA | | ||
594 | SC_OP_WAIT_FOR_TX_ACK)); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, | ||
599 | struct ieee80211_rx_status *rx_status) | ||
600 | { | ||
601 | struct ieee80211_hdr *hdr; | ||
602 | |||
603 | hdr = (struct ieee80211_hdr *)skb->data; | ||
604 | |||
605 | /* Send the frame to mac80211 */ | ||
606 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
607 | int i; | ||
608 | /* | ||
609 | * Deliver broadcast/multicast frames to all suitable | ||
610 | * virtual wiphys. | ||
611 | */ | ||
612 | /* TODO: filter based on channel configuration */ | ||
613 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
614 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
615 | struct sk_buff *nskb; | ||
616 | if (aphy == NULL) | ||
617 | continue; | ||
618 | nskb = skb_copy(skb, GFP_ATOMIC); | ||
619 | if (nskb) | ||
620 | __ieee80211_rx(aphy->hw, nskb, rx_status); | ||
621 | } | ||
622 | __ieee80211_rx(sc->hw, skb, rx_status); | ||
623 | } else { | ||
624 | /* Deliver unicast frames based on receiver address */ | ||
625 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); | ||
626 | } | ||
627 | } | ||
628 | |||
476 | int ath_rx_tasklet(struct ath_softc *sc, int flush) | 629 | int ath_rx_tasklet(struct ath_softc *sc, int flush) |
477 | { | 630 | { |
478 | #define PA2DESC(_sc, _pa) \ | 631 | #define PA2DESC(_sc, _pa) \ |
@@ -622,7 +775,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
622 | 775 | ||
623 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { | 776 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { |
624 | rx_status.flag |= RX_FLAG_DECRYPTED; | 777 | rx_status.flag |= RX_FLAG_DECRYPTED; |
625 | } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) | 778 | } else if (ieee80211_has_protected(fc) |
626 | && !decrypt_error && skb->len >= hdrlen + 4) { | 779 | && !decrypt_error && skb->len >= hdrlen + 4) { |
627 | keyix = skb->data[hdrlen + 3] >> 6; | 780 | keyix = skb->data[hdrlen + 3] >> 6; |
628 | 781 | ||
@@ -631,36 +784,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
631 | } | 784 | } |
632 | if (ah->sw_mgmt_crypto && | 785 | if (ah->sw_mgmt_crypto && |
633 | (rx_status.flag & RX_FLAG_DECRYPTED) && | 786 | (rx_status.flag & RX_FLAG_DECRYPTED) && |
634 | ieee80211_is_mgmt(hdr->frame_control)) { | 787 | ieee80211_is_mgmt(fc)) { |
635 | /* Use software decrypt for management frames. */ | 788 | /* Use software decrypt for management frames. */ |
636 | rx_status.flag &= ~RX_FLAG_DECRYPTED; | 789 | rx_status.flag &= ~RX_FLAG_DECRYPTED; |
637 | } | 790 | } |
638 | 791 | ||
639 | /* Send the frame to mac80211 */ | ||
640 | if (hdr->addr1[5] & 0x01) { | ||
641 | int i; | ||
642 | /* | ||
643 | * Deliver broadcast/multicast frames to all suitable | ||
644 | * virtual wiphys. | ||
645 | */ | ||
646 | /* TODO: filter based on channel configuration */ | ||
647 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
648 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
649 | struct sk_buff *nskb; | ||
650 | if (aphy == NULL) | ||
651 | continue; | ||
652 | nskb = skb_copy(skb, GFP_ATOMIC); | ||
653 | if (nskb) | ||
654 | __ieee80211_rx(aphy->hw, nskb, | ||
655 | &rx_status); | ||
656 | } | ||
657 | __ieee80211_rx(sc->hw, skb, &rx_status); | ||
658 | } else { | ||
659 | /* Deliver unicast frames based on receiver address */ | ||
660 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, | ||
661 | &rx_status); | ||
662 | } | ||
663 | |||
664 | /* We will now give hardware our shiny new allocated skb */ | 792 | /* We will now give hardware our shiny new allocated skb */ |
665 | bf->bf_mpdu = requeue_skb; | 793 | bf->bf_mpdu = requeue_skb; |
666 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, | 794 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, |
@@ -672,6 +800,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
672 | bf->bf_mpdu = NULL; | 800 | bf->bf_mpdu = NULL; |
673 | DPRINTF(sc, ATH_DBG_FATAL, | 801 | DPRINTF(sc, ATH_DBG_FATAL, |
674 | "dma_mapping_error() on RX\n"); | 802 | "dma_mapping_error() on RX\n"); |
803 | ath_rx_send_to_mac80211(sc, skb, &rx_status); | ||
675 | break; | 804 | break; |
676 | } | 805 | } |
677 | bf->bf_dmacontext = bf->bf_buf_addr; | 806 | bf->bf_dmacontext = bf->bf_buf_addr; |
@@ -687,11 +816,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
687 | sc->rx.rxotherant = 0; | 816 | sc->rx.rxotherant = 0; |
688 | } | 817 | } |
689 | 818 | ||
690 | if (ieee80211_is_beacon(fc) && | 819 | if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | |
691 | (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { | 820 | SC_OP_WAIT_FOR_PSPOLL_DATA))) |
692 | sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; | 821 | ath_rx_ps(sc, skb); |
693 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); | 822 | |
694 | } | 823 | ath_rx_send_to_mac80211(sc, skb, &rx_status); |
824 | |||
695 | requeue: | 825 | requeue: |
696 | list_move_tail(&bf->list, &sc->rx.rxbuf); | 826 | list_move_tail(&bf->list, &sc->rx.rxbuf); |
697 | ath_rx_buf_link(sc, bf); | 827 | ath_rx_buf_link(sc, bf); |
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 41c42824a5ca..a8def4fa449c 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1070,7 +1070,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) | |||
1070 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); | 1070 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true); |
1071 | if (r) | 1071 | if (r) |
1072 | DPRINTF(sc, ATH_DBG_FATAL, | 1072 | DPRINTF(sc, ATH_DBG_FATAL, |
1073 | "Unable to reset hardware; reset status %u\n", | 1073 | "Unable to reset hardware; reset status %d\n", |
1074 | r); | 1074 | r); |
1075 | spin_unlock_bh(&sc->sc_resetlock); | 1075 | spin_unlock_bh(&sc->sc_resetlock); |
1076 | } | 1076 | } |
@@ -1790,6 +1790,16 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
1790 | skb_pull(skb, padsize); | 1790 | skb_pull(skb, padsize); |
1791 | } | 1791 | } |
1792 | 1792 | ||
1793 | if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { | ||
1794 | sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; | ||
1795 | DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " | ||
1796 | "received TX status (0x%x)\n", | ||
1797 | sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | ||
1798 | SC_OP_WAIT_FOR_CAB | | ||
1799 | SC_OP_WAIT_FOR_PSPOLL_DATA | | ||
1800 | SC_OP_WAIT_FOR_TX_ACK)); | ||
1801 | } | ||
1802 | |||
1793 | if (frame_type == ATH9K_NOT_INTERNAL) | 1803 | if (frame_type == ATH9K_NOT_INTERNAL) |
1794 | ieee80211_tx_status(hw, skb); | 1804 | ieee80211_tx_status(hw, skb); |
1795 | else | 1805 | else |
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index fdf07c822081..7a89f9fac7d4 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c | |||
@@ -200,8 +200,10 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, | |||
200 | continue; | 200 | continue; |
201 | 201 | ||
202 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 202 | if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { |
203 | r = freq_reg_info(wiphy, ch->center_freq, | 203 | r = freq_reg_info(wiphy, |
204 | &bandwidth, ®_rule); | 204 | ch->center_freq, |
205 | bandwidth, | ||
206 | ®_rule); | ||
205 | if (r) | 207 | if (r) |
206 | continue; | 208 | continue; |
207 | /* | 209 | /* |
@@ -265,7 +267,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, | |||
265 | */ | 267 | */ |
266 | 268 | ||
267 | ch = &sband->channels[11]; /* CH 12 */ | 269 | ch = &sband->channels[11]; /* CH 12 */ |
268 | r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); | 270 | r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); |
269 | if (!r) { | 271 | if (!r) { |
270 | if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) | 272 | if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) |
271 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 273 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
@@ -273,7 +275,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, | |||
273 | } | 275 | } |
274 | 276 | ||
275 | ch = &sband->channels[12]; /* CH 13 */ | 277 | ch = &sband->channels[12]; /* CH 13 */ |
276 | r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); | 278 | r = freq_reg_info(wiphy, ch->center_freq, bandwidth, ®_rule); |
277 | if (!r) { | 279 | if (!r) { |
278 | if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) | 280 | if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) |
279 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 281 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2615aaf7df6a..cb4a8712946a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -3553,27 +3553,25 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, | |||
3553 | 3553 | ||
3554 | B43_WARN_ON(wl->vif != vif); | 3554 | B43_WARN_ON(wl->vif != vif); |
3555 | 3555 | ||
3556 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3556 | if (changed & BSS_CHANGED_BSSID) { | 3557 | if (changed & BSS_CHANGED_BSSID) { |
3557 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
3558 | if (conf->bssid) | 3558 | if (conf->bssid) |
3559 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | 3559 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); |
3560 | else | 3560 | else |
3561 | memset(wl->bssid, 0, ETH_ALEN); | 3561 | memset(wl->bssid, 0, ETH_ALEN); |
3562 | } | ||
3562 | 3563 | ||
3563 | if (b43_status(dev) >= B43_STAT_INITIALIZED) { | 3564 | if (b43_status(dev) >= B43_STAT_INITIALIZED) { |
3564 | if (b43_is_mode(wl, NL80211_IFTYPE_AP) || | 3565 | if (changed & BSS_CHANGED_BEACON && |
3565 | b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { | 3566 | (b43_is_mode(wl, NL80211_IFTYPE_AP) || |
3566 | B43_WARN_ON(vif->type != wl->if_type); | 3567 | b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || |
3567 | if (changed & BSS_CHANGED_BEACON) | 3568 | b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) |
3568 | b43_update_templates(wl); | 3569 | b43_update_templates(wl); |
3569 | } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { | 3570 | |
3570 | if (changed & BSS_CHANGED_BEACON) | 3571 | if (changed & BSS_CHANGED_BSSID) |
3571 | b43_update_templates(wl); | ||
3572 | } | ||
3573 | b43_write_mac_bssid_templates(dev); | 3572 | b43_write_mac_bssid_templates(dev); |
3574 | } | ||
3575 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3576 | } | 3573 | } |
3574 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
3577 | 3575 | ||
3578 | b43_mac_suspend(dev); | 3576 | b43_mac_suspend(dev); |
3579 | 3577 | ||
@@ -3639,7 +3637,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3639 | err = -EINVAL; | 3637 | err = -EINVAL; |
3640 | switch (key->alg) { | 3638 | switch (key->alg) { |
3641 | case ALG_WEP: | 3639 | case ALG_WEP: |
3642 | if (key->keylen == LEN_WEP40) | 3640 | if (key->keylen == WLAN_KEY_LEN_WEP40) |
3643 | algorithm = B43_SEC_ALGO_WEP40; | 3641 | algorithm = B43_SEC_ALGO_WEP40; |
3644 | else | 3642 | else |
3645 | algorithm = B43_SEC_ALGO_WEP104; | 3643 | algorithm = B43_SEC_ALGO_WEP104; |
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index da59ef02b6ef..19a4b0bc0d87 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h | |||
@@ -694,8 +694,8 @@ struct b43legacy_wldev { | |||
694 | /* Reason code of the last interrupt. */ | 694 | /* Reason code of the last interrupt. */ |
695 | u32 irq_reason; | 695 | u32 irq_reason; |
696 | u32 dma_reason[6]; | 696 | u32 dma_reason[6]; |
697 | /* saved irq enable/disable state bitfield. */ | 697 | /* The currently active generic-interrupt mask. */ |
698 | u32 irq_savedstate; | 698 | u32 irq_mask; |
699 | /* Link Quality calculation context. */ | 699 | /* Link Quality calculation context. */ |
700 | struct b43legacy_noise_calculation noisecalc; | 700 | struct b43legacy_noise_calculation noisecalc; |
701 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ | 701 | /* if > 0 MAC is suspended. if == 0 MAC is enabled. */ |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 07c7898c87ac..f6f3fbf0a2f4 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -583,35 +583,6 @@ static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) | |||
583 | b43legacy_set_slot_time(dev, 20); | 583 | b43legacy_set_slot_time(dev, 20); |
584 | } | 584 | } |
585 | 585 | ||
586 | /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. | ||
587 | * Returns the _previously_ enabled IRQ mask. | ||
588 | */ | ||
589 | static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev, | ||
590 | u32 mask) | ||
591 | { | ||
592 | u32 old_mask; | ||
593 | |||
594 | old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); | ||
595 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask | | ||
596 | mask); | ||
597 | |||
598 | return old_mask; | ||
599 | } | ||
600 | |||
601 | /* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. | ||
602 | * Returns the _previously_ enabled IRQ mask. | ||
603 | */ | ||
604 | static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev, | ||
605 | u32 mask) | ||
606 | { | ||
607 | u32 old_mask; | ||
608 | |||
609 | old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); | ||
610 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask); | ||
611 | |||
612 | return old_mask; | ||
613 | } | ||
614 | |||
615 | /* Synchronize IRQ top- and bottom-half. | 586 | /* Synchronize IRQ top- and bottom-half. |
616 | * IRQs must be masked before calling this. | 587 | * IRQs must be masked before calling this. |
617 | * This must not be called with the irq_lock held. | 588 | * This must not be called with the irq_lock held. |
@@ -1200,7 +1171,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) | |||
1200 | /* This is the bottom half of the asynchronous beacon update. */ | 1171 | /* This is the bottom half of the asynchronous beacon update. */ |
1201 | 1172 | ||
1202 | /* Ignore interrupt in the future. */ | 1173 | /* Ignore interrupt in the future. */ |
1203 | dev->irq_savedstate &= ~B43legacy_IRQ_BEACON; | 1174 | dev->irq_mask &= ~B43legacy_IRQ_BEACON; |
1204 | 1175 | ||
1205 | cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); | 1176 | cmd = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); |
1206 | beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); | 1177 | beacon0_valid = (cmd & B43legacy_MACCMD_BEACON0_VALID); |
@@ -1209,7 +1180,7 @@ static void handle_irq_beacon(struct b43legacy_wldev *dev) | |||
1209 | /* Schedule interrupt manually, if busy. */ | 1180 | /* Schedule interrupt manually, if busy. */ |
1210 | if (beacon0_valid && beacon1_valid) { | 1181 | if (beacon0_valid && beacon1_valid) { |
1211 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); | 1182 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, B43legacy_IRQ_BEACON); |
1212 | dev->irq_savedstate |= B43legacy_IRQ_BEACON; | 1183 | dev->irq_mask |= B43legacy_IRQ_BEACON; |
1213 | return; | 1184 | return; |
1214 | } | 1185 | } |
1215 | 1186 | ||
@@ -1247,12 +1218,11 @@ static void b43legacy_beacon_update_trigger_work(struct work_struct *work) | |||
1247 | dev = wl->current_dev; | 1218 | dev = wl->current_dev; |
1248 | if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { | 1219 | if (likely(dev && (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED))) { |
1249 | spin_lock_irq(&wl->irq_lock); | 1220 | spin_lock_irq(&wl->irq_lock); |
1250 | /* update beacon right away or defer to irq */ | 1221 | /* Update beacon right away or defer to IRQ. */ |
1251 | dev->irq_savedstate = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); | ||
1252 | handle_irq_beacon(dev); | 1222 | handle_irq_beacon(dev); |
1253 | /* The handler might have updated the IRQ mask. */ | 1223 | /* The handler might have updated the IRQ mask. */ |
1254 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, | 1224 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, |
1255 | dev->irq_savedstate); | 1225 | dev->irq_mask); |
1256 | mmiowb(); | 1226 | mmiowb(); |
1257 | spin_unlock_irq(&wl->irq_lock); | 1227 | spin_unlock_irq(&wl->irq_lock); |
1258 | } | 1228 | } |
@@ -1398,7 +1368,7 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) | |||
1398 | if (reason & B43legacy_IRQ_TX_OK) | 1368 | if (reason & B43legacy_IRQ_TX_OK) |
1399 | handle_irq_transmit_status(dev); | 1369 | handle_irq_transmit_status(dev); |
1400 | 1370 | ||
1401 | b43legacy_interrupt_enable(dev, dev->irq_savedstate); | 1371 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
1402 | mmiowb(); | 1372 | mmiowb(); |
1403 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | 1373 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); |
1404 | } | 1374 | } |
@@ -1450,18 +1420,18 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) | |||
1450 | struct b43legacy_wldev *dev = dev_id; | 1420 | struct b43legacy_wldev *dev = dev_id; |
1451 | u32 reason; | 1421 | u32 reason; |
1452 | 1422 | ||
1453 | if (!dev) | 1423 | B43legacy_WARN_ON(!dev); |
1454 | return IRQ_NONE; | ||
1455 | 1424 | ||
1456 | spin_lock(&dev->wl->irq_lock); | 1425 | spin_lock(&dev->wl->irq_lock); |
1457 | 1426 | ||
1458 | if (b43legacy_status(dev) < B43legacy_STAT_STARTED) | 1427 | if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED)) |
1428 | /* This can only happen on shared IRQ lines. */ | ||
1459 | goto out; | 1429 | goto out; |
1460 | reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); | 1430 | reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); |
1461 | if (reason == 0xffffffff) /* shared IRQ */ | 1431 | if (reason == 0xffffffff) /* shared IRQ */ |
1462 | goto out; | 1432 | goto out; |
1463 | ret = IRQ_HANDLED; | 1433 | ret = IRQ_HANDLED; |
1464 | reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); | 1434 | reason &= dev->irq_mask; |
1465 | if (!reason) | 1435 | if (!reason) |
1466 | goto out; | 1436 | goto out; |
1467 | 1437 | ||
@@ -1485,10 +1455,9 @@ static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id) | |||
1485 | & 0x0000DC00; | 1455 | & 0x0000DC00; |
1486 | 1456 | ||
1487 | b43legacy_interrupt_ack(dev, reason); | 1457 | b43legacy_interrupt_ack(dev, reason); |
1488 | /* disable all IRQs. They are enabled again in the bottom half. */ | 1458 | /* Disable all IRQs. They are enabled again in the bottom half. */ |
1489 | dev->irq_savedstate = b43legacy_interrupt_disable(dev, | 1459 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); |
1490 | B43legacy_IRQ_ALL); | 1460 | /* Save the reason code and call our bottom half. */ |
1491 | /* save the reason code and call our bottom half. */ | ||
1492 | dev->irq_reason = reason; | 1461 | dev->irq_reason = reason; |
1493 | tasklet_schedule(&dev->isr_tasklet); | 1462 | tasklet_schedule(&dev->isr_tasklet); |
1494 | out: | 1463 | out: |
@@ -1948,7 +1917,8 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) | |||
1948 | 1917 | ||
1949 | /* Re-enable IRQs. */ | 1918 | /* Re-enable IRQs. */ |
1950 | spin_lock_irq(&dev->wl->irq_lock); | 1919 | spin_lock_irq(&dev->wl->irq_lock); |
1951 | b43legacy_interrupt_enable(dev, dev->irq_savedstate); | 1920 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, |
1921 | dev->irq_mask); | ||
1952 | spin_unlock_irq(&dev->wl->irq_lock); | 1922 | spin_unlock_irq(&dev->wl->irq_lock); |
1953 | } | 1923 | } |
1954 | } | 1924 | } |
@@ -1967,10 +1937,9 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) | |||
1967 | /* Mask IRQs before suspending MAC. Otherwise | 1937 | /* Mask IRQs before suspending MAC. Otherwise |
1968 | * the MAC stays busy and won't suspend. */ | 1938 | * the MAC stays busy and won't suspend. */ |
1969 | spin_lock_irq(&dev->wl->irq_lock); | 1939 | spin_lock_irq(&dev->wl->irq_lock); |
1970 | tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); | 1940 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); |
1971 | spin_unlock_irq(&dev->wl->irq_lock); | 1941 | spin_unlock_irq(&dev->wl->irq_lock); |
1972 | b43legacy_synchronize_irq(dev); | 1942 | b43legacy_synchronize_irq(dev); |
1973 | dev->irq_savedstate = tmp; | ||
1974 | 1943 | ||
1975 | b43legacy_power_saving_ctl_bits(dev, -1, 1); | 1944 | b43legacy_power_saving_ctl_bits(dev, -1, 1); |
1976 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, | 1945 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, |
@@ -2659,7 +2628,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, | |||
2659 | int antenna_tx; | 2628 | int antenna_tx; |
2660 | int antenna_rx; | 2629 | int antenna_rx; |
2661 | int err = 0; | 2630 | int err = 0; |
2662 | u32 savedirqs; | ||
2663 | 2631 | ||
2664 | antenna_tx = B43legacy_ANTENNA_DEFAULT; | 2632 | antenna_tx = B43legacy_ANTENNA_DEFAULT; |
2665 | antenna_rx = B43legacy_ANTENNA_DEFAULT; | 2633 | antenna_rx = B43legacy_ANTENNA_DEFAULT; |
@@ -2699,7 +2667,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, | |||
2699 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2667 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
2700 | goto out_unlock_mutex; | 2668 | goto out_unlock_mutex; |
2701 | } | 2669 | } |
2702 | savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); | 2670 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); |
2703 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2671 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
2704 | b43legacy_synchronize_irq(dev); | 2672 | b43legacy_synchronize_irq(dev); |
2705 | 2673 | ||
@@ -2738,7 +2706,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, | |||
2738 | } | 2706 | } |
2739 | 2707 | ||
2740 | spin_lock_irqsave(&wl->irq_lock, flags); | 2708 | spin_lock_irqsave(&wl->irq_lock, flags); |
2741 | b43legacy_interrupt_enable(dev, savedirqs); | 2709 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
2742 | mmiowb(); | 2710 | mmiowb(); |
2743 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2711 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
2744 | out_unlock_mutex: | 2712 | out_unlock_mutex: |
@@ -2801,7 +2769,6 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, | |||
2801 | struct b43legacy_wldev *dev; | 2769 | struct b43legacy_wldev *dev; |
2802 | struct b43legacy_phy *phy; | 2770 | struct b43legacy_phy *phy; |
2803 | unsigned long flags; | 2771 | unsigned long flags; |
2804 | u32 savedirqs; | ||
2805 | 2772 | ||
2806 | mutex_lock(&wl->mutex); | 2773 | mutex_lock(&wl->mutex); |
2807 | B43legacy_WARN_ON(wl->vif != vif); | 2774 | B43legacy_WARN_ON(wl->vif != vif); |
@@ -2817,30 +2784,27 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, | |||
2817 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2784 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
2818 | goto out_unlock_mutex; | 2785 | goto out_unlock_mutex; |
2819 | } | 2786 | } |
2820 | savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); | 2787 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); |
2821 | 2788 | ||
2822 | if (changed & BSS_CHANGED_BSSID) { | 2789 | if (changed & BSS_CHANGED_BSSID) { |
2823 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2824 | b43legacy_synchronize_irq(dev); | 2790 | b43legacy_synchronize_irq(dev); |
2825 | 2791 | ||
2826 | if (conf->bssid) | 2792 | if (conf->bssid) |
2827 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | 2793 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); |
2828 | else | 2794 | else |
2829 | memset(wl->bssid, 0, ETH_ALEN); | 2795 | memset(wl->bssid, 0, ETH_ALEN); |
2796 | } | ||
2797 | |||
2798 | if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { | ||
2799 | if (changed & BSS_CHANGED_BEACON && | ||
2800 | (b43legacy_is_mode(wl, NL80211_IFTYPE_AP) || | ||
2801 | b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC))) | ||
2802 | b43legacy_update_templates(wl); | ||
2830 | 2803 | ||
2831 | if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { | 2804 | if (changed & BSS_CHANGED_BSSID) |
2832 | if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { | ||
2833 | B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); | ||
2834 | if (changed & BSS_CHANGED_BEACON) | ||
2835 | b43legacy_update_templates(wl); | ||
2836 | } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { | ||
2837 | if (changed & BSS_CHANGED_BEACON) | ||
2838 | b43legacy_update_templates(wl); | ||
2839 | } | ||
2840 | b43legacy_write_mac_bssid_templates(dev); | 2805 | b43legacy_write_mac_bssid_templates(dev); |
2841 | } | ||
2842 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2843 | } | 2806 | } |
2807 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2844 | 2808 | ||
2845 | b43legacy_mac_suspend(dev); | 2809 | b43legacy_mac_suspend(dev); |
2846 | 2810 | ||
@@ -2862,7 +2826,7 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, | |||
2862 | b43legacy_mac_enable(dev); | 2826 | b43legacy_mac_enable(dev); |
2863 | 2827 | ||
2864 | spin_lock_irqsave(&wl->irq_lock, flags); | 2828 | spin_lock_irqsave(&wl->irq_lock, flags); |
2865 | b43legacy_interrupt_enable(dev, savedirqs); | 2829 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
2866 | /* XXX: why? */ | 2830 | /* XXX: why? */ |
2867 | mmiowb(); | 2831 | mmiowb(); |
2868 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2832 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
@@ -2922,8 +2886,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev) | |||
2922 | * setting the status to INITIALIZED, as the interrupt handler | 2886 | * setting the status to INITIALIZED, as the interrupt handler |
2923 | * won't care about IRQs then. */ | 2887 | * won't care about IRQs then. */ |
2924 | spin_lock_irqsave(&wl->irq_lock, flags); | 2888 | spin_lock_irqsave(&wl->irq_lock, flags); |
2925 | dev->irq_savedstate = b43legacy_interrupt_disable(dev, | 2889 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, 0); |
2926 | B43legacy_IRQ_ALL); | ||
2927 | b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ | 2890 | b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */ |
2928 | spin_unlock_irqrestore(&wl->irq_lock, flags); | 2891 | spin_unlock_irqrestore(&wl->irq_lock, flags); |
2929 | b43legacy_synchronize_irq(dev); | 2892 | b43legacy_synchronize_irq(dev); |
@@ -2963,7 +2926,7 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev) | |||
2963 | 2926 | ||
2964 | /* Start data flow (TX/RX) */ | 2927 | /* Start data flow (TX/RX) */ |
2965 | b43legacy_mac_enable(dev); | 2928 | b43legacy_mac_enable(dev); |
2966 | b43legacy_interrupt_enable(dev, dev->irq_savedstate); | 2929 | b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, dev->irq_mask); |
2967 | 2930 | ||
2968 | /* Start maintenance work */ | 2931 | /* Start maintenance work */ |
2969 | b43legacy_periodic_tasks_setup(dev); | 2932 | b43legacy_periodic_tasks_setup(dev); |
@@ -3126,7 +3089,7 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev) | |||
3126 | /* IRQ related flags */ | 3089 | /* IRQ related flags */ |
3127 | dev->irq_reason = 0; | 3090 | dev->irq_reason = 0; |
3128 | memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); | 3091 | memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); |
3129 | dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE; | 3092 | dev->irq_mask = B43legacy_IRQ_MASKTEMPLATE; |
3130 | 3093 | ||
3131 | dev->mac_suspended = 1; | 3094 | dev->mac_suspended = 1; |
3132 | 3095 | ||
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index 746d5361bba0..51866c9a2769 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c | |||
@@ -443,7 +443,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev) | |||
443 | pio->queue3 = queue; | 443 | pio->queue3 = queue; |
444 | 444 | ||
445 | if (dev->dev->id.revision < 3) | 445 | if (dev->dev->id.revision < 3) |
446 | dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND; | 446 | dev->irq_mask |= B43legacy_IRQ_PIO_WORKAROUND; |
447 | 447 | ||
448 | b43legacydbg(dev->wl, "PIO initialized\n"); | 448 | b43legacydbg(dev->wl, "PIO initialized\n"); |
449 | err = 0; | 449 | err = 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index ac22f59be9ef..bd7e520d98c2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c | |||
@@ -44,6 +44,15 @@ | |||
44 | #include "iwl-core.h" | 44 | #include "iwl-core.h" |
45 | #include "iwl-dev.h" | 45 | #include "iwl-dev.h" |
46 | 46 | ||
47 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
48 | static const char *led_type_str[] = { | ||
49 | __stringify(IWL_LED_TRG_TX), | ||
50 | __stringify(IWL_LED_TRG_RX), | ||
51 | __stringify(IWL_LED_TRG_ASSOC), | ||
52 | __stringify(IWL_LED_TRG_RADIO), | ||
53 | NULL | ||
54 | }; | ||
55 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
47 | 56 | ||
48 | static const struct { | 57 | static const struct { |
49 | u16 brightness; | 58 | u16 brightness; |
@@ -61,7 +70,7 @@ static const struct { | |||
61 | {10, 110, 110}, | 70 | {10, 110, 110}, |
62 | {5, 130, 130}, | 71 | {5, 130, 130}, |
63 | {0, 167, 167}, | 72 | {0, 167, 167}, |
64 | /*SOLID_ON*/ | 73 | /* SOLID_ON */ |
65 | {-1, IWL_LED_SOLID, 0} | 74 | {-1, IWL_LED_SOLID, 0} |
66 | }; | 75 | }; |
67 | 76 | ||
@@ -143,6 +152,30 @@ static int iwl3945_led_off(struct iwl_priv *priv, int led_id) | |||
143 | } | 152 | } |
144 | 153 | ||
145 | /* | 154 | /* |
155 | * Set led on in case of association | ||
156 | * */ | ||
157 | static int iwl3945_led_associate(struct iwl_priv *priv, int led_id) | ||
158 | { | ||
159 | IWL_DEBUG_LED(priv, "Associated\n"); | ||
160 | |||
161 | priv->allow_blinking = 1; | ||
162 | return iwl3945_led_on(priv, led_id); | ||
163 | } | ||
164 | /* Set Led off in case of disassociation */ | ||
165 | static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id) | ||
166 | { | ||
167 | IWL_DEBUG_LED(priv, "Disassociated\n"); | ||
168 | |||
169 | priv->allow_blinking = 0; | ||
170 | if (iwl_is_rfkill(priv)) | ||
171 | iwl3945_led_off(priv, led_id); | ||
172 | else | ||
173 | iwl3945_led_on(priv, led_id); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | /* | ||
146 | * brightness call back function for Tx/Rx LED | 179 | * brightness call back function for Tx/Rx LED |
147 | */ | 180 | */ |
148 | static int iwl3945_led_associated(struct iwl_priv *priv, int led_id) | 181 | static int iwl3945_led_associated(struct iwl_priv *priv, int led_id) |
@@ -165,26 +198,21 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, | |||
165 | enum led_brightness brightness) | 198 | enum led_brightness brightness) |
166 | { | 199 | { |
167 | struct iwl_led *led = container_of(led_cdev, | 200 | struct iwl_led *led = container_of(led_cdev, |
168 | struct iwl_led, led_dev); | 201 | struct iwl_led, led_dev); |
169 | struct iwl_priv *priv = led->priv; | 202 | struct iwl_priv *priv = led->priv; |
170 | 203 | ||
171 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 204 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
172 | return; | 205 | return; |
173 | 206 | ||
207 | IWL_DEBUG_LED(priv, "Led type = %s brightness = %d\n", | ||
208 | led_type_str[led->type], brightness); | ||
209 | |||
174 | switch (brightness) { | 210 | switch (brightness) { |
175 | case LED_FULL: | 211 | case LED_FULL: |
176 | if (led->type == IWL_LED_TRG_ASSOC) { | ||
177 | priv->allow_blinking = 1; | ||
178 | IWL_DEBUG_LED(priv, "MAC is associated\n"); | ||
179 | } | ||
180 | if (led->led_on) | 212 | if (led->led_on) |
181 | led->led_on(priv, IWL_LED_LINK); | 213 | led->led_on(priv, IWL_LED_LINK); |
182 | break; | 214 | break; |
183 | case LED_OFF: | 215 | case LED_OFF: |
184 | if (led->type == IWL_LED_TRG_ASSOC) { | ||
185 | priv->allow_blinking = 0; | ||
186 | IWL_DEBUG_LED(priv, "MAC is disassociated\n"); | ||
187 | } | ||
188 | if (led->led_off) | 216 | if (led->led_off) |
189 | led->led_off(priv, IWL_LED_LINK); | 217 | led->led_off(priv, IWL_LED_LINK); |
190 | break; | 218 | break; |
@@ -197,8 +225,6 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev, | |||
197 | } | 225 | } |
198 | } | 226 | } |
199 | 227 | ||
200 | |||
201 | |||
202 | /* | 228 | /* |
203 | * Register led class with the system | 229 | * Register led class with the system |
204 | */ | 230 | */ |
@@ -237,12 +263,12 @@ static int iwl3945_led_register_led(struct iwl_priv *priv, | |||
237 | static inline u8 get_blink_rate(struct iwl_priv *priv) | 263 | static inline u8 get_blink_rate(struct iwl_priv *priv) |
238 | { | 264 | { |
239 | int index; | 265 | int index; |
240 | u64 current_tpt = priv->rxtxpackets; | 266 | s64 tpt = priv->rxtxpackets; |
241 | s64 tpt = current_tpt - priv->led_tpt; | ||
242 | 267 | ||
243 | if (tpt < 0) | 268 | if (tpt < 0) |
244 | tpt = -tpt; | 269 | tpt = -tpt; |
245 | priv->led_tpt = current_tpt; | 270 | |
271 | IWL_DEBUG_LED(priv, "tpt %lld \n", (long long)tpt); | ||
246 | 272 | ||
247 | if (!priv->allow_blinking) | 273 | if (!priv->allow_blinking) |
248 | index = IWL_MAX_BLINK_TBL; | 274 | index = IWL_MAX_BLINK_TBL; |
@@ -250,13 +276,9 @@ static inline u8 get_blink_rate(struct iwl_priv *priv) | |||
250 | for (index = 0; index < IWL_MAX_BLINK_TBL; index++) | 276 | for (index = 0; index < IWL_MAX_BLINK_TBL; index++) |
251 | if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) | 277 | if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE)) |
252 | break; | 278 | break; |
253 | return index; | ||
254 | } | ||
255 | 279 | ||
256 | static inline int is_rf_kill(struct iwl_priv *priv) | 280 | IWL_DEBUG_LED(priv, "LED BLINK IDX=%d\n", index); |
257 | { | 281 | return index; |
258 | return test_bit(STATUS_RF_KILL_HW, &priv->status) || | ||
259 | test_bit(STATUS_RF_KILL_SW, &priv->status); | ||
260 | } | 282 | } |
261 | 283 | ||
262 | /* | 284 | /* |
@@ -272,7 +294,7 @@ void iwl3945_led_background(struct iwl_priv *priv) | |||
272 | priv->last_blink_time = 0; | 294 | priv->last_blink_time = 0; |
273 | return; | 295 | return; |
274 | } | 296 | } |
275 | if (is_rf_kill(priv)) { | 297 | if (iwl_is_rfkill(priv)) { |
276 | priv->last_blink_time = 0; | 298 | priv->last_blink_time = 0; |
277 | return; | 299 | return; |
278 | } | 300 | } |
@@ -341,8 +363,8 @@ int iwl3945_led_register(struct iwl_priv *priv) | |||
341 | IWL_LED_TRG_ASSOC, 0, trigger); | 363 | IWL_LED_TRG_ASSOC, 0, trigger); |
342 | 364 | ||
343 | /* for assoc always turn led on */ | 365 | /* for assoc always turn led on */ |
344 | priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on; | 366 | priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_associate; |
345 | priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on; | 367 | priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_disassociate; |
346 | priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; | 368 | priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; |
347 | 369 | ||
348 | if (ret) | 370 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 5b0c6e5bda92..fd65e1c3e055 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -98,7 +98,6 @@ const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT_3945] = { | |||
98 | * ... and set IWL_EVT_DISABLE to 1. */ | 98 | * ... and set IWL_EVT_DISABLE to 1. */ |
99 | void iwl3945_disable_events(struct iwl_priv *priv) | 99 | void iwl3945_disable_events(struct iwl_priv *priv) |
100 | { | 100 | { |
101 | int ret; | ||
102 | int i; | 101 | int i; |
103 | u32 base; /* SRAM address of event log header */ | 102 | u32 base; /* SRAM address of event log header */ |
104 | u32 disable_ptr; /* SRAM address of event-disable bitmap array */ | 103 | u32 disable_ptr; /* SRAM address of event-disable bitmap array */ |
@@ -159,26 +158,17 @@ void iwl3945_disable_events(struct iwl_priv *priv) | |||
159 | return; | 158 | return; |
160 | } | 159 | } |
161 | 160 | ||
162 | ret = iwl_grab_nic_access(priv); | ||
163 | if (ret) { | ||
164 | IWL_WARN(priv, "Can not read from adapter at this time.\n"); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32))); | 161 | disable_ptr = iwl_read_targ_mem(priv, base + (4 * sizeof(u32))); |
169 | array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32))); | 162 | array_size = iwl_read_targ_mem(priv, base + (5 * sizeof(u32))); |
170 | iwl_release_nic_access(priv); | ||
171 | 163 | ||
172 | if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { | 164 | if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { |
173 | IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n", | 165 | IWL_DEBUG_INFO(priv, "Disabling selected uCode log events at 0x%x\n", |
174 | disable_ptr); | 166 | disable_ptr); |
175 | ret = iwl_grab_nic_access(priv); | ||
176 | for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) | 167 | for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) |
177 | iwl_write_targ_mem(priv, | 168 | iwl_write_targ_mem(priv, |
178 | disable_ptr + (i * sizeof(u32)), | 169 | disable_ptr + (i * sizeof(u32)), |
179 | evt_disable[i]); | 170 | evt_disable[i]); |
180 | 171 | ||
181 | iwl_release_nic_access(priv); | ||
182 | } else { | 172 | } else { |
183 | IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n"); | 173 | IWL_DEBUG_INFO(priv, "Selected uCode log events may be disabled\n"); |
184 | IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n"); | 174 | IWL_DEBUG_INFO(priv, " by writing \"1\"s into disable bitmap\n"); |
@@ -908,55 +898,30 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) | |||
908 | 898 | ||
909 | static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) | 899 | static int iwl3945_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) |
910 | { | 900 | { |
911 | int ret; | ||
912 | unsigned long flags; | ||
913 | |||
914 | spin_lock_irqsave(&priv->lock, flags); | ||
915 | ret = iwl_grab_nic_access(priv); | ||
916 | if (ret) { | ||
917 | spin_unlock_irqrestore(&priv->lock, flags); | ||
918 | return ret; | ||
919 | } | ||
920 | |||
921 | if (src == IWL_PWR_SRC_VAUX) { | 901 | if (src == IWL_PWR_SRC_VAUX) { |
922 | if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { | 902 | if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) { |
923 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 903 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
924 | APMG_PS_CTRL_VAL_PWR_SRC_VAUX, | 904 | APMG_PS_CTRL_VAL_PWR_SRC_VAUX, |
925 | ~APMG_PS_CTRL_MSK_PWR_SRC); | 905 | ~APMG_PS_CTRL_MSK_PWR_SRC); |
926 | iwl_release_nic_access(priv); | ||
927 | 906 | ||
928 | iwl_poll_bit(priv, CSR_GPIO_IN, | 907 | iwl_poll_bit(priv, CSR_GPIO_IN, |
929 | CSR_GPIO_IN_VAL_VAUX_PWR_SRC, | 908 | CSR_GPIO_IN_VAL_VAUX_PWR_SRC, |
930 | CSR_GPIO_IN_BIT_AUX_POWER, 5000); | 909 | CSR_GPIO_IN_BIT_AUX_POWER, 5000); |
931 | } else { | ||
932 | iwl_release_nic_access(priv); | ||
933 | } | 910 | } |
934 | } else { | 911 | } else { |
935 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 912 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
936 | APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, | 913 | APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, |
937 | ~APMG_PS_CTRL_MSK_PWR_SRC); | 914 | ~APMG_PS_CTRL_MSK_PWR_SRC); |
938 | 915 | ||
939 | iwl_release_nic_access(priv); | ||
940 | iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, | 916 | iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, |
941 | CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ | 917 | CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ |
942 | } | 918 | } |
943 | spin_unlock_irqrestore(&priv->lock, flags); | ||
944 | 919 | ||
945 | return ret; | 920 | return 0; |
946 | } | 921 | } |
947 | 922 | ||
948 | static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | 923 | static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) |
949 | { | 924 | { |
950 | int rc; | ||
951 | unsigned long flags; | ||
952 | |||
953 | spin_lock_irqsave(&priv->lock, flags); | ||
954 | rc = iwl_grab_nic_access(priv); | ||
955 | if (rc) { | ||
956 | spin_unlock_irqrestore(&priv->lock, flags); | ||
957 | return rc; | ||
958 | } | ||
959 | |||
960 | iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr); | 925 | iwl_write_direct32(priv, FH39_RCSR_RBD_BASE(0), rxq->dma_addr); |
961 | iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma); | 926 | iwl_write_direct32(priv, FH39_RCSR_RPTR_ADDR(0), rxq->rb_stts_dma); |
962 | iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0); | 927 | iwl_write_direct32(priv, FH39_RCSR_WPTR(0), 0); |
@@ -973,23 +938,11 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
973 | /* fake read to flush all prev I/O */ | 938 | /* fake read to flush all prev I/O */ |
974 | iwl_read_direct32(priv, FH39_RSSR_CTRL); | 939 | iwl_read_direct32(priv, FH39_RSSR_CTRL); |
975 | 940 | ||
976 | iwl_release_nic_access(priv); | ||
977 | spin_unlock_irqrestore(&priv->lock, flags); | ||
978 | |||
979 | return 0; | 941 | return 0; |
980 | } | 942 | } |
981 | 943 | ||
982 | static int iwl3945_tx_reset(struct iwl_priv *priv) | 944 | static int iwl3945_tx_reset(struct iwl_priv *priv) |
983 | { | 945 | { |
984 | int rc; | ||
985 | unsigned long flags; | ||
986 | |||
987 | spin_lock_irqsave(&priv->lock, flags); | ||
988 | rc = iwl_grab_nic_access(priv); | ||
989 | if (rc) { | ||
990 | spin_unlock_irqrestore(&priv->lock, flags); | ||
991 | return rc; | ||
992 | } | ||
993 | 946 | ||
994 | /* bypass mode */ | 947 | /* bypass mode */ |
995 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2); | 948 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0x2); |
@@ -1017,8 +970,6 @@ static int iwl3945_tx_reset(struct iwl_priv *priv) | |||
1017 | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | | 970 | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | |
1018 | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); | 971 | FH39_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); |
1019 | 972 | ||
1020 | iwl_release_nic_access(priv); | ||
1021 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1022 | 973 | ||
1023 | return 0; | 974 | return 0; |
1024 | } | 975 | } |
@@ -1061,7 +1012,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) | |||
1061 | 1012 | ||
1062 | static int iwl3945_apm_init(struct iwl_priv *priv) | 1013 | static int iwl3945_apm_init(struct iwl_priv *priv) |
1063 | { | 1014 | { |
1064 | int ret = 0; | 1015 | int ret; |
1065 | 1016 | ||
1066 | iwl_power_initialize(priv); | 1017 | iwl_power_initialize(priv); |
1067 | 1018 | ||
@@ -1083,10 +1034,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) | |||
1083 | goto out; | 1034 | goto out; |
1084 | } | 1035 | } |
1085 | 1036 | ||
1086 | ret = iwl_grab_nic_access(priv); | ||
1087 | if (ret) | ||
1088 | goto out; | ||
1089 | |||
1090 | /* enable DMA */ | 1037 | /* enable DMA */ |
1091 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | | 1038 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | |
1092 | APMG_CLK_VAL_BSM_CLK_RQT); | 1039 | APMG_CLK_VAL_BSM_CLK_RQT); |
@@ -1097,7 +1044,6 @@ static int iwl3945_apm_init(struct iwl_priv *priv) | |||
1097 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, | 1044 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, |
1098 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 1045 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
1099 | 1046 | ||
1100 | iwl_release_nic_access(priv); | ||
1101 | out: | 1047 | out: |
1102 | return ret; | 1048 | return ret; |
1103 | } | 1049 | } |
@@ -1196,22 +1142,13 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) | |||
1196 | 1142 | ||
1197 | iwl3945_rx_init(priv, rxq); | 1143 | iwl3945_rx_init(priv, rxq); |
1198 | 1144 | ||
1199 | spin_lock_irqsave(&priv->lock, flags); | ||
1200 | 1145 | ||
1201 | /* Look at using this instead: | 1146 | /* Look at using this instead: |
1202 | rxq->need_update = 1; | 1147 | rxq->need_update = 1; |
1203 | iwl_rx_queue_update_write_ptr(priv, rxq); | 1148 | iwl_rx_queue_update_write_ptr(priv, rxq); |
1204 | */ | 1149 | */ |
1205 | 1150 | ||
1206 | rc = iwl_grab_nic_access(priv); | ||
1207 | if (rc) { | ||
1208 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1209 | return rc; | ||
1210 | } | ||
1211 | iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7); | 1151 | iwl_write_direct32(priv, FH39_RCSR_WPTR(0), rxq->write & ~7); |
1212 | iwl_release_nic_access(priv); | ||
1213 | |||
1214 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1215 | 1152 | ||
1216 | rc = iwl3945_txq_ctx_reset(priv); | 1153 | rc = iwl3945_txq_ctx_reset(priv); |
1217 | if (rc) | 1154 | if (rc) |
@@ -1243,14 +1180,6 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) | |||
1243 | void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) | 1180 | void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) |
1244 | { | 1181 | { |
1245 | int txq_id; | 1182 | int txq_id; |
1246 | unsigned long flags; | ||
1247 | |||
1248 | spin_lock_irqsave(&priv->lock, flags); | ||
1249 | if (iwl_grab_nic_access(priv)) { | ||
1250 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1251 | iwl3945_hw_txq_ctx_free(priv); | ||
1252 | return; | ||
1253 | } | ||
1254 | 1183 | ||
1255 | /* stop SCD */ | 1184 | /* stop SCD */ |
1256 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); | 1185 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); |
@@ -1263,9 +1192,6 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) | |||
1263 | 1000); | 1192 | 1000); |
1264 | } | 1193 | } |
1265 | 1194 | ||
1266 | iwl_release_nic_access(priv); | ||
1267 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1268 | |||
1269 | iwl3945_hw_txq_ctx_free(priv); | 1195 | iwl3945_hw_txq_ctx_free(priv); |
1270 | } | 1196 | } |
1271 | 1197 | ||
@@ -1310,12 +1236,8 @@ static void iwl3945_apm_stop(struct iwl_priv *priv) | |||
1310 | 1236 | ||
1311 | static int iwl3945_apm_reset(struct iwl_priv *priv) | 1237 | static int iwl3945_apm_reset(struct iwl_priv *priv) |
1312 | { | 1238 | { |
1313 | int rc; | ||
1314 | unsigned long flags; | ||
1315 | |||
1316 | iwl3945_apm_stop_master(priv); | 1239 | iwl3945_apm_stop_master(priv); |
1317 | 1240 | ||
1318 | spin_lock_irqsave(&priv->lock, flags); | ||
1319 | 1241 | ||
1320 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | 1242 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
1321 | udelay(10); | 1243 | udelay(10); |
@@ -1325,36 +1247,31 @@ static int iwl3945_apm_reset(struct iwl_priv *priv) | |||
1325 | iwl_poll_direct_bit(priv, CSR_GP_CNTRL, | 1247 | iwl_poll_direct_bit(priv, CSR_GP_CNTRL, |
1326 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); | 1248 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); |
1327 | 1249 | ||
1328 | rc = iwl_grab_nic_access(priv); | 1250 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, |
1329 | if (!rc) { | 1251 | APMG_CLK_VAL_BSM_CLK_RQT); |
1330 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, | ||
1331 | APMG_CLK_VAL_BSM_CLK_RQT); | ||
1332 | 1252 | ||
1333 | iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); | 1253 | iwl_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); |
1334 | iwl_write_prph(priv, APMG_RTC_INT_STT_REG, | 1254 | iwl_write_prph(priv, APMG_RTC_INT_STT_REG, |
1335 | 0xFFFFFFFF); | 1255 | 0xFFFFFFFF); |
1336 | 1256 | ||
1337 | /* enable DMA */ | 1257 | /* enable DMA */ |
1338 | iwl_write_prph(priv, APMG_CLK_EN_REG, | 1258 | iwl_write_prph(priv, APMG_CLK_EN_REG, |
1339 | APMG_CLK_VAL_DMA_CLK_RQT | | 1259 | APMG_CLK_VAL_DMA_CLK_RQT | |
1340 | APMG_CLK_VAL_BSM_CLK_RQT); | 1260 | APMG_CLK_VAL_BSM_CLK_RQT); |
1341 | udelay(10); | 1261 | udelay(10); |
1342 | 1262 | ||
1343 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, | 1263 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, |
1344 | APMG_PS_CTRL_VAL_RESET_REQ); | 1264 | APMG_PS_CTRL_VAL_RESET_REQ); |
1345 | udelay(5); | 1265 | udelay(5); |
1346 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, | 1266 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, |
1347 | APMG_PS_CTRL_VAL_RESET_REQ); | 1267 | APMG_PS_CTRL_VAL_RESET_REQ); |
1348 | iwl_release_nic_access(priv); | ||
1349 | } | ||
1350 | 1268 | ||
1351 | /* Clear the 'host command active' bit... */ | 1269 | /* Clear the 'host command active' bit... */ |
1352 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 1270 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
1353 | 1271 | ||
1354 | wake_up_interruptible(&priv->wait_command_queue); | 1272 | wake_up_interruptible(&priv->wait_command_queue); |
1355 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1356 | 1273 | ||
1357 | return rc; | 1274 | return 0; |
1358 | } | 1275 | } |
1359 | 1276 | ||
1360 | /** | 1277 | /** |
@@ -2500,14 +2417,6 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) | |||
2500 | int iwl3945_hw_rxq_stop(struct iwl_priv *priv) | 2417 | int iwl3945_hw_rxq_stop(struct iwl_priv *priv) |
2501 | { | 2418 | { |
2502 | int rc; | 2419 | int rc; |
2503 | unsigned long flags; | ||
2504 | |||
2505 | spin_lock_irqsave(&priv->lock, flags); | ||
2506 | rc = iwl_grab_nic_access(priv); | ||
2507 | if (rc) { | ||
2508 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2509 | return rc; | ||
2510 | } | ||
2511 | 2420 | ||
2512 | iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0); | 2421 | iwl_write_direct32(priv, FH39_RCSR_CONFIG(0), 0); |
2513 | rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS, | 2422 | rc = iwl_poll_direct_bit(priv, FH39_RSSR_STATUS, |
@@ -2515,28 +2424,17 @@ int iwl3945_hw_rxq_stop(struct iwl_priv *priv) | |||
2515 | if (rc < 0) | 2424 | if (rc < 0) |
2516 | IWL_ERR(priv, "Can't stop Rx DMA.\n"); | 2425 | IWL_ERR(priv, "Can't stop Rx DMA.\n"); |
2517 | 2426 | ||
2518 | iwl_release_nic_access(priv); | ||
2519 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2520 | |||
2521 | return 0; | 2427 | return 0; |
2522 | } | 2428 | } |
2523 | 2429 | ||
2524 | int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) | 2430 | int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) |
2525 | { | 2431 | { |
2526 | int rc; | ||
2527 | unsigned long flags; | ||
2528 | int txq_id = txq->q.id; | 2432 | int txq_id = txq->q.id; |
2529 | 2433 | ||
2530 | struct iwl3945_shared *shared_data = priv->shared_virt; | 2434 | struct iwl3945_shared *shared_data = priv->shared_virt; |
2531 | 2435 | ||
2532 | shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); | 2436 | shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); |
2533 | 2437 | ||
2534 | spin_lock_irqsave(&priv->lock, flags); | ||
2535 | rc = iwl_grab_nic_access(priv); | ||
2536 | if (rc) { | ||
2537 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2538 | return rc; | ||
2539 | } | ||
2540 | iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0); | 2438 | iwl_write_direct32(priv, FH39_CBCC_CTRL(txq_id), 0); |
2541 | iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0); | 2439 | iwl_write_direct32(priv, FH39_CBCC_BASE(txq_id), 0); |
2542 | 2440 | ||
@@ -2546,11 +2444,9 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
2546 | FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | | 2444 | FH39_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | |
2547 | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | | 2445 | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | |
2548 | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); | 2446 | FH39_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); |
2549 | iwl_release_nic_access(priv); | ||
2550 | 2447 | ||
2551 | /* fake read to flush all prev. writes */ | 2448 | /* fake read to flush all prev. writes */ |
2552 | iwl_read32(priv, FH39_TSSR_CBB_BASE); | 2449 | iwl_read32(priv, FH39_TSSR_CBB_BASE); |
2553 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2554 | 2450 | ||
2555 | return 0; | 2451 | return 0; |
2556 | } | 2452 | } |
@@ -2858,10 +2754,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) | |||
2858 | inst_len = priv->ucode_init.len; | 2754 | inst_len = priv->ucode_init.len; |
2859 | data_len = priv->ucode_init_data.len; | 2755 | data_len = priv->ucode_init_data.len; |
2860 | 2756 | ||
2861 | rc = iwl_grab_nic_access(priv); | ||
2862 | if (rc) | ||
2863 | return rc; | ||
2864 | |||
2865 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); | 2757 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); |
2866 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); | 2758 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); |
2867 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); | 2759 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); |
@@ -2875,10 +2767,8 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) | |||
2875 | le32_to_cpu(*image)); | 2767 | le32_to_cpu(*image)); |
2876 | 2768 | ||
2877 | rc = iwl3945_verify_bsm(priv); | 2769 | rc = iwl3945_verify_bsm(priv); |
2878 | if (rc) { | 2770 | if (rc) |
2879 | iwl_release_nic_access(priv); | ||
2880 | return rc; | 2771 | return rc; |
2881 | } | ||
2882 | 2772 | ||
2883 | /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ | 2773 | /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ |
2884 | iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); | 2774 | iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); |
@@ -2910,8 +2800,6 @@ static int iwl3945_load_bsm(struct iwl_priv *priv) | |||
2910 | iwl_write_prph(priv, BSM_WR_CTRL_REG, | 2800 | iwl_write_prph(priv, BSM_WR_CTRL_REG, |
2911 | BSM_WR_CTRL_REG_BIT_START_EN); | 2801 | BSM_WR_CTRL_REG_BIT_START_EN); |
2912 | 2802 | ||
2913 | iwl_release_nic_access(priv); | ||
2914 | |||
2915 | return 0; | 2803 | return 0; |
2916 | } | 2804 | } |
2917 | 2805 | ||
@@ -2950,6 +2838,7 @@ static struct iwl_lib_ops iwl3945_lib = { | |||
2950 | .send_tx_power = iwl3945_send_tx_power, | 2838 | .send_tx_power = iwl3945_send_tx_power, |
2951 | .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, | 2839 | .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, |
2952 | .post_associate = iwl3945_post_associate, | 2840 | .post_associate = iwl3945_post_associate, |
2841 | .isr = iwl_isr_legacy, | ||
2953 | .config_ap = iwl3945_config_ap, | 2842 | .config_ap = iwl3945_config_ap, |
2954 | }; | 2843 | }; |
2955 | 2844 | ||
@@ -2983,7 +2872,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { | |||
2983 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, | 2872 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, |
2984 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, | 2873 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, |
2985 | .ops = &iwl3945_ops, | 2874 | .ops = &iwl3945_ops, |
2986 | .mod_params = &iwl3945_mod_params | 2875 | .mod_params = &iwl3945_mod_params, |
2876 | .use_isr_legacy = true | ||
2987 | }; | 2877 | }; |
2988 | 2878 | ||
2989 | static struct iwl_cfg iwl3945_abg_cfg = { | 2879 | static struct iwl_cfg iwl3945_abg_cfg = { |
@@ -2995,7 +2885,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { | |||
2995 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, | 2885 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, |
2996 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, | 2886 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, |
2997 | .ops = &iwl3945_ops, | 2887 | .ops = &iwl3945_ops, |
2998 | .mod_params = &iwl3945_mod_params | 2888 | .mod_params = &iwl3945_mod_params, |
2889 | .use_isr_legacy = true | ||
2999 | }; | 2890 | }; |
3000 | 2891 | ||
3001 | struct pci_device_id iwl3945_hw_card_ids[] = { | 2892 | struct pci_device_id iwl3945_hw_card_ids[] = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a98ff4ead720..a0b29411a4b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -163,10 +163,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) | |||
163 | inst_len = priv->ucode_init.len; | 163 | inst_len = priv->ucode_init.len; |
164 | data_len = priv->ucode_init_data.len; | 164 | data_len = priv->ucode_init_data.len; |
165 | 165 | ||
166 | ret = iwl_grab_nic_access(priv); | ||
167 | if (ret) | ||
168 | return ret; | ||
169 | |||
170 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); | 166 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); |
171 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); | 167 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); |
172 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); | 168 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); |
@@ -179,10 +175,8 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) | |||
179 | _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); | 175 | _iwl_write_prph(priv, reg_offset, le32_to_cpu(*image)); |
180 | 176 | ||
181 | ret = iwl4965_verify_bsm(priv); | 177 | ret = iwl4965_verify_bsm(priv); |
182 | if (ret) { | 178 | if (ret) |
183 | iwl_release_nic_access(priv); | ||
184 | return ret; | 179 | return ret; |
185 | } | ||
186 | 180 | ||
187 | /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ | 181 | /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ |
188 | iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); | 182 | iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); |
@@ -211,7 +205,6 @@ static int iwl4965_load_bsm(struct iwl_priv *priv) | |||
211 | * (e.g. when powering back up after power-save shutdown) */ | 205 | * (e.g. when powering back up after power-save shutdown) */ |
212 | iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); | 206 | iwl_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); |
213 | 207 | ||
214 | iwl_release_nic_access(priv); | ||
215 | 208 | ||
216 | return 0; | 209 | return 0; |
217 | } | 210 | } |
@@ -229,20 +222,12 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) | |||
229 | { | 222 | { |
230 | dma_addr_t pinst; | 223 | dma_addr_t pinst; |
231 | dma_addr_t pdata; | 224 | dma_addr_t pdata; |
232 | unsigned long flags; | ||
233 | int ret = 0; | 225 | int ret = 0; |
234 | 226 | ||
235 | /* bits 35:4 for 4965 */ | 227 | /* bits 35:4 for 4965 */ |
236 | pinst = priv->ucode_code.p_addr >> 4; | 228 | pinst = priv->ucode_code.p_addr >> 4; |
237 | pdata = priv->ucode_data_backup.p_addr >> 4; | 229 | pdata = priv->ucode_data_backup.p_addr >> 4; |
238 | 230 | ||
239 | spin_lock_irqsave(&priv->lock, flags); | ||
240 | ret = iwl_grab_nic_access(priv); | ||
241 | if (ret) { | ||
242 | spin_unlock_irqrestore(&priv->lock, flags); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | /* Tell bootstrap uCode where to find image to load */ | 231 | /* Tell bootstrap uCode where to find image to load */ |
247 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); | 232 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); |
248 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); | 233 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); |
@@ -253,10 +238,6 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) | |||
253 | * that all new ptr/size info is in place */ | 238 | * that all new ptr/size info is in place */ |
254 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, | 239 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, |
255 | priv->ucode_code.len | BSM_DRAM_INST_LOAD); | 240 | priv->ucode_code.len | BSM_DRAM_INST_LOAD); |
256 | iwl_release_nic_access(priv); | ||
257 | |||
258 | spin_unlock_irqrestore(&priv->lock, flags); | ||
259 | |||
260 | IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); | 241 | IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); |
261 | 242 | ||
262 | return ret; | 243 | return ret; |
@@ -312,10 +293,12 @@ restart: | |||
312 | queue_work(priv->workqueue, &priv->restart); | 293 | queue_work(priv->workqueue, &priv->restart); |
313 | } | 294 | } |
314 | 295 | ||
315 | static int is_fat_channel(__le32 rxon_flags) | 296 | static bool is_fat_channel(__le32 rxon_flags) |
316 | { | 297 | { |
317 | return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || | 298 | int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) |
318 | (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); | 299 | >> RXON_FLG_CHANNEL_MODE_POS; |
300 | return ((chan_mod == CHANNEL_MODE_PURE_40) || | ||
301 | (chan_mod == CHANNEL_MODE_MIXED)); | ||
319 | } | 302 | } |
320 | 303 | ||
321 | /* | 304 | /* |
@@ -358,10 +341,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) | |||
358 | goto out; | 341 | goto out; |
359 | } | 342 | } |
360 | 343 | ||
361 | ret = iwl_grab_nic_access(priv); | ||
362 | if (ret) | ||
363 | goto out; | ||
364 | |||
365 | /* enable DMA */ | 344 | /* enable DMA */ |
366 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | | 345 | iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | |
367 | APMG_CLK_VAL_BSM_CLK_RQT); | 346 | APMG_CLK_VAL_BSM_CLK_RQT); |
@@ -372,7 +351,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv) | |||
372 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, | 351 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, |
373 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 352 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
374 | 353 | ||
375 | iwl_release_nic_access(priv); | ||
376 | out: | 354 | out: |
377 | return ret; | 355 | return ret; |
378 | } | 356 | } |
@@ -454,11 +432,9 @@ static void iwl4965_apm_stop(struct iwl_priv *priv) | |||
454 | static int iwl4965_apm_reset(struct iwl_priv *priv) | 432 | static int iwl4965_apm_reset(struct iwl_priv *priv) |
455 | { | 433 | { |
456 | int ret = 0; | 434 | int ret = 0; |
457 | unsigned long flags; | ||
458 | 435 | ||
459 | iwl4965_apm_stop_master(priv); | 436 | iwl4965_apm_stop_master(priv); |
460 | 437 | ||
461 | spin_lock_irqsave(&priv->lock, flags); | ||
462 | 438 | ||
463 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | 439 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
464 | 440 | ||
@@ -475,9 +451,6 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) | |||
475 | 451 | ||
476 | udelay(10); | 452 | udelay(10); |
477 | 453 | ||
478 | ret = iwl_grab_nic_access(priv); | ||
479 | if (ret) | ||
480 | goto out; | ||
481 | /* Enable DMA and BSM Clock */ | 454 | /* Enable DMA and BSM Clock */ |
482 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | | 455 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | |
483 | APMG_CLK_VAL_BSM_CLK_RQT); | 456 | APMG_CLK_VAL_BSM_CLK_RQT); |
@@ -488,14 +461,10 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) | |||
488 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, | 461 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, |
489 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 462 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
490 | 463 | ||
491 | iwl_release_nic_access(priv); | ||
492 | |||
493 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); | 464 | clear_bit(STATUS_HCMD_ACTIVE, &priv->status); |
494 | wake_up_interruptible(&priv->wait_command_queue); | 465 | wake_up_interruptible(&priv->wait_command_queue); |
495 | 466 | ||
496 | out: | 467 | out: |
497 | spin_unlock_irqrestore(&priv->lock, flags); | ||
498 | |||
499 | return ret; | 468 | return ret; |
500 | } | 469 | } |
501 | 470 | ||
@@ -681,18 +650,11 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) | |||
681 | { | 650 | { |
682 | u32 a; | 651 | u32 a; |
683 | unsigned long flags; | 652 | unsigned long flags; |
684 | int ret; | ||
685 | int i, chan; | 653 | int i, chan; |
686 | u32 reg_val; | 654 | u32 reg_val; |
687 | 655 | ||
688 | spin_lock_irqsave(&priv->lock, flags); | 656 | spin_lock_irqsave(&priv->lock, flags); |
689 | 657 | ||
690 | ret = iwl_grab_nic_access(priv); | ||
691 | if (ret) { | ||
692 | spin_unlock_irqrestore(&priv->lock, flags); | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | /* Clear 4965's internal Tx Scheduler data base */ | 658 | /* Clear 4965's internal Tx Scheduler data base */ |
697 | priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); | 659 | priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR); |
698 | a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; | 660 | a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET; |
@@ -759,10 +721,9 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) | |||
759 | iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); | 721 | iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); |
760 | } | 722 | } |
761 | 723 | ||
762 | iwl_release_nic_access(priv); | ||
763 | spin_unlock_irqrestore(&priv->lock, flags); | 724 | spin_unlock_irqrestore(&priv->lock, flags); |
764 | 725 | ||
765 | return ret; | 726 | return 0; |
766 | } | 727 | } |
767 | 728 | ||
768 | static struct iwl_sensitivity_ranges iwl4965_sensitivity = { | 729 | static struct iwl_sensitivity_ranges iwl4965_sensitivity = { |
@@ -788,6 +749,12 @@ static struct iwl_sensitivity_ranges iwl4965_sensitivity = { | |||
788 | .nrg_th_ofdm = 100, | 749 | .nrg_th_ofdm = 100, |
789 | }; | 750 | }; |
790 | 751 | ||
752 | static void iwl4965_set_ct_threshold(struct iwl_priv *priv) | ||
753 | { | ||
754 | /* want Kelvin */ | ||
755 | priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); | ||
756 | } | ||
757 | |||
791 | /** | 758 | /** |
792 | * iwl4965_hw_set_hw_params | 759 | * iwl4965_hw_set_hw_params |
793 | * | 760 | * |
@@ -822,7 +789,8 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) | |||
822 | priv->hw_params.rx_chains_num = 2; | 789 | priv->hw_params.rx_chains_num = 2; |
823 | priv->hw_params.valid_tx_ant = ANT_A | ANT_B; | 790 | priv->hw_params.valid_tx_ant = ANT_A | ANT_B; |
824 | priv->hw_params.valid_rx_ant = ANT_A | ANT_B; | 791 | priv->hw_params.valid_rx_ant = ANT_A | ANT_B; |
825 | priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); | 792 | if (priv->cfg->ops->lib->temp_ops.set_ct_kill) |
793 | priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); | ||
826 | 794 | ||
827 | priv->hw_params.sens = &iwl4965_sensitivity; | 795 | priv->hw_params.sens = &iwl4965_sensitivity; |
828 | 796 | ||
@@ -1524,7 +1492,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) | |||
1524 | struct iwl4965_txpowertable_cmd cmd = { 0 }; | 1492 | struct iwl4965_txpowertable_cmd cmd = { 0 }; |
1525 | int ret; | 1493 | int ret; |
1526 | u8 band = 0; | 1494 | u8 band = 0; |
1527 | u8 is_fat = 0; | 1495 | bool is_fat = false; |
1528 | u8 ctrl_chan_high = 0; | 1496 | u8 ctrl_chan_high = 0; |
1529 | 1497 | ||
1530 | if (test_bit(STATUS_SCANNING, &priv->status)) { | 1498 | if (test_bit(STATUS_SCANNING, &priv->status)) { |
@@ -1602,7 +1570,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1602 | { | 1570 | { |
1603 | int rc; | 1571 | int rc; |
1604 | u8 band = 0; | 1572 | u8 band = 0; |
1605 | u8 is_fat = 0; | 1573 | bool is_fat = false; |
1606 | u8 ctrl_chan_high = 0; | 1574 | u8 ctrl_chan_high = 0; |
1607 | struct iwl4965_channel_switch_cmd cmd = { 0 }; | 1575 | struct iwl4965_channel_switch_cmd cmd = { 0 }; |
1608 | const struct iwl_channel_info *ch_info; | 1576 | const struct iwl_channel_info *ch_info; |
@@ -1833,8 +1801,6 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, | |||
1833 | static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | 1801 | static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, |
1834 | u16 ssn_idx, u8 tx_fifo) | 1802 | u16 ssn_idx, u8 tx_fifo) |
1835 | { | 1803 | { |
1836 | int ret = 0; | ||
1837 | |||
1838 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || | 1804 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || |
1839 | (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { | 1805 | (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) { |
1840 | IWL_WARN(priv, | 1806 | IWL_WARN(priv, |
@@ -1844,10 +1810,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
1844 | return -EINVAL; | 1810 | return -EINVAL; |
1845 | } | 1811 | } |
1846 | 1812 | ||
1847 | ret = iwl_grab_nic_access(priv); | ||
1848 | if (ret) | ||
1849 | return ret; | ||
1850 | |||
1851 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 1813 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); |
1852 | 1814 | ||
1853 | iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); | 1815 | iwl_clear_bits_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, (1 << txq_id)); |
@@ -1861,8 +1823,6 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
1861 | iwl_txq_ctx_deactivate(priv, txq_id); | 1823 | iwl_txq_ctx_deactivate(priv, txq_id); |
1862 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); | 1824 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); |
1863 | 1825 | ||
1864 | iwl_release_nic_access(priv); | ||
1865 | |||
1866 | return 0; | 1826 | return 0; |
1867 | } | 1827 | } |
1868 | 1828 | ||
@@ -1904,7 +1864,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1904 | int tx_fifo, int sta_id, int tid, u16 ssn_idx) | 1864 | int tx_fifo, int sta_id, int tid, u16 ssn_idx) |
1905 | { | 1865 | { |
1906 | unsigned long flags; | 1866 | unsigned long flags; |
1907 | int ret; | ||
1908 | u16 ra_tid; | 1867 | u16 ra_tid; |
1909 | 1868 | ||
1910 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || | 1869 | if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) || |
@@ -1922,11 +1881,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1922 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); | 1881 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); |
1923 | 1882 | ||
1924 | spin_lock_irqsave(&priv->lock, flags); | 1883 | spin_lock_irqsave(&priv->lock, flags); |
1925 | ret = iwl_grab_nic_access(priv); | ||
1926 | if (ret) { | ||
1927 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1928 | return ret; | ||
1929 | } | ||
1930 | 1884 | ||
1931 | /* Stop this Tx queue before configuring it */ | 1885 | /* Stop this Tx queue before configuring it */ |
1932 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); | 1886 | iwl4965_tx_queue_stop_scheduler(priv, txq_id); |
@@ -1959,7 +1913,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1959 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ | 1913 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ |
1960 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); | 1914 | iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); |
1961 | 1915 | ||
1962 | iwl_release_nic_access(priv); | ||
1963 | spin_unlock_irqrestore(&priv->lock, flags); | 1916 | spin_unlock_irqrestore(&priv->lock, flags); |
1964 | 1917 | ||
1965 | return 0; | 1918 | return 0; |
@@ -2331,9 +2284,13 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2331 | }, | 2284 | }, |
2332 | .send_tx_power = iwl4965_send_tx_power, | 2285 | .send_tx_power = iwl4965_send_tx_power, |
2333 | .update_chain_flags = iwl_update_chain_flags, | 2286 | .update_chain_flags = iwl_update_chain_flags, |
2334 | .temperature = iwl4965_temperature_calib, | ||
2335 | .post_associate = iwl_post_associate, | 2287 | .post_associate = iwl_post_associate, |
2336 | .config_ap = iwl_config_ap, | 2288 | .config_ap = iwl_config_ap, |
2289 | .isr = iwl_isr_legacy, | ||
2290 | .temp_ops = { | ||
2291 | .temperature = iwl4965_temperature_calib, | ||
2292 | .set_ct_kill = iwl4965_set_ct_threshold, | ||
2293 | }, | ||
2337 | }; | 2294 | }; |
2338 | 2295 | ||
2339 | static struct iwl_ops iwl4965_ops = { | 2296 | static struct iwl_ops iwl4965_ops = { |
@@ -2354,6 +2311,7 @@ struct iwl_cfg iwl4965_agn_cfg = { | |||
2354 | .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, | 2311 | .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, |
2355 | .ops = &iwl4965_ops, | 2312 | .ops = &iwl4965_ops, |
2356 | .mod_params = &iwl4965_mod_params, | 2313 | .mod_params = &iwl4965_mod_params, |
2314 | .use_isr_legacy = true | ||
2357 | }; | 2315 | }; |
2358 | 2316 | ||
2359 | /* Module firmware */ | 2317 | /* Module firmware */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index 15cac70e36e2..4ef6804a455a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h | |||
@@ -87,6 +87,18 @@ | |||
87 | #define IWL50_NUM_AMPDU_QUEUES 10 | 87 | #define IWL50_NUM_AMPDU_QUEUES 10 |
88 | #define IWL50_FIRST_AMPDU_QUEUE 10 | 88 | #define IWL50_FIRST_AMPDU_QUEUE 10 |
89 | 89 | ||
90 | /* 5150 only */ | ||
91 | #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) | ||
92 | |||
93 | static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) | ||
94 | { | ||
95 | u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, | ||
96 | EEPROM_5000_TEMPERATURE); | ||
97 | /* offset = temperature - voltage / coef */ | ||
98 | s32 offset = (s32)(temp_calib[0] - temp_calib[1] / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); | ||
99 | return offset; | ||
100 | } | ||
101 | |||
90 | /* Fixed (non-configurable) rx data from phy */ | 102 | /* Fixed (non-configurable) rx data from phy */ |
91 | 103 | ||
92 | /** | 104 | /** |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d731a836e6c8..89e1477b5143 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -124,10 +124,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) | |||
124 | return ret; | 124 | return ret; |
125 | } | 125 | } |
126 | 126 | ||
127 | ret = iwl_grab_nic_access(priv); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | /* enable DMA */ | 127 | /* enable DMA */ |
132 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); | 128 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); |
133 | 129 | ||
@@ -137,8 +133,6 @@ static int iwl5000_apm_init(struct iwl_priv *priv) | |||
137 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, | 133 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, |
138 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 134 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
139 | 135 | ||
140 | iwl_release_nic_access(priv); | ||
141 | |||
142 | return ret; | 136 | return ret; |
143 | } | 137 | } |
144 | 138 | ||
@@ -165,12 +159,9 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) | |||
165 | static int iwl5000_apm_reset(struct iwl_priv *priv) | 159 | static int iwl5000_apm_reset(struct iwl_priv *priv) |
166 | { | 160 | { |
167 | int ret = 0; | 161 | int ret = 0; |
168 | unsigned long flags; | ||
169 | 162 | ||
170 | iwl5000_apm_stop_master(priv); | 163 | iwl5000_apm_stop_master(priv); |
171 | 164 | ||
172 | spin_lock_irqsave(&priv->lock, flags); | ||
173 | |||
174 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); | 165 | iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
175 | 166 | ||
176 | udelay(10); | 167 | udelay(10); |
@@ -193,10 +184,6 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) | |||
193 | goto out; | 184 | goto out; |
194 | } | 185 | } |
195 | 186 | ||
196 | ret = iwl_grab_nic_access(priv); | ||
197 | if (ret) | ||
198 | goto out; | ||
199 | |||
200 | /* enable DMA */ | 187 | /* enable DMA */ |
201 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); | 188 | iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); |
202 | 189 | ||
@@ -205,11 +192,7 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) | |||
205 | /* disable L1-Active */ | 192 | /* disable L1-Active */ |
206 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, | 193 | iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, |
207 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); | 194 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
208 | |||
209 | iwl_release_nic_access(priv); | ||
210 | |||
211 | out: | 195 | out: |
212 | spin_unlock_irqrestore(&priv->lock, flags); | ||
213 | 196 | ||
214 | return ret; | 197 | return ret; |
215 | } | 198 | } |
@@ -252,11 +235,9 @@ static void iwl5000_nic_config(struct iwl_priv *priv) | |||
252 | * (PCIe power is lost before PERST# is asserted), | 235 | * (PCIe power is lost before PERST# is asserted), |
253 | * causing ME FW to lose ownership and not being able to obtain it back. | 236 | * causing ME FW to lose ownership and not being able to obtain it back. |
254 | */ | 237 | */ |
255 | iwl_grab_nic_access(priv); | ||
256 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 238 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
257 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, | 239 | APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, |
258 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); | 240 | ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); |
259 | iwl_release_nic_access(priv); | ||
260 | 241 | ||
261 | spin_unlock_irqrestore(&priv->lock, flags); | 242 | spin_unlock_irqrestore(&priv->lock, flags); |
262 | } | 243 | } |
@@ -434,15 +415,19 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, | |||
434 | return &priv->eeprom[address]; | 415 | return &priv->eeprom[address]; |
435 | } | 416 | } |
436 | 417 | ||
437 | static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) | 418 | static void iwl5150_set_ct_threshold(struct iwl_priv *priv) |
438 | { | 419 | { |
439 | const s32 volt2temp_coef = -5; | 420 | const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; |
440 | u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, | 421 | s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - |
441 | EEPROM_5000_TEMPERATURE); | 422 | iwl_temp_calib_to_offset(priv); |
442 | /* offset = temperate - voltage / coef */ | 423 | |
443 | s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; | 424 | priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; |
444 | s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; | 425 | } |
445 | return threshold * volt2temp_coef; | 426 | |
427 | static void iwl5000_set_ct_threshold(struct iwl_priv *priv) | ||
428 | { | ||
429 | /* want Celsius */ | ||
430 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
446 | } | 431 | } |
447 | 432 | ||
448 | /* | 433 | /* |
@@ -533,19 +518,9 @@ static int iwl5000_load_section(struct iwl_priv *priv, | |||
533 | struct fw_desc *image, | 518 | struct fw_desc *image, |
534 | u32 dst_addr) | 519 | u32 dst_addr) |
535 | { | 520 | { |
536 | int ret = 0; | ||
537 | unsigned long flags; | ||
538 | |||
539 | dma_addr_t phy_addr = image->p_addr; | 521 | dma_addr_t phy_addr = image->p_addr; |
540 | u32 byte_cnt = image->len; | 522 | u32 byte_cnt = image->len; |
541 | 523 | ||
542 | spin_lock_irqsave(&priv->lock, flags); | ||
543 | ret = iwl_grab_nic_access(priv); | ||
544 | if (ret) { | ||
545 | spin_unlock_irqrestore(&priv->lock, flags); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | iwl_write_direct32(priv, | 524 | iwl_write_direct32(priv, |
550 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), | 525 | FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), |
551 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); | 526 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); |
@@ -574,8 +549,6 @@ static int iwl5000_load_section(struct iwl_priv *priv, | |||
574 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | | 549 | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | |
575 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); | 550 | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); |
576 | 551 | ||
577 | iwl_release_nic_access(priv); | ||
578 | spin_unlock_irqrestore(&priv->lock, flags); | ||
579 | return 0; | 552 | return 0; |
580 | } | 553 | } |
581 | 554 | ||
@@ -736,18 +709,11 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) | |||
736 | { | 709 | { |
737 | u32 a; | 710 | u32 a; |
738 | unsigned long flags; | 711 | unsigned long flags; |
739 | int ret; | ||
740 | int i, chan; | 712 | int i, chan; |
741 | u32 reg_val; | 713 | u32 reg_val; |
742 | 714 | ||
743 | spin_lock_irqsave(&priv->lock, flags); | 715 | spin_lock_irqsave(&priv->lock, flags); |
744 | 716 | ||
745 | ret = iwl_grab_nic_access(priv); | ||
746 | if (ret) { | ||
747 | spin_unlock_irqrestore(&priv->lock, flags); | ||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); | 717 | priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR); |
752 | a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; | 718 | a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET; |
753 | for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; | 719 | for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET; |
@@ -815,7 +781,6 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) | |||
815 | iwl_txq_ctx_activate(priv, 8); | 781 | iwl_txq_ctx_activate(priv, 8); |
816 | iwl_txq_ctx_activate(priv, 9); | 782 | iwl_txq_ctx_activate(priv, 9); |
817 | 783 | ||
818 | iwl_release_nic_access(priv); | ||
819 | spin_unlock_irqrestore(&priv->lock, flags); | 784 | spin_unlock_irqrestore(&priv->lock, flags); |
820 | 785 | ||
821 | 786 | ||
@@ -868,17 +833,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
868 | priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; | 833 | priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; |
869 | priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; | 834 | priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; |
870 | 835 | ||
871 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 836 | if (priv->cfg->ops->lib->temp_ops.set_ct_kill) |
872 | case CSR_HW_REV_TYPE_5150: | 837 | priv->cfg->ops->lib->temp_ops.set_ct_kill(priv); |
873 | /* 5150 wants in Kelvin */ | ||
874 | priv->hw_params.ct_kill_threshold = | ||
875 | iwl5150_get_ct_threshold(priv); | ||
876 | break; | ||
877 | default: | ||
878 | /* all others want Celsius */ | ||
879 | priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; | ||
880 | break; | ||
881 | } | ||
882 | 838 | ||
883 | /* Set initial calibration set */ | 839 | /* Set initial calibration set */ |
884 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | 840 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { |
@@ -900,7 +856,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) | |||
900 | break; | 856 | break; |
901 | } | 857 | } |
902 | 858 | ||
903 | |||
904 | return 0; | 859 | return 0; |
905 | } | 860 | } |
906 | 861 | ||
@@ -1006,7 +961,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1006 | int tx_fifo, int sta_id, int tid, u16 ssn_idx) | 961 | int tx_fifo, int sta_id, int tid, u16 ssn_idx) |
1007 | { | 962 | { |
1008 | unsigned long flags; | 963 | unsigned long flags; |
1009 | int ret; | ||
1010 | u16 ra_tid; | 964 | u16 ra_tid; |
1011 | 965 | ||
1012 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || | 966 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || |
@@ -1024,11 +978,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1024 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); | 978 | iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); |
1025 | 979 | ||
1026 | spin_lock_irqsave(&priv->lock, flags); | 980 | spin_lock_irqsave(&priv->lock, flags); |
1027 | ret = iwl_grab_nic_access(priv); | ||
1028 | if (ret) { | ||
1029 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1030 | return ret; | ||
1031 | } | ||
1032 | 981 | ||
1033 | /* Stop this Tx queue before configuring it */ | 982 | /* Stop this Tx queue before configuring it */ |
1034 | iwl5000_tx_queue_stop_scheduler(priv, txq_id); | 983 | iwl5000_tx_queue_stop_scheduler(priv, txq_id); |
@@ -1064,7 +1013,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1064 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ | 1013 | /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ |
1065 | iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); | 1014 | iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); |
1066 | 1015 | ||
1067 | iwl_release_nic_access(priv); | ||
1068 | spin_unlock_irqrestore(&priv->lock, flags); | 1016 | spin_unlock_irqrestore(&priv->lock, flags); |
1069 | 1017 | ||
1070 | return 0; | 1018 | return 0; |
@@ -1073,8 +1021,6 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, | |||
1073 | static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | 1021 | static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, |
1074 | u16 ssn_idx, u8 tx_fifo) | 1022 | u16 ssn_idx, u8 tx_fifo) |
1075 | { | 1023 | { |
1076 | int ret; | ||
1077 | |||
1078 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || | 1024 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || |
1079 | (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { | 1025 | (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { |
1080 | IWL_ERR(priv, | 1026 | IWL_ERR(priv, |
@@ -1084,10 +1030,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
1084 | return -EINVAL; | 1030 | return -EINVAL; |
1085 | } | 1031 | } |
1086 | 1032 | ||
1087 | ret = iwl_grab_nic_access(priv); | ||
1088 | if (ret) | ||
1089 | return ret; | ||
1090 | |||
1091 | iwl5000_tx_queue_stop_scheduler(priv, txq_id); | 1033 | iwl5000_tx_queue_stop_scheduler(priv, txq_id); |
1092 | 1034 | ||
1093 | iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id)); | 1035 | iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id)); |
@@ -1101,8 +1043,6 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
1101 | iwl_txq_ctx_deactivate(priv, txq_id); | 1043 | iwl_txq_ctx_deactivate(priv, txq_id); |
1102 | iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); | 1044 | iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); |
1103 | 1045 | ||
1104 | iwl_release_nic_access(priv); | ||
1105 | |||
1106 | return 0; | 1046 | return 0; |
1107 | } | 1047 | } |
1108 | 1048 | ||
@@ -1434,6 +1374,17 @@ static void iwl5000_temperature(struct iwl_priv *priv) | |||
1434 | priv->temperature = le32_to_cpu(priv->statistics.general.temperature); | 1374 | priv->temperature = le32_to_cpu(priv->statistics.general.temperature); |
1435 | } | 1375 | } |
1436 | 1376 | ||
1377 | static void iwl5150_temperature(struct iwl_priv *priv) | ||
1378 | { | ||
1379 | u32 vt = 0; | ||
1380 | s32 offset = iwl_temp_calib_to_offset(priv); | ||
1381 | |||
1382 | vt = le32_to_cpu(priv->statistics.general.temperature); | ||
1383 | vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset; | ||
1384 | /* now vt hold the temperature in Kelvin */ | ||
1385 | priv->temperature = KELVIN_TO_CELSIUS(vt); | ||
1386 | } | ||
1387 | |||
1437 | /* Calc max signal level (dBm) among 3 possible receivers */ | 1388 | /* Calc max signal level (dBm) among 3 possible receivers */ |
1438 | int iwl5000_calc_rssi(struct iwl_priv *priv, | 1389 | int iwl5000_calc_rssi(struct iwl_priv *priv, |
1439 | struct iwl_rx_phy_res *rx_resp) | 1390 | struct iwl_rx_phy_res *rx_resp) |
@@ -1511,7 +1462,6 @@ struct iwl_lib_ops iwl5000_lib = { | |||
1511 | .init_alive_start = iwl5000_init_alive_start, | 1462 | .init_alive_start = iwl5000_init_alive_start, |
1512 | .alive_notify = iwl5000_alive_notify, | 1463 | .alive_notify = iwl5000_alive_notify, |
1513 | .send_tx_power = iwl5000_send_tx_power, | 1464 | .send_tx_power = iwl5000_send_tx_power, |
1514 | .temperature = iwl5000_temperature, | ||
1515 | .update_chain_flags = iwl_update_chain_flags, | 1465 | .update_chain_flags = iwl_update_chain_flags, |
1516 | .apm_ops = { | 1466 | .apm_ops = { |
1517 | .init = iwl5000_apm_init, | 1467 | .init = iwl5000_apm_init, |
@@ -1537,7 +1487,62 @@ struct iwl_lib_ops iwl5000_lib = { | |||
1537 | .query_addr = iwl5000_eeprom_query_addr, | 1487 | .query_addr = iwl5000_eeprom_query_addr, |
1538 | }, | 1488 | }, |
1539 | .post_associate = iwl_post_associate, | 1489 | .post_associate = iwl_post_associate, |
1490 | .isr = iwl_isr_ict, | ||
1540 | .config_ap = iwl_config_ap, | 1491 | .config_ap = iwl_config_ap, |
1492 | .temp_ops = { | ||
1493 | .temperature = iwl5000_temperature, | ||
1494 | .set_ct_kill = iwl5000_set_ct_threshold, | ||
1495 | }, | ||
1496 | }; | ||
1497 | |||
1498 | static struct iwl_lib_ops iwl5150_lib = { | ||
1499 | .set_hw_params = iwl5000_hw_set_hw_params, | ||
1500 | .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, | ||
1501 | .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, | ||
1502 | .txq_set_sched = iwl5000_txq_set_sched, | ||
1503 | .txq_agg_enable = iwl5000_txq_agg_enable, | ||
1504 | .txq_agg_disable = iwl5000_txq_agg_disable, | ||
1505 | .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd, | ||
1506 | .txq_free_tfd = iwl_hw_txq_free_tfd, | ||
1507 | .txq_init = iwl_hw_tx_queue_init, | ||
1508 | .rx_handler_setup = iwl5000_rx_handler_setup, | ||
1509 | .setup_deferred_work = iwl5000_setup_deferred_work, | ||
1510 | .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr, | ||
1511 | .load_ucode = iwl5000_load_ucode, | ||
1512 | .init_alive_start = iwl5000_init_alive_start, | ||
1513 | .alive_notify = iwl5000_alive_notify, | ||
1514 | .send_tx_power = iwl5000_send_tx_power, | ||
1515 | .update_chain_flags = iwl_update_chain_flags, | ||
1516 | .apm_ops = { | ||
1517 | .init = iwl5000_apm_init, | ||
1518 | .reset = iwl5000_apm_reset, | ||
1519 | .stop = iwl5000_apm_stop, | ||
1520 | .config = iwl5000_nic_config, | ||
1521 | .set_pwr_src = iwl_set_pwr_src, | ||
1522 | }, | ||
1523 | .eeprom_ops = { | ||
1524 | .regulatory_bands = { | ||
1525 | EEPROM_5000_REG_BAND_1_CHANNELS, | ||
1526 | EEPROM_5000_REG_BAND_2_CHANNELS, | ||
1527 | EEPROM_5000_REG_BAND_3_CHANNELS, | ||
1528 | EEPROM_5000_REG_BAND_4_CHANNELS, | ||
1529 | EEPROM_5000_REG_BAND_5_CHANNELS, | ||
1530 | EEPROM_5000_REG_BAND_24_FAT_CHANNELS, | ||
1531 | EEPROM_5000_REG_BAND_52_FAT_CHANNELS | ||
1532 | }, | ||
1533 | .verify_signature = iwlcore_eeprom_verify_signature, | ||
1534 | .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, | ||
1535 | .release_semaphore = iwlcore_eeprom_release_semaphore, | ||
1536 | .calib_version = iwl5000_eeprom_calib_version, | ||
1537 | .query_addr = iwl5000_eeprom_query_addr, | ||
1538 | }, | ||
1539 | .post_associate = iwl_post_associate, | ||
1540 | .isr = iwl_isr_ict, | ||
1541 | .config_ap = iwl_config_ap, | ||
1542 | .temp_ops = { | ||
1543 | .temperature = iwl5150_temperature, | ||
1544 | .set_ct_kill = iwl5150_set_ct_threshold, | ||
1545 | }, | ||
1541 | }; | 1546 | }; |
1542 | 1547 | ||
1543 | struct iwl_ops iwl5000_ops = { | 1548 | struct iwl_ops iwl5000_ops = { |
@@ -1547,6 +1552,13 @@ struct iwl_ops iwl5000_ops = { | |||
1547 | .smgmt = &iwl5000_station_mgmt, | 1552 | .smgmt = &iwl5000_station_mgmt, |
1548 | }; | 1553 | }; |
1549 | 1554 | ||
1555 | static struct iwl_ops iwl5150_ops = { | ||
1556 | .lib = &iwl5150_lib, | ||
1557 | .hcmd = &iwl5000_hcmd, | ||
1558 | .utils = &iwl5000_hcmd_utils, | ||
1559 | .smgmt = &iwl5000_station_mgmt, | ||
1560 | }; | ||
1561 | |||
1550 | struct iwl_mod_params iwl50_mod_params = { | 1562 | struct iwl_mod_params iwl50_mod_params = { |
1551 | .num_of_queues = IWL50_NUM_QUEUES, | 1563 | .num_of_queues = IWL50_NUM_QUEUES, |
1552 | .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, | 1564 | .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, |
@@ -1642,7 +1654,7 @@ struct iwl_cfg iwl5150_agn_cfg = { | |||
1642 | .ucode_api_max = IWL5150_UCODE_API_MAX, | 1654 | .ucode_api_max = IWL5150_UCODE_API_MAX, |
1643 | .ucode_api_min = IWL5150_UCODE_API_MIN, | 1655 | .ucode_api_min = IWL5150_UCODE_API_MIN, |
1644 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, | 1656 | .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, |
1645 | .ops = &iwl5000_ops, | 1657 | .ops = &iwl5150_ops, |
1646 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, | 1658 | .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, |
1647 | .eeprom_ver = EEPROM_5050_EEPROM_VERSION, | 1659 | .eeprom_ver = EEPROM_5050_EEPROM_VERSION, |
1648 | .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, | 1660 | .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 4c88e8715df2..23a58b00f180 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -270,6 +270,8 @@ const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | |||
270 | {"60", "64QAM 5/6"} | 270 | {"60", "64QAM 5/6"} |
271 | }; | 271 | }; |
272 | 272 | ||
273 | #define MCS_INDEX_PER_STREAM (8) | ||
274 | |||
273 | static inline u8 rs_extract_rate(u32 rate_n_flags) | 275 | static inline u8 rs_extract_rate(u32 rate_n_flags) |
274 | { | 276 | { |
275 | return (u8)(rate_n_flags & 0xFF); | 277 | return (u8)(rate_n_flags & 0xFF); |
@@ -652,19 +654,19 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, | |||
652 | return 1; | 654 | return 1; |
653 | } | 655 | } |
654 | 656 | ||
655 | /* FIXME:RS: in 4965 we don't use greenfield at all */ | 657 | /* in 4965 we don't use greenfield at all */ |
656 | /* FIXME:RS: don't use greenfield for now in TX */ | 658 | static inline u8 rs_use_green(struct iwl_priv *priv, |
657 | #if 0 | 659 | struct ieee80211_conf *conf) |
658 | static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) | ||
659 | { | ||
660 | return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && | ||
661 | priv->current_ht_config.is_green_field && | ||
662 | !priv->current_ht_config.non_GF_STA_present; | ||
663 | } | ||
664 | #endif | ||
665 | static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf) | ||
666 | { | 660 | { |
667 | return 0; | 661 | u8 is_green; |
662 | |||
663 | if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) | ||
664 | is_green = 0; | ||
665 | else | ||
666 | is_green = (conf_is_ht(conf) && | ||
667 | priv->current_ht_config.is_green_field && | ||
668 | !priv->current_ht_config.non_GF_STA_present); | ||
669 | return is_green; | ||
668 | } | 670 | } |
669 | 671 | ||
670 | /** | 672 | /** |
@@ -2061,6 +2063,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, | |||
2061 | active_tbl = 1 - lq_sta->active_tbl; | 2063 | active_tbl = 1 - lq_sta->active_tbl; |
2062 | 2064 | ||
2063 | tbl = &(lq_sta->lq_info[active_tbl]); | 2065 | tbl = &(lq_sta->lq_info[active_tbl]); |
2066 | if (is_legacy(tbl->lq_type)) | ||
2067 | lq_sta->is_green = 0; | ||
2068 | else | ||
2069 | lq_sta->is_green = rs_use_green(priv, conf); | ||
2064 | is_green = lq_sta->is_green; | 2070 | is_green = lq_sta->is_green; |
2065 | 2071 | ||
2066 | /* current tx rate */ | 2072 | /* current tx rate */ |
@@ -2514,12 +2520,33 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2514 | } | 2520 | } |
2515 | } | 2521 | } |
2516 | 2522 | ||
2517 | if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) | 2523 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { |
2518 | rate_idx = rate_lowest_index(sband, sta); | ||
2519 | else if (sband->band == IEEE80211_BAND_5GHZ) | ||
2520 | rate_idx -= IWL_FIRST_OFDM_RATE; | 2524 | rate_idx -= IWL_FIRST_OFDM_RATE; |
2521 | 2525 | /* 6M and 9M shared same MCS index */ | |
2526 | rate_idx = (rate_idx > 0) ? (rate_idx - 1) : 0; | ||
2527 | if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2528 | IWL_RATE_MIMO3_6M_PLCP) | ||
2529 | rate_idx = rate_idx + (2 * MCS_INDEX_PER_STREAM); | ||
2530 | else if (rs_extract_rate(lq_sta->last_rate_n_flags) >= | ||
2531 | IWL_RATE_MIMO2_6M_PLCP) | ||
2532 | rate_idx = rate_idx + MCS_INDEX_PER_STREAM; | ||
2533 | info->control.rates[0].flags = IEEE80211_TX_RC_MCS; | ||
2534 | if (lq_sta->last_rate_n_flags & RATE_MCS_SGI_MSK) | ||
2535 | info->control.rates[0].flags |= IEEE80211_TX_RC_SHORT_GI; | ||
2536 | if (lq_sta->last_rate_n_flags & RATE_MCS_DUP_MSK) | ||
2537 | info->control.rates[0].flags |= IEEE80211_TX_RC_DUP_DATA; | ||
2538 | if (lq_sta->last_rate_n_flags & RATE_MCS_FAT_MSK) | ||
2539 | info->control.rates[0].flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
2540 | if (lq_sta->last_rate_n_flags & RATE_MCS_GF_MSK) | ||
2541 | info->control.rates[0].flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
2542 | } else { | ||
2543 | if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) | ||
2544 | rate_idx = rate_lowest_index(sband, sta); | ||
2545 | else if (sband->band == IEEE80211_BAND_5GHZ) | ||
2546 | rate_idx -= IWL_FIRST_OFDM_RATE; | ||
2547 | } | ||
2522 | info->control.rates[0].idx = rate_idx; | 2548 | info->control.rates[0].idx = rate_idx; |
2549 | |||
2523 | } | 2550 | } |
2524 | 2551 | ||
2525 | static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, | 2552 | static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, |
@@ -2896,7 +2923,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, | |||
2896 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); | 2923 | ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3")); |
2897 | desc += sprintf(buff+desc, " %s", | 2924 | desc += sprintf(buff+desc, " %s", |
2898 | (tbl->is_fat) ? "40MHz" : "20MHz"); | 2925 | (tbl->is_fat) ? "40MHz" : "20MHz"); |
2899 | desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : ""); | 2926 | desc += sprintf(buff+desc, " %s %s\n", (tbl->is_SGI) ? "SGI" : "", |
2927 | (lq_sta->is_green) ? "GF enabled" : ""); | ||
2900 | } | 2928 | } |
2901 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", | 2929 | desc += sprintf(buff+desc, "last tx rate=0x%X\n", |
2902 | lq_sta->last_rate_n_flags); | 2930 | lq_sta->last_rate_n_flags); |
@@ -2959,13 +2987,14 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, | |||
2959 | return -ENOMEM; | 2987 | return -ENOMEM; |
2960 | 2988 | ||
2961 | for (i = 0; i < LQ_SIZE; i++) { | 2989 | for (i = 0; i < LQ_SIZE; i++) { |
2962 | desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" | 2990 | desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d GF=%d\n" |
2963 | "rate=0x%X\n", | 2991 | "rate=0x%X\n", |
2964 | lq_sta->active_tbl == i ? "*" : "x", | 2992 | lq_sta->active_tbl == i ? "*" : "x", |
2965 | lq_sta->lq_info[i].lq_type, | 2993 | lq_sta->lq_info[i].lq_type, |
2966 | lq_sta->lq_info[i].is_SGI, | 2994 | lq_sta->lq_info[i].is_SGI, |
2967 | lq_sta->lq_info[i].is_fat, | 2995 | lq_sta->lq_info[i].is_fat, |
2968 | lq_sta->lq_info[i].is_dup, | 2996 | lq_sta->lq_info[i].is_dup, |
2997 | lq_sta->is_green, | ||
2969 | lq_sta->lq_info[i].current_rate); | 2998 | lq_sta->lq_info[i].current_rate); |
2970 | for (j = 0; j < IWL_RATE_COUNT; j++) { | 2999 | for (j = 0; j < IWL_RATE_COUNT; j++) { |
2971 | desc += sprintf(buff+desc, | 3000 | desc += sprintf(buff+desc, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 596977d71c94..0a5507cbeb3f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -503,24 +503,12 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, | |||
503 | int iwl_hw_tx_queue_init(struct iwl_priv *priv, | 503 | int iwl_hw_tx_queue_init(struct iwl_priv *priv, |
504 | struct iwl_tx_queue *txq) | 504 | struct iwl_tx_queue *txq) |
505 | { | 505 | { |
506 | int ret; | ||
507 | unsigned long flags; | ||
508 | int txq_id = txq->q.id; | 506 | int txq_id = txq->q.id; |
509 | 507 | ||
510 | spin_lock_irqsave(&priv->lock, flags); | ||
511 | ret = iwl_grab_nic_access(priv); | ||
512 | if (ret) { | ||
513 | spin_unlock_irqrestore(&priv->lock, flags); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | /* Circular buffer (TFD queue in DRAM) physical base address */ | 508 | /* Circular buffer (TFD queue in DRAM) physical base address */ |
518 | iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), | 509 | iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), |
519 | txq->q.dma_addr >> 8); | 510 | txq->q.dma_addr >> 8); |
520 | 511 | ||
521 | iwl_release_nic_access(priv); | ||
522 | spin_unlock_irqrestore(&priv->lock, flags); | ||
523 | |||
524 | return 0; | 512 | return 0; |
525 | } | 513 | } |
526 | 514 | ||
@@ -709,6 +697,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, | |||
709 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | 697 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; |
710 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); | 698 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); |
711 | unsigned long status = priv->status; | 699 | unsigned long status = priv->status; |
700 | unsigned long reg_flags; | ||
712 | 701 | ||
713 | IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", | 702 | IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n", |
714 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", | 703 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", |
@@ -720,32 +709,25 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, | |||
720 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | 709 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, |
721 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 710 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
722 | 711 | ||
723 | if (!iwl_grab_nic_access(priv)) { | 712 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, |
724 | iwl_write_direct32( | 713 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); |
725 | priv, HBUS_TARG_MBX_C, | ||
726 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | ||
727 | |||
728 | iwl_release_nic_access(priv); | ||
729 | } | ||
730 | 714 | ||
731 | if (!(flags & RXON_CARD_DISABLED)) { | 715 | if (!(flags & RXON_CARD_DISABLED)) { |
732 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | 716 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, |
733 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | 717 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); |
734 | if (!iwl_grab_nic_access(priv)) { | 718 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, |
735 | iwl_write_direct32( | ||
736 | priv, HBUS_TARG_MBX_C, | ||
737 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | 719 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); |
738 | 720 | ||
739 | iwl_release_nic_access(priv); | ||
740 | } | ||
741 | } | 721 | } |
742 | 722 | ||
743 | if (flags & RF_CARD_DISABLED) { | 723 | if (flags & RF_CARD_DISABLED) { |
744 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | 724 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, |
745 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); | 725 | CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); |
746 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | 726 | iwl_read32(priv, CSR_UCODE_DRV_GP1); |
727 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
747 | if (!iwl_grab_nic_access(priv)) | 728 | if (!iwl_grab_nic_access(priv)) |
748 | iwl_release_nic_access(priv); | 729 | iwl_release_nic_access(priv); |
730 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
749 | } | 731 | } |
750 | } | 732 | } |
751 | 733 | ||
@@ -774,14 +756,6 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, | |||
774 | 756 | ||
775 | int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) | 757 | int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) |
776 | { | 758 | { |
777 | int ret; | ||
778 | unsigned long flags; | ||
779 | |||
780 | spin_lock_irqsave(&priv->lock, flags); | ||
781 | ret = iwl_grab_nic_access(priv); | ||
782 | if (ret) | ||
783 | goto err; | ||
784 | |||
785 | if (src == IWL_PWR_SRC_VAUX) { | 759 | if (src == IWL_PWR_SRC_VAUX) { |
786 | if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) | 760 | if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) |
787 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, | 761 | iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, |
@@ -793,10 +767,7 @@ int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) | |||
793 | ~APMG_PS_CTRL_MSK_PWR_SRC); | 767 | ~APMG_PS_CTRL_MSK_PWR_SRC); |
794 | } | 768 | } |
795 | 769 | ||
796 | iwl_release_nic_access(priv); | 770 | return 0; |
797 | err: | ||
798 | spin_unlock_irqrestore(&priv->lock, flags); | ||
799 | return ret; | ||
800 | } | 771 | } |
801 | 772 | ||
802 | /** | 773 | /** |
@@ -860,6 +831,7 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
860 | unsigned long flags; | 831 | unsigned long flags; |
861 | u8 fill_rx = 0; | 832 | u8 fill_rx = 0; |
862 | u32 count = 8; | 833 | u32 count = 8; |
834 | int total_empty; | ||
863 | 835 | ||
864 | /* uCode's read index (stored in shared DRAM) indicates the last Rx | 836 | /* uCode's read index (stored in shared DRAM) indicates the last Rx |
865 | * buffer that the driver may process (last buffer filled by ucode). */ | 837 | * buffer that the driver may process (last buffer filled by ucode). */ |
@@ -870,7 +842,12 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
870 | if (i == r) | 842 | if (i == r) |
871 | IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); | 843 | IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); |
872 | 844 | ||
873 | if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) | 845 | /* calculate total frames need to be restock after handling RX */ |
846 | total_empty = r - priv->rxq.write_actual; | ||
847 | if (total_empty < 0) | ||
848 | total_empty += RX_QUEUE_SIZE; | ||
849 | |||
850 | if (total_empty > (RX_QUEUE_SIZE / 2)) | ||
874 | fill_rx = 1; | 851 | fill_rx = 1; |
875 | 852 | ||
876 | while (i != r) { | 853 | while (i != r) { |
@@ -947,7 +924,7 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
947 | count++; | 924 | count++; |
948 | if (count >= 8) { | 925 | if (count >= 8) { |
949 | priv->rxq.read = i; | 926 | priv->rxq.read = i; |
950 | iwl_rx_queue_restock(priv); | 927 | iwl_rx_replenish_now(priv); |
951 | count = 0; | 928 | count = 0; |
952 | } | 929 | } |
953 | } | 930 | } |
@@ -955,7 +932,10 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
955 | 932 | ||
956 | /* Backtrack one entry */ | 933 | /* Backtrack one entry */ |
957 | priv->rxq.read = i; | 934 | priv->rxq.read = i; |
958 | iwl_rx_queue_restock(priv); | 935 | if (fill_rx) |
936 | iwl_rx_replenish_now(priv); | ||
937 | else | ||
938 | iwl_rx_queue_restock(priv); | ||
959 | } | 939 | } |
960 | 940 | ||
961 | /* call this function to flush any scheduled tasklet */ | 941 | /* call this function to flush any scheduled tasklet */ |
@@ -966,7 +946,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) | |||
966 | tasklet_kill(&priv->irq_tasklet); | 946 | tasklet_kill(&priv->irq_tasklet); |
967 | } | 947 | } |
968 | 948 | ||
969 | static void iwl_irq_tasklet(struct iwl_priv *priv) | 949 | static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) |
970 | { | 950 | { |
971 | u32 inta, handled = 0; | 951 | u32 inta, handled = 0; |
972 | u32 inta_fh; | 952 | u32 inta_fh; |
@@ -1127,9 +1107,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1127 | priv->isr_stats.unhandled++; | 1107 | priv->isr_stats.unhandled++; |
1128 | } | 1108 | } |
1129 | 1109 | ||
1130 | if (inta & ~CSR_INI_SET_MASK) { | 1110 | if (inta & ~(priv->inta_mask)) { |
1131 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", | 1111 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", |
1132 | inta & ~CSR_INI_SET_MASK); | 1112 | inta & ~priv->inta_mask); |
1133 | IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); | 1113 | IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); |
1134 | } | 1114 | } |
1135 | 1115 | ||
@@ -1150,6 +1130,199 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1150 | spin_unlock_irqrestore(&priv->lock, flags); | 1130 | spin_unlock_irqrestore(&priv->lock, flags); |
1151 | } | 1131 | } |
1152 | 1132 | ||
1133 | /* tasklet for iwlagn interrupt */ | ||
1134 | static void iwl_irq_tasklet(struct iwl_priv *priv) | ||
1135 | { | ||
1136 | u32 inta = 0; | ||
1137 | u32 handled = 0; | ||
1138 | unsigned long flags; | ||
1139 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1140 | u32 inta_mask; | ||
1141 | #endif | ||
1142 | |||
1143 | spin_lock_irqsave(&priv->lock, flags); | ||
1144 | |||
1145 | /* Ack/clear/reset pending uCode interrupts. | ||
1146 | * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, | ||
1147 | */ | ||
1148 | iwl_write32(priv, CSR_INT, priv->inta); | ||
1149 | |||
1150 | inta = priv->inta; | ||
1151 | |||
1152 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1153 | if (priv->debug_level & IWL_DL_ISR) { | ||
1154 | /* just for debug */ | ||
1155 | inta_mask = iwl_read32(priv, CSR_INT_MASK); | ||
1156 | IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", | ||
1157 | inta, inta_mask); | ||
1158 | } | ||
1159 | #endif | ||
1160 | /* saved interrupt in inta variable now we can reset priv->inta */ | ||
1161 | priv->inta = 0; | ||
1162 | |||
1163 | /* Now service all interrupt bits discovered above. */ | ||
1164 | if (inta & CSR_INT_BIT_HW_ERR) { | ||
1165 | IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); | ||
1166 | |||
1167 | /* Tell the device to stop sending interrupts */ | ||
1168 | iwl_disable_interrupts(priv); | ||
1169 | |||
1170 | priv->isr_stats.hw++; | ||
1171 | iwl_irq_handle_error(priv); | ||
1172 | |||
1173 | handled |= CSR_INT_BIT_HW_ERR; | ||
1174 | |||
1175 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1176 | |||
1177 | return; | ||
1178 | } | ||
1179 | |||
1180 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1181 | if (priv->debug_level & (IWL_DL_ISR)) { | ||
1182 | /* NIC fires this, but we don't use it, redundant with WAKEUP */ | ||
1183 | if (inta & CSR_INT_BIT_SCD) { | ||
1184 | IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " | ||
1185 | "the frame/frames.\n"); | ||
1186 | priv->isr_stats.sch++; | ||
1187 | } | ||
1188 | |||
1189 | /* Alive notification via Rx interrupt will do the real work */ | ||
1190 | if (inta & CSR_INT_BIT_ALIVE) { | ||
1191 | IWL_DEBUG_ISR(priv, "Alive interrupt\n"); | ||
1192 | priv->isr_stats.alive++; | ||
1193 | } | ||
1194 | } | ||
1195 | #endif | ||
1196 | /* Safely ignore these bits for debug checks below */ | ||
1197 | inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); | ||
1198 | |||
1199 | /* HW RF KILL switch toggled */ | ||
1200 | if (inta & CSR_INT_BIT_RF_KILL) { | ||
1201 | int hw_rf_kill = 0; | ||
1202 | if (!(iwl_read32(priv, CSR_GP_CNTRL) & | ||
1203 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) | ||
1204 | hw_rf_kill = 1; | ||
1205 | |||
1206 | IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n", | ||
1207 | hw_rf_kill ? "disable radio" : "enable radio"); | ||
1208 | |||
1209 | priv->isr_stats.rfkill++; | ||
1210 | |||
1211 | /* driver only loads ucode once setting the interface up. | ||
1212 | * the driver allows loading the ucode even if the radio | ||
1213 | * is killed. Hence update the killswitch state here. The | ||
1214 | * rfkill handler will care about restarting if needed. | ||
1215 | */ | ||
1216 | if (!test_bit(STATUS_ALIVE, &priv->status)) { | ||
1217 | if (hw_rf_kill) | ||
1218 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
1219 | else | ||
1220 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
1221 | queue_work(priv->workqueue, &priv->rf_kill); | ||
1222 | } | ||
1223 | |||
1224 | handled |= CSR_INT_BIT_RF_KILL; | ||
1225 | } | ||
1226 | |||
1227 | /* Chip got too hot and stopped itself */ | ||
1228 | if (inta & CSR_INT_BIT_CT_KILL) { | ||
1229 | IWL_ERR(priv, "Microcode CT kill error detected.\n"); | ||
1230 | priv->isr_stats.ctkill++; | ||
1231 | handled |= CSR_INT_BIT_CT_KILL; | ||
1232 | } | ||
1233 | |||
1234 | /* Error detected by uCode */ | ||
1235 | if (inta & CSR_INT_BIT_SW_ERR) { | ||
1236 | IWL_ERR(priv, "Microcode SW error detected. " | ||
1237 | " Restarting 0x%X.\n", inta); | ||
1238 | priv->isr_stats.sw++; | ||
1239 | priv->isr_stats.sw_err = inta; | ||
1240 | iwl_irq_handle_error(priv); | ||
1241 | handled |= CSR_INT_BIT_SW_ERR; | ||
1242 | } | ||
1243 | |||
1244 | /* uCode wakes up after power-down sleep */ | ||
1245 | if (inta & CSR_INT_BIT_WAKEUP) { | ||
1246 | IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); | ||
1247 | iwl_rx_queue_update_write_ptr(priv, &priv->rxq); | ||
1248 | iwl_txq_update_write_ptr(priv, &priv->txq[0]); | ||
1249 | iwl_txq_update_write_ptr(priv, &priv->txq[1]); | ||
1250 | iwl_txq_update_write_ptr(priv, &priv->txq[2]); | ||
1251 | iwl_txq_update_write_ptr(priv, &priv->txq[3]); | ||
1252 | iwl_txq_update_write_ptr(priv, &priv->txq[4]); | ||
1253 | iwl_txq_update_write_ptr(priv, &priv->txq[5]); | ||
1254 | |||
1255 | priv->isr_stats.wakeup++; | ||
1256 | |||
1257 | handled |= CSR_INT_BIT_WAKEUP; | ||
1258 | } | ||
1259 | |||
1260 | /* All uCode command responses, including Tx command responses, | ||
1261 | * Rx "responses" (frame-received notification), and other | ||
1262 | * notifications from uCode come through here*/ | ||
1263 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | | ||
1264 | CSR_INT_BIT_RX_PERIODIC)) { | ||
1265 | IWL_DEBUG_ISR(priv, "Rx interrupt\n"); | ||
1266 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { | ||
1267 | handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); | ||
1268 | iwl_write32(priv, CSR_FH_INT_STATUS, | ||
1269 | CSR49_FH_INT_RX_MASK); | ||
1270 | } | ||
1271 | if (inta & CSR_INT_BIT_RX_PERIODIC) { | ||
1272 | handled |= CSR_INT_BIT_RX_PERIODIC; | ||
1273 | iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC); | ||
1274 | } | ||
1275 | /* Sending RX interrupt require many steps to be done in the | ||
1276 | * the device: | ||
1277 | * 1- write interrupt to current index in ICT table. | ||
1278 | * 2- dma RX frame. | ||
1279 | * 3- update RX shared data to indicate last write index. | ||
1280 | * 4- send interrupt. | ||
1281 | * This could lead to RX race, driver could receive RX interrupt | ||
1282 | * but the shared data changes does not reflect this. | ||
1283 | * this could lead to RX race, RX periodic will solve this race | ||
1284 | */ | ||
1285 | iwl_write32(priv, CSR_INT_PERIODIC_REG, | ||
1286 | CSR_INT_PERIODIC_DIS); | ||
1287 | iwl_rx_handle(priv); | ||
1288 | /* Only set RX periodic if real RX is received. */ | ||
1289 | if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) | ||
1290 | iwl_write32(priv, CSR_INT_PERIODIC_REG, | ||
1291 | CSR_INT_PERIODIC_ENA); | ||
1292 | |||
1293 | priv->isr_stats.rx++; | ||
1294 | } | ||
1295 | |||
1296 | if (inta & CSR_INT_BIT_FH_TX) { | ||
1297 | iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK); | ||
1298 | IWL_DEBUG_ISR(priv, "Tx interrupt\n"); | ||
1299 | priv->isr_stats.tx++; | ||
1300 | handled |= CSR_INT_BIT_FH_TX; | ||
1301 | /* FH finished to write, send event */ | ||
1302 | priv->ucode_write_complete = 1; | ||
1303 | wake_up_interruptible(&priv->wait_command_queue); | ||
1304 | } | ||
1305 | |||
1306 | if (inta & ~handled) { | ||
1307 | IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); | ||
1308 | priv->isr_stats.unhandled++; | ||
1309 | } | ||
1310 | |||
1311 | if (inta & ~(priv->inta_mask)) { | ||
1312 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", | ||
1313 | inta & ~priv->inta_mask); | ||
1314 | } | ||
1315 | |||
1316 | |||
1317 | /* Re-enable all interrupts */ | ||
1318 | /* only Re-enable if diabled by irq */ | ||
1319 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
1320 | iwl_enable_interrupts(priv); | ||
1321 | |||
1322 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1323 | |||
1324 | } | ||
1325 | |||
1153 | 1326 | ||
1154 | /****************************************************************************** | 1327 | /****************************************************************************** |
1155 | * | 1328 | * |
@@ -1579,6 +1752,8 @@ static void __iwl_down(struct iwl_priv *priv) | |||
1579 | test_bit(STATUS_EXIT_PENDING, &priv->status) << | 1752 | test_bit(STATUS_EXIT_PENDING, &priv->status) << |
1580 | STATUS_EXIT_PENDING; | 1753 | STATUS_EXIT_PENDING; |
1581 | 1754 | ||
1755 | /* device going down, Stop using ICT table */ | ||
1756 | iwl_disable_ict(priv); | ||
1582 | spin_lock_irqsave(&priv->lock, flags); | 1757 | spin_lock_irqsave(&priv->lock, flags); |
1583 | iwl_clear_bit(priv, CSR_GP_CNTRL, | 1758 | iwl_clear_bit(priv, CSR_GP_CNTRL, |
1584 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 1759 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
@@ -1587,13 +1762,8 @@ static void __iwl_down(struct iwl_priv *priv) | |||
1587 | iwl_txq_ctx_stop(priv); | 1762 | iwl_txq_ctx_stop(priv); |
1588 | iwl_rxq_stop(priv); | 1763 | iwl_rxq_stop(priv); |
1589 | 1764 | ||
1590 | spin_lock_irqsave(&priv->lock, flags); | 1765 | iwl_write_prph(priv, APMG_CLK_DIS_REG, |
1591 | if (!iwl_grab_nic_access(priv)) { | 1766 | APMG_CLK_VAL_DMA_CLK_RQT); |
1592 | iwl_write_prph(priv, APMG_CLK_DIS_REG, | ||
1593 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
1594 | iwl_release_nic_access(priv); | ||
1595 | } | ||
1596 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1597 | 1767 | ||
1598 | udelay(5); | 1768 | udelay(5); |
1599 | 1769 | ||
@@ -1622,6 +1792,49 @@ static void iwl_down(struct iwl_priv *priv) | |||
1622 | iwl_cancel_deferred_work(priv); | 1792 | iwl_cancel_deferred_work(priv); |
1623 | } | 1793 | } |
1624 | 1794 | ||
1795 | #define HW_READY_TIMEOUT (50) | ||
1796 | |||
1797 | static int iwl_set_hw_ready(struct iwl_priv *priv) | ||
1798 | { | ||
1799 | int ret = 0; | ||
1800 | |||
1801 | iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
1802 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); | ||
1803 | |||
1804 | /* See if we got it */ | ||
1805 | ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
1806 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, | ||
1807 | CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, | ||
1808 | HW_READY_TIMEOUT); | ||
1809 | if (ret != -ETIMEDOUT) | ||
1810 | priv->hw_ready = true; | ||
1811 | else | ||
1812 | priv->hw_ready = false; | ||
1813 | |||
1814 | IWL_DEBUG_INFO(priv, "hardware %s\n", | ||
1815 | (priv->hw_ready == 1) ? "ready" : "not ready"); | ||
1816 | return ret; | ||
1817 | } | ||
1818 | |||
1819 | static int iwl_prepare_card_hw(struct iwl_priv *priv) | ||
1820 | { | ||
1821 | int ret = 0; | ||
1822 | |||
1823 | IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n"); | ||
1824 | |||
1825 | iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
1826 | CSR_HW_IF_CONFIG_REG_PREPARE); | ||
1827 | |||
1828 | ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, | ||
1829 | ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, | ||
1830 | CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); | ||
1831 | |||
1832 | if (ret != -ETIMEDOUT) | ||
1833 | iwl_set_hw_ready(priv); | ||
1834 | |||
1835 | return ret; | ||
1836 | } | ||
1837 | |||
1625 | #define MAX_HW_RESTARTS 5 | 1838 | #define MAX_HW_RESTARTS 5 |
1626 | 1839 | ||
1627 | static int __iwl_up(struct iwl_priv *priv) | 1840 | static int __iwl_up(struct iwl_priv *priv) |
@@ -1639,6 +1852,13 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1639 | return -EIO; | 1852 | return -EIO; |
1640 | } | 1853 | } |
1641 | 1854 | ||
1855 | iwl_prepare_card_hw(priv); | ||
1856 | |||
1857 | if (!priv->hw_ready) { | ||
1858 | IWL_WARN(priv, "Exit HW not ready\n"); | ||
1859 | return -EIO; | ||
1860 | } | ||
1861 | |||
1642 | /* If platform's RF_KILL switch is NOT set to KILL */ | 1862 | /* If platform's RF_KILL switch is NOT set to KILL */ |
1643 | if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | 1863 | if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) |
1644 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 1864 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
@@ -1667,6 +1887,8 @@ static int __iwl_up(struct iwl_priv *priv) | |||
1667 | 1887 | ||
1668 | /* clear (again), then enable host interrupts */ | 1888 | /* clear (again), then enable host interrupts */ |
1669 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 1889 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
1890 | /* enable dram interrupt */ | ||
1891 | iwl_reset_ict(priv); | ||
1670 | iwl_enable_interrupts(priv); | 1892 | iwl_enable_interrupts(priv); |
1671 | 1893 | ||
1672 | /* really make sure rfkill handshake bits are cleared */ | 1894 | /* really make sure rfkill handshake bits are cleared */ |
@@ -2298,8 +2520,10 @@ static ssize_t show_version(struct device *d, | |||
2298 | 2520 | ||
2299 | if (priv->eeprom) { | 2521 | if (priv->eeprom) { |
2300 | eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); | 2522 | eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); |
2301 | pos += sprintf(buf + pos, "EEPROM version: 0x%x\n", | 2523 | pos += sprintf(buf + pos, "NVM Type: %s, version: 0x%x\n", |
2302 | eeprom_ver); | 2524 | (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) |
2525 | ? "OTP" : "EEPROM", eeprom_ver); | ||
2526 | |||
2303 | } else { | 2527 | } else { |
2304 | pos += sprintf(buf + pos, "EEPROM not initialzed\n"); | 2528 | pos += sprintf(buf + pos, "EEPROM not initialzed\n"); |
2305 | } | 2529 | } |
@@ -2478,7 +2702,7 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, | |||
2478 | static ssize_t show_qos(struct device *d, | 2702 | static ssize_t show_qos(struct device *d, |
2479 | struct device_attribute *attr, char *buf) | 2703 | struct device_attribute *attr, char *buf) |
2480 | { | 2704 | { |
2481 | struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; | 2705 | struct iwl_priv *priv = dev_get_drvdata(d); |
2482 | char *p = buf; | 2706 | char *p = buf; |
2483 | int q; | 2707 | int q; |
2484 | 2708 | ||
@@ -2565,8 +2789,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
2565 | priv->statistics_periodic.data = (unsigned long)priv; | 2789 | priv->statistics_periodic.data = (unsigned long)priv; |
2566 | priv->statistics_periodic.function = iwl_bg_statistics_periodic; | 2790 | priv->statistics_periodic.function = iwl_bg_statistics_periodic; |
2567 | 2791 | ||
2568 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 2792 | if (!priv->cfg->use_isr_legacy) |
2569 | iwl_irq_tasklet, (unsigned long)priv); | 2793 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
2794 | iwl_irq_tasklet, (unsigned long)priv); | ||
2795 | else | ||
2796 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | ||
2797 | iwl_irq_tasklet_legacy, (unsigned long)priv); | ||
2570 | } | 2798 | } |
2571 | 2799 | ||
2572 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) | 2800 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) |
@@ -2655,6 +2883,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2655 | IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); | 2883 | IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); |
2656 | priv->cfg = cfg; | 2884 | priv->cfg = cfg; |
2657 | priv->pci_dev = pdev; | 2885 | priv->pci_dev = pdev; |
2886 | priv->inta_mask = CSR_INI_SET_MASK; | ||
2658 | 2887 | ||
2659 | #ifdef CONFIG_IWLWIFI_DEBUG | 2888 | #ifdef CONFIG_IWLWIFI_DEBUG |
2660 | priv->debug_level = priv->cfg->mod_params->debug; | 2889 | priv->debug_level = priv->cfg->mod_params->debug; |
@@ -2705,6 +2934,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2705 | (unsigned long long) pci_resource_len(pdev, 0)); | 2934 | (unsigned long long) pci_resource_len(pdev, 0)); |
2706 | IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); | 2935 | IWL_DEBUG_INFO(priv, "pci_resource_base = %p\n", priv->hw_base); |
2707 | 2936 | ||
2937 | /* this spin lock will be used in apm_ops.init and EEPROM access | ||
2938 | * we should init now | ||
2939 | */ | ||
2940 | spin_lock_init(&priv->reg_lock); | ||
2708 | iwl_hw_detect(priv); | 2941 | iwl_hw_detect(priv); |
2709 | IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", | 2942 | IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", |
2710 | priv->cfg->name, priv->hw_rev); | 2943 | priv->cfg->name, priv->hw_rev); |
@@ -2713,6 +2946,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2713 | * PCI Tx retries from interfering with C3 CPU state */ | 2946 | * PCI Tx retries from interfering with C3 CPU state */ |
2714 | pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); | 2947 | pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); |
2715 | 2948 | ||
2949 | iwl_prepare_card_hw(priv); | ||
2950 | if (!priv->hw_ready) { | ||
2951 | IWL_WARN(priv, "Failed, HW not ready\n"); | ||
2952 | goto out_iounmap; | ||
2953 | } | ||
2954 | |||
2716 | /* amp init */ | 2955 | /* amp init */ |
2717 | err = priv->cfg->ops->lib->apm_ops.init(priv); | 2956 | err = priv->cfg->ops->lib->apm_ops.init(priv); |
2718 | if (err < 0) { | 2957 | if (err < 0) { |
@@ -2763,8 +3002,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2763 | 3002 | ||
2764 | pci_enable_msi(priv->pci_dev); | 3003 | pci_enable_msi(priv->pci_dev); |
2765 | 3004 | ||
2766 | err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | 3005 | iwl_alloc_isr_ict(priv); |
2767 | DRV_NAME, priv); | 3006 | err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, |
3007 | IRQF_SHARED, DRV_NAME, priv); | ||
2768 | if (err) { | 3008 | if (err) { |
2769 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 3009 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
2770 | goto out_disable_msi; | 3010 | goto out_disable_msi; |
@@ -2821,6 +3061,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2821 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | 3061 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); |
2822 | out_free_irq: | 3062 | out_free_irq: |
2823 | free_irq(priv->pci_dev->irq, priv); | 3063 | free_irq(priv->pci_dev->irq, priv); |
3064 | iwl_free_isr_ict(priv); | ||
2824 | out_disable_msi: | 3065 | out_disable_msi: |
2825 | pci_disable_msi(priv->pci_dev); | 3066 | pci_disable_msi(priv->pci_dev); |
2826 | iwl_uninit_drv(priv); | 3067 | iwl_uninit_drv(priv); |
@@ -2902,6 +3143,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
2902 | 3143 | ||
2903 | iwl_uninit_drv(priv); | 3144 | iwl_uninit_drv(priv); |
2904 | 3145 | ||
3146 | iwl_free_isr_ict(priv); | ||
3147 | |||
2905 | if (priv->ibss_beacon) | 3148 | if (priv->ibss_beacon) |
2906 | dev_kfree_skb(priv->ibss_beacon); | 3149 | dev_kfree_skb(priv->ibss_beacon); |
2907 | 3150 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7b84d5246b36..e581dc323f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -614,8 +614,18 @@ enum { | |||
614 | 614 | ||
615 | #define RXON_FLG_CHANNEL_MODE_POS (25) | 615 | #define RXON_FLG_CHANNEL_MODE_POS (25) |
616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) | 616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) |
617 | #define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) | 617 | |
618 | #define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) | 618 | /* channel mode */ |
619 | enum { | ||
620 | CHANNEL_MODE_LEGACY = 0, | ||
621 | CHANNEL_MODE_PURE_40 = 1, | ||
622 | CHANNEL_MODE_MIXED = 2, | ||
623 | CHANNEL_MODE_RESERVED = 3, | ||
624 | }; | ||
625 | #define RXON_FLG_CHANNEL_MODE_LEGACY cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS) | ||
626 | #define RXON_FLG_CHANNEL_MODE_PURE_40 cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS) | ||
627 | #define RXON_FLG_CHANNEL_MODE_MIXED cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS) | ||
628 | |||
619 | /* CTS to self (if spec allows) flag */ | 629 | /* CTS to self (if spec allows) flag */ |
620 | #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) | 630 | #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) |
621 | 631 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 5393fb3f452c..e93ddb74457e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "iwl-rfkill.h" | 39 | #include "iwl-rfkill.h" |
40 | #include "iwl-power.h" | 40 | #include "iwl-power.h" |
41 | #include "iwl-sta.h" | 41 | #include "iwl-sta.h" |
42 | #include "iwl-helpers.h" | ||
42 | 43 | ||
43 | 44 | ||
44 | MODULE_DESCRIPTION("iwl core"); | 45 | MODULE_DESCRIPTION("iwl core"); |
@@ -59,6 +60,8 @@ MODULE_LICENSE("GPL"); | |||
59 | IWL_RATE_##pp##M_INDEX, \ | 60 | IWL_RATE_##pp##M_INDEX, \ |
60 | IWL_RATE_##np##M_INDEX } | 61 | IWL_RATE_##np##M_INDEX } |
61 | 62 | ||
63 | static irqreturn_t iwl_isr(int irq, void *data); | ||
64 | |||
62 | /* | 65 | /* |
63 | * Parameter order: | 66 | * Parameter order: |
64 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate | 67 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate |
@@ -603,10 +606,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, | |||
603 | 606 | ||
604 | if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) | 607 | if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) |
605 | return !(ch_info->fat_extension_channel & | 608 | return !(ch_info->fat_extension_channel & |
606 | IEEE80211_CHAN_NO_FAT_ABOVE); | 609 | IEEE80211_CHAN_NO_HT40PLUS); |
607 | else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) | 610 | else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) |
608 | return !(ch_info->fat_extension_channel & | 611 | return !(ch_info->fat_extension_channel & |
609 | IEEE80211_CHAN_NO_FAT_BELOW); | 612 | IEEE80211_CHAN_NO_HT40MINUS); |
610 | 613 | ||
611 | return 0; | 614 | return 0; |
612 | } | 615 | } |
@@ -617,19 +620,23 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | |||
617 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; | 620 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; |
618 | 621 | ||
619 | if ((!iwl_ht_conf->is_ht) || | 622 | if ((!iwl_ht_conf->is_ht) || |
620 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || | 623 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) |
621 | (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) | ||
622 | return 0; | 624 | return 0; |
623 | 625 | ||
626 | /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
627 | * the bit will not set if it is pure 40MHz case | ||
628 | */ | ||
624 | if (sta_ht_inf) { | 629 | if (sta_ht_inf) { |
625 | if ((!sta_ht_inf->ht_supported) || | 630 | if (!sta_ht_inf->ht_supported) |
626 | (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) | ||
627 | return 0; | 631 | return 0; |
628 | } | 632 | } |
629 | 633 | ||
630 | return iwl_is_channel_extension(priv, priv->band, | 634 | if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) |
631 | le16_to_cpu(priv->staging_rxon.channel), | 635 | return 1; |
632 | iwl_ht_conf->extension_chan_offset); | 636 | else |
637 | return iwl_is_channel_extension(priv, priv->band, | ||
638 | le16_to_cpu(priv->staging_rxon.channel), | ||
639 | iwl_ht_conf->extension_chan_offset); | ||
633 | } | 640 | } |
634 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); | 641 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); |
635 | 642 | ||
@@ -799,42 +806,51 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); | |||
799 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | 806 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) |
800 | { | 807 | { |
801 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 808 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
802 | u32 val; | ||
803 | 809 | ||
804 | if (!ht_info->is_ht) { | 810 | if (!ht_info->is_ht) { |
805 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 811 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
806 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK | | ||
807 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | 812 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | |
808 | RXON_FLG_FAT_PROT_MSK | | 813 | RXON_FLG_FAT_PROT_MSK | |
809 | RXON_FLG_HT_PROT_MSK); | 814 | RXON_FLG_HT_PROT_MSK); |
810 | return; | 815 | return; |
811 | } | 816 | } |
812 | 817 | ||
813 | /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ | 818 | /* FIXME: if the definition of ht_protection changed, the "translation" |
814 | if (iwl_is_fat_tx_allowed(priv, NULL)) | 819 | * will be needed for rxon->flags |
815 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 820 | */ |
816 | else | 821 | rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); |
817 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 822 | |
818 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); | 823 | /* Set up channel bandwidth: |
819 | 824 | * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ | |
820 | /* Note: control channel is opposite of extension channel */ | 825 | /* clear the HT channel mode before set the mode */ |
821 | switch (ht_info->extension_chan_offset) { | 826 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
822 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 827 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
823 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | 828 | if (iwl_is_fat_tx_allowed(priv, NULL)) { |
824 | break; | 829 | /* pure 40 fat */ |
825 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 830 | if (rxon->flags & RXON_FLG_FAT_PROT_MSK) |
826 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | 831 | rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; |
827 | break; | 832 | else { |
828 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 833 | /* Note: control channel is opposite of extension channel */ |
829 | default: | 834 | switch (ht_info->extension_chan_offset) { |
830 | rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 835 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
831 | break; | 836 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
837 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | ||
838 | break; | ||
839 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
840 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | ||
841 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | ||
842 | break; | ||
843 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
844 | default: | ||
845 | /* channel location only valid if in Mixed mode */ | ||
846 | IWL_ERR(priv, "invalid extension channel offset\n"); | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | } else { | ||
851 | rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; | ||
832 | } | 852 | } |
833 | 853 | ||
834 | val = ht_info->ht_protection; | ||
835 | |||
836 | rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); | ||
837 | |||
838 | if (priv->cfg->ops->hcmd->set_rxon_chain) | 854 | if (priv->cfg->ops->hcmd->set_rxon_chain) |
839 | priv->cfg->ops->hcmd->set_rxon_chain(priv); | 855 | priv->cfg->ops->hcmd->set_rxon_chain(priv); |
840 | 856 | ||
@@ -1122,8 +1138,9 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) | |||
1122 | priv->staging_rxon.cck_basic_rates = | 1138 | priv->staging_rxon.cck_basic_rates = |
1123 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; | 1139 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; |
1124 | 1140 | ||
1125 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 1141 | /* clear both MIX and PURE40 mode flag */ |
1126 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); | 1142 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | |
1143 | RXON_FLG_CHANNEL_MODE_PURE_40); | ||
1127 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 1144 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
1128 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); | 1145 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); |
1129 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; | 1146 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; |
@@ -1483,11 +1500,272 @@ void iwl_enable_interrupts(struct iwl_priv *priv) | |||
1483 | { | 1500 | { |
1484 | IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); | 1501 | IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); |
1485 | set_bit(STATUS_INT_ENABLED, &priv->status); | 1502 | set_bit(STATUS_INT_ENABLED, &priv->status); |
1486 | iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); | 1503 | iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); |
1487 | } | 1504 | } |
1488 | EXPORT_SYMBOL(iwl_enable_interrupts); | 1505 | EXPORT_SYMBOL(iwl_enable_interrupts); |
1489 | 1506 | ||
1490 | irqreturn_t iwl_isr(int irq, void *data) | 1507 | |
1508 | #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) | ||
1509 | |||
1510 | /* Free dram table */ | ||
1511 | void iwl_free_isr_ict(struct iwl_priv *priv) | ||
1512 | { | ||
1513 | if (priv->ict_tbl_vir) { | ||
1514 | pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + | ||
1515 | PAGE_SIZE, priv->ict_tbl_vir, | ||
1516 | priv->ict_tbl_dma); | ||
1517 | priv->ict_tbl_vir = NULL; | ||
1518 | } | ||
1519 | } | ||
1520 | EXPORT_SYMBOL(iwl_free_isr_ict); | ||
1521 | |||
1522 | |||
1523 | /* allocate dram shared table it is a PAGE_SIZE aligned | ||
1524 | * also reset all data related to ICT table interrupt. | ||
1525 | */ | ||
1526 | int iwl_alloc_isr_ict(struct iwl_priv *priv) | ||
1527 | { | ||
1528 | |||
1529 | if (priv->cfg->use_isr_legacy) | ||
1530 | return 0; | ||
1531 | /* allocate shrared data table */ | ||
1532 | priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * | ||
1533 | ICT_COUNT) + PAGE_SIZE, | ||
1534 | &priv->ict_tbl_dma); | ||
1535 | if (!priv->ict_tbl_vir) | ||
1536 | return -ENOMEM; | ||
1537 | |||
1538 | /* align table to PAGE_SIZE boundry */ | ||
1539 | priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE); | ||
1540 | |||
1541 | IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", | ||
1542 | (unsigned long long)priv->ict_tbl_dma, | ||
1543 | (unsigned long long)priv->aligned_ict_tbl_dma, | ||
1544 | (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); | ||
1545 | |||
1546 | priv->ict_tbl = priv->ict_tbl_vir + | ||
1547 | (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma); | ||
1548 | |||
1549 | IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n", | ||
1550 | priv->ict_tbl, priv->ict_tbl_vir, | ||
1551 | (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); | ||
1552 | |||
1553 | /* reset table and index to all 0 */ | ||
1554 | memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); | ||
1555 | priv->ict_index = 0; | ||
1556 | |||
1557 | /* add periodic RX interrupt */ | ||
1558 | priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC; | ||
1559 | return 0; | ||
1560 | } | ||
1561 | EXPORT_SYMBOL(iwl_alloc_isr_ict); | ||
1562 | |||
1563 | /* Device is going up inform it about using ICT interrupt table, | ||
1564 | * also we need to tell the driver to start using ICT interrupt. | ||
1565 | */ | ||
1566 | int iwl_reset_ict(struct iwl_priv *priv) | ||
1567 | { | ||
1568 | u32 val; | ||
1569 | unsigned long flags; | ||
1570 | |||
1571 | if (!priv->ict_tbl_vir) | ||
1572 | return 0; | ||
1573 | |||
1574 | spin_lock_irqsave(&priv->lock, flags); | ||
1575 | iwl_disable_interrupts(priv); | ||
1576 | |||
1577 | memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); | ||
1578 | |||
1579 | val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; | ||
1580 | |||
1581 | val |= CSR_DRAM_INT_TBL_ENABLE; | ||
1582 | val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; | ||
1583 | |||
1584 | IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X " | ||
1585 | "aligned dma address %Lx\n", | ||
1586 | val, (unsigned long long)priv->aligned_ict_tbl_dma); | ||
1587 | |||
1588 | iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); | ||
1589 | priv->use_ict = true; | ||
1590 | priv->ict_index = 0; | ||
1591 | iwl_write32(priv, CSR_INT, priv->inta_mask); | ||
1592 | iwl_enable_interrupts(priv); | ||
1593 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | EXPORT_SYMBOL(iwl_reset_ict); | ||
1598 | |||
1599 | /* Device is going down disable ict interrupt usage */ | ||
1600 | void iwl_disable_ict(struct iwl_priv *priv) | ||
1601 | { | ||
1602 | unsigned long flags; | ||
1603 | |||
1604 | spin_lock_irqsave(&priv->lock, flags); | ||
1605 | priv->use_ict = false; | ||
1606 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1607 | } | ||
1608 | EXPORT_SYMBOL(iwl_disable_ict); | ||
1609 | |||
1610 | /* interrupt handler using ict table, with this interrupt driver will | ||
1611 | * stop using INTA register to get device's interrupt, reading this register | ||
1612 | * is expensive, device will write interrupts in ICT dram table, increment | ||
1613 | * index then will fire interrupt to driver, driver will OR all ICT table | ||
1614 | * entries from current index up to table entry with 0 value. the result is | ||
1615 | * the interrupt we need to service, driver will set the entries back to 0 and | ||
1616 | * set index. | ||
1617 | */ | ||
1618 | irqreturn_t iwl_isr_ict(int irq, void *data) | ||
1619 | { | ||
1620 | struct iwl_priv *priv = data; | ||
1621 | u32 inta, inta_mask; | ||
1622 | u32 val = 0; | ||
1623 | |||
1624 | if (!priv) | ||
1625 | return IRQ_NONE; | ||
1626 | |||
1627 | /* dram interrupt table not set yet, | ||
1628 | * use legacy interrupt. | ||
1629 | */ | ||
1630 | if (!priv->use_ict) | ||
1631 | return iwl_isr(irq, data); | ||
1632 | |||
1633 | spin_lock(&priv->lock); | ||
1634 | |||
1635 | /* Disable (but don't clear!) interrupts here to avoid | ||
1636 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1637 | * If we have something to service, the tasklet will re-enable ints. | ||
1638 | * If we *don't* have something, we'll re-enable before leaving here. | ||
1639 | */ | ||
1640 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1641 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1642 | |||
1643 | |||
1644 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1645 | * This may be due to IRQ shared with another device, | ||
1646 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1647 | if (!priv->ict_tbl[priv->ict_index]) { | ||
1648 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); | ||
1649 | goto none; | ||
1650 | } | ||
1651 | |||
1652 | /* read all entries that not 0 start with ict_index */ | ||
1653 | while (priv->ict_tbl[priv->ict_index]) { | ||
1654 | |||
1655 | val |= priv->ict_tbl[priv->ict_index]; | ||
1656 | IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", | ||
1657 | priv->ict_index, | ||
1658 | priv->ict_tbl[priv->ict_index]); | ||
1659 | priv->ict_tbl[priv->ict_index] = 0; | ||
1660 | priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, | ||
1661 | ICT_COUNT); | ||
1662 | |||
1663 | } | ||
1664 | |||
1665 | /* We should not get this value, just ignore it. */ | ||
1666 | if (val == 0xffffffff) | ||
1667 | val = 0; | ||
1668 | |||
1669 | inta = (0xff & val) | ((0xff00 & val) << 16); | ||
1670 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", | ||
1671 | inta, inta_mask, val); | ||
1672 | |||
1673 | inta &= priv->inta_mask; | ||
1674 | priv->inta |= inta; | ||
1675 | |||
1676 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1677 | if (likely(inta)) | ||
1678 | tasklet_schedule(&priv->irq_tasklet); | ||
1679 | else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) { | ||
1680 | /* Allow interrupt if was disabled by this handler and | ||
1681 | * no tasklet was schedules, We should not enable interrupt, | ||
1682 | * tasklet will enable it. | ||
1683 | */ | ||
1684 | iwl_enable_interrupts(priv); | ||
1685 | } | ||
1686 | |||
1687 | spin_unlock(&priv->lock); | ||
1688 | return IRQ_HANDLED; | ||
1689 | |||
1690 | none: | ||
1691 | /* re-enable interrupts here since we don't have anything to service. | ||
1692 | * only Re-enable if disabled by irq. | ||
1693 | */ | ||
1694 | if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1695 | iwl_enable_interrupts(priv); | ||
1696 | |||
1697 | spin_unlock(&priv->lock); | ||
1698 | return IRQ_NONE; | ||
1699 | } | ||
1700 | EXPORT_SYMBOL(iwl_isr_ict); | ||
1701 | |||
1702 | |||
1703 | static irqreturn_t iwl_isr(int irq, void *data) | ||
1704 | { | ||
1705 | struct iwl_priv *priv = data; | ||
1706 | u32 inta, inta_mask; | ||
1707 | u32 inta_fh; | ||
1708 | |||
1709 | if (!priv) | ||
1710 | return IRQ_NONE; | ||
1711 | |||
1712 | spin_lock(&priv->lock); | ||
1713 | |||
1714 | /* Disable (but don't clear!) interrupts here to avoid | ||
1715 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1716 | * If we have something to service, the tasklet will re-enable ints. | ||
1717 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
1718 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1719 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1720 | |||
1721 | /* Discover which interrupts are active/pending */ | ||
1722 | inta = iwl_read32(priv, CSR_INT); | ||
1723 | |||
1724 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1725 | * This may be due to IRQ shared with another device, | ||
1726 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1727 | if (!inta) { | ||
1728 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); | ||
1729 | goto none; | ||
1730 | } | ||
1731 | |||
1732 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
1733 | /* Hardware disappeared. It might have already raised | ||
1734 | * an interrupt */ | ||
1735 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
1736 | goto unplugged; | ||
1737 | } | ||
1738 | |||
1739 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1740 | if (priv->debug_level & (IWL_DL_ISR)) { | ||
1741 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
1742 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " | ||
1743 | "fh 0x%08x\n", inta, inta_mask, inta_fh); | ||
1744 | } | ||
1745 | #endif | ||
1746 | |||
1747 | priv->inta |= inta; | ||
1748 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1749 | if (likely(inta)) | ||
1750 | tasklet_schedule(&priv->irq_tasklet); | ||
1751 | else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1752 | iwl_enable_interrupts(priv); | ||
1753 | |||
1754 | unplugged: | ||
1755 | spin_unlock(&priv->lock); | ||
1756 | return IRQ_HANDLED; | ||
1757 | |||
1758 | none: | ||
1759 | /* re-enable interrupts here since we don't have anything to service. */ | ||
1760 | /* only Re-enable if diabled by irq and no schedules tasklet. */ | ||
1761 | if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1762 | iwl_enable_interrupts(priv); | ||
1763 | |||
1764 | spin_unlock(&priv->lock); | ||
1765 | return IRQ_NONE; | ||
1766 | } | ||
1767 | |||
1768 | irqreturn_t iwl_isr_legacy(int irq, void *data) | ||
1491 | { | 1769 | { |
1492 | struct iwl_priv *priv = data; | 1770 | struct iwl_priv *priv = data; |
1493 | u32 inta, inta_mask; | 1771 | u32 inta, inta_mask; |
@@ -1544,7 +1822,7 @@ irqreturn_t iwl_isr(int irq, void *data) | |||
1544 | spin_unlock(&priv->lock); | 1822 | spin_unlock(&priv->lock); |
1545 | return IRQ_NONE; | 1823 | return IRQ_NONE; |
1546 | } | 1824 | } |
1547 | EXPORT_SYMBOL(iwl_isr); | 1825 | EXPORT_SYMBOL(iwl_isr_legacy); |
1548 | 1826 | ||
1549 | int iwl_send_bt_config(struct iwl_priv *priv) | 1827 | int iwl_send_bt_config(struct iwl_priv *priv) |
1550 | { | 1828 | { |
@@ -1588,10 +1866,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 | |||
1588 | 1866 | ||
1589 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 1867 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
1590 | 1868 | ||
1591 | ret = iwl_grab_nic_access(priv); | ||
1592 | if (ret) | ||
1593 | return ret; | ||
1594 | |||
1595 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { | 1869 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { |
1596 | /* read data comes through single port, auto-incr addr */ | 1870 | /* read data comes through single port, auto-incr addr */ |
1597 | /* NOTE: Use the debugless read so we don't flood kernel log | 1871 | /* NOTE: Use the debugless read so we don't flood kernel log |
@@ -1607,8 +1881,6 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 | |||
1607 | } | 1881 | } |
1608 | } | 1882 | } |
1609 | 1883 | ||
1610 | iwl_release_nic_access(priv); | ||
1611 | |||
1612 | return ret; | 1884 | return ret; |
1613 | } | 1885 | } |
1614 | 1886 | ||
@@ -1626,10 +1898,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, | |||
1626 | 1898 | ||
1627 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 1899 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
1628 | 1900 | ||
1629 | ret = iwl_grab_nic_access(priv); | ||
1630 | if (ret) | ||
1631 | return ret; | ||
1632 | |||
1633 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | 1901 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, |
1634 | IWL49_RTC_INST_LOWER_BOUND); | 1902 | IWL49_RTC_INST_LOWER_BOUND); |
1635 | 1903 | ||
@@ -1650,8 +1918,6 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, | |||
1650 | } | 1918 | } |
1651 | } | 1919 | } |
1652 | 1920 | ||
1653 | iwl_release_nic_access(priv); | ||
1654 | |||
1655 | if (!errcnt) | 1921 | if (!errcnt) |
1656 | IWL_DEBUG_INFO(priv, | 1922 | IWL_DEBUG_INFO(priv, |
1657 | "ucode image in INSTRUCTION memory is good\n"); | 1923 | "ucode image in INSTRUCTION memory is good\n"); |
@@ -1760,7 +2026,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
1760 | u32 data2, line; | 2026 | u32 data2, line; |
1761 | u32 desc, time, count, base, data1; | 2027 | u32 desc, time, count, base, data1; |
1762 | u32 blink1, blink2, ilink1, ilink2; | 2028 | u32 blink1, blink2, ilink1, ilink2; |
1763 | int ret; | ||
1764 | 2029 | ||
1765 | if (priv->ucode_type == UCODE_INIT) | 2030 | if (priv->ucode_type == UCODE_INIT) |
1766 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); | 2031 | base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr); |
@@ -1772,12 +2037,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
1772 | return; | 2037 | return; |
1773 | } | 2038 | } |
1774 | 2039 | ||
1775 | ret = iwl_grab_nic_access(priv); | ||
1776 | if (ret) { | ||
1777 | IWL_WARN(priv, "Can not read from adapter at this time.\n"); | ||
1778 | return; | ||
1779 | } | ||
1780 | |||
1781 | count = iwl_read_targ_mem(priv, base); | 2040 | count = iwl_read_targ_mem(priv, base); |
1782 | 2041 | ||
1783 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { | 2042 | if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { |
@@ -1804,7 +2063,6 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) | |||
1804 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, | 2063 | IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, |
1805 | ilink1, ilink2); | 2064 | ilink1, ilink2); |
1806 | 2065 | ||
1807 | iwl_release_nic_access(priv); | ||
1808 | } | 2066 | } |
1809 | EXPORT_SYMBOL(iwl_dump_nic_error_log); | 2067 | EXPORT_SYMBOL(iwl_dump_nic_error_log); |
1810 | 2068 | ||
@@ -1813,7 +2071,6 @@ EXPORT_SYMBOL(iwl_dump_nic_error_log); | |||
1813 | /** | 2071 | /** |
1814 | * iwl_print_event_log - Dump error event log to syslog | 2072 | * iwl_print_event_log - Dump error event log to syslog |
1815 | * | 2073 | * |
1816 | * NOTE: Must be called with iwl_grab_nic_access() already obtained! | ||
1817 | */ | 2074 | */ |
1818 | static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | 2075 | static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, |
1819 | u32 num_events, u32 mode) | 2076 | u32 num_events, u32 mode) |
@@ -1859,7 +2116,6 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1859 | 2116 | ||
1860 | void iwl_dump_nic_event_log(struct iwl_priv *priv) | 2117 | void iwl_dump_nic_event_log(struct iwl_priv *priv) |
1861 | { | 2118 | { |
1862 | int ret; | ||
1863 | u32 base; /* SRAM byte address of event log header */ | 2119 | u32 base; /* SRAM byte address of event log header */ |
1864 | u32 capacity; /* event log capacity in # entries */ | 2120 | u32 capacity; /* event log capacity in # entries */ |
1865 | u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ | 2121 | u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ |
@@ -1877,12 +2133,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
1877 | return; | 2133 | return; |
1878 | } | 2134 | } |
1879 | 2135 | ||
1880 | ret = iwl_grab_nic_access(priv); | ||
1881 | if (ret) { | ||
1882 | IWL_WARN(priv, "Can not read from adapter at this time.\n"); | ||
1883 | return; | ||
1884 | } | ||
1885 | |||
1886 | /* event log header */ | 2136 | /* event log header */ |
1887 | capacity = iwl_read_targ_mem(priv, base); | 2137 | capacity = iwl_read_targ_mem(priv, base); |
1888 | mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); | 2138 | mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); |
@@ -1894,7 +2144,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
1894 | /* bail out if nothing in log */ | 2144 | /* bail out if nothing in log */ |
1895 | if (size == 0) { | 2145 | if (size == 0) { |
1896 | IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); | 2146 | IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); |
1897 | iwl_release_nic_access(priv); | ||
1898 | return; | 2147 | return; |
1899 | } | 2148 | } |
1900 | 2149 | ||
@@ -1909,7 +2158,6 @@ void iwl_dump_nic_event_log(struct iwl_priv *priv) | |||
1909 | /* (then/else) start at top of log */ | 2158 | /* (then/else) start at top of log */ |
1910 | iwl_print_event_log(priv, 0, next_entry, mode); | 2159 | iwl_print_event_log(priv, 0, next_entry, mode); |
1911 | 2160 | ||
1912 | iwl_release_nic_access(priv); | ||
1913 | } | 2161 | } |
1914 | EXPORT_SYMBOL(iwl_dump_nic_event_log); | 2162 | EXPORT_SYMBOL(iwl_dump_nic_event_log); |
1915 | 2163 | ||
@@ -2016,11 +2264,11 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) | |||
2016 | /* wake up ucode */ | 2264 | /* wake up ucode */ |
2017 | msleep(10); | 2265 | msleep(10); |
2018 | 2266 | ||
2019 | spin_lock_irqsave(&priv->lock, flags); | ||
2020 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | 2267 | iwl_read32(priv, CSR_UCODE_DRV_GP1); |
2268 | spin_lock_irqsave(&priv->reg_lock, flags); | ||
2021 | if (!iwl_grab_nic_access(priv)) | 2269 | if (!iwl_grab_nic_access(priv)) |
2022 | iwl_release_nic_access(priv); | 2270 | iwl_release_nic_access(priv); |
2023 | spin_unlock_irqrestore(&priv->lock, flags); | 2271 | spin_unlock_irqrestore(&priv->reg_lock, flags); |
2024 | 2272 | ||
2025 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | 2273 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { |
2026 | IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " | 2274 | IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index f3544ea559a2..87df1b767941 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -112,6 +112,19 @@ struct iwl_hcmd_utils_ops { | |||
112 | struct iwl_rx_phy_res *rx_resp); | 112 | struct iwl_rx_phy_res *rx_resp); |
113 | }; | 113 | }; |
114 | 114 | ||
115 | struct iwl_apm_ops { | ||
116 | int (*init)(struct iwl_priv *priv); | ||
117 | int (*reset)(struct iwl_priv *priv); | ||
118 | void (*stop)(struct iwl_priv *priv); | ||
119 | void (*config)(struct iwl_priv *priv); | ||
120 | int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); | ||
121 | }; | ||
122 | |||
123 | struct iwl_temp_ops { | ||
124 | void (*temperature)(struct iwl_priv *priv); | ||
125 | void (*set_ct_kill)(struct iwl_priv *priv); | ||
126 | }; | ||
127 | |||
115 | struct iwl_lib_ops { | 128 | struct iwl_lib_ops { |
116 | /* set hw dependent parameters */ | 129 | /* set hw dependent parameters */ |
117 | int (*set_hw_params)(struct iwl_priv *priv); | 130 | int (*set_hw_params)(struct iwl_priv *priv); |
@@ -149,23 +162,21 @@ struct iwl_lib_ops { | |||
149 | int (*is_valid_rtc_data_addr)(u32 addr); | 162 | int (*is_valid_rtc_data_addr)(u32 addr); |
150 | /* 1st ucode load */ | 163 | /* 1st ucode load */ |
151 | int (*load_ucode)(struct iwl_priv *priv); | 164 | int (*load_ucode)(struct iwl_priv *priv); |
152 | /* power management */ | 165 | /* power management */ |
153 | struct { | 166 | struct iwl_apm_ops apm_ops; |
154 | int (*init)(struct iwl_priv *priv); | 167 | |
155 | int (*reset)(struct iwl_priv *priv); | ||
156 | void (*stop)(struct iwl_priv *priv); | ||
157 | void (*config)(struct iwl_priv *priv); | ||
158 | int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src); | ||
159 | } apm_ops; | ||
160 | /* power */ | 168 | /* power */ |
161 | int (*send_tx_power) (struct iwl_priv *priv); | 169 | int (*send_tx_power) (struct iwl_priv *priv); |
162 | void (*update_chain_flags)(struct iwl_priv *priv); | 170 | void (*update_chain_flags)(struct iwl_priv *priv); |
163 | void (*temperature) (struct iwl_priv *priv); | ||
164 | void (*post_associate) (struct iwl_priv *priv); | 171 | void (*post_associate) (struct iwl_priv *priv); |
165 | void (*config_ap) (struct iwl_priv *priv); | 172 | void (*config_ap) (struct iwl_priv *priv); |
173 | irqreturn_t (*isr) (int irq, void *data); | ||
166 | 174 | ||
167 | /* eeprom operations (as defined in iwl-eeprom.h) */ | 175 | /* eeprom operations (as defined in iwl-eeprom.h) */ |
168 | struct iwl_eeprom_ops eeprom_ops; | 176 | struct iwl_eeprom_ops eeprom_ops; |
177 | |||
178 | /* temperature */ | ||
179 | struct iwl_temp_ops temp_ops; | ||
169 | }; | 180 | }; |
170 | 181 | ||
171 | struct iwl_ops { | 182 | struct iwl_ops { |
@@ -229,6 +240,7 @@ struct iwl_cfg { | |||
229 | u8 valid_tx_ant; | 240 | u8 valid_tx_ant; |
230 | u8 valid_rx_ant; | 241 | u8 valid_rx_ant; |
231 | bool need_pll_cfg; | 242 | bool need_pll_cfg; |
243 | bool use_isr_legacy; | ||
232 | }; | 244 | }; |
233 | 245 | ||
234 | /*************************** | 246 | /*************************** |
@@ -306,10 +318,11 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, | |||
306 | struct iwl_rx_queue *q); | 318 | struct iwl_rx_queue *q); |
307 | void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 319 | void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
308 | void iwl_rx_replenish(struct iwl_priv *priv); | 320 | void iwl_rx_replenish(struct iwl_priv *priv); |
321 | void iwl_rx_replenish_now(struct iwl_priv *priv); | ||
309 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 322 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
310 | int iwl_rx_queue_restock(struct iwl_priv *priv); | 323 | int iwl_rx_queue_restock(struct iwl_priv *priv); |
311 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); | 324 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); |
312 | void iwl_rx_allocate(struct iwl_priv *priv); | 325 | void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); |
313 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | 326 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); |
314 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); | 327 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); |
315 | /* Handlers */ | 328 | /* Handlers */ |
@@ -456,7 +469,13 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, | |||
456 | *****************************************************/ | 469 | *****************************************************/ |
457 | void iwl_disable_interrupts(struct iwl_priv *priv); | 470 | void iwl_disable_interrupts(struct iwl_priv *priv); |
458 | void iwl_enable_interrupts(struct iwl_priv *priv); | 471 | void iwl_enable_interrupts(struct iwl_priv *priv); |
459 | irqreturn_t iwl_isr(int irq, void *data); | 472 | irqreturn_t iwl_isr_legacy(int irq, void *data); |
473 | int iwl_reset_ict(struct iwl_priv *priv); | ||
474 | void iwl_disable_ict(struct iwl_priv *priv); | ||
475 | int iwl_alloc_isr_ict(struct iwl_priv *priv); | ||
476 | void iwl_free_isr_ict(struct iwl_priv *priv); | ||
477 | irqreturn_t iwl_isr_ict(int irq, void *data); | ||
478 | |||
460 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) | 479 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) |
461 | { | 480 | { |
462 | int pos; | 481 | int pos; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 6e983149b83b..f03dae1b2f36 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -89,6 +89,7 @@ | |||
89 | /* EEPROM reads */ | 89 | /* EEPROM reads */ |
90 | #define CSR_EEPROM_REG (CSR_BASE+0x02c) | 90 | #define CSR_EEPROM_REG (CSR_BASE+0x02c) |
91 | #define CSR_EEPROM_GP (CSR_BASE+0x030) | 91 | #define CSR_EEPROM_GP (CSR_BASE+0x030) |
92 | #define CSR_OTP_GP_REG (CSR_BASE+0x034) | ||
92 | #define CSR_GIO_REG (CSR_BASE+0x03C) | 93 | #define CSR_GIO_REG (CSR_BASE+0x03C) |
93 | #define CSR_GP_UCODE (CSR_BASE+0x044) | 94 | #define CSR_GP_UCODE (CSR_BASE+0x044) |
94 | #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) | 95 | #define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) |
@@ -96,8 +97,10 @@ | |||
96 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | 97 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) |
97 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | 98 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) |
98 | #define CSR_LED_REG (CSR_BASE+0x094) | 99 | #define CSR_LED_REG (CSR_BASE+0x094) |
100 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) | ||
99 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) | 101 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) |
100 | 102 | ||
103 | #define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) | ||
101 | /* Analog phase-lock-loop configuration */ | 104 | /* Analog phase-lock-loop configuration */ |
102 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) | 105 | #define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) |
103 | /* | 106 | /* |
@@ -123,16 +126,18 @@ | |||
123 | 126 | ||
124 | #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) | 127 | #define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000) |
125 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) | 128 | #define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) |
126 | #define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM (0x00400000) | 129 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) |
127 | #define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000) | 130 | #define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) |
128 | #define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000) | 131 | #define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) |
129 | 132 | ||
133 | #define CSR_INT_PERIODIC_DIS (0x00) | ||
134 | #define CSR_INT_PERIODIC_ENA (0xFF) | ||
130 | 135 | ||
131 | /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), | 136 | /* interrupt flags in INTA, set by uCode or hardware (e.g. dma), |
132 | * acknowledged (reset) by host writing "1" to flagged bits. */ | 137 | * acknowledged (reset) by host writing "1" to flagged bits. */ |
133 | #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ | 138 | #define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ |
134 | #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ | 139 | #define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ |
135 | #define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ | 140 | #define CSR_INT_BIT_RX_PERIODIC (1 << 28) /* Rx periodic */ |
136 | #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ | 141 | #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ |
137 | #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ | 142 | #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ |
138 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ | 143 | #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ |
@@ -226,6 +231,10 @@ | |||
226 | #define CSR_EEPROM_GP_VALID_MSK (0x00000007) | 231 | #define CSR_EEPROM_GP_VALID_MSK (0x00000007) |
227 | #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) | 232 | #define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) |
228 | #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) | 233 | #define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) |
234 | #define CSR_OTP_GP_REG_DEVICE_SELECT (0x00010000) /* 0 - EEPROM, 1 - OTP */ | ||
235 | #define CSR_OTP_GP_REG_OTP_ACCESS_MODE (0x00020000) /* 0 - absolute, 1 - relative */ | ||
236 | #define CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK (0x00100000) /* bit 20 */ | ||
237 | #define CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK (0x00200000) /* bit 21 */ | ||
229 | 238 | ||
230 | /* CSR GIO */ | 239 | /* CSR GIO */ |
231 | #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) | 240 | #define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002) |
@@ -251,6 +260,11 @@ | |||
251 | 260 | ||
252 | /* HPET MEM debug */ | 261 | /* HPET MEM debug */ |
253 | #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) | 262 | #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) |
263 | |||
264 | /* DRAM INT TABLE */ | ||
265 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) | ||
266 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) | ||
267 | |||
254 | /*=== HBUS (Host-side Bus) ===*/ | 268 | /*=== HBUS (Host-side Bus) ===*/ |
255 | #define HBUS_BASE (0x400) | 269 | #define HBUS_BASE (0x400) |
256 | /* | 270 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index db069801bc41..2cf014f523be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h | |||
@@ -68,7 +68,7 @@ struct iwl_debugfs { | |||
68 | struct dentry *dir_rf; | 68 | struct dentry *dir_rf; |
69 | struct dir_data_files { | 69 | struct dir_data_files { |
70 | struct dentry *file_sram; | 70 | struct dentry *file_sram; |
71 | struct dentry *file_eeprom; | 71 | struct dentry *file_nvm; |
72 | struct dentry *file_stations; | 72 | struct dentry *file_stations; |
73 | struct dentry *file_rx_statistics; | 73 | struct dentry *file_rx_statistics; |
74 | struct dentry *file_tx_statistics; | 74 | struct dentry *file_tx_statistics; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ffc4be3842b2..af70229144b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -172,7 +172,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, | |||
172 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 172 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; |
173 | const size_t bufsz = sizeof(buf); | 173 | const size_t bufsz = sizeof(buf); |
174 | 174 | ||
175 | iwl_grab_nic_access(priv); | ||
176 | for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { | 175 | for (i = priv->dbgfs->sram_len; i > 0; i -= 4) { |
177 | val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ | 176 | val = iwl_read_targ_mem(priv, priv->dbgfs->sram_offset + \ |
178 | priv->dbgfs->sram_len - i); | 177 | priv->dbgfs->sram_len - i); |
@@ -192,7 +191,6 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, | |||
192 | pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); | 191 | pos += scnprintf(buf + pos, bufsz - pos, "0x%08x ", val); |
193 | } | 192 | } |
194 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); | 193 | pos += scnprintf(buf + pos, bufsz - pos, "\n"); |
195 | iwl_release_nic_access(priv); | ||
196 | 194 | ||
197 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 195 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
198 | return ret; | 196 | return ret; |
@@ -292,7 +290,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | |||
292 | return ret; | 290 | return ret; |
293 | } | 291 | } |
294 | 292 | ||
295 | static ssize_t iwl_dbgfs_eeprom_read(struct file *file, | 293 | static ssize_t iwl_dbgfs_nvm_read(struct file *file, |
296 | char __user *user_buf, | 294 | char __user *user_buf, |
297 | size_t count, | 295 | size_t count, |
298 | loff_t *ppos) | 296 | loff_t *ppos) |
@@ -306,7 +304,7 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, | |||
306 | buf_size = 4 * eeprom_len + 256; | 304 | buf_size = 4 * eeprom_len + 256; |
307 | 305 | ||
308 | if (eeprom_len % 16) { | 306 | if (eeprom_len % 16) { |
309 | IWL_ERR(priv, "EEPROM size is not multiple of 16.\n"); | 307 | IWL_ERR(priv, "NVM size is not multiple of 16.\n"); |
310 | return -ENODATA; | 308 | return -ENODATA; |
311 | } | 309 | } |
312 | 310 | ||
@@ -318,6 +316,13 @@ static ssize_t iwl_dbgfs_eeprom_read(struct file *file, | |||
318 | } | 316 | } |
319 | 317 | ||
320 | ptr = priv->eeprom; | 318 | ptr = priv->eeprom; |
319 | if (!ptr) { | ||
320 | IWL_ERR(priv, "Invalid EEPROM/OTP memory\n"); | ||
321 | return -ENOMEM; | ||
322 | } | ||
323 | pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s\n", | ||
324 | (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) | ||
325 | ? "OTP" : "EEPROM"); | ||
321 | for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { | 326 | for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) { |
322 | pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); | 327 | pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); |
323 | hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, | 328 | hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos, |
@@ -375,51 +380,53 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, | |||
375 | } | 380 | } |
376 | 381 | ||
377 | supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); | 382 | supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); |
378 | channels = supp_band->channels; | 383 | if (supp_band) { |
384 | channels = supp_band->channels; | ||
379 | 385 | ||
380 | pos += scnprintf(buf + pos, bufsz - pos, | ||
381 | "Displaying %d channels in 2.4GHz band 802.11bg):\n", | ||
382 | supp_band->n_channels); | ||
383 | |||
384 | for (i = 0; i < supp_band->n_channels; i++) | ||
385 | pos += scnprintf(buf + pos, bufsz - pos, | 386 | pos += scnprintf(buf + pos, bufsz - pos, |
386 | "%d: %ddBm: BSS%s%s, %s.\n", | 387 | "Displaying %d channels in 2.4GHz band 802.11bg):\n", |
387 | ieee80211_frequency_to_channel( | 388 | supp_band->n_channels); |
388 | channels[i].center_freq), | ||
389 | channels[i].max_power, | ||
390 | channels[i].flags & IEEE80211_CHAN_RADAR ? | ||
391 | " (IEEE 802.11h required)" : "", | ||
392 | ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) | ||
393 | || (channels[i].flags & | ||
394 | IEEE80211_CHAN_RADAR)) ? "" : | ||
395 | ", IBSS", | ||
396 | channels[i].flags & | ||
397 | IEEE80211_CHAN_PASSIVE_SCAN ? | ||
398 | "passive only" : "active/passive"); | ||
399 | 389 | ||
390 | for (i = 0; i < supp_band->n_channels; i++) | ||
391 | pos += scnprintf(buf + pos, bufsz - pos, | ||
392 | "%d: %ddBm: BSS%s%s, %s.\n", | ||
393 | ieee80211_frequency_to_channel( | ||
394 | channels[i].center_freq), | ||
395 | channels[i].max_power, | ||
396 | channels[i].flags & IEEE80211_CHAN_RADAR ? | ||
397 | " (IEEE 802.11h required)" : "", | ||
398 | ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) | ||
399 | || (channels[i].flags & | ||
400 | IEEE80211_CHAN_RADAR)) ? "" : | ||
401 | ", IBSS", | ||
402 | channels[i].flags & | ||
403 | IEEE80211_CHAN_PASSIVE_SCAN ? | ||
404 | "passive only" : "active/passive"); | ||
405 | } | ||
400 | supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); | 406 | supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); |
401 | channels = supp_band->channels; | 407 | if (supp_band) { |
402 | 408 | channels = supp_band->channels; | |
403 | pos += scnprintf(buf + pos, bufsz - pos, | ||
404 | "Displaying %d channels in 5.2GHz band (802.11a)\n", | ||
405 | supp_band->n_channels); | ||
406 | 409 | ||
407 | for (i = 0; i < supp_band->n_channels; i++) | ||
408 | pos += scnprintf(buf + pos, bufsz - pos, | 410 | pos += scnprintf(buf + pos, bufsz - pos, |
409 | "%d: %ddBm: BSS%s%s, %s.\n", | 411 | "Displaying %d channels in 5.2GHz band (802.11a)\n", |
410 | ieee80211_frequency_to_channel( | 412 | supp_band->n_channels); |
411 | channels[i].center_freq), | ||
412 | channels[i].max_power, | ||
413 | channels[i].flags & IEEE80211_CHAN_RADAR ? | ||
414 | " (IEEE 802.11h required)" : "", | ||
415 | ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) | ||
416 | || (channels[i].flags & | ||
417 | IEEE80211_CHAN_RADAR)) ? "" : | ||
418 | ", IBSS", | ||
419 | channels[i].flags & | ||
420 | IEEE80211_CHAN_PASSIVE_SCAN ? | ||
421 | "passive only" : "active/passive"); | ||
422 | 413 | ||
414 | for (i = 0; i < supp_band->n_channels; i++) | ||
415 | pos += scnprintf(buf + pos, bufsz - pos, | ||
416 | "%d: %ddBm: BSS%s%s, %s.\n", | ||
417 | ieee80211_frequency_to_channel( | ||
418 | channels[i].center_freq), | ||
419 | channels[i].max_power, | ||
420 | channels[i].flags & IEEE80211_CHAN_RADAR ? | ||
421 | " (IEEE 802.11h required)" : "", | ||
422 | ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) | ||
423 | || (channels[i].flags & | ||
424 | IEEE80211_CHAN_RADAR)) ? "" : | ||
425 | ", IBSS", | ||
426 | channels[i].flags & | ||
427 | IEEE80211_CHAN_PASSIVE_SCAN ? | ||
428 | "passive only" : "active/passive"); | ||
429 | } | ||
423 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 430 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
424 | kfree(buf); | 431 | kfree(buf); |
425 | return ret; | 432 | return ret; |
@@ -564,7 +571,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, | |||
564 | 571 | ||
565 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 572 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
566 | DEBUGFS_WRITE_FILE_OPS(log_event); | 573 | DEBUGFS_WRITE_FILE_OPS(log_event); |
567 | DEBUGFS_READ_FILE_OPS(eeprom); | 574 | DEBUGFS_READ_FILE_OPS(nvm); |
568 | DEBUGFS_READ_FILE_OPS(stations); | 575 | DEBUGFS_READ_FILE_OPS(stations); |
569 | DEBUGFS_READ_FILE_OPS(rx_statistics); | 576 | DEBUGFS_READ_FILE_OPS(rx_statistics); |
570 | DEBUGFS_READ_FILE_OPS(tx_statistics); | 577 | DEBUGFS_READ_FILE_OPS(tx_statistics); |
@@ -598,7 +605,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
598 | 605 | ||
599 | DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); | 606 | DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); |
600 | DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); | 607 | DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv); |
601 | DEBUGFS_ADD_FILE(eeprom, data); | 608 | DEBUGFS_ADD_FILE(nvm, data); |
602 | DEBUGFS_ADD_FILE(sram, data); | 609 | DEBUGFS_ADD_FILE(sram, data); |
603 | DEBUGFS_ADD_FILE(log_event, data); | 610 | DEBUGFS_ADD_FILE(log_event, data); |
604 | DEBUGFS_ADD_FILE(stations, data); | 611 | DEBUGFS_ADD_FILE(stations, data); |
@@ -629,7 +636,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
629 | if (!priv->dbgfs) | 636 | if (!priv->dbgfs) |
630 | return; | 637 | return; |
631 | 638 | ||
632 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom); | 639 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_nvm); |
633 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); | 640 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics); |
634 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); | 641 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics); |
635 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); | 642 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 3049ba25c3fc..2dafc26fb6a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -382,6 +382,7 @@ struct iwl_rx_queue { | |||
382 | u32 read; | 382 | u32 read; |
383 | u32 write; | 383 | u32 write; |
384 | u32 free_count; | 384 | u32 free_count; |
385 | u32 write_actual; | ||
385 | struct list_head rx_free; | 386 | struct list_head rx_free; |
386 | struct list_head rx_used; | 387 | struct list_head rx_used; |
387 | int need_update; | 388 | int need_update; |
@@ -499,22 +500,13 @@ struct iwl_qos_info { | |||
499 | #define STA_PS_STATUS_WAKE 0 | 500 | #define STA_PS_STATUS_WAKE 0 |
500 | #define STA_PS_STATUS_SLEEP 1 | 501 | #define STA_PS_STATUS_SLEEP 1 |
501 | 502 | ||
502 | struct iwl3945_tid_data { | ||
503 | u16 seq_number; | ||
504 | }; | ||
505 | |||
506 | struct iwl3945_hw_key { | ||
507 | enum ieee80211_key_alg alg; | ||
508 | int keylen; | ||
509 | u8 key[32]; | ||
510 | }; | ||
511 | 503 | ||
512 | struct iwl3945_station_entry { | 504 | struct iwl3945_station_entry { |
513 | struct iwl3945_addsta_cmd sta; | 505 | struct iwl3945_addsta_cmd sta; |
514 | struct iwl3945_tid_data tid[MAX_TID_COUNT]; | 506 | struct iwl_tid_data tid[MAX_TID_COUNT]; |
515 | u8 used; | 507 | u8 used; |
516 | u8 ps_status; | 508 | u8 ps_status; |
517 | struct iwl3945_hw_key keyinfo; | 509 | struct iwl_hw_key keyinfo; |
518 | }; | 510 | }; |
519 | 511 | ||
520 | struct iwl_station_entry { | 512 | struct iwl_station_entry { |
@@ -823,6 +815,11 @@ enum { | |||
823 | MEASUREMENT_ACTIVE = (1 << 1), | 815 | MEASUREMENT_ACTIVE = (1 << 1), |
824 | }; | 816 | }; |
825 | 817 | ||
818 | enum iwl_nvm_type { | ||
819 | NVM_DEVICE_TYPE_EEPROM = 0, | ||
820 | NVM_DEVICE_TYPE_OTP, | ||
821 | }; | ||
822 | |||
826 | /* interrupt statistics */ | 823 | /* interrupt statistics */ |
827 | struct isr_statistics { | 824 | struct isr_statistics { |
828 | u32 hw; | 825 | u32 hw; |
@@ -900,6 +897,7 @@ struct iwl_priv { | |||
900 | /* spinlock */ | 897 | /* spinlock */ |
901 | spinlock_t lock; /* protect general shared data */ | 898 | spinlock_t lock; /* protect general shared data */ |
902 | spinlock_t hcmd_lock; /* protect hcmd */ | 899 | spinlock_t hcmd_lock; /* protect hcmd */ |
900 | spinlock_t reg_lock; /* protect hw register access */ | ||
903 | struct mutex mutex; | 901 | struct mutex mutex; |
904 | 902 | ||
905 | /* basic pci-network driver stuff */ | 903 | /* basic pci-network driver stuff */ |
@@ -1033,6 +1031,7 @@ struct iwl_priv { | |||
1033 | 1031 | ||
1034 | /* eeprom */ | 1032 | /* eeprom */ |
1035 | u8 *eeprom; | 1033 | u8 *eeprom; |
1034 | int nvm_device_type; | ||
1036 | struct iwl_eeprom_calib_info *calib_info; | 1035 | struct iwl_eeprom_calib_info *calib_info; |
1037 | 1036 | ||
1038 | enum nl80211_iftype iw_mode; | 1037 | enum nl80211_iftype iw_mode; |
@@ -1050,7 +1049,16 @@ struct iwl_priv { | |||
1050 | /*End*/ | 1049 | /*End*/ |
1051 | struct iwl_hw_params hw_params; | 1050 | struct iwl_hw_params hw_params; |
1052 | 1051 | ||
1052 | /* INT ICT Table */ | ||
1053 | u32 *ict_tbl; | ||
1054 | dma_addr_t ict_tbl_dma; | ||
1055 | dma_addr_t aligned_ict_tbl_dma; | ||
1056 | int ict_index; | ||
1057 | void *ict_tbl_vir; | ||
1058 | u32 inta; | ||
1059 | bool use_ict; | ||
1053 | 1060 | ||
1061 | u32 inta_mask; | ||
1054 | /* Current association information needed to configure the | 1062 | /* Current association information needed to configure the |
1055 | * hardware */ | 1063 | * hardware */ |
1056 | u16 assoc_id; | 1064 | u16 assoc_id; |
@@ -1105,7 +1113,7 @@ struct iwl_priv { | |||
1105 | u32 disable_tx_power_cal; | 1113 | u32 disable_tx_power_cal; |
1106 | struct work_struct run_time_calib_work; | 1114 | struct work_struct run_time_calib_work; |
1107 | struct timer_list statistics_periodic; | 1115 | struct timer_list statistics_periodic; |
1108 | 1116 | bool hw_ready; | |
1109 | /*For 3945*/ | 1117 | /*For 3945*/ |
1110 | #define IWL_DEFAULT_TX_POWER 0x0F | 1118 | #define IWL_DEFAULT_TX_POWER 0x0F |
1111 | 1119 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 401438aec19c..cefa501e5971 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c | |||
@@ -152,6 +152,32 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv) | |||
152 | } | 152 | } |
153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); | 153 | EXPORT_SYMBOL(iwlcore_eeprom_verify_signature); |
154 | 154 | ||
155 | static int iwlcore_get_nvm_type(struct iwl_priv *priv) | ||
156 | { | ||
157 | u32 otpgp; | ||
158 | int nvm_type; | ||
159 | |||
160 | /* OTP only valid for CP/PP and after */ | ||
161 | switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { | ||
162 | case CSR_HW_REV_TYPE_3945: | ||
163 | case CSR_HW_REV_TYPE_4965: | ||
164 | case CSR_HW_REV_TYPE_5300: | ||
165 | case CSR_HW_REV_TYPE_5350: | ||
166 | case CSR_HW_REV_TYPE_5100: | ||
167 | case CSR_HW_REV_TYPE_5150: | ||
168 | nvm_type = NVM_DEVICE_TYPE_EEPROM; | ||
169 | break; | ||
170 | default: | ||
171 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
172 | if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) | ||
173 | nvm_type = NVM_DEVICE_TYPE_OTP; | ||
174 | else | ||
175 | nvm_type = NVM_DEVICE_TYPE_EEPROM; | ||
176 | break; | ||
177 | } | ||
178 | return nvm_type; | ||
179 | } | ||
180 | |||
155 | /* | 181 | /* |
156 | * The device's EEPROM semaphore prevents conflicts between driver and uCode | 182 | * The device's EEPROM semaphore prevents conflicts between driver and uCode |
157 | * when accessing the EEPROM; each access is a series of pulses to/from the | 183 | * when accessing the EEPROM; each access is a series of pulses to/from the |
@@ -198,6 +224,33 @@ const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) | |||
198 | } | 224 | } |
199 | EXPORT_SYMBOL(iwlcore_eeprom_query_addr); | 225 | EXPORT_SYMBOL(iwlcore_eeprom_query_addr); |
200 | 226 | ||
227 | static int iwl_init_otp_access(struct iwl_priv *priv) | ||
228 | { | ||
229 | int ret; | ||
230 | |||
231 | /* Enable 40MHz radio clock */ | ||
232 | _iwl_write32(priv, CSR_GP_CNTRL, | ||
233 | _iwl_read32(priv, CSR_GP_CNTRL) | | ||
234 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | ||
235 | |||
236 | /* wait for clock to be ready */ | ||
237 | ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, | ||
238 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, | ||
239 | 25000); | ||
240 | if (ret < 0) | ||
241 | IWL_ERR(priv, "Time out access OTP\n"); | ||
242 | else { | ||
243 | if (!ret) { | ||
244 | iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, | ||
245 | APMG_PS_CTRL_VAL_RESET_REQ); | ||
246 | udelay(5); | ||
247 | iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, | ||
248 | APMG_PS_CTRL_VAL_RESET_REQ); | ||
249 | } | ||
250 | } | ||
251 | return ret; | ||
252 | } | ||
253 | |||
201 | /** | 254 | /** |
202 | * iwl_eeprom_init - read EEPROM contents | 255 | * iwl_eeprom_init - read EEPROM contents |
203 | * | 256 | * |
@@ -209,11 +262,18 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
209 | { | 262 | { |
210 | u16 *e; | 263 | u16 *e; |
211 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); | 264 | u32 gp = iwl_read32(priv, CSR_EEPROM_GP); |
212 | int sz = priv->cfg->eeprom_size; | 265 | int sz; |
213 | int ret; | 266 | int ret; |
214 | u16 addr; | 267 | u16 addr; |
268 | u32 otpgp; | ||
269 | |||
270 | priv->nvm_device_type = iwlcore_get_nvm_type(priv); | ||
215 | 271 | ||
216 | /* allocate eeprom */ | 272 | /* allocate eeprom */ |
273 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) | ||
274 | priv->cfg->eeprom_size = | ||
275 | OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL; | ||
276 | sz = priv->cfg->eeprom_size; | ||
217 | priv->eeprom = kzalloc(sz, GFP_KERNEL); | 277 | priv->eeprom = kzalloc(sz, GFP_KERNEL); |
218 | if (!priv->eeprom) { | 278 | if (!priv->eeprom) { |
219 | ret = -ENOMEM; | 279 | ret = -ENOMEM; |
@@ -235,30 +295,77 @@ int iwl_eeprom_init(struct iwl_priv *priv) | |||
235 | ret = -ENOENT; | 295 | ret = -ENOENT; |
236 | goto err; | 296 | goto err; |
237 | } | 297 | } |
238 | 298 | if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) { | |
239 | /* eeprom is an array of 16bit values */ | 299 | ret = iwl_init_otp_access(priv); |
240 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | 300 | if (ret) { |
241 | u32 r; | 301 | IWL_ERR(priv, "Failed to initialize OTP access.\n"); |
242 | 302 | ret = -ENOENT; | |
243 | _iwl_write32(priv, CSR_EEPROM_REG, | 303 | goto err; |
244 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | 304 | } |
245 | 305 | _iwl_write32(priv, CSR_EEPROM_GP, | |
246 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | 306 | iwl_read32(priv, CSR_EEPROM_GP) & |
247 | CSR_EEPROM_REG_READ_VALID_MSK, | 307 | ~CSR_EEPROM_GP_IF_OWNER_MSK); |
248 | IWL_EEPROM_ACCESS_TIMEOUT); | 308 | /* clear */ |
249 | if (ret < 0) { | 309 | _iwl_write32(priv, CSR_OTP_GP_REG, |
250 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); | 310 | iwl_read32(priv, CSR_OTP_GP_REG) | |
251 | goto done; | 311 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | |
312 | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); | ||
313 | |||
314 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | ||
315 | u32 r; | ||
316 | |||
317 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
318 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
319 | |||
320 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
321 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
322 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
323 | if (ret < 0) { | ||
324 | IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); | ||
325 | goto done; | ||
326 | } | ||
327 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
328 | /* check for ECC errors: */ | ||
329 | otpgp = iwl_read32(priv, CSR_OTP_GP_REG); | ||
330 | if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { | ||
331 | /* stop in this case */ | ||
332 | IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n"); | ||
333 | goto done; | ||
334 | } | ||
335 | if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { | ||
336 | /* continue in this case */ | ||
337 | _iwl_write32(priv, CSR_OTP_GP_REG, | ||
338 | iwl_read32(priv, CSR_OTP_GP_REG) | | ||
339 | CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); | ||
340 | IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); | ||
341 | } | ||
342 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
343 | } | ||
344 | } else { | ||
345 | /* eeprom is an array of 16bit values */ | ||
346 | for (addr = 0; addr < sz; addr += sizeof(u16)) { | ||
347 | u32 r; | ||
348 | |||
349 | _iwl_write32(priv, CSR_EEPROM_REG, | ||
350 | CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); | ||
351 | |||
352 | ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, | ||
353 | CSR_EEPROM_REG_READ_VALID_MSK, | ||
354 | IWL_EEPROM_ACCESS_TIMEOUT); | ||
355 | if (ret < 0) { | ||
356 | IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); | ||
357 | goto done; | ||
358 | } | ||
359 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
360 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
252 | } | 361 | } |
253 | r = _iwl_read_direct32(priv, CSR_EEPROM_REG); | ||
254 | e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); | ||
255 | } | 362 | } |
256 | ret = 0; | 363 | ret = 0; |
257 | done: | 364 | done: |
258 | priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); | 365 | priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); |
259 | err: | 366 | err: |
260 | if (ret) | 367 | if (ret) |
261 | kfree(priv->eeprom); | 368 | iwl_eeprom_free(priv); |
262 | alloc_err: | 369 | alloc_err: |
263 | return ret; | 370 | return ret; |
264 | } | 371 | } |
@@ -301,6 +408,8 @@ EXPORT_SYMBOL(iwl_eeprom_query_addr); | |||
301 | 408 | ||
302 | u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) | 409 | u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) |
303 | { | 410 | { |
411 | if (!priv->eeprom) | ||
412 | return 0; | ||
304 | return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); | 413 | return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); |
305 | } | 414 | } |
306 | EXPORT_SYMBOL(iwl_eeprom_query16); | 415 | EXPORT_SYMBOL(iwl_eeprom_query16); |
@@ -481,8 +590,8 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
481 | /* First write that fat is not enabled, and then enable | 590 | /* First write that fat is not enabled, and then enable |
482 | * one by one */ | 591 | * one by one */ |
483 | ch_info->fat_extension_channel = | 592 | ch_info->fat_extension_channel = |
484 | (IEEE80211_CHAN_NO_FAT_ABOVE | | 593 | (IEEE80211_CHAN_NO_HT40PLUS | |
485 | IEEE80211_CHAN_NO_FAT_BELOW); | 594 | IEEE80211_CHAN_NO_HT40MINUS); |
486 | 595 | ||
487 | if (!(is_channel_valid(ch_info))) { | 596 | if (!(is_channel_valid(ch_info))) { |
488 | IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " | 597 | IWL_DEBUG_INFO(priv, "Ch. %d Flags %x [%sGHz] - " |
@@ -561,7 +670,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
561 | fat_extension_chan = 0; | 670 | fat_extension_chan = 0; |
562 | else | 671 | else |
563 | fat_extension_chan = | 672 | fat_extension_chan = |
564 | IEEE80211_CHAN_NO_FAT_BELOW; | 673 | IEEE80211_CHAN_NO_HT40MINUS; |
565 | 674 | ||
566 | /* Set up driver's info for lower half */ | 675 | /* Set up driver's info for lower half */ |
567 | iwl_set_fat_chan_info(priv, ieeeband, | 676 | iwl_set_fat_chan_info(priv, ieeeband, |
@@ -573,7 +682,7 @@ int iwl_init_channel_map(struct iwl_priv *priv) | |||
573 | iwl_set_fat_chan_info(priv, ieeeband, | 682 | iwl_set_fat_chan_info(priv, ieeeband, |
574 | (eeprom_ch_index[ch] + 4), | 683 | (eeprom_ch_index[ch] + 4), |
575 | &(eeprom_ch_info[ch]), | 684 | &(eeprom_ch_info[ch]), |
576 | IEEE80211_CHAN_NO_FAT_ABOVE); | 685 | IEEE80211_CHAN_NO_HT40PLUS); |
577 | } | 686 | } |
578 | } | 687 | } |
579 | 688 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 3479153d96ca..195b4ef12c27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h | |||
@@ -179,6 +179,10 @@ struct iwl_eeprom_channel { | |||
179 | #define EEPROM_5050_TX_POWER_VERSION (4) | 179 | #define EEPROM_5050_TX_POWER_VERSION (4) |
180 | #define EEPROM_5050_EEPROM_VERSION (0x21E) | 180 | #define EEPROM_5050_EEPROM_VERSION (0x21E) |
181 | 181 | ||
182 | /* OTP */ | ||
183 | #define OTP_LOWER_BLOCKS_TOTAL (3) | ||
184 | #define OTP_BLOCK_SIZE (0x400) | ||
185 | |||
182 | /* 2.4 GHz */ | 186 | /* 2.4 GHz */ |
183 | extern const u8 iwl_eeprom_band_1[14]; | 187 | extern const u8 iwl_eeprom_band_1[14]; |
184 | 188 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 083ea1ffbe87..d30cb0275d19 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -131,9 +131,23 @@ static inline void __iwl_set_bit(const char *f, u32 l, | |||
131 | IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); | 131 | IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); |
132 | _iwl_write32(priv, reg, val); | 132 | _iwl_write32(priv, reg, val); |
133 | } | 133 | } |
134 | #define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) | 134 | static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) |
135 | { | ||
136 | unsigned long reg_flags; | ||
137 | |||
138 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
139 | __iwl_set_bit(__FILE__, __LINE__, p, r, m); | ||
140 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
141 | } | ||
135 | #else | 142 | #else |
136 | #define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) | 143 | static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m) |
144 | { | ||
145 | unsigned long reg_flags; | ||
146 | |||
147 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
148 | _iwl_set_bit(p, r, m); | ||
149 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
150 | } | ||
137 | #endif | 151 | #endif |
138 | 152 | ||
139 | static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) | 153 | static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) |
@@ -148,19 +162,30 @@ static inline void __iwl_clear_bit(const char *f, u32 l, | |||
148 | IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); | 162 | IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); |
149 | _iwl_write32(priv, reg, val); | 163 | _iwl_write32(priv, reg, val); |
150 | } | 164 | } |
151 | #define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) | 165 | static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) |
166 | { | ||
167 | unsigned long reg_flags; | ||
168 | |||
169 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
170 | __iwl_clear_bit(__FILE__, __LINE__, p, r, m); | ||
171 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
172 | } | ||
152 | #else | 173 | #else |
153 | #define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) | 174 | static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m) |
175 | { | ||
176 | unsigned long reg_flags; | ||
177 | |||
178 | spin_lock_irqsave(&p->reg_lock, reg_flags); | ||
179 | _iwl_clear_bit(p, r, m); | ||
180 | spin_unlock_irqrestore(&p->reg_lock, reg_flags); | ||
181 | } | ||
154 | #endif | 182 | #endif |
155 | 183 | ||
156 | static inline int _iwl_grab_nic_access(struct iwl_priv *priv) | 184 | static inline int _iwl_grab_nic_access(struct iwl_priv *priv) |
157 | { | 185 | { |
158 | int ret; | 186 | int ret; |
159 | u32 val; | 187 | u32 val; |
160 | #ifdef CONFIG_IWLWIFI_DEBUG | 188 | |
161 | if (atomic_read(&priv->restrict_refcnt)) | ||
162 | return 0; | ||
163 | #endif | ||
164 | /* this bit wakes up the NIC */ | 189 | /* this bit wakes up the NIC */ |
165 | _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | 190 | _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
166 | ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, | 191 | ret = _iwl_poll_bit(priv, CSR_GP_CNTRL, |
@@ -170,12 +195,10 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) | |||
170 | if (ret < 0) { | 195 | if (ret < 0) { |
171 | val = _iwl_read32(priv, CSR_GP_CNTRL); | 196 | val = _iwl_read32(priv, CSR_GP_CNTRL); |
172 | IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); | 197 | IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); |
198 | _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); | ||
173 | return -EIO; | 199 | return -EIO; |
174 | } | 200 | } |
175 | 201 | ||
176 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
177 | atomic_inc(&priv->restrict_refcnt); | ||
178 | #endif | ||
179 | return 0; | 202 | return 0; |
180 | } | 203 | } |
181 | 204 | ||
@@ -183,9 +206,6 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv) | |||
183 | static inline int __iwl_grab_nic_access(const char *f, u32 l, | 206 | static inline int __iwl_grab_nic_access(const char *f, u32 l, |
184 | struct iwl_priv *priv) | 207 | struct iwl_priv *priv) |
185 | { | 208 | { |
186 | if (atomic_read(&priv->restrict_refcnt)) | ||
187 | IWL_ERR(priv, "Grabbing access while already held %s %d.\n", f, l); | ||
188 | |||
189 | IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); | 209 | IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l); |
190 | return _iwl_grab_nic_access(priv); | 210 | return _iwl_grab_nic_access(priv); |
191 | } | 211 | } |
@@ -198,18 +218,13 @@ static inline int __iwl_grab_nic_access(const char *f, u32 l, | |||
198 | 218 | ||
199 | static inline void _iwl_release_nic_access(struct iwl_priv *priv) | 219 | static inline void _iwl_release_nic_access(struct iwl_priv *priv) |
200 | { | 220 | { |
201 | #ifdef CONFIG_IWLWIFI_DEBUG | 221 | _iwl_clear_bit(priv, CSR_GP_CNTRL, |
202 | if (atomic_dec_and_test(&priv->restrict_refcnt)) | 222 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); |
203 | #endif | ||
204 | _iwl_clear_bit(priv, CSR_GP_CNTRL, | ||
205 | CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); | ||
206 | } | 223 | } |
207 | #ifdef CONFIG_IWLWIFI_DEBUG | 224 | #ifdef CONFIG_IWLWIFI_DEBUG |
208 | static inline void __iwl_release_nic_access(const char *f, u32 l, | 225 | static inline void __iwl_release_nic_access(const char *f, u32 l, |
209 | struct iwl_priv *priv) | 226 | struct iwl_priv *priv) |
210 | { | 227 | { |
211 | if (atomic_read(&priv->restrict_refcnt) <= 0) | ||
212 | IWL_ERR(priv, "Release unheld nic access at line %s %d.\n", f, l); | ||
213 | 228 | ||
214 | IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); | 229 | IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l); |
215 | _iwl_release_nic_access(priv); | 230 | _iwl_release_nic_access(priv); |
@@ -230,16 +245,37 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l, | |||
230 | struct iwl_priv *priv, u32 reg) | 245 | struct iwl_priv *priv, u32 reg) |
231 | { | 246 | { |
232 | u32 value = _iwl_read_direct32(priv, reg); | 247 | u32 value = _iwl_read_direct32(priv, reg); |
233 | if (!atomic_read(&priv->restrict_refcnt)) | ||
234 | IWL_ERR(priv, "Nic access not held from %s %d\n", f, l); | ||
235 | IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, | 248 | IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, |
236 | f, l); | 249 | f, l); |
237 | return value; | 250 | return value; |
238 | } | 251 | } |
239 | #define iwl_read_direct32(priv, reg) \ | 252 | static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) |
240 | __iwl_read_direct32(__FILE__, __LINE__, priv, reg) | 253 | { |
254 | u32 value; | ||
255 | unsigned long reg_flags; | ||
256 | |||
257 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
258 | iwl_grab_nic_access(priv); | ||
259 | value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg); | ||
260 | iwl_release_nic_access(priv); | ||
261 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
262 | return value; | ||
263 | } | ||
264 | |||
241 | #else | 265 | #else |
242 | #define iwl_read_direct32 _iwl_read_direct32 | 266 | static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) |
267 | { | ||
268 | u32 value; | ||
269 | unsigned long reg_flags; | ||
270 | |||
271 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
272 | iwl_grab_nic_access(priv); | ||
273 | value = _iwl_read_direct32(priv, reg); | ||
274 | iwl_release_nic_access(priv); | ||
275 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
276 | return value; | ||
277 | |||
278 | } | ||
243 | #endif | 279 | #endif |
244 | 280 | ||
245 | static inline void _iwl_write_direct32(struct iwl_priv *priv, | 281 | static inline void _iwl_write_direct32(struct iwl_priv *priv, |
@@ -247,19 +283,17 @@ static inline void _iwl_write_direct32(struct iwl_priv *priv, | |||
247 | { | 283 | { |
248 | _iwl_write32(priv, reg, value); | 284 | _iwl_write32(priv, reg, value); |
249 | } | 285 | } |
250 | #ifdef CONFIG_IWLWIFI_DEBUG | 286 | static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) |
251 | static void __iwl_write_direct32(const char *f , u32 line, | ||
252 | struct iwl_priv *priv, u32 reg, u32 value) | ||
253 | { | 287 | { |
254 | if (!atomic_read(&priv->restrict_refcnt)) | 288 | unsigned long reg_flags; |
255 | IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); | 289 | |
256 | _iwl_write_direct32(priv, reg, value); | 290 | spin_lock_irqsave(&priv->reg_lock, reg_flags); |
291 | if (!iwl_grab_nic_access(priv)) { | ||
292 | _iwl_write_direct32(priv, reg, value); | ||
293 | iwl_release_nic_access(priv); | ||
294 | } | ||
295 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
257 | } | 296 | } |
258 | #define iwl_write_direct32(priv, reg, value) \ | ||
259 | __iwl_write_direct32(__func__, __LINE__, priv, reg, value) | ||
260 | #else | ||
261 | #define iwl_write_direct32 _iwl_write_direct32 | ||
262 | #endif | ||
263 | 297 | ||
264 | static inline void iwl_write_reg_buf(struct iwl_priv *priv, | 298 | static inline void iwl_write_reg_buf(struct iwl_priv *priv, |
265 | u32 reg, u32 len, u32 *values) | 299 | u32 reg, u32 len, u32 *values) |
@@ -268,14 +302,23 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, | |||
268 | 302 | ||
269 | if ((priv != NULL) && (values != NULL)) { | 303 | if ((priv != NULL) && (values != NULL)) { |
270 | for (; 0 < len; len -= count, reg += count, values++) | 304 | for (; 0 < len; len -= count, reg += count, values++) |
271 | _iwl_write_direct32(priv, reg, *values); | 305 | iwl_write_direct32(priv, reg, *values); |
272 | } | 306 | } |
273 | } | 307 | } |
274 | 308 | ||
275 | static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, | 309 | static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, |
276 | u32 mask, int timeout) | 310 | u32 mask, int timeout) |
277 | { | 311 | { |
278 | return _iwl_poll_bit(priv, addr, mask, mask, timeout); | 312 | int t = 0; |
313 | |||
314 | do { | ||
315 | if ((iwl_read_direct32(priv, addr) & mask) == mask) | ||
316 | return t; | ||
317 | udelay(IWL_POLL_INTERVAL); | ||
318 | t += IWL_POLL_INTERVAL; | ||
319 | } while (t < timeout); | ||
320 | |||
321 | return -ETIMEDOUT; | ||
279 | } | 322 | } |
280 | 323 | ||
281 | #ifdef CONFIG_IWLWIFI_DEBUG | 324 | #ifdef CONFIG_IWLWIFI_DEBUG |
@@ -305,20 +348,18 @@ static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) | |||
305 | rmb(); | 348 | rmb(); |
306 | return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); | 349 | return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); |
307 | } | 350 | } |
308 | #ifdef CONFIG_IWLWIFI_DEBUG | 351 | static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) |
309 | static inline u32 __iwl_read_prph(const char *f, u32 line, | ||
310 | struct iwl_priv *priv, u32 reg) | ||
311 | { | 352 | { |
312 | if (!atomic_read(&priv->restrict_refcnt)) | 353 | unsigned long reg_flags; |
313 | IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); | 354 | u32 val; |
314 | return _iwl_read_prph(priv, reg); | ||
315 | } | ||
316 | 355 | ||
317 | #define iwl_read_prph(priv, reg) \ | 356 | spin_lock_irqsave(&priv->reg_lock, reg_flags); |
318 | __iwl_read_prph(__func__, __LINE__, priv, reg) | 357 | iwl_grab_nic_access(priv); |
319 | #else | 358 | val = _iwl_read_prph(priv, reg); |
320 | #define iwl_read_prph _iwl_read_prph | 359 | iwl_release_nic_access(priv); |
321 | #endif | 360 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); |
361 | return val; | ||
362 | } | ||
322 | 363 | ||
323 | static inline void _iwl_write_prph(struct iwl_priv *priv, | 364 | static inline void _iwl_write_prph(struct iwl_priv *priv, |
324 | u32 addr, u32 val) | 365 | u32 addr, u32 val) |
@@ -328,83 +369,107 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, | |||
328 | wmb(); | 369 | wmb(); |
329 | _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); | 370 | _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); |
330 | } | 371 | } |
331 | #ifdef CONFIG_IWLWIFI_DEBUG | 372 | |
332 | static inline void __iwl_write_prph(const char *f, u32 line, | 373 | static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) |
333 | struct iwl_priv *priv, u32 addr, u32 val) | ||
334 | { | 374 | { |
335 | if (!atomic_read(&priv->restrict_refcnt)) | 375 | unsigned long reg_flags; |
336 | IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); | ||
337 | _iwl_write_prph(priv, addr, val); | ||
338 | } | ||
339 | 376 | ||
340 | #define iwl_write_prph(priv, addr, val) \ | 377 | spin_lock_irqsave(&priv->reg_lock, reg_flags); |
341 | __iwl_write_prph(__func__, __LINE__, priv, addr, val); | 378 | if (!iwl_grab_nic_access(priv)) { |
342 | #else | 379 | _iwl_write_prph(priv, addr, val); |
343 | #define iwl_write_prph _iwl_write_prph | 380 | iwl_release_nic_access(priv); |
344 | #endif | 381 | } |
382 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
383 | } | ||
345 | 384 | ||
346 | #define _iwl_set_bits_prph(priv, reg, mask) \ | 385 | #define _iwl_set_bits_prph(priv, reg, mask) \ |
347 | _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) | 386 | _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask)) |
348 | #ifdef CONFIG_IWLWIFI_DEBUG | 387 | |
349 | static inline void __iwl_set_bits_prph(const char *f, u32 line, | 388 | static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) |
350 | struct iwl_priv *priv, | ||
351 | u32 reg, u32 mask) | ||
352 | { | 389 | { |
353 | if (!atomic_read(&priv->restrict_refcnt)) | 390 | unsigned long reg_flags; |
354 | IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); | ||
355 | 391 | ||
392 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
393 | iwl_grab_nic_access(priv); | ||
356 | _iwl_set_bits_prph(priv, reg, mask); | 394 | _iwl_set_bits_prph(priv, reg, mask); |
395 | iwl_release_nic_access(priv); | ||
396 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
357 | } | 397 | } |
358 | #define iwl_set_bits_prph(priv, reg, mask) \ | ||
359 | __iwl_set_bits_prph(__func__, __LINE__, priv, reg, mask) | ||
360 | #else | ||
361 | #define iwl_set_bits_prph _iwl_set_bits_prph | ||
362 | #endif | ||
363 | 398 | ||
364 | #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ | 399 | #define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \ |
365 | _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) | 400 | _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits)) |
366 | 401 | ||
367 | #ifdef CONFIG_IWLWIFI_DEBUG | 402 | static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, |
368 | static inline void __iwl_set_bits_mask_prph(const char *f, u32 line, | 403 | u32 bits, u32 mask) |
369 | struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) | ||
370 | { | 404 | { |
371 | if (!atomic_read(&priv->restrict_refcnt)) | 405 | unsigned long reg_flags; |
372 | IWL_ERR(priv, "Nic access not held from %s line %d\n", f, line); | 406 | |
407 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
408 | iwl_grab_nic_access(priv); | ||
373 | _iwl_set_bits_mask_prph(priv, reg, bits, mask); | 409 | _iwl_set_bits_mask_prph(priv, reg, bits, mask); |
410 | iwl_release_nic_access(priv); | ||
411 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
374 | } | 412 | } |
375 | #define iwl_set_bits_mask_prph(priv, reg, bits, mask) \ | ||
376 | __iwl_set_bits_mask_prph(__func__, __LINE__, priv, reg, bits, mask) | ||
377 | #else | ||
378 | #define iwl_set_bits_mask_prph _iwl_set_bits_mask_prph | ||
379 | #endif | ||
380 | 413 | ||
381 | static inline void iwl_clear_bits_prph(struct iwl_priv | 414 | static inline void iwl_clear_bits_prph(struct iwl_priv |
382 | *priv, u32 reg, u32 mask) | 415 | *priv, u32 reg, u32 mask) |
383 | { | 416 | { |
384 | u32 val = _iwl_read_prph(priv, reg); | 417 | unsigned long reg_flags; |
418 | u32 val; | ||
419 | |||
420 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
421 | iwl_grab_nic_access(priv); | ||
422 | val = _iwl_read_prph(priv, reg); | ||
385 | _iwl_write_prph(priv, reg, (val & ~mask)); | 423 | _iwl_write_prph(priv, reg, (val & ~mask)); |
424 | iwl_release_nic_access(priv); | ||
425 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
386 | } | 426 | } |
387 | 427 | ||
388 | static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) | 428 | static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) |
389 | { | 429 | { |
390 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); | 430 | unsigned long reg_flags; |
431 | u32 value; | ||
432 | |||
433 | spin_lock_irqsave(&priv->reg_lock, reg_flags); | ||
434 | iwl_grab_nic_access(priv); | ||
435 | |||
436 | _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); | ||
391 | rmb(); | 437 | rmb(); |
392 | return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | 438 | value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); |
439 | |||
440 | iwl_release_nic_access(priv); | ||
441 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
442 | return value; | ||
393 | } | 443 | } |
394 | 444 | ||
395 | static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) | 445 | static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) |
396 | { | 446 | { |
397 | iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | 447 | unsigned long reg_flags; |
398 | wmb(); | 448 | |
399 | iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); | 449 | spin_lock_irqsave(&priv->reg_lock, reg_flags); |
450 | if (!iwl_grab_nic_access(priv)) { | ||
451 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | ||
452 | wmb(); | ||
453 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); | ||
454 | iwl_release_nic_access(priv); | ||
455 | } | ||
456 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
400 | } | 457 | } |
401 | 458 | ||
402 | static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, | 459 | static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, |
403 | u32 len, u32 *values) | 460 | u32 len, u32 *values) |
404 | { | 461 | { |
405 | iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | 462 | unsigned long reg_flags; |
406 | wmb(); | 463 | |
407 | for (; 0 < len; len -= sizeof(u32), values++) | 464 | spin_lock_irqsave(&priv->reg_lock, reg_flags); |
408 | iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); | 465 | if (!iwl_grab_nic_access(priv)) { |
466 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); | ||
467 | wmb(); | ||
468 | for (; 0 < len; len -= sizeof(u32), values++) | ||
469 | _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); | ||
470 | |||
471 | iwl_release_nic_access(priv); | ||
472 | } | ||
473 | spin_unlock_irqrestore(&priv->reg_lock, reg_flags); | ||
409 | } | 474 | } |
410 | #endif | 475 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index fae84262efb6..2b8d40b37a1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -145,18 +145,14 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) | |||
145 | goto exit_unlock; | 145 | goto exit_unlock; |
146 | } | 146 | } |
147 | 147 | ||
148 | ret = iwl_grab_nic_access(priv); | 148 | q->write_actual = (q->write & ~0x7); |
149 | if (ret) | 149 | iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); |
150 | goto exit_unlock; | ||
151 | |||
152 | /* Device expects a multiple of 8 */ | ||
153 | iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7); | ||
154 | iwl_release_nic_access(priv); | ||
155 | 150 | ||
156 | /* Else device is assumed to be awake */ | 151 | /* Else device is assumed to be awake */ |
157 | } else { | 152 | } else { |
158 | /* Device expects a multiple of 8 */ | 153 | /* Device expects a multiple of 8 */ |
159 | iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7); | 154 | q->write_actual = (q->write & ~0x7); |
155 | iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); | ||
160 | } | 156 | } |
161 | 157 | ||
162 | q->need_update = 0; | 158 | q->need_update = 0; |
@@ -218,7 +214,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) | |||
218 | 214 | ||
219 | /* If we've added more space for the firmware to place data, tell it. | 215 | /* If we've added more space for the firmware to place data, tell it. |
220 | * Increment device's write pointer in multiples of 8. */ | 216 | * Increment device's write pointer in multiples of 8. */ |
221 | if (write != (rxq->write & ~0x7)) { | 217 | if (rxq->write_actual != (rxq->write & ~0x7)) { |
222 | spin_lock_irqsave(&rxq->lock, flags); | 218 | spin_lock_irqsave(&rxq->lock, flags); |
223 | rxq->need_update = 1; | 219 | rxq->need_update = 1; |
224 | spin_unlock_irqrestore(&rxq->lock, flags); | 220 | spin_unlock_irqrestore(&rxq->lock, flags); |
@@ -238,7 +234,7 @@ EXPORT_SYMBOL(iwl_rx_queue_restock); | |||
238 | * Also restock the Rx queue via iwl_rx_queue_restock. | 234 | * Also restock the Rx queue via iwl_rx_queue_restock. |
239 | * This is called as a scheduled work item (except for during initialization) | 235 | * This is called as a scheduled work item (except for during initialization) |
240 | */ | 236 | */ |
241 | void iwl_rx_allocate(struct iwl_priv *priv) | 237 | void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) |
242 | { | 238 | { |
243 | struct iwl_rx_queue *rxq = &priv->rxq; | 239 | struct iwl_rx_queue *rxq = &priv->rxq; |
244 | struct list_head *element; | 240 | struct list_head *element; |
@@ -260,7 +256,8 @@ void iwl_rx_allocate(struct iwl_priv *priv) | |||
260 | 256 | ||
261 | /* Alloc a new receive buffer */ | 257 | /* Alloc a new receive buffer */ |
262 | rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, | 258 | rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, |
263 | GFP_KERNEL); | 259 | priority); |
260 | |||
264 | if (!rxb->skb) { | 261 | if (!rxb->skb) { |
265 | IWL_CRIT(priv, "Can not allocate SKB buffers\n"); | 262 | IWL_CRIT(priv, "Can not allocate SKB buffers\n"); |
266 | /* We don't reschedule replenish work here -- we will | 263 | /* We don't reschedule replenish work here -- we will |
@@ -295,7 +292,7 @@ void iwl_rx_replenish(struct iwl_priv *priv) | |||
295 | { | 292 | { |
296 | unsigned long flags; | 293 | unsigned long flags; |
297 | 294 | ||
298 | iwl_rx_allocate(priv); | 295 | iwl_rx_allocate(priv, GFP_KERNEL); |
299 | 296 | ||
300 | spin_lock_irqsave(&priv->lock, flags); | 297 | spin_lock_irqsave(&priv->lock, flags); |
301 | iwl_rx_queue_restock(priv); | 298 | iwl_rx_queue_restock(priv); |
@@ -303,6 +300,14 @@ void iwl_rx_replenish(struct iwl_priv *priv) | |||
303 | } | 300 | } |
304 | EXPORT_SYMBOL(iwl_rx_replenish); | 301 | EXPORT_SYMBOL(iwl_rx_replenish); |
305 | 302 | ||
303 | void iwl_rx_replenish_now(struct iwl_priv *priv) | ||
304 | { | ||
305 | iwl_rx_allocate(priv, GFP_ATOMIC); | ||
306 | |||
307 | iwl_rx_queue_restock(priv); | ||
308 | } | ||
309 | EXPORT_SYMBOL(iwl_rx_replenish_now); | ||
310 | |||
306 | 311 | ||
307 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. | 312 | /* Assumes that the skb field of the buffers in 'pool' is kept accurate. |
308 | * If an SKB has been detached, the POOL needs to have its SKB set to NULL | 313 | * If an SKB has been detached, the POOL needs to have its SKB set to NULL |
@@ -358,6 +363,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) | |||
358 | /* Set us so that we have processed and used all buffers, but have | 363 | /* Set us so that we have processed and used all buffers, but have |
359 | * not restocked the Rx queue with fresh buffers */ | 364 | * not restocked the Rx queue with fresh buffers */ |
360 | rxq->read = rxq->write = 0; | 365 | rxq->read = rxq->write = 0; |
366 | rxq->write_actual = 0; | ||
361 | rxq->free_count = 0; | 367 | rxq->free_count = 0; |
362 | rxq->need_update = 0; | 368 | rxq->need_update = 0; |
363 | return 0; | 369 | return 0; |
@@ -396,6 +402,7 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
396 | /* Set us so that we have processed and used all buffers, but have | 402 | /* Set us so that we have processed and used all buffers, but have |
397 | * not restocked the Rx queue with fresh buffers */ | 403 | * not restocked the Rx queue with fresh buffers */ |
398 | rxq->read = rxq->write = 0; | 404 | rxq->read = rxq->write = 0; |
405 | rxq->write_actual = 0; | ||
399 | rxq->free_count = 0; | 406 | rxq->free_count = 0; |
400 | spin_unlock_irqrestore(&rxq->lock, flags); | 407 | spin_unlock_irqrestore(&rxq->lock, flags); |
401 | } | 408 | } |
@@ -403,18 +410,12 @@ EXPORT_SYMBOL(iwl_rx_queue_reset); | |||
403 | 410 | ||
404 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | 411 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) |
405 | { | 412 | { |
406 | int ret; | ||
407 | unsigned long flags; | ||
408 | u32 rb_size; | 413 | u32 rb_size; |
409 | const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ | 414 | const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ |
410 | const u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT why this stalls RX */ | 415 | u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ |
411 | 416 | ||
412 | spin_lock_irqsave(&priv->lock, flags); | 417 | if (!priv->cfg->use_isr_legacy) |
413 | ret = iwl_grab_nic_access(priv); | 418 | rb_timeout = RX_RB_TIMEOUT; |
414 | if (ret) { | ||
415 | spin_unlock_irqrestore(&priv->lock, flags); | ||
416 | return ret; | ||
417 | } | ||
418 | 419 | ||
419 | if (priv->cfg->mod_params->amsdu_size_8K) | 420 | if (priv->cfg->mod_params->amsdu_size_8K) |
420 | rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; | 421 | rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; |
@@ -452,35 +453,19 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) | |||
452 | (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| | 453 | (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| |
453 | (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); | 454 | (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); |
454 | 455 | ||
455 | iwl_release_nic_access(priv); | ||
456 | |||
457 | iwl_write32(priv, CSR_INT_COALESCING, 0x40); | 456 | iwl_write32(priv, CSR_INT_COALESCING, 0x40); |
458 | 457 | ||
459 | spin_unlock_irqrestore(&priv->lock, flags); | ||
460 | |||
461 | return 0; | 458 | return 0; |
462 | } | 459 | } |
463 | 460 | ||
464 | int iwl_rxq_stop(struct iwl_priv *priv) | 461 | int iwl_rxq_stop(struct iwl_priv *priv) |
465 | { | 462 | { |
466 | int ret; | ||
467 | unsigned long flags; | ||
468 | |||
469 | spin_lock_irqsave(&priv->lock, flags); | ||
470 | ret = iwl_grab_nic_access(priv); | ||
471 | if (unlikely(ret)) { | ||
472 | spin_unlock_irqrestore(&priv->lock, flags); | ||
473 | return ret; | ||
474 | } | ||
475 | 463 | ||
476 | /* stop Rx DMA */ | 464 | /* stop Rx DMA */ |
477 | iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); | 465 | iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); |
478 | iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, | 466 | iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, |
479 | FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); | 467 | FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); |
480 | 468 | ||
481 | iwl_release_nic_access(priv); | ||
482 | spin_unlock_irqrestore(&priv->lock, flags); | ||
483 | |||
484 | return 0; | 469 | return 0; |
485 | } | 470 | } |
486 | EXPORT_SYMBOL(iwl_rxq_stop); | 471 | EXPORT_SYMBOL(iwl_rxq_stop); |
@@ -582,8 +567,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
582 | 567 | ||
583 | iwl_leds_background(priv); | 568 | iwl_leds_background(priv); |
584 | 569 | ||
585 | if (priv->cfg->ops->lib->temperature && change) | 570 | if (priv->cfg->ops->lib->temp_ops.temperature && change) |
586 | priv->cfg->ops->lib->temperature(priv); | 571 | priv->cfg->ops->lib->temp_ops.temperature(priv); |
587 | } | 572 | } |
588 | EXPORT_SYMBOL(iwl_rx_statistics); | 573 | EXPORT_SYMBOL(iwl_rx_statistics); |
589 | 574 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 065214b55895..f6d4af5c7509 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -586,6 +586,7 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
586 | u8 rx_ant = priv->hw_params.valid_rx_ant; | 586 | u8 rx_ant = priv->hw_params.valid_rx_ant; |
587 | u8 rate; | 587 | u8 rate; |
588 | bool is_active = false; | 588 | bool is_active = false; |
589 | int chan_mod; | ||
589 | 590 | ||
590 | conf = ieee80211_get_hw_conf(priv->hw); | 591 | conf = ieee80211_get_hw_conf(priv->hw); |
591 | 592 | ||
@@ -703,7 +704,9 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
703 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { | 704 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { |
704 | band = IEEE80211_BAND_2GHZ; | 705 | band = IEEE80211_BAND_2GHZ; |
705 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; | 706 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; |
706 | if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { | 707 | chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) |
708 | >> RXON_FLG_CHANNEL_MODE_POS; | ||
709 | if (chan_mod == CHANNEL_MODE_PURE_40) { | ||
707 | rate = IWL_RATE_6M_PLCP; | 710 | rate = IWL_RATE_6M_PLCP; |
708 | } else { | 711 | } else { |
709 | rate = IWL_RATE_1M_PLCP; | 712 | rate = IWL_RATE_1M_PLCP; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index a82cca0a30c7..85ae7a62109c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -102,13 +102,8 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
102 | return ret; | 102 | return ret; |
103 | } | 103 | } |
104 | 104 | ||
105 | /* restore this queue's parameters in nic hardware. */ | ||
106 | ret = iwl_grab_nic_access(priv); | ||
107 | if (ret) | ||
108 | return ret; | ||
109 | iwl_write_direct32(priv, HBUS_TARG_WRPTR, | 105 | iwl_write_direct32(priv, HBUS_TARG_WRPTR, |
110 | txq->q.write_ptr | (txq_id << 8)); | 106 | txq->q.write_ptr | (txq_id << 8)); |
111 | iwl_release_nic_access(priv); | ||
112 | 107 | ||
113 | /* else not in power-save mode, uCode will never sleep when we're | 108 | /* else not in power-save mode, uCode will never sleep when we're |
114 | * trying to tx (during RFKILL, we're not trying to tx). */ | 109 | * trying to tx (during RFKILL, we're not trying to tx). */ |
@@ -429,11 +424,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) | |||
429 | goto error_kw; | 424 | goto error_kw; |
430 | } | 425 | } |
431 | spin_lock_irqsave(&priv->lock, flags); | 426 | spin_lock_irqsave(&priv->lock, flags); |
432 | ret = iwl_grab_nic_access(priv); | ||
433 | if (unlikely(ret)) { | ||
434 | spin_unlock_irqrestore(&priv->lock, flags); | ||
435 | goto error_reset; | ||
436 | } | ||
437 | 427 | ||
438 | /* Turn off all Tx DMA fifos */ | 428 | /* Turn off all Tx DMA fifos */ |
439 | priv->cfg->ops->lib->txq_set_sched(priv, 0); | 429 | priv->cfg->ops->lib->txq_set_sched(priv, 0); |
@@ -441,7 +431,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) | |||
441 | /* Tell NIC where to find the "keep warm" buffer */ | 431 | /* Tell NIC where to find the "keep warm" buffer */ |
442 | iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); | 432 | iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); |
443 | 433 | ||
444 | iwl_release_nic_access(priv); | ||
445 | spin_unlock_irqrestore(&priv->lock, flags); | 434 | spin_unlock_irqrestore(&priv->lock, flags); |
446 | 435 | ||
447 | /* Alloc and init all Tx queues, including the command queue (#4) */ | 436 | /* Alloc and init all Tx queues, including the command queue (#4) */ |
@@ -460,7 +449,6 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) | |||
460 | 449 | ||
461 | error: | 450 | error: |
462 | iwl_hw_txq_ctx_free(priv); | 451 | iwl_hw_txq_ctx_free(priv); |
463 | error_reset: | ||
464 | iwl_free_dma_ptr(priv, &priv->kw); | 452 | iwl_free_dma_ptr(priv, &priv->kw); |
465 | error_kw: | 453 | error_kw: |
466 | iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); | 454 | iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); |
@@ -478,10 +466,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) | |||
478 | 466 | ||
479 | /* Turn off all Tx DMA fifos */ | 467 | /* Turn off all Tx DMA fifos */ |
480 | spin_lock_irqsave(&priv->lock, flags); | 468 | spin_lock_irqsave(&priv->lock, flags); |
481 | if (iwl_grab_nic_access(priv)) { | ||
482 | spin_unlock_irqrestore(&priv->lock, flags); | ||
483 | return; | ||
484 | } | ||
485 | 469 | ||
486 | priv->cfg->ops->lib->txq_set_sched(priv, 0); | 470 | priv->cfg->ops->lib->txq_set_sched(priv, 0); |
487 | 471 | ||
@@ -492,7 +476,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) | |||
492 | FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), | 476 | FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), |
493 | 1000); | 477 | 1000); |
494 | } | 478 | } |
495 | iwl_release_nic_access(priv); | ||
496 | spin_unlock_irqrestore(&priv->lock, flags); | 479 | spin_unlock_irqrestore(&priv->lock, flags); |
497 | 480 | ||
498 | /* Deallocate memory for all Tx queues */ | 481 | /* Deallocate memory for all Tx queues */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index c32ec809053f..c434f493daf5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -340,7 +340,7 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) | |||
340 | unsigned long flags; | 340 | unsigned long flags; |
341 | 341 | ||
342 | spin_lock_irqsave(&priv->sta_lock, flags); | 342 | spin_lock_irqsave(&priv->sta_lock, flags); |
343 | memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key)); | 343 | memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); |
344 | memset(&priv->stations_39[sta_id].sta.key, 0, | 344 | memset(&priv->stations_39[sta_id].sta.key, 0, |
345 | sizeof(struct iwl4965_keyinfo)); | 345 | sizeof(struct iwl4965_keyinfo)); |
346 | priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; | 346 | priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; |
@@ -578,8 +578,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv, | |||
578 | int sta_id) | 578 | int sta_id) |
579 | { | 579 | { |
580 | struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; | 580 | struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload; |
581 | struct iwl3945_hw_key *keyinfo = | 581 | struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo; |
582 | &priv->stations_39[sta_id].keyinfo; | ||
583 | 582 | ||
584 | switch (keyinfo->alg) { | 583 | switch (keyinfo->alg) { |
585 | case ALG_CCMP: | 584 | case ALG_CCMP: |
@@ -1687,7 +1686,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) | |||
1687 | u32 i; | 1686 | u32 i; |
1688 | u32 desc, time, count, base, data1; | 1687 | u32 desc, time, count, base, data1; |
1689 | u32 blink1, blink2, ilink1, ilink2; | 1688 | u32 blink1, blink2, ilink1, ilink2; |
1690 | int rc; | ||
1691 | 1689 | ||
1692 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); | 1690 | base = le32_to_cpu(priv->card_alive.error_event_table_ptr); |
1693 | 1691 | ||
@@ -1696,11 +1694,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) | |||
1696 | return; | 1694 | return; |
1697 | } | 1695 | } |
1698 | 1696 | ||
1699 | rc = iwl_grab_nic_access(priv); | ||
1700 | if (rc) { | ||
1701 | IWL_WARN(priv, "Can not read from adapter at this time.\n"); | ||
1702 | return; | ||
1703 | } | ||
1704 | 1697 | ||
1705 | count = iwl_read_targ_mem(priv, base); | 1698 | count = iwl_read_targ_mem(priv, base); |
1706 | 1699 | ||
@@ -1735,8 +1728,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) | |||
1735 | ilink1, ilink2, data1); | 1728 | ilink1, ilink2, data1); |
1736 | } | 1729 | } |
1737 | 1730 | ||
1738 | iwl_release_nic_access(priv); | ||
1739 | |||
1740 | } | 1731 | } |
1741 | 1732 | ||
1742 | #define EVENT_START_OFFSET (6 * sizeof(u32)) | 1733 | #define EVENT_START_OFFSET (6 * sizeof(u32)) |
@@ -1744,7 +1735,6 @@ static void iwl3945_dump_nic_error_log(struct iwl_priv *priv) | |||
1744 | /** | 1735 | /** |
1745 | * iwl3945_print_event_log - Dump error event log to syslog | 1736 | * iwl3945_print_event_log - Dump error event log to syslog |
1746 | * | 1737 | * |
1747 | * NOTE: Must be called with iwl_grab_nic_access() already obtained! | ||
1748 | */ | 1738 | */ |
1749 | static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, | 1739 | static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, |
1750 | u32 num_events, u32 mode) | 1740 | u32 num_events, u32 mode) |
@@ -1787,7 +1777,6 @@ static void iwl3945_print_event_log(struct iwl_priv *priv, u32 start_idx, | |||
1787 | 1777 | ||
1788 | static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | 1778 | static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) |
1789 | { | 1779 | { |
1790 | int rc; | ||
1791 | u32 base; /* SRAM byte address of event log header */ | 1780 | u32 base; /* SRAM byte address of event log header */ |
1792 | u32 capacity; /* event log capacity in # entries */ | 1781 | u32 capacity; /* event log capacity in # entries */ |
1793 | u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ | 1782 | u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ |
@@ -1801,12 +1790,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | |||
1801 | return; | 1790 | return; |
1802 | } | 1791 | } |
1803 | 1792 | ||
1804 | rc = iwl_grab_nic_access(priv); | ||
1805 | if (rc) { | ||
1806 | IWL_WARN(priv, "Can not read from adapter at this time.\n"); | ||
1807 | return; | ||
1808 | } | ||
1809 | |||
1810 | /* event log header */ | 1793 | /* event log header */ |
1811 | capacity = iwl_read_targ_mem(priv, base); | 1794 | capacity = iwl_read_targ_mem(priv, base); |
1812 | mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); | 1795 | mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); |
@@ -1818,7 +1801,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | |||
1818 | /* bail out if nothing in log */ | 1801 | /* bail out if nothing in log */ |
1819 | if (size == 0) { | 1802 | if (size == 0) { |
1820 | IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); | 1803 | IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); |
1821 | iwl_release_nic_access(priv); | ||
1822 | return; | 1804 | return; |
1823 | } | 1805 | } |
1824 | 1806 | ||
@@ -1834,7 +1816,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv) | |||
1834 | /* (then/else) start at top of log */ | 1816 | /* (then/else) start at top of log */ |
1835 | iwl3945_print_event_log(priv, 0, next_entry, mode); | 1817 | iwl3945_print_event_log(priv, 0, next_entry, mode); |
1836 | 1818 | ||
1837 | iwl_release_nic_access(priv); | ||
1838 | } | 1819 | } |
1839 | 1820 | ||
1840 | static void iwl3945_irq_tasklet(struct iwl_priv *priv) | 1821 | static void iwl3945_irq_tasklet(struct iwl_priv *priv) |
@@ -1953,11 +1934,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
1953 | priv->isr_stats.tx++; | 1934 | priv->isr_stats.tx++; |
1954 | 1935 | ||
1955 | iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); | 1936 | iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); |
1956 | if (!iwl_grab_nic_access(priv)) { | 1937 | iwl_write_direct32(priv, FH39_TCSR_CREDIT |
1957 | iwl_write_direct32(priv, FH39_TCSR_CREDIT | 1938 | (FH39_SRVC_CHNL), 0x0); |
1958 | (FH39_SRVC_CHNL), 0x0); | ||
1959 | iwl_release_nic_access(priv); | ||
1960 | } | ||
1961 | handled |= CSR_INT_BIT_FH_TX; | 1939 | handled |= CSR_INT_BIT_FH_TX; |
1962 | } | 1940 | } |
1963 | 1941 | ||
@@ -1966,9 +1944,9 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
1966 | priv->isr_stats.unhandled++; | 1944 | priv->isr_stats.unhandled++; |
1967 | } | 1945 | } |
1968 | 1946 | ||
1969 | if (inta & ~CSR_INI_SET_MASK) { | 1947 | if (inta & ~priv->inta_mask) { |
1970 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", | 1948 | IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", |
1971 | inta & ~CSR_INI_SET_MASK); | 1949 | inta & ~priv->inta_mask); |
1972 | IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); | 1950 | IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh); |
1973 | } | 1951 | } |
1974 | 1952 | ||
@@ -2132,10 +2110,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le | |||
2132 | 2110 | ||
2133 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 2111 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
2134 | 2112 | ||
2135 | rc = iwl_grab_nic_access(priv); | ||
2136 | if (rc) | ||
2137 | return rc; | ||
2138 | |||
2139 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | 2113 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, |
2140 | IWL39_RTC_INST_LOWER_BOUND); | 2114 | IWL39_RTC_INST_LOWER_BOUND); |
2141 | 2115 | ||
@@ -2156,7 +2130,6 @@ static int iwl3945_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 le | |||
2156 | } | 2130 | } |
2157 | } | 2131 | } |
2158 | 2132 | ||
2159 | iwl_release_nic_access(priv); | ||
2160 | 2133 | ||
2161 | if (!errcnt) | 2134 | if (!errcnt) |
2162 | IWL_DEBUG_INFO(priv, | 2135 | IWL_DEBUG_INFO(priv, |
@@ -2180,10 +2153,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 | |||
2180 | 2153 | ||
2181 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | 2154 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); |
2182 | 2155 | ||
2183 | rc = iwl_grab_nic_access(priv); | ||
2184 | if (rc) | ||
2185 | return rc; | ||
2186 | |||
2187 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { | 2156 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { |
2188 | /* read data comes through single port, auto-incr addr */ | 2157 | /* read data comes through single port, auto-incr addr */ |
2189 | /* NOTE: Use the debugless read so we don't flood kernel log | 2158 | /* NOTE: Use the debugless read so we don't flood kernel log |
@@ -2204,8 +2173,6 @@ static int iwl3945_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 | |||
2204 | } | 2173 | } |
2205 | } | 2174 | } |
2206 | 2175 | ||
2207 | iwl_release_nic_access(priv); | ||
2208 | |||
2209 | return rc; | 2176 | return rc; |
2210 | } | 2177 | } |
2211 | 2178 | ||
@@ -2529,20 +2496,11 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) | |||
2529 | { | 2496 | { |
2530 | dma_addr_t pinst; | 2497 | dma_addr_t pinst; |
2531 | dma_addr_t pdata; | 2498 | dma_addr_t pdata; |
2532 | int rc = 0; | ||
2533 | unsigned long flags; | ||
2534 | 2499 | ||
2535 | /* bits 31:0 for 3945 */ | 2500 | /* bits 31:0 for 3945 */ |
2536 | pinst = priv->ucode_code.p_addr; | 2501 | pinst = priv->ucode_code.p_addr; |
2537 | pdata = priv->ucode_data_backup.p_addr; | 2502 | pdata = priv->ucode_data_backup.p_addr; |
2538 | 2503 | ||
2539 | spin_lock_irqsave(&priv->lock, flags); | ||
2540 | rc = iwl_grab_nic_access(priv); | ||
2541 | if (rc) { | ||
2542 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2543 | return rc; | ||
2544 | } | ||
2545 | |||
2546 | /* Tell bootstrap uCode where to find image to load */ | 2504 | /* Tell bootstrap uCode where to find image to load */ |
2547 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); | 2505 | iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); |
2548 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); | 2506 | iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); |
@@ -2554,13 +2512,9 @@ static int iwl3945_set_ucode_ptrs(struct iwl_priv *priv) | |||
2554 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, | 2512 | iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, |
2555 | priv->ucode_code.len | BSM_DRAM_INST_LOAD); | 2513 | priv->ucode_code.len | BSM_DRAM_INST_LOAD); |
2556 | 2514 | ||
2557 | iwl_release_nic_access(priv); | ||
2558 | |||
2559 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2560 | |||
2561 | IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); | 2515 | IWL_DEBUG_INFO(priv, "Runtime uCode pointers are set.\n"); |
2562 | 2516 | ||
2563 | return rc; | 2517 | return 0; |
2564 | } | 2518 | } |
2565 | 2519 | ||
2566 | /** | 2520 | /** |
@@ -2613,7 +2567,6 @@ static void iwl3945_init_alive_start(struct iwl_priv *priv) | |||
2613 | */ | 2567 | */ |
2614 | static void iwl3945_alive_start(struct iwl_priv *priv) | 2568 | static void iwl3945_alive_start(struct iwl_priv *priv) |
2615 | { | 2569 | { |
2616 | int rc = 0; | ||
2617 | int thermal_spin = 0; | 2570 | int thermal_spin = 0; |
2618 | u32 rfkill; | 2571 | u32 rfkill; |
2619 | 2572 | ||
@@ -2638,15 +2591,8 @@ static void iwl3945_alive_start(struct iwl_priv *priv) | |||
2638 | 2591 | ||
2639 | priv->cfg->ops->smgmt->clear_station_table(priv); | 2592 | priv->cfg->ops->smgmt->clear_station_table(priv); |
2640 | 2593 | ||
2641 | rc = iwl_grab_nic_access(priv); | ||
2642 | if (rc) { | ||
2643 | IWL_WARN(priv, "Can not read RFKILL status from adapter\n"); | ||
2644 | return; | ||
2645 | } | ||
2646 | |||
2647 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); | 2594 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); |
2648 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); | 2595 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); |
2649 | iwl_release_nic_access(priv); | ||
2650 | 2596 | ||
2651 | if (rfkill & 0x1) { | 2597 | if (rfkill & 0x1) { |
2652 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | 2598 | clear_bit(STATUS_RF_KILL_HW, &priv->status); |
@@ -2792,13 +2738,8 @@ static void __iwl3945_down(struct iwl_priv *priv) | |||
2792 | iwl3945_hw_txq_ctx_stop(priv); | 2738 | iwl3945_hw_txq_ctx_stop(priv); |
2793 | iwl3945_hw_rxq_stop(priv); | 2739 | iwl3945_hw_rxq_stop(priv); |
2794 | 2740 | ||
2795 | spin_lock_irqsave(&priv->lock, flags); | 2741 | iwl_write_prph(priv, APMG_CLK_DIS_REG, |
2796 | if (!iwl_grab_nic_access(priv)) { | 2742 | APMG_CLK_VAL_DMA_CLK_RQT); |
2797 | iwl_write_prph(priv, APMG_CLK_DIS_REG, | ||
2798 | APMG_CLK_VAL_DMA_CLK_RQT); | ||
2799 | iwl_release_nic_access(priv); | ||
2800 | } | ||
2801 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2802 | 2743 | ||
2803 | udelay(5); | 2744 | udelay(5); |
2804 | 2745 | ||
@@ -4243,6 +4184,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
4243 | IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); | 4184 | IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); |
4244 | priv->cfg = cfg; | 4185 | priv->cfg = cfg; |
4245 | priv->pci_dev = pdev; | 4186 | priv->pci_dev = pdev; |
4187 | priv->inta_mask = CSR_INI_SET_MASK; | ||
4246 | 4188 | ||
4247 | #ifdef CONFIG_IWLWIFI_DEBUG | 4189 | #ifdef CONFIG_IWLWIFI_DEBUG |
4248 | priv->debug_level = iwl3945_mod_params.debug; | 4190 | priv->debug_level = iwl3945_mod_params.debug; |
@@ -4289,6 +4231,11 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
4289 | * PCI Tx retries from interfering with C3 CPU state */ | 4231 | * PCI Tx retries from interfering with C3 CPU state */ |
4290 | pci_write_config_byte(pdev, 0x41, 0x00); | 4232 | pci_write_config_byte(pdev, 0x41, 0x00); |
4291 | 4233 | ||
4234 | /* this spin lock will be used in apm_ops.init and EEPROM access | ||
4235 | * we should init now | ||
4236 | */ | ||
4237 | spin_lock_init(&priv->reg_lock); | ||
4238 | |||
4292 | /* amp init */ | 4239 | /* amp init */ |
4293 | err = priv->cfg->ops->lib->apm_ops.init(priv); | 4240 | err = priv->cfg->ops->lib->apm_ops.init(priv); |
4294 | if (err < 0) { | 4241 | if (err < 0) { |
@@ -4344,8 +4291,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
4344 | 4291 | ||
4345 | pci_enable_msi(priv->pci_dev); | 4292 | pci_enable_msi(priv->pci_dev); |
4346 | 4293 | ||
4347 | err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | 4294 | err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, |
4348 | DRV_NAME, priv); | 4295 | IRQF_SHARED, DRV_NAME, priv); |
4349 | if (err) { | 4296 | if (err) { |
4350 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 4297 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
4351 | goto out_disable_msi; | 4298 | goto out_disable_msi; |
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig new file mode 100644 index 000000000000..ae84ddabcc1c --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig | |||
@@ -0,0 +1,23 @@ | |||
1 | config IWM | ||
2 | tristate "Intel Wireless Multicomm 3200 WiFi driver" | ||
3 | depends on MMC && WLAN_80211 && EXPERIMENTAL | ||
4 | select LIB80211 | ||
5 | select FW_LOADER | ||
6 | select RFKILL | ||
7 | |||
8 | config IWM_DEBUG | ||
9 | bool "Enable full debugging output in iwmc3200wifi" | ||
10 | depends on IWM && DEBUG_FS | ||
11 | ---help--- | ||
12 | This option will enable debug tracing and setting for iwm | ||
13 | |||
14 | You can set the debug level and module through debugfs. By | ||
15 | default all modules are set to the IWL_DL_ERR level. | ||
16 | To see the list of debug modules and levels, see iwm/debug.h | ||
17 | |||
18 | For example, if you want the full MLME debug output: | ||
19 | echo 0xff > /debug/iwm/phyN/debug/mlme | ||
20 | |||
21 | Or, if you want the full debug, for all modules: | ||
22 | echo 0xff > /debug/iwm/phyN/debug/level | ||
23 | echo 0xff > /debug/iwm/phyN/debug/modules | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile new file mode 100644 index 000000000000..7cb415e5c11b --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_IWM) := iwmc3200wifi.o | ||
2 | iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o | ||
3 | iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o | ||
4 | |||
5 | iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h new file mode 100644 index 000000000000..836663eec257 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/bus.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_BUS_H__ | ||
25 | #define __IWM_BUS_H__ | ||
26 | |||
27 | #include "iwm.h" | ||
28 | |||
29 | struct iwm_if_ops { | ||
30 | int (*enable)(struct iwm_priv *iwm); | ||
31 | int (*disable)(struct iwm_priv *iwm); | ||
32 | int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count); | ||
33 | |||
34 | int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir); | ||
35 | void (*debugfs_exit)(struct iwm_priv *iwm); | ||
36 | |||
37 | const char *umac_name; | ||
38 | const char *calib_lmac_name; | ||
39 | const char *lmac_name; | ||
40 | }; | ||
41 | |||
42 | static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) | ||
43 | { | ||
44 | return iwm->bus_ops->send_chunk(iwm, buf, count); | ||
45 | } | ||
46 | |||
47 | static inline int iwm_bus_enable(struct iwm_priv *iwm) | ||
48 | { | ||
49 | return iwm->bus_ops->enable(iwm); | ||
50 | } | ||
51 | |||
52 | static inline int iwm_bus_disable(struct iwm_priv *iwm) | ||
53 | { | ||
54 | return iwm->bus_ops->disable(iwm); | ||
55 | } | ||
56 | |||
57 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c new file mode 100644 index 000000000000..3256ad2c96ce --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c | |||
@@ -0,0 +1,409 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/wireless.h> | ||
27 | #include <linux/ieee80211.h> | ||
28 | #include <net/cfg80211.h> | ||
29 | |||
30 | #include "iwm.h" | ||
31 | #include "commands.h" | ||
32 | #include "cfg80211.h" | ||
33 | #include "debug.h" | ||
34 | |||
35 | #define RATETAB_ENT(_rate, _rateid, _flags) \ | ||
36 | { \ | ||
37 | .bitrate = (_rate), \ | ||
38 | .hw_value = (_rateid), \ | ||
39 | .flags = (_flags), \ | ||
40 | } | ||
41 | |||
42 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
43 | .band = IEEE80211_BAND_2GHZ, \ | ||
44 | .center_freq = (_freq), \ | ||
45 | .hw_value = (_channel), \ | ||
46 | .flags = (_flags), \ | ||
47 | .max_antenna_gain = 0, \ | ||
48 | .max_power = 30, \ | ||
49 | } | ||
50 | |||
51 | #define CHAN5G(_channel, _flags) { \ | ||
52 | .band = IEEE80211_BAND_5GHZ, \ | ||
53 | .center_freq = 5000 + (5 * (_channel)), \ | ||
54 | .hw_value = (_channel), \ | ||
55 | .flags = (_flags), \ | ||
56 | .max_antenna_gain = 0, \ | ||
57 | .max_power = 30, \ | ||
58 | } | ||
59 | |||
60 | static struct ieee80211_rate iwm_rates[] = { | ||
61 | RATETAB_ENT(10, 0x1, 0), | ||
62 | RATETAB_ENT(20, 0x2, 0), | ||
63 | RATETAB_ENT(55, 0x4, 0), | ||
64 | RATETAB_ENT(110, 0x8, 0), | ||
65 | RATETAB_ENT(60, 0x10, 0), | ||
66 | RATETAB_ENT(90, 0x20, 0), | ||
67 | RATETAB_ENT(120, 0x40, 0), | ||
68 | RATETAB_ENT(180, 0x80, 0), | ||
69 | RATETAB_ENT(240, 0x100, 0), | ||
70 | RATETAB_ENT(360, 0x200, 0), | ||
71 | RATETAB_ENT(480, 0x400, 0), | ||
72 | RATETAB_ENT(540, 0x800, 0), | ||
73 | }; | ||
74 | |||
75 | #define iwm_a_rates (iwm_rates + 4) | ||
76 | #define iwm_a_rates_size 8 | ||
77 | #define iwm_g_rates (iwm_rates + 0) | ||
78 | #define iwm_g_rates_size 12 | ||
79 | |||
80 | static struct ieee80211_channel iwm_2ghz_channels[] = { | ||
81 | CHAN2G(1, 2412, 0), | ||
82 | CHAN2G(2, 2417, 0), | ||
83 | CHAN2G(3, 2422, 0), | ||
84 | CHAN2G(4, 2427, 0), | ||
85 | CHAN2G(5, 2432, 0), | ||
86 | CHAN2G(6, 2437, 0), | ||
87 | CHAN2G(7, 2442, 0), | ||
88 | CHAN2G(8, 2447, 0), | ||
89 | CHAN2G(9, 2452, 0), | ||
90 | CHAN2G(10, 2457, 0), | ||
91 | CHAN2G(11, 2462, 0), | ||
92 | CHAN2G(12, 2467, 0), | ||
93 | CHAN2G(13, 2472, 0), | ||
94 | CHAN2G(14, 2484, 0), | ||
95 | }; | ||
96 | |||
97 | static struct ieee80211_channel iwm_5ghz_a_channels[] = { | ||
98 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
99 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
100 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
101 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
102 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
103 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
104 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
105 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
106 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
107 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
108 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
109 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
110 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
111 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
112 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
113 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
114 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
115 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
116 | CHAN5G(216, 0), | ||
117 | }; | ||
118 | |||
119 | static struct ieee80211_supported_band iwm_band_2ghz = { | ||
120 | .channels = iwm_2ghz_channels, | ||
121 | .n_channels = ARRAY_SIZE(iwm_2ghz_channels), | ||
122 | .bitrates = iwm_g_rates, | ||
123 | .n_bitrates = iwm_g_rates_size, | ||
124 | }; | ||
125 | |||
126 | static struct ieee80211_supported_band iwm_band_5ghz = { | ||
127 | .channels = iwm_5ghz_a_channels, | ||
128 | .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels), | ||
129 | .bitrates = iwm_a_rates, | ||
130 | .n_bitrates = iwm_a_rates_size, | ||
131 | }; | ||
132 | |||
133 | int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) | ||
134 | { | ||
135 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
136 | struct iwm_bss_info *bss, *next; | ||
137 | struct iwm_umac_notif_bss_info *umac_bss; | ||
138 | struct ieee80211_mgmt *mgmt; | ||
139 | struct ieee80211_channel *channel; | ||
140 | struct ieee80211_supported_band *band; | ||
141 | s32 signal; | ||
142 | int freq; | ||
143 | |||
144 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { | ||
145 | umac_bss = bss->bss; | ||
146 | mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); | ||
147 | |||
148 | if (umac_bss->band == UMAC_BAND_2GHZ) | ||
149 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
150 | else if (umac_bss->band == UMAC_BAND_5GHZ) | ||
151 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
152 | else { | ||
153 | IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | freq = ieee80211_channel_to_frequency(umac_bss->channel); | ||
158 | channel = ieee80211_get_channel(wiphy, freq); | ||
159 | signal = umac_bss->rssi * 100; | ||
160 | |||
161 | if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt, | ||
162 | le16_to_cpu(umac_bss->frame_len), | ||
163 | signal, GFP_KERNEL)) | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, | ||
171 | enum nl80211_iftype type, u32 *flags, | ||
172 | struct vif_params *params) | ||
173 | { | ||
174 | struct net_device *ndev; | ||
175 | struct wireless_dev *wdev; | ||
176 | struct iwm_priv *iwm; | ||
177 | u32 old_mode; | ||
178 | |||
179 | /* we're under RTNL */ | ||
180 | ndev = __dev_get_by_index(&init_net, ifindex); | ||
181 | if (!ndev) | ||
182 | return -ENODEV; | ||
183 | |||
184 | wdev = ndev->ieee80211_ptr; | ||
185 | iwm = ndev_to_iwm(ndev); | ||
186 | old_mode = iwm->conf.mode; | ||
187 | |||
188 | switch (type) { | ||
189 | case NL80211_IFTYPE_STATION: | ||
190 | iwm->conf.mode = UMAC_MODE_BSS; | ||
191 | break; | ||
192 | case NL80211_IFTYPE_ADHOC: | ||
193 | iwm->conf.mode = UMAC_MODE_IBSS; | ||
194 | break; | ||
195 | default: | ||
196 | return -EOPNOTSUPP; | ||
197 | } | ||
198 | |||
199 | wdev->iftype = type; | ||
200 | |||
201 | if ((old_mode == iwm->conf.mode) || !iwm->umac_profile) | ||
202 | return 0; | ||
203 | |||
204 | iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); | ||
205 | |||
206 | if (iwm->umac_profile_active) { | ||
207 | int ret = iwm_invalidate_mlme_profile(iwm); | ||
208 | if (ret < 0) | ||
209 | IWM_ERR(iwm, "Couldn't invalidate profile\n"); | ||
210 | } | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | ||
216 | struct cfg80211_scan_request *request) | ||
217 | { | ||
218 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
219 | int ret; | ||
220 | |||
221 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) { | ||
222 | IWM_ERR(iwm, "Scan while device is not ready\n"); | ||
223 | return -EIO; | ||
224 | } | ||
225 | |||
226 | if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) { | ||
227 | IWM_ERR(iwm, "Scanning already\n"); | ||
228 | return -EAGAIN; | ||
229 | } | ||
230 | |||
231 | if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) { | ||
232 | IWM_ERR(iwm, "Scanning being aborted\n"); | ||
233 | return -EAGAIN; | ||
234 | } | ||
235 | |||
236 | set_bit(IWM_STATUS_SCANNING, &iwm->status); | ||
237 | |||
238 | ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids); | ||
239 | if (ret) { | ||
240 | clear_bit(IWM_STATUS_SCANNING, &iwm->status); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | iwm->scan_request = request; | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | ||
249 | { | ||
250 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
251 | |||
252 | if (changed & WIPHY_PARAM_RTS_THRESHOLD && | ||
253 | (iwm->conf.rts_threshold != wiphy->rts_threshold)) { | ||
254 | int ret; | ||
255 | |||
256 | iwm->conf.rts_threshold = wiphy->rts_threshold; | ||
257 | |||
258 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
259 | CFG_RTS_THRESHOLD, | ||
260 | iwm->conf.rts_threshold); | ||
261 | if (ret < 0) | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD && | ||
266 | (iwm->conf.frag_threshold != wiphy->frag_threshold)) { | ||
267 | int ret; | ||
268 | |||
269 | iwm->conf.frag_threshold = wiphy->frag_threshold; | ||
270 | |||
271 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
272 | CFG_FRAG_THRESHOLD, | ||
273 | iwm->conf.frag_threshold); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, | ||
282 | struct cfg80211_ibss_params *params) | ||
283 | { | ||
284 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
285 | struct ieee80211_channel *chan = params->channel; | ||
286 | struct cfg80211_bss *bss; | ||
287 | |||
288 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
289 | return -EIO; | ||
290 | |||
291 | /* UMAC doesn't support creating IBSS network with specified bssid. | ||
292 | * This should be removed after we have join only mode supported. */ | ||
293 | if (params->bssid) | ||
294 | return -EOPNOTSUPP; | ||
295 | |||
296 | bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, | ||
297 | params->ssid, params->ssid_len); | ||
298 | if (!bss) { | ||
299 | iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len); | ||
300 | schedule_timeout_interruptible(2 * HZ); | ||
301 | bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL, | ||
302 | params->ssid, params->ssid_len); | ||
303 | } | ||
304 | /* IBSS join only mode is not supported by UMAC ATM */ | ||
305 | if (bss) { | ||
306 | cfg80211_put_bss(bss); | ||
307 | return -EOPNOTSUPP; | ||
308 | } | ||
309 | |||
310 | iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); | ||
311 | iwm->umac_profile->ibss.band = chan->band; | ||
312 | iwm->umac_profile->ibss.channel = iwm->channel; | ||
313 | iwm->umac_profile->ssid.ssid_len = params->ssid_len; | ||
314 | memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); | ||
315 | |||
316 | if (params->bssid) | ||
317 | memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN); | ||
318 | |||
319 | return iwm_send_mlme_profile(iwm); | ||
320 | } | ||
321 | |||
322 | static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | ||
323 | { | ||
324 | struct iwm_priv *iwm = wiphy_to_iwm(wiphy); | ||
325 | |||
326 | if (iwm->umac_profile_active) | ||
327 | return iwm_invalidate_mlme_profile(iwm); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static struct cfg80211_ops iwm_cfg80211_ops = { | ||
333 | .change_virtual_intf = iwm_cfg80211_change_iface, | ||
334 | .scan = iwm_cfg80211_scan, | ||
335 | .set_wiphy_params = iwm_cfg80211_set_wiphy_params, | ||
336 | .join_ibss = iwm_cfg80211_join_ibss, | ||
337 | .leave_ibss = iwm_cfg80211_leave_ibss, | ||
338 | }; | ||
339 | |||
340 | struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) | ||
341 | { | ||
342 | int ret = 0; | ||
343 | struct wireless_dev *wdev; | ||
344 | |||
345 | /* | ||
346 | * We're trying to have the following memory | ||
347 | * layout: | ||
348 | * | ||
349 | * +-------------------------+ | ||
350 | * | struct wiphy | | ||
351 | * +-------------------------+ | ||
352 | * | struct iwm_priv | | ||
353 | * +-------------------------+ | ||
354 | * | bus private data | | ||
355 | * | (e.g. iwm_priv_sdio) | | ||
356 | * +-------------------------+ | ||
357 | * | ||
358 | */ | ||
359 | |||
360 | wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); | ||
361 | if (!wdev) { | ||
362 | dev_err(dev, "Couldn't allocate wireless device\n"); | ||
363 | return ERR_PTR(-ENOMEM); | ||
364 | } | ||
365 | |||
366 | wdev->wiphy = wiphy_new(&iwm_cfg80211_ops, | ||
367 | sizeof(struct iwm_priv) + sizeof_bus); | ||
368 | if (!wdev->wiphy) { | ||
369 | dev_err(dev, "Couldn't allocate wiphy device\n"); | ||
370 | ret = -ENOMEM; | ||
371 | goto out_err_new; | ||
372 | } | ||
373 | |||
374 | set_wiphy_dev(wdev->wiphy, dev); | ||
375 | wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; | ||
376 | wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
377 | BIT(NL80211_IFTYPE_ADHOC); | ||
378 | wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; | ||
379 | wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; | ||
380 | wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
381 | |||
382 | ret = wiphy_register(wdev->wiphy); | ||
383 | if (ret < 0) { | ||
384 | dev_err(dev, "Couldn't register wiphy device\n"); | ||
385 | goto out_err_register; | ||
386 | } | ||
387 | |||
388 | return wdev; | ||
389 | |||
390 | out_err_register: | ||
391 | wiphy_free(wdev->wiphy); | ||
392 | |||
393 | out_err_new: | ||
394 | kfree(wdev); | ||
395 | |||
396 | return ERR_PTR(ret); | ||
397 | } | ||
398 | |||
399 | void iwm_wdev_free(struct iwm_priv *iwm) | ||
400 | { | ||
401 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
402 | |||
403 | if (!wdev) | ||
404 | return; | ||
405 | |||
406 | wiphy_unregister(wdev->wiphy); | ||
407 | wiphy_free(wdev->wiphy); | ||
408 | kfree(wdev); | ||
409 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h new file mode 100644 index 000000000000..56a34145acbf --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_CFG80211_H__ | ||
25 | #define __IWM_CFG80211_H__ | ||
26 | |||
27 | int iwm_cfg80211_inform_bss(struct iwm_priv *iwm); | ||
28 | struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev); | ||
29 | void iwm_wdev_free(struct iwm_priv *iwm); | ||
30 | |||
31 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c new file mode 100644 index 000000000000..834a7f544e5d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.c | |||
@@ -0,0 +1,920 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/wireless.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/ieee80211.h> | ||
43 | |||
44 | #include "iwm.h" | ||
45 | #include "bus.h" | ||
46 | #include "hal.h" | ||
47 | #include "umac.h" | ||
48 | #include "commands.h" | ||
49 | #include "debug.h" | ||
50 | |||
51 | static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, | ||
52 | u8 lmac_cmd_id, | ||
53 | const void *lmac_payload, | ||
54 | u16 lmac_payload_size, | ||
55 | u8 resp) | ||
56 | { | ||
57 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; | ||
58 | struct iwm_umac_cmd umac_cmd; | ||
59 | struct iwm_lmac_cmd lmac_cmd; | ||
60 | |||
61 | lmac_cmd.id = lmac_cmd_id; | ||
62 | |||
63 | umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; | ||
64 | umac_cmd.resp = resp; | ||
65 | |||
66 | return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, | ||
67 | lmac_payload, lmac_payload_size); | ||
68 | } | ||
69 | |||
70 | int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, | ||
71 | bool resp) | ||
72 | { | ||
73 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
74 | struct iwm_umac_cmd umac_cmd; | ||
75 | |||
76 | umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; | ||
77 | umac_cmd.resp = resp; | ||
78 | |||
79 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, | ||
80 | payload, payload_size); | ||
81 | } | ||
82 | |||
83 | static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = | ||
84 | { | ||
85 | {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, | ||
86 | {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, | ||
87 | {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, | ||
88 | {4, 3, 0, COEX_CALIBRATION_FLAGS}, | ||
89 | {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, | ||
90 | {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, | ||
91 | {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, | ||
92 | {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, | ||
93 | {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, | ||
94 | {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, | ||
95 | {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, | ||
96 | {4, 3, 0, COEX_RF_OFF_FLAGS}, | ||
97 | {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, | ||
98 | {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, | ||
99 | {4, 3, 0, COEX_RSRVD1_FLAGS}, | ||
100 | {4, 3, 0, COEX_RSRVD2_FLAGS} | ||
101 | }; | ||
102 | |||
103 | static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = | ||
104 | { | ||
105 | {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, | ||
106 | {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, | ||
107 | {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, | ||
108 | {5, 5, 0, COEX_CALIBRATION_FLAGS}, | ||
109 | {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, | ||
110 | {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, | ||
111 | {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, | ||
112 | {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, | ||
113 | {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, | ||
114 | {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, | ||
115 | {1, 1, 0, COEX_RF_ON_FLAGS}, | ||
116 | {1, 1, 0, COEX_RF_OFF_FLAGS}, | ||
117 | {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, | ||
118 | {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, | ||
119 | {1, 1, 0, COEX_RSRVD1_FLAGS}, | ||
120 | {1, 1, 0, COEX_RSRVD2_FLAGS} | ||
121 | }; | ||
122 | |||
123 | int iwm_send_prio_table(struct iwm_priv *iwm) | ||
124 | { | ||
125 | struct iwm_coex_prio_table_cmd coex_table_cmd; | ||
126 | u32 coex_enabled, mode_enabled; | ||
127 | |||
128 | memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); | ||
129 | |||
130 | coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; | ||
131 | |||
132 | switch (iwm->conf.coexist_mode) { | ||
133 | case COEX_MODE_XOR: | ||
134 | case COEX_MODE_CM: | ||
135 | coex_enabled = 1; | ||
136 | break; | ||
137 | default: | ||
138 | coex_enabled = 0; | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | switch (iwm->conf.mode) { | ||
143 | case UMAC_MODE_BSS: | ||
144 | case UMAC_MODE_IBSS: | ||
145 | mode_enabled = 1; | ||
146 | break; | ||
147 | default: | ||
148 | mode_enabled = 0; | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | if (coex_enabled && mode_enabled) { | ||
153 | coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | | ||
154 | COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | | ||
155 | COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; | ||
156 | |||
157 | switch (iwm->conf.coexist_mode) { | ||
158 | case COEX_MODE_XOR: | ||
159 | memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, | ||
160 | sizeof(iwm_sta_xor_prio_tbl)); | ||
161 | break; | ||
162 | case COEX_MODE_CM: | ||
163 | memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, | ||
164 | sizeof(iwm_sta_cm_prio_tbl)); | ||
165 | break; | ||
166 | default: | ||
167 | IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", | ||
168 | iwm->conf.coexist_mode); | ||
169 | break; | ||
170 | } | ||
171 | } else | ||
172 | IWM_WARN(iwm, "coexistense disabled\n"); | ||
173 | |||
174 | return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, | ||
175 | &coex_table_cmd, | ||
176 | sizeof(struct iwm_coex_prio_table_cmd), 1); | ||
177 | } | ||
178 | |||
179 | int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) | ||
180 | { | ||
181 | struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; | ||
182 | |||
183 | memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); | ||
184 | |||
185 | cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); | ||
186 | cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); | ||
187 | cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); | ||
188 | cal_cfg_cmd.ucode_cfg.flags = | ||
189 | cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); | ||
190 | |||
191 | return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, | ||
192 | sizeof(struct iwm_lmac_cal_cfg_cmd), 1); | ||
193 | } | ||
194 | |||
195 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) | ||
196 | { | ||
197 | struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; | ||
198 | |||
199 | memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); | ||
200 | |||
201 | cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); | ||
202 | cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); | ||
203 | |||
204 | return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, | ||
205 | sizeof(struct iwm_lmac_cal_cfg_cmd), 0); | ||
206 | } | ||
207 | |||
208 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) | ||
209 | { | ||
210 | struct iwm_calib_rxiq *rxiq; | ||
211 | u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); | ||
212 | int grplen = sizeof(struct iwm_calib_rxiq_group); | ||
213 | |||
214 | rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); | ||
215 | if (!rxiq) { | ||
216 | IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); | ||
217 | return -ENOMEM; | ||
218 | } | ||
219 | |||
220 | eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); | ||
221 | if (IS_ERR(eeprom_rxiq)) { | ||
222 | IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); | ||
223 | return PTR_ERR(eeprom_rxiq); | ||
224 | } | ||
225 | |||
226 | iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; | ||
227 | iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); | ||
228 | |||
229 | rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; | ||
230 | rxiq->hdr.first_grp = 0; | ||
231 | rxiq->hdr.grp_num = 1; | ||
232 | rxiq->hdr.all_data_valid = 1; | ||
233 | |||
234 | memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); | ||
235 | memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | int iwm_send_calib_results(struct iwm_priv *iwm) | ||
241 | { | ||
242 | int i, ret = 0; | ||
243 | |||
244 | for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { | ||
245 | if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, | ||
246 | &iwm->calib_done_map)) { | ||
247 | IWM_DBG_CMD(iwm, DBG, | ||
248 | "Send calibration %d result\n", i); | ||
249 | ret |= iwm_send_lmac_ptrough_cmd(iwm, | ||
250 | REPLY_PHY_CALIBRATION_CMD, | ||
251 | iwm->calib_res[i].buf, | ||
252 | iwm->calib_res[i].size, 0); | ||
253 | |||
254 | kfree(iwm->calib_res[i].buf); | ||
255 | iwm->calib_res[i].buf = NULL; | ||
256 | iwm->calib_res[i].size = 0; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) | ||
264 | { | ||
265 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
266 | struct iwm_umac_cmd umac_cmd; | ||
267 | struct iwm_umac_cmd_reset reset; | ||
268 | |||
269 | reset.flags = reset_flags; | ||
270 | |||
271 | umac_cmd.id = UMAC_CMD_OPCODE_RESET; | ||
272 | umac_cmd.resp = resp; | ||
273 | |||
274 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, | ||
275 | sizeof(struct iwm_umac_cmd_reset)); | ||
276 | } | ||
277 | |||
278 | int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) | ||
279 | { | ||
280 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
281 | struct iwm_umac_cmd umac_cmd; | ||
282 | struct iwm_umac_cmd_set_param_fix param; | ||
283 | |||
284 | if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && | ||
285 | (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) | ||
286 | return -EINVAL; | ||
287 | |||
288 | umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; | ||
289 | umac_cmd.resp = 0; | ||
290 | |||
291 | param.tbl = cpu_to_le16(tbl); | ||
292 | param.key = cpu_to_le16(key); | ||
293 | param.value = cpu_to_le32(value); | ||
294 | |||
295 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ¶m, | ||
296 | sizeof(struct iwm_umac_cmd_set_param_fix)); | ||
297 | } | ||
298 | |||
299 | int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, | ||
300 | void *payload, u16 payload_size) | ||
301 | { | ||
302 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
303 | struct iwm_umac_cmd umac_cmd; | ||
304 | struct iwm_umac_cmd_set_param_var *param_hdr; | ||
305 | u8 *param; | ||
306 | int ret; | ||
307 | |||
308 | param = kzalloc(payload_size + | ||
309 | sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); | ||
310 | if (!param) { | ||
311 | IWM_ERR(iwm, "Couldn't allocate param\n"); | ||
312 | return -ENOMEM; | ||
313 | } | ||
314 | |||
315 | param_hdr = (struct iwm_umac_cmd_set_param_var *)param; | ||
316 | |||
317 | umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; | ||
318 | umac_cmd.resp = 0; | ||
319 | |||
320 | param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); | ||
321 | param_hdr->key = cpu_to_le16(key); | ||
322 | param_hdr->len = cpu_to_le16(payload_size); | ||
323 | memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), | ||
324 | payload, payload_size); | ||
325 | |||
326 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, | ||
327 | sizeof(struct iwm_umac_cmd_set_param_var) + | ||
328 | payload_size); | ||
329 | kfree(param); | ||
330 | |||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | int iwm_send_umac_config(struct iwm_priv *iwm, | ||
335 | __le32 reset_flags) | ||
336 | { | ||
337 | int ret; | ||
338 | |||
339 | /* Use UMAC default values */ | ||
340 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
341 | CFG_POWER_INDEX, iwm->conf.power_index); | ||
342 | if (ret < 0) | ||
343 | return ret; | ||
344 | |||
345 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, | ||
346 | CFG_FRAG_THRESHOLD, | ||
347 | iwm->conf.frag_threshold); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
352 | CFG_RTS_THRESHOLD, | ||
353 | iwm->conf.rts_threshold); | ||
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | |||
357 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
358 | CFG_CTS_TO_SELF, iwm->conf.cts_to_self); | ||
359 | if (ret < 0) | ||
360 | return ret; | ||
361 | |||
362 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
363 | CFG_COEX_MODE, iwm->conf.coexist_mode); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | |||
367 | /* | ||
368 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
369 | CFG_ASSOCIATION_TIMEOUT, | ||
370 | iwm->conf.assoc_timeout); | ||
371 | if (ret < 0) | ||
372 | return ret; | ||
373 | |||
374 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
375 | CFG_ROAM_TIMEOUT, | ||
376 | iwm->conf.roam_timeout); | ||
377 | if (ret < 0) | ||
378 | return ret; | ||
379 | |||
380 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
381 | CFG_WIRELESS_MODE, | ||
382 | WIRELESS_MODE_11A | WIRELESS_MODE_11G); | ||
383 | if (ret < 0) | ||
384 | return ret; | ||
385 | */ | ||
386 | |||
387 | ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, | ||
388 | iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); | ||
389 | if (ret < 0) | ||
390 | return ret; | ||
391 | |||
392 | /* UMAC PM static configurations */ | ||
393 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
394 | CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); | ||
395 | if (ret < 0) | ||
396 | return ret; | ||
397 | |||
398 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
399 | CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); | ||
400 | if (ret < 0) | ||
401 | return ret; | ||
402 | |||
403 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
404 | CFG_PM_CTRL_FLAGS, 0x30001); | ||
405 | if (ret < 0) | ||
406 | return ret; | ||
407 | |||
408 | ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
409 | CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); | ||
410 | if (ret < 0) | ||
411 | return ret; | ||
412 | |||
413 | /* reset UMAC */ | ||
414 | ret = iwm_send_umac_reset(iwm, reset_flags, 1); | ||
415 | if (ret < 0) | ||
416 | return ret; | ||
417 | |||
418 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, | ||
419 | WAIT_NOTIF_TIMEOUT); | ||
420 | if (ret) { | ||
421 | IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) | ||
429 | { | ||
430 | struct iwm_udma_wifi_cmd udma_cmd; | ||
431 | struct iwm_umac_cmd umac_cmd; | ||
432 | struct iwm_tx_info *tx_info = skb_to_tx_info(skb); | ||
433 | |||
434 | udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ | ||
435 | udma_cmd.credit_group = pool_id; | ||
436 | udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; | ||
437 | udma_cmd.lmac_offset = 0; | ||
438 | |||
439 | umac_cmd.id = REPLY_TX; | ||
440 | umac_cmd.color = tx_info->color; | ||
441 | umac_cmd.resp = 0; | ||
442 | |||
443 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, | ||
444 | skb->data, skb->len); | ||
445 | } | ||
446 | |||
447 | static int iwm_target_read(struct iwm_priv *iwm, __le32 address, | ||
448 | u8 *response, u32 resp_size) | ||
449 | { | ||
450 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
451 | struct iwm_nonwifi_cmd *cmd; | ||
452 | u16 seq_num; | ||
453 | int ret = 0; | ||
454 | |||
455 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; | ||
456 | target_cmd.addr = address; | ||
457 | target_cmd.op1_sz = cpu_to_le32(resp_size); | ||
458 | target_cmd.op2 = 0; | ||
459 | target_cmd.handle_by_hw = 0; | ||
460 | target_cmd.resp = 1; | ||
461 | target_cmd.eop = 1; | ||
462 | |||
463 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
464 | if (ret < 0) | ||
465 | IWM_ERR(iwm, "Couldn't send READ command\n"); | ||
466 | |||
467 | /* When succeding, the send_target routine returns the seq number */ | ||
468 | seq_num = ret; | ||
469 | |||
470 | ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, | ||
471 | (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, | ||
472 | UMAC_HDI_OUT_OPCODE_READ)) != NULL, | ||
473 | 2 * HZ); | ||
474 | |||
475 | if (!ret) { | ||
476 | IWM_ERR(iwm, "Didn't receive a target READ answer\n"); | ||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), | ||
481 | resp_size); | ||
482 | |||
483 | kfree(cmd); | ||
484 | |||
485 | return ret; | ||
486 | } | ||
487 | |||
488 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) | ||
489 | { | ||
490 | int ret; | ||
491 | u8 mac_align[ALIGN(ETH_ALEN, 8)]; | ||
492 | |||
493 | ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), | ||
494 | mac_align, sizeof(mac_align)); | ||
495 | if (ret < 0) | ||
496 | return ret; | ||
497 | |||
498 | if (is_valid_ether_addr(mac_align)) | ||
499 | memcpy(mac, mac_align, ETH_ALEN); | ||
500 | else { | ||
501 | IWM_ERR(iwm, "Invalid EEPROM MAC\n"); | ||
502 | memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); | ||
503 | get_random_bytes(&mac[3], 3); | ||
504 | } | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) | ||
510 | { | ||
511 | struct iwm_umac_tx_key_id tx_key_id; | ||
512 | |||
513 | if (!iwm->default_key || !iwm->default_key->in_use) | ||
514 | return -EINVAL; | ||
515 | |||
516 | tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; | ||
517 | tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - | ||
518 | sizeof(struct iwm_umac_wifi_if)); | ||
519 | |||
520 | tx_key_id.key_idx = key_idx; | ||
521 | |||
522 | return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); | ||
523 | } | ||
524 | |||
525 | static int iwm_check_profile(struct iwm_priv *iwm) | ||
526 | { | ||
527 | if (!iwm->umac_profile_active) | ||
528 | return -EAGAIN; | ||
529 | |||
530 | if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && | ||
531 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && | ||
532 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && | ||
533 | iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { | ||
534 | IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", | ||
535 | iwm->umac_profile->sec.ucast_cipher); | ||
536 | return -EAGAIN; | ||
537 | } | ||
538 | |||
539 | if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && | ||
540 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && | ||
541 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && | ||
542 | iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { | ||
543 | IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", | ||
544 | iwm->umac_profile->sec.mcast_cipher); | ||
545 | return -EAGAIN; | ||
546 | } | ||
547 | |||
548 | if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || | ||
549 | iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && | ||
550 | (iwm->umac_profile->sec.ucast_cipher != | ||
551 | iwm->umac_profile->sec.mcast_cipher)) { | ||
552 | IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, | ||
559 | struct iwm_key *key) | ||
560 | { | ||
561 | int ret; | ||
562 | u8 cmd[64], *sta_addr, *key_data, key_len; | ||
563 | s8 key_idx; | ||
564 | u16 cmd_size = 0; | ||
565 | struct iwm_umac_key_hdr *key_hdr = &key->hdr; | ||
566 | struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; | ||
567 | struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; | ||
568 | struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; | ||
569 | struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; | ||
570 | |||
571 | if (set_tx_key) | ||
572 | iwm->default_key = key; | ||
573 | |||
574 | /* | ||
575 | * We check if our current profile is valid. | ||
576 | * If not, we dont push the key, we just cache them, | ||
577 | * so that with the next siwsessid call, the keys | ||
578 | * will be actually pushed. | ||
579 | */ | ||
580 | if (!remove) { | ||
581 | ret = iwm_check_profile(iwm); | ||
582 | if (ret < 0) | ||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | sta_addr = key->hdr.mac; | ||
587 | key_data = key->key; | ||
588 | key_len = key->key_len; | ||
589 | key_idx = key->hdr.key_idx; | ||
590 | |||
591 | if (!remove) { | ||
592 | IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", | ||
593 | key_idx, set_tx_key); | ||
594 | IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); | ||
595 | IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", | ||
596 | key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); | ||
597 | |||
598 | IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", | ||
599 | iwm->umac_profile->sec.mcast_cipher, | ||
600 | iwm->umac_profile->sec.ucast_cipher); | ||
601 | IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", | ||
602 | iwm->umac_profile->sec.auth_type, | ||
603 | iwm->umac_profile->sec.flags); | ||
604 | |||
605 | switch (key->alg) { | ||
606 | case UMAC_CIPHER_TYPE_WEP_40: | ||
607 | wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; | ||
608 | wep40->hdr.buf_size = | ||
609 | cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - | ||
610 | sizeof(struct iwm_umac_wifi_if)); | ||
611 | |||
612 | memcpy(&wep40->key_hdr, key_hdr, | ||
613 | sizeof(struct iwm_umac_key_hdr)); | ||
614 | memcpy(wep40->key, key_data, key_len); | ||
615 | wep40->static_key = 1; | ||
616 | |||
617 | cmd_size = sizeof(struct iwm_umac_key_wep40); | ||
618 | break; | ||
619 | |||
620 | case UMAC_CIPHER_TYPE_WEP_104: | ||
621 | wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; | ||
622 | wep104->hdr.buf_size = | ||
623 | cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - | ||
624 | sizeof(struct iwm_umac_wifi_if)); | ||
625 | |||
626 | memcpy(&wep104->key_hdr, key_hdr, | ||
627 | sizeof(struct iwm_umac_key_hdr)); | ||
628 | memcpy(wep104->key, key_data, key_len); | ||
629 | wep104->static_key = 1; | ||
630 | |||
631 | cmd_size = sizeof(struct iwm_umac_key_wep104); | ||
632 | break; | ||
633 | |||
634 | case UMAC_CIPHER_TYPE_CCMP: | ||
635 | key_hdr->key_idx++; | ||
636 | ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; | ||
637 | ccmp->hdr.buf_size = | ||
638 | cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - | ||
639 | sizeof(struct iwm_umac_wifi_if)); | ||
640 | |||
641 | memcpy(&ccmp->key_hdr, key_hdr, | ||
642 | sizeof(struct iwm_umac_key_hdr)); | ||
643 | |||
644 | memcpy(ccmp->key, key_data, key_len); | ||
645 | |||
646 | if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) | ||
647 | memcpy(ccmp->iv_count, key->rx_seq, 6); | ||
648 | |||
649 | cmd_size = sizeof(struct iwm_umac_key_ccmp); | ||
650 | break; | ||
651 | |||
652 | case UMAC_CIPHER_TYPE_TKIP: | ||
653 | key_hdr->key_idx++; | ||
654 | tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; | ||
655 | tkip->hdr.buf_size = | ||
656 | cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - | ||
657 | sizeof(struct iwm_umac_wifi_if)); | ||
658 | |||
659 | memcpy(&tkip->key_hdr, key_hdr, | ||
660 | sizeof(struct iwm_umac_key_hdr)); | ||
661 | |||
662 | memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); | ||
663 | memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, | ||
664 | IWM_TKIP_MIC_SIZE); | ||
665 | memcpy(tkip->mic_rx_key, | ||
666 | key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, | ||
667 | IWM_TKIP_MIC_SIZE); | ||
668 | |||
669 | if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) | ||
670 | memcpy(ccmp->iv_count, key->rx_seq, 6); | ||
671 | |||
672 | cmd_size = sizeof(struct iwm_umac_key_tkip); | ||
673 | break; | ||
674 | |||
675 | default: | ||
676 | return -ENOTSUPP; | ||
677 | } | ||
678 | |||
679 | if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || | ||
680 | (key->alg == UMAC_CIPHER_TYPE_TKIP)) | ||
681 | /* | ||
682 | * UGLY_UGLY_UGLY | ||
683 | * Copied HACK from the MWG driver. | ||
684 | * Without it, the key is set before the second | ||
685 | * EAPOL frame is sent, and the latter is thus | ||
686 | * encrypted. | ||
687 | */ | ||
688 | schedule_timeout_interruptible(usecs_to_jiffies(300)); | ||
689 | |||
690 | ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); | ||
691 | if (ret < 0) | ||
692 | goto err; | ||
693 | |||
694 | /* | ||
695 | * We need a default key only if it is set and | ||
696 | * if we're doing WEP. | ||
697 | */ | ||
698 | if (iwm->default_key == key && | ||
699 | ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || | ||
700 | (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { | ||
701 | ret = iwm_set_tx_key(iwm, key_idx); | ||
702 | if (ret < 0) | ||
703 | goto err; | ||
704 | } | ||
705 | } else { | ||
706 | struct iwm_umac_key_remove key_remove; | ||
707 | |||
708 | key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; | ||
709 | key_remove.hdr.buf_size = | ||
710 | cpu_to_le16(sizeof(struct iwm_umac_key_remove) - | ||
711 | sizeof(struct iwm_umac_wifi_if)); | ||
712 | memcpy(&key_remove.key_hdr, key_hdr, | ||
713 | sizeof(struct iwm_umac_key_hdr)); | ||
714 | |||
715 | ret = iwm_send_wifi_if_cmd(iwm, &key_remove, | ||
716 | sizeof(struct iwm_umac_key_remove), | ||
717 | 1); | ||
718 | if (ret < 0) | ||
719 | return ret; | ||
720 | |||
721 | iwm->keys[key_idx].in_use = 0; | ||
722 | } | ||
723 | |||
724 | return 0; | ||
725 | |||
726 | err: | ||
727 | kfree(key); | ||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | |||
732 | int iwm_send_mlme_profile(struct iwm_priv *iwm) | ||
733 | { | ||
734 | int ret, i; | ||
735 | struct iwm_umac_profile profile; | ||
736 | |||
737 | memcpy(&profile, iwm->umac_profile, sizeof(profile)); | ||
738 | |||
739 | profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; | ||
740 | profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - | ||
741 | sizeof(struct iwm_umac_wifi_if)); | ||
742 | |||
743 | ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); | ||
744 | if (ret < 0) { | ||
745 | IWM_ERR(iwm, "Send profile command failed\n"); | ||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | /* Wait for the profile to be active */ | ||
750 | ret = wait_event_interruptible_timeout(iwm->mlme_queue, | ||
751 | iwm->umac_profile_active == 1, | ||
752 | 3 * HZ); | ||
753 | if (!ret) | ||
754 | return -EBUSY; | ||
755 | |||
756 | |||
757 | for (i = 0; i < IWM_NUM_KEYS; i++) | ||
758 | if (iwm->keys[i].in_use) { | ||
759 | int default_key = 0; | ||
760 | struct iwm_key *key = &iwm->keys[i]; | ||
761 | |||
762 | if (key == iwm->default_key) | ||
763 | default_key = 1; | ||
764 | |||
765 | /* Wait for the profile before sending the keys */ | ||
766 | wait_event_interruptible_timeout(iwm->mlme_queue, | ||
767 | (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || | ||
768 | test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), | ||
769 | 3 * HZ); | ||
770 | |||
771 | ret = iwm_set_key(iwm, 0, default_key, key); | ||
772 | if (ret < 0) | ||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) | ||
780 | { | ||
781 | int ret; | ||
782 | struct iwm_umac_invalidate_profile invalid; | ||
783 | |||
784 | invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; | ||
785 | invalid.hdr.buf_size = | ||
786 | cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - | ||
787 | sizeof(struct iwm_umac_wifi_if)); | ||
788 | |||
789 | invalid.reason = WLAN_REASON_UNSPECIFIED; | ||
790 | |||
791 | ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); | ||
792 | if (ret < 0) | ||
793 | return ret; | ||
794 | |||
795 | ret = wait_event_interruptible_timeout(iwm->mlme_queue, | ||
796 | (iwm->umac_profile_active == 0), | ||
797 | 2 * HZ); | ||
798 | if (!ret) | ||
799 | return -EBUSY; | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) | ||
805 | { | ||
806 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
807 | struct iwm_umac_cmd umac_cmd; | ||
808 | struct iwm_umac_cmd_stats_req stats_req; | ||
809 | |||
810 | stats_req.flags = cpu_to_le32(flags); | ||
811 | |||
812 | umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; | ||
813 | umac_cmd.resp = 0; | ||
814 | |||
815 | return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, | ||
816 | sizeof(struct iwm_umac_cmd_stats_req)); | ||
817 | } | ||
818 | |||
819 | int iwm_send_umac_channel_list(struct iwm_priv *iwm) | ||
820 | { | ||
821 | struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; | ||
822 | struct iwm_umac_cmd umac_cmd; | ||
823 | struct iwm_umac_cmd_get_channel_list *ch_list; | ||
824 | int size = sizeof(struct iwm_umac_cmd_get_channel_list) + | ||
825 | sizeof(struct iwm_umac_channel_info) * 4; | ||
826 | int ret; | ||
827 | |||
828 | ch_list = kzalloc(size, GFP_KERNEL); | ||
829 | if (!ch_list) { | ||
830 | IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); | ||
831 | return -ENOMEM; | ||
832 | } | ||
833 | |||
834 | ch_list->ch[0].band = UMAC_BAND_2GHZ; | ||
835 | ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
836 | ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; | ||
837 | |||
838 | ch_list->ch[1].band = UMAC_BAND_5GHZ; | ||
839 | ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
840 | ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; | ||
841 | |||
842 | ch_list->ch[2].band = UMAC_BAND_2GHZ; | ||
843 | ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
844 | ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; | ||
845 | |||
846 | ch_list->ch[3].band = UMAC_BAND_5GHZ; | ||
847 | ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; | ||
848 | ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; | ||
849 | |||
850 | ch_list->count = cpu_to_le16(4); | ||
851 | |||
852 | umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; | ||
853 | umac_cmd.resp = 1; | ||
854 | |||
855 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); | ||
856 | |||
857 | kfree(ch_list); | ||
858 | |||
859 | return ret; | ||
860 | } | ||
861 | |||
862 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, | ||
863 | int ssid_num) | ||
864 | { | ||
865 | struct iwm_umac_cmd_scan_request req; | ||
866 | int i, ret; | ||
867 | |||
868 | memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); | ||
869 | |||
870 | req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; | ||
871 | req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) | ||
872 | - sizeof(struct iwm_umac_wifi_if)); | ||
873 | req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; | ||
874 | req.timeout = 2; | ||
875 | req.seq_num = iwm->scan_id; | ||
876 | req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); | ||
877 | |||
878 | for (i = 0; i < req.ssid_num; i++) { | ||
879 | memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); | ||
880 | req.ssids[i].ssid_len = ssids[i].ssid_len; | ||
881 | } | ||
882 | |||
883 | ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); | ||
884 | if (ret < 0) { | ||
885 | IWM_ERR(iwm, "Couldn't send scan request\n"); | ||
886 | return ret; | ||
887 | } | ||
888 | |||
889 | iwm->scan_id = iwm->scan_id++ % IWM_SCAN_ID_MAX; | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) | ||
895 | { | ||
896 | struct cfg80211_ssid one_ssid; | ||
897 | |||
898 | if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) | ||
899 | return 0; | ||
900 | |||
901 | one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); | ||
902 | memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); | ||
903 | |||
904 | return iwm_scan_ssids(iwm, &one_ssid, 1); | ||
905 | } | ||
906 | |||
907 | int iwm_target_reset(struct iwm_priv *iwm) | ||
908 | { | ||
909 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
910 | |||
911 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; | ||
912 | target_cmd.addr = 0; | ||
913 | target_cmd.op1_sz = 0; | ||
914 | target_cmd.op2 = 0; | ||
915 | target_cmd.handle_by_hw = 0; | ||
916 | target_cmd.resp = 0; | ||
917 | target_cmd.eop = 1; | ||
918 | |||
919 | return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
920 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h new file mode 100644 index 000000000000..36b13a130595 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/commands.h | |||
@@ -0,0 +1,419 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_COMMANDS_H__ | ||
40 | #define __IWM_COMMANDS_H__ | ||
41 | |||
42 | #include <linux/ieee80211.h> | ||
43 | |||
44 | #define IWM_BARKER_REBOOT_NOTIFICATION 0xF | ||
45 | #define IWM_ACK_BARKER_NOTIFICATION 0x10 | ||
46 | |||
47 | /* UMAC commands */ | ||
48 | #define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001 | ||
49 | #define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002 | ||
50 | #define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004 | ||
51 | #define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008 | ||
52 | #define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010 | ||
53 | #define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040 | ||
54 | #define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080 | ||
55 | #define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100 | ||
56 | |||
57 | struct iwm_umac_cmd_reset { | ||
58 | __le32 flags; | ||
59 | } __attribute__ ((packed)); | ||
60 | |||
61 | #define UMAC_PARAM_TBL_ORD_FIX 0x0 | ||
62 | #define UMAC_PARAM_TBL_ORD_VAR 0x1 | ||
63 | #define UMAC_PARAM_TBL_CFG_FIX 0x2 | ||
64 | #define UMAC_PARAM_TBL_CFG_VAR 0x3 | ||
65 | #define UMAC_PARAM_TBL_BSS_TRK 0x4 | ||
66 | #define UMAC_PARAM_TBL_FA_CFG_FIX 0x5 | ||
67 | #define UMAC_PARAM_TBL_STA 0x6 | ||
68 | #define UMAC_PARAM_TBL_CHN 0x7 | ||
69 | #define UMAC_PARAM_TBL_STATISTICS 0x8 | ||
70 | |||
71 | /* fast access table */ | ||
72 | enum { | ||
73 | CFG_FRAG_THRESHOLD = 0, | ||
74 | CFG_FRAME_RETRY_LIMIT, | ||
75 | CFG_OS_QUEUE_UTIL_TH, | ||
76 | CFG_RX_FILTER, | ||
77 | /* <-- LAST --> */ | ||
78 | FAST_ACCESS_CFG_TBL_FIX_LAST | ||
79 | }; | ||
80 | |||
81 | /* fixed size table */ | ||
82 | enum { | ||
83 | CFG_POWER_INDEX = 0, | ||
84 | CFG_PM_LEGACY_RX_TIMEOUT, | ||
85 | CFG_PM_LEGACY_TX_TIMEOUT, | ||
86 | CFG_PM_CTRL_FLAGS, | ||
87 | CFG_PM_KEEP_ALIVE_IN_BEACONS, | ||
88 | CFG_BT_ON_THRESHOLD, | ||
89 | CFG_RTS_THRESHOLD, | ||
90 | CFG_CTS_TO_SELF, | ||
91 | CFG_COEX_MODE, | ||
92 | CFG_WIRELESS_MODE, | ||
93 | CFG_ASSOCIATION_TIMEOUT, | ||
94 | CFG_ROAM_TIMEOUT, | ||
95 | CFG_CAPABILITY_SUPPORTED_RATES, | ||
96 | CFG_SCAN_ALLOWED_UNASSOC_FLAGS, | ||
97 | CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS, | ||
98 | CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS, | ||
99 | CFG_SCAN_INTERNAL_PERIODIC_ENABLED, | ||
100 | CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT, | ||
101 | CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC, | ||
102 | CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, | ||
103 | CFG_TLC_SUPPORTED_TX_HT_RATES, | ||
104 | CFG_TLC_SUPPORTED_TX_RATES, | ||
105 | CFG_TLC_VALID_ANTENNA, | ||
106 | CFG_TLC_SPATIAL_STREAM_SUPPORTED, | ||
107 | CFG_TLC_RETRY_PER_RATE, | ||
108 | CFG_TLC_RETRY_PER_HT_RATE, | ||
109 | CFG_TLC_FIXED_RATE, | ||
110 | CFG_TLC_FIXED_RATE_FLAGS, | ||
111 | CFG_TLC_CONTROL_FLAGS, | ||
112 | CFG_TLC_SR_MIN_FAIL, | ||
113 | CFG_TLC_SR_MIN_PASS, | ||
114 | CFG_TLC_HT_STAY_IN_COL_PASS_THRESH, | ||
115 | CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH, | ||
116 | CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH, | ||
117 | CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH, | ||
118 | CFG_TLC_HT_FLUSH_STATS_PACKETS, | ||
119 | CFG_TLC_LEGACY_FLUSH_STATS_PACKETS, | ||
120 | CFG_TLC_LEGACY_FLUSH_STATS_MS, | ||
121 | CFG_TLC_HT_FLUSH_STATS_MS, | ||
122 | CFG_TLC_STAY_IN_COL_TIME_OUT, | ||
123 | CFG_TLC_AGG_SHORT_LIM, | ||
124 | CFG_TLC_AGG_LONG_LIM, | ||
125 | CFG_TLC_HT_SR_NO_DECREASE, | ||
126 | CFG_TLC_LEGACY_SR_NO_DECREASE, | ||
127 | CFG_TLC_SR_FORCE_DECREASE, | ||
128 | CFG_TLC_SR_ALLOW_INCREASE, | ||
129 | CFG_TLC_AGG_SET_LONG, | ||
130 | CFG_TLC_AUTO_AGGREGATION, | ||
131 | CFG_TLC_AGG_THRESHOLD, | ||
132 | CFG_TLC_TID_LOAD_THRESHOLD, | ||
133 | CFG_TLC_BLOCK_ACK_TIMEOUT, | ||
134 | CFG_TLC_NO_BA_COUNTED_AS_ONE, | ||
135 | CFG_TLC_NUM_BA_STREAMS_ALLOWED, | ||
136 | CFG_TLC_NUM_BA_STREAMS_PRESENT, | ||
137 | CFG_TLC_RENEW_ADDBA_DELAY, | ||
138 | CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, | ||
139 | CFG_TLC_IS_STABLE_IN_HT, | ||
140 | CFG_RLC_CHAIN_CTRL, | ||
141 | CFG_TRK_TABLE_OP_MODE, | ||
142 | CFG_TRK_TABLE_RSSI_THRESHOLD, | ||
143 | CFG_TX_PWR_TARGET, /* Used By xVT */ | ||
144 | CFG_TX_PWR_LIMIT_USR, | ||
145 | CFG_TX_PWR_LIMIT_BSS, /* 11d limit */ | ||
146 | CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */ | ||
147 | CFG_TX_PWR_MODE, | ||
148 | CFG_MLME_DBG_NOTIF_BLOCK, | ||
149 | CFG_BT_OFF_BECONS_INTERVALS, | ||
150 | CFG_BT_FRAG_DURATION, | ||
151 | |||
152 | /* <-- LAST --> */ | ||
153 | CFG_TBL_FIX_LAST | ||
154 | }; | ||
155 | |||
156 | /* variable size table */ | ||
157 | enum { | ||
158 | CFG_NET_ADDR = 0, | ||
159 | CFG_PROFILE, | ||
160 | /* <-- LAST --> */ | ||
161 | CFG_TBL_VAR_LAST | ||
162 | }; | ||
163 | |||
164 | struct iwm_umac_cmd_set_param_fix { | ||
165 | __le16 tbl; | ||
166 | __le16 key; | ||
167 | __le32 value; | ||
168 | } __attribute__ ((packed)); | ||
169 | |||
170 | struct iwm_umac_cmd_set_param_var { | ||
171 | __le16 tbl; | ||
172 | __le16 key; | ||
173 | __le16 len; | ||
174 | __le16 reserved; | ||
175 | } __attribute__ ((packed)); | ||
176 | |||
177 | struct iwm_umac_cmd_get_param { | ||
178 | __le16 tbl; | ||
179 | __le16 key; | ||
180 | } __attribute__ ((packed)); | ||
181 | |||
182 | struct iwm_umac_cmd_get_param_resp { | ||
183 | __le16 tbl; | ||
184 | __le16 key; | ||
185 | __le16 len; | ||
186 | __le16 reserved; | ||
187 | } __attribute__ ((packed)); | ||
188 | |||
189 | struct iwm_umac_cmd_eeprom_proxy_hdr { | ||
190 | __le32 type; | ||
191 | __le32 offset; | ||
192 | __le32 len; | ||
193 | } __attribute__ ((packed)); | ||
194 | |||
195 | struct iwm_umac_cmd_eeprom_proxy { | ||
196 | struct iwm_umac_cmd_eeprom_proxy_hdr hdr; | ||
197 | u8 buf[0]; | ||
198 | } __attribute__ ((packed)); | ||
199 | |||
200 | #define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1 | ||
201 | #define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2 | ||
202 | |||
203 | #define UMAC_CHANNEL_FLAG_VALID BIT(0) | ||
204 | #define UMAC_CHANNEL_FLAG_IBSS BIT(1) | ||
205 | #define UMAC_CHANNEL_FLAG_ACTIVE BIT(3) | ||
206 | #define UMAC_CHANNEL_FLAG_RADAR BIT(4) | ||
207 | #define UMAC_CHANNEL_FLAG_DFS BIT(7) | ||
208 | |||
209 | struct iwm_umac_channel_info { | ||
210 | u8 band; | ||
211 | u8 type; | ||
212 | u8 reserved; | ||
213 | u8 flags; | ||
214 | __le32 channels_mask; | ||
215 | } __attribute__ ((packed)); | ||
216 | |||
217 | struct iwm_umac_cmd_get_channel_list { | ||
218 | __le16 count; | ||
219 | __le16 reserved; | ||
220 | struct iwm_umac_channel_info ch[0]; | ||
221 | } __attribute__ ((packed)); | ||
222 | |||
223 | |||
224 | /* UMAC WiFi interface commands */ | ||
225 | |||
226 | /* Coexistence mode */ | ||
227 | #define COEX_MODE_SA 0x1 | ||
228 | #define COEX_MODE_XOR 0x2 | ||
229 | #define COEX_MODE_CM 0x3 | ||
230 | #define COEX_MODE_MAX 0x4 | ||
231 | |||
232 | /* Wireless mode */ | ||
233 | #define WIRELESS_MODE_11A 0x1 | ||
234 | #define WIRELESS_MODE_11G 0x2 | ||
235 | |||
236 | #define UMAC_PROFILE_EX_IE_REQUIRED 0x1 | ||
237 | #define UMAC_PROFILE_QOS_ALLOWED 0x2 | ||
238 | |||
239 | /* Scanning */ | ||
240 | #define UMAC_WIFI_IF_PROBE_OPTION_MAX 10 | ||
241 | |||
242 | #define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0 | ||
243 | #define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1 | ||
244 | #define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2 | ||
245 | #define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3 | ||
246 | |||
247 | struct iwm_umac_ssid { | ||
248 | u8 ssid_len; | ||
249 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
250 | u8 reserved[3]; | ||
251 | } __attribute__ ((packed)); | ||
252 | |||
253 | struct iwm_umac_cmd_scan_request { | ||
254 | struct iwm_umac_wifi_if hdr; | ||
255 | __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */ | ||
256 | u8 ssid_num; | ||
257 | u8 seq_num; | ||
258 | u8 timeout; /* In seconds */ | ||
259 | u8 reserved; | ||
260 | struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX]; | ||
261 | } __attribute__ ((packed)); | ||
262 | |||
263 | #define UMAC_CIPHER_TYPE_NONE 0xFF | ||
264 | #define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00 | ||
265 | #define UMAC_CIPHER_TYPE_WEP_40 0x01 | ||
266 | #define UMAC_CIPHER_TYPE_WEP_104 0x02 | ||
267 | #define UMAC_CIPHER_TYPE_TKIP 0x04 | ||
268 | #define UMAC_CIPHER_TYPE_CCMP 0x08 | ||
269 | |||
270 | /* Supported authentication types - bitmap */ | ||
271 | #define UMAC_AUTH_TYPE_OPEN 0x00 | ||
272 | #define UMAC_AUTH_TYPE_LEGACY_PSK 0x01 | ||
273 | #define UMAC_AUTH_TYPE_8021X 0x02 | ||
274 | #define UMAC_AUTH_TYPE_RSNA_PSK 0x04 | ||
275 | |||
276 | /* iwm_umac_security.flag is WPA supported -- bits[0:0] */ | ||
277 | #define UMAC_SEC_FLG_WPA_ON_POS 0 | ||
278 | #define UMAC_SEC_FLG_WPA_ON_SEED 1 | ||
279 | #define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \ | ||
280 | UMAC_SEC_FLG_WPA_ON_POS) | ||
281 | |||
282 | /* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */ | ||
283 | #define UMAC_SEC_FLG_RSNA_ON_POS 1 | ||
284 | #define UMAC_SEC_FLG_RSNA_ON_SEED 1 | ||
285 | #define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \ | ||
286 | UMAC_SEC_FLG_RSNA_ON_POS) | ||
287 | |||
288 | /* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ | ||
289 | #define UMAC_SEC_FLG_WSC_ON_POS 2 | ||
290 | #define UMAC_SEC_FLG_WSC_ON_SEED 1 | ||
291 | |||
292 | /* Legacy profile can use only WEP40 and WEP104 for encryption and | ||
293 | * OPEN or PSK for authentication */ | ||
294 | #define UMAC_SEC_FLG_LEGACY_PROFILE 0 | ||
295 | |||
296 | struct iwm_umac_security { | ||
297 | u8 auth_type; | ||
298 | u8 ucast_cipher; | ||
299 | u8 mcast_cipher; | ||
300 | u8 flags; | ||
301 | } __attribute__ ((packed)); | ||
302 | |||
303 | struct iwm_umac_ibss { | ||
304 | u8 beacon_interval; /* in millisecond */ | ||
305 | u8 atim; /* in millisecond */ | ||
306 | s8 join_only; | ||
307 | u8 band; | ||
308 | u8 channel; | ||
309 | u8 reserved[3]; | ||
310 | } __attribute__ ((packed)); | ||
311 | |||
312 | #define UMAC_MODE_BSS 0 | ||
313 | #define UMAC_MODE_IBSS 1 | ||
314 | |||
315 | #define UMAC_BSSID_MAX 4 | ||
316 | |||
317 | struct iwm_umac_profile { | ||
318 | struct iwm_umac_wifi_if hdr; | ||
319 | __le32 mode; | ||
320 | struct iwm_umac_ssid ssid; | ||
321 | u8 bssid[UMAC_BSSID_MAX][ETH_ALEN]; | ||
322 | struct iwm_umac_security sec; | ||
323 | struct iwm_umac_ibss ibss; | ||
324 | __le32 channel_2ghz; | ||
325 | __le32 channel_5ghz; | ||
326 | __le16 flags; | ||
327 | u8 wireless_mode; | ||
328 | u8 bss_num; | ||
329 | } __attribute__ ((packed)); | ||
330 | |||
331 | struct iwm_umac_invalidate_profile { | ||
332 | struct iwm_umac_wifi_if hdr; | ||
333 | u8 reason; | ||
334 | u8 reserved[3]; | ||
335 | } __attribute__ ((packed)); | ||
336 | |||
337 | /* Encryption key commands */ | ||
338 | struct iwm_umac_key_wep40 { | ||
339 | struct iwm_umac_wifi_if hdr; | ||
340 | struct iwm_umac_key_hdr key_hdr; | ||
341 | u8 key[WLAN_KEY_LEN_WEP40]; | ||
342 | u8 static_key; | ||
343 | u8 reserved[2]; | ||
344 | } __attribute__ ((packed)); | ||
345 | |||
346 | struct iwm_umac_key_wep104 { | ||
347 | struct iwm_umac_wifi_if hdr; | ||
348 | struct iwm_umac_key_hdr key_hdr; | ||
349 | u8 key[WLAN_KEY_LEN_WEP104]; | ||
350 | u8 static_key; | ||
351 | u8 reserved[2]; | ||
352 | } __attribute__ ((packed)); | ||
353 | |||
354 | #define IWM_TKIP_KEY_SIZE 16 | ||
355 | #define IWM_TKIP_MIC_SIZE 8 | ||
356 | struct iwm_umac_key_tkip { | ||
357 | struct iwm_umac_wifi_if hdr; | ||
358 | struct iwm_umac_key_hdr key_hdr; | ||
359 | u8 iv_count[6]; | ||
360 | u8 reserved[2]; | ||
361 | u8 tkip_key[IWM_TKIP_KEY_SIZE]; | ||
362 | u8 mic_rx_key[IWM_TKIP_MIC_SIZE]; | ||
363 | u8 mic_tx_key[IWM_TKIP_MIC_SIZE]; | ||
364 | } __attribute__ ((packed)); | ||
365 | |||
366 | struct iwm_umac_key_ccmp { | ||
367 | struct iwm_umac_wifi_if hdr; | ||
368 | struct iwm_umac_key_hdr key_hdr; | ||
369 | u8 iv_count[6]; | ||
370 | u8 reserved[2]; | ||
371 | u8 key[WLAN_KEY_LEN_CCMP]; | ||
372 | } __attribute__ ((packed)); | ||
373 | |||
374 | struct iwm_umac_key_remove { | ||
375 | struct iwm_umac_wifi_if hdr; | ||
376 | struct iwm_umac_key_hdr key_hdr; | ||
377 | } __attribute__ ((packed)); | ||
378 | |||
379 | struct iwm_umac_tx_key_id { | ||
380 | struct iwm_umac_wifi_if hdr; | ||
381 | u8 key_idx; | ||
382 | u8 reserved[3]; | ||
383 | } __attribute__ ((packed)); | ||
384 | |||
385 | struct iwm_umac_cmd_stats_req { | ||
386 | __le32 flags; | ||
387 | } __attribute__ ((packed)); | ||
388 | |||
389 | /* LMAC commands */ | ||
390 | int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); | ||
391 | int iwm_send_prio_table(struct iwm_priv *iwm); | ||
392 | int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); | ||
393 | int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); | ||
394 | int iwm_send_calib_results(struct iwm_priv *iwm); | ||
395 | int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); | ||
396 | |||
397 | /* UMAC commands */ | ||
398 | int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, | ||
399 | bool resp); | ||
400 | int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp); | ||
401 | int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value); | ||
402 | int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, | ||
403 | void *payload, u16 payload_size); | ||
404 | int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags); | ||
405 | int iwm_send_mlme_profile(struct iwm_priv *iwm); | ||
406 | int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); | ||
407 | int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); | ||
408 | int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); | ||
409 | int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, | ||
410 | struct iwm_key *key); | ||
411 | int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); | ||
412 | int iwm_send_umac_channel_list(struct iwm_priv *iwm); | ||
413 | int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, | ||
414 | int ssid_num); | ||
415 | int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); | ||
416 | |||
417 | /* UDMA commands */ | ||
418 | int iwm_target_reset(struct iwm_priv *iwm); | ||
419 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h new file mode 100644 index 000000000000..8fbb42d9c21f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debug.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef __IWM_DEBUG_H__ | ||
25 | #define __IWM_DEBUG_H__ | ||
26 | |||
27 | #define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a) | ||
28 | #define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a) | ||
29 | #define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a) | ||
30 | #define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a) | ||
31 | |||
32 | #ifdef CONFIG_IWM_DEBUG | ||
33 | |||
34 | #define IWM_DEBUG_MODULE(i, level, module, f, a...) \ | ||
35 | do { \ | ||
36 | if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ | ||
37 | dev_printk(KERN_INFO, (iwm_to_dev(i)), \ | ||
38 | "%s " f, __func__ , ## a); \ | ||
39 | } while (0) | ||
40 | |||
41 | #define IWM_HEXDUMP(i, level, module, pref, buf, len) \ | ||
42 | do { \ | ||
43 | if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ | ||
44 | print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \ | ||
45 | 16, 1, buf, len, 1); \ | ||
46 | } while (0) | ||
47 | |||
48 | #else | ||
49 | |||
50 | #define IWM_DEBUG_MODULE(i, level, module, f, a...) | ||
51 | #define IWM_HEXDUMP(i, level, module, pref, buf, len) | ||
52 | |||
53 | #endif /* CONFIG_IWM_DEBUG */ | ||
54 | |||
55 | /* Debug modules */ | ||
56 | enum iwm_debug_module_id { | ||
57 | IWM_DM_BOOT = 0, | ||
58 | IWM_DM_FW, | ||
59 | IWM_DM_SDIO, | ||
60 | IWM_DM_NTF, | ||
61 | IWM_DM_RX, | ||
62 | IWM_DM_TX, | ||
63 | IWM_DM_MLME, | ||
64 | IWM_DM_CMD, | ||
65 | IWM_DM_WEXT, | ||
66 | __IWM_DM_NR, | ||
67 | }; | ||
68 | #define IWM_DM_DEFAULT 0 | ||
69 | |||
70 | #define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a) | ||
71 | #define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a) | ||
72 | #define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a) | ||
73 | #define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a) | ||
74 | #define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a) | ||
75 | #define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a) | ||
76 | #define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a) | ||
77 | #define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a) | ||
78 | #define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a) | ||
79 | |||
80 | /* Debug levels */ | ||
81 | enum iwm_debug_level { | ||
82 | IWM_DL_NONE = 0, | ||
83 | IWM_DL_ERR, | ||
84 | IWM_DL_WARN, | ||
85 | IWM_DL_INFO, | ||
86 | IWM_DL_DBG, | ||
87 | }; | ||
88 | #define IWM_DL_DEFAULT IWM_DL_ERR | ||
89 | |||
90 | struct iwm_debugfs { | ||
91 | struct iwm_priv *iwm; | ||
92 | struct dentry *rootdir; | ||
93 | struct dentry *devdir; | ||
94 | struct dentry *dbgdir; | ||
95 | struct dentry *txdir; | ||
96 | struct dentry *rxdir; | ||
97 | struct dentry *busdir; | ||
98 | |||
99 | u32 dbg_level; | ||
100 | struct dentry *dbg_level_dentry; | ||
101 | |||
102 | unsigned long dbg_modules; | ||
103 | struct dentry *dbg_modules_dentry; | ||
104 | |||
105 | u8 dbg_module[__IWM_DM_NR]; | ||
106 | struct dentry *dbg_module_dentries[__IWM_DM_NR]; | ||
107 | |||
108 | struct dentry *txq_dentry; | ||
109 | struct dentry *tx_credit_dentry; | ||
110 | struct dentry *rx_ticket_dentry; | ||
111 | }; | ||
112 | |||
113 | #ifdef CONFIG_IWM_DEBUG | ||
114 | int iwm_debugfs_init(struct iwm_priv *iwm); | ||
115 | void iwm_debugfs_exit(struct iwm_priv *iwm); | ||
116 | #else | ||
117 | static inline int iwm_debugfs_init(struct iwm_priv *iwm) | ||
118 | { | ||
119 | return 0; | ||
120 | } | ||
121 | static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {} | ||
122 | #endif | ||
123 | |||
124 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c new file mode 100644 index 000000000000..0fa7b9150d58 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/debugfs.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/bitops.h> | ||
26 | #include <linux/debugfs.h> | ||
27 | |||
28 | #include "iwm.h" | ||
29 | #include "bus.h" | ||
30 | #include "rx.h" | ||
31 | #include "debug.h" | ||
32 | |||
33 | static struct { | ||
34 | u8 id; | ||
35 | char *name; | ||
36 | } iwm_debug_module[__IWM_DM_NR] = { | ||
37 | {IWM_DM_BOOT, "boot"}, | ||
38 | {IWM_DM_FW, "fw"}, | ||
39 | {IWM_DM_SDIO, "sdio"}, | ||
40 | {IWM_DM_NTF, "ntf"}, | ||
41 | {IWM_DM_RX, "rx"}, | ||
42 | {IWM_DM_TX, "tx"}, | ||
43 | {IWM_DM_MLME, "mlme"}, | ||
44 | {IWM_DM_CMD, "cmd"}, | ||
45 | {IWM_DM_WEXT, "wext"}, | ||
46 | }; | ||
47 | |||
48 | #define add_dbg_module(dbg, name, id, initlevel) \ | ||
49 | do { \ | ||
50 | struct dentry *d; \ | ||
51 | dbg.dbg_module[id] = (initlevel); \ | ||
52 | d = debugfs_create_x8(name, 0600, dbg.dbgdir, \ | ||
53 | &(dbg.dbg_module[id])); \ | ||
54 | if (!IS_ERR(d)) \ | ||
55 | dbg.dbg_module_dentries[id] = d; \ | ||
56 | } while (0) | ||
57 | |||
58 | static int iwm_debugfs_u32_read(void *data, u64 *val) | ||
59 | { | ||
60 | struct iwm_priv *iwm = data; | ||
61 | |||
62 | *val = iwm->dbg.dbg_level; | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int iwm_debugfs_dbg_level_write(void *data, u64 val) | ||
67 | { | ||
68 | struct iwm_priv *iwm = data; | ||
69 | int i; | ||
70 | |||
71 | iwm->dbg.dbg_level = val; | ||
72 | |||
73 | for (i = 0; i < __IWM_DM_NR; i++) | ||
74 | iwm->dbg.dbg_module[i] = val; | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level, | ||
79 | iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write, | ||
80 | "%llu\n"); | ||
81 | |||
82 | static int iwm_debugfs_dbg_modules_write(void *data, u64 val) | ||
83 | { | ||
84 | struct iwm_priv *iwm = data; | ||
85 | int i, bit; | ||
86 | |||
87 | iwm->dbg.dbg_modules = val; | ||
88 | |||
89 | for (i = 0; i < __IWM_DM_NR; i++) | ||
90 | iwm->dbg.dbg_module[i] = 0; | ||
91 | |||
92 | for_each_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) | ||
93 | iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, | ||
98 | iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, | ||
99 | "%llu\n"); | ||
100 | |||
101 | static int iwm_txrx_open(struct inode *inode, struct file *filp) | ||
102 | { | ||
103 | filp->private_data = inode->i_private; | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | |||
108 | static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, | ||
109 | size_t count, loff_t *ppos) | ||
110 | { | ||
111 | struct iwm_priv *iwm = filp->private_data; | ||
112 | char *buf; | ||
113 | int i, buf_len = 4096; | ||
114 | size_t len = 0; | ||
115 | ssize_t ret; | ||
116 | |||
117 | if (*ppos != 0) | ||
118 | return 0; | ||
119 | if (count < sizeof(buf)) | ||
120 | return -ENOSPC; | ||
121 | |||
122 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
123 | if (!buf) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
127 | struct iwm_tx_queue *txq = &iwm->txq[i]; | ||
128 | struct sk_buff *skb; | ||
129 | int j; | ||
130 | unsigned long flags; | ||
131 | |||
132 | spin_lock_irqsave(&txq->queue.lock, flags); | ||
133 | |||
134 | skb = (struct sk_buff *)&txq->queue; | ||
135 | |||
136 | len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i); | ||
137 | len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n", | ||
138 | __netif_subqueue_stopped(iwm_to_ndev(iwm), | ||
139 | txq->id)); | ||
140 | len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n", | ||
141 | txq->concat_count); | ||
142 | len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n", | ||
143 | skb_queue_len(&txq->queue)); | ||
144 | for (j = 0; j < skb_queue_len(&txq->queue); j++) { | ||
145 | struct iwm_tx_info *tx_info; | ||
146 | |||
147 | skb = skb->next; | ||
148 | tx_info = skb_to_tx_info(skb); | ||
149 | |||
150 | len += snprintf(buf + len, buf_len - len, | ||
151 | "\tSKB #%d\n", j); | ||
152 | len += snprintf(buf + len, buf_len - len, | ||
153 | "\t\tsta: %d\n", tx_info->sta); | ||
154 | len += snprintf(buf + len, buf_len - len, | ||
155 | "\t\tcolor: %d\n", tx_info->color); | ||
156 | len += snprintf(buf + len, buf_len - len, | ||
157 | "\t\ttid: %d\n", tx_info->tid); | ||
158 | } | ||
159 | |||
160 | spin_unlock_irqrestore(&txq->queue.lock, flags); | ||
161 | } | ||
162 | |||
163 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
164 | kfree(buf); | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static ssize_t iwm_debugfs_tx_credit_read(struct file *filp, | ||
170 | char __user *buffer, | ||
171 | size_t count, loff_t *ppos) | ||
172 | { | ||
173 | struct iwm_priv *iwm = filp->private_data; | ||
174 | struct iwm_tx_credit *credit = &iwm->tx_credit; | ||
175 | char *buf; | ||
176 | int i, buf_len = 4096; | ||
177 | size_t len = 0; | ||
178 | ssize_t ret; | ||
179 | |||
180 | if (*ppos != 0) | ||
181 | return 0; | ||
182 | if (count < sizeof(buf)) | ||
183 | return -ENOSPC; | ||
184 | |||
185 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
186 | if (!buf) | ||
187 | return -ENOMEM; | ||
188 | |||
189 | len += snprintf(buf + len, buf_len - len, | ||
190 | "NR pools: %d\n", credit->pool_nr); | ||
191 | len += snprintf(buf + len, buf_len - len, | ||
192 | "pools map: 0x%lx\n", credit->full_pools_map); | ||
193 | |||
194 | len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n"); | ||
195 | for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) { | ||
196 | len += snprintf(buf + len, buf_len - len, | ||
197 | "pools entry #%d\n", i); | ||
198 | len += snprintf(buf + len, buf_len - len, | ||
199 | "\tid: %d\n", | ||
200 | credit->pools[i].id); | ||
201 | len += snprintf(buf + len, buf_len - len, | ||
202 | "\tsid: %d\n", | ||
203 | credit->pools[i].sid); | ||
204 | len += snprintf(buf + len, buf_len - len, | ||
205 | "\tmin_pages: %d\n", | ||
206 | credit->pools[i].min_pages); | ||
207 | len += snprintf(buf + len, buf_len - len, | ||
208 | "\tmax_pages: %d\n", | ||
209 | credit->pools[i].max_pages); | ||
210 | len += snprintf(buf + len, buf_len - len, | ||
211 | "\talloc_pages: %d\n", | ||
212 | credit->pools[i].alloc_pages); | ||
213 | len += snprintf(buf + len, buf_len - len, | ||
214 | "\tfreed_pages: %d\n", | ||
215 | credit->pools[i].total_freed_pages); | ||
216 | } | ||
217 | |||
218 | len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n"); | ||
219 | for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) { | ||
220 | len += snprintf(buf + len, buf_len - len, | ||
221 | "spools entry #%d\n", i); | ||
222 | len += snprintf(buf + len, buf_len - len, | ||
223 | "\tid: %d\n", | ||
224 | credit->spools[i].id); | ||
225 | len += snprintf(buf + len, buf_len - len, | ||
226 | "\tmax_pages: %d\n", | ||
227 | credit->spools[i].max_pages); | ||
228 | len += snprintf(buf + len, buf_len - len, | ||
229 | "\talloc_pages: %d\n", | ||
230 | credit->spools[i].alloc_pages); | ||
231 | |||
232 | } | ||
233 | |||
234 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
235 | kfree(buf); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, | ||
241 | char __user *buffer, | ||
242 | size_t count, loff_t *ppos) | ||
243 | { | ||
244 | struct iwm_priv *iwm = filp->private_data; | ||
245 | struct iwm_rx_ticket_node *ticket, *next; | ||
246 | char *buf; | ||
247 | int buf_len = 4096, i; | ||
248 | size_t len = 0; | ||
249 | ssize_t ret; | ||
250 | |||
251 | if (*ppos != 0) | ||
252 | return 0; | ||
253 | if (count < sizeof(buf)) | ||
254 | return -ENOSPC; | ||
255 | |||
256 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
257 | if (!buf) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { | ||
261 | len += snprintf(buf + len, buf_len - len, "Ticket #%d\n", | ||
262 | ticket->ticket->id); | ||
263 | len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n", | ||
264 | ticket->ticket->action); | ||
265 | len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n", | ||
266 | ticket->ticket->flags); | ||
267 | } | ||
268 | |||
269 | for (i = 0; i < IWM_RX_ID_HASH; i++) { | ||
270 | struct iwm_rx_packet *packet, *nxt; | ||
271 | struct list_head *pkt_list = &iwm->rx_packets[i]; | ||
272 | if (!list_empty(pkt_list)) { | ||
273 | len += snprintf(buf + len, buf_len - len, | ||
274 | "Packet hash #%d\n", i); | ||
275 | list_for_each_entry_safe(packet, nxt, pkt_list, node) { | ||
276 | len += snprintf(buf + len, buf_len - len, | ||
277 | "\tPacket id: %d\n", | ||
278 | packet->id); | ||
279 | len += snprintf(buf + len, buf_len - len, | ||
280 | "\tPacket length: %lu\n", | ||
281 | packet->pkt_size); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
287 | kfree(buf); | ||
288 | |||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | |||
293 | static const struct file_operations iwm_debugfs_txq_fops = { | ||
294 | .owner = THIS_MODULE, | ||
295 | .open = iwm_txrx_open, | ||
296 | .read = iwm_debugfs_txq_read, | ||
297 | }; | ||
298 | |||
299 | static const struct file_operations iwm_debugfs_tx_credit_fops = { | ||
300 | .owner = THIS_MODULE, | ||
301 | .open = iwm_txrx_open, | ||
302 | .read = iwm_debugfs_tx_credit_read, | ||
303 | }; | ||
304 | |||
305 | static const struct file_operations iwm_debugfs_rx_ticket_fops = { | ||
306 | .owner = THIS_MODULE, | ||
307 | .open = iwm_txrx_open, | ||
308 | .read = iwm_debugfs_rx_ticket_read, | ||
309 | }; | ||
310 | |||
311 | int iwm_debugfs_init(struct iwm_priv *iwm) | ||
312 | { | ||
313 | int i, result; | ||
314 | char devdir[16]; | ||
315 | |||
316 | iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
317 | result = PTR_ERR(iwm->dbg.rootdir); | ||
318 | if (!result || IS_ERR(iwm->dbg.rootdir)) { | ||
319 | if (result == -ENODEV) { | ||
320 | IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not " | ||
321 | "enabled in kernel config\n"); | ||
322 | result = 0; /* No debugfs support */ | ||
323 | } | ||
324 | IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result); | ||
325 | goto error; | ||
326 | } | ||
327 | |||
328 | snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm))); | ||
329 | |||
330 | iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir); | ||
331 | result = PTR_ERR(iwm->dbg.devdir); | ||
332 | if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) { | ||
333 | IWM_ERR(iwm, "Couldn't create devdir: %d\n", result); | ||
334 | goto error; | ||
335 | } | ||
336 | |||
337 | iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir); | ||
338 | result = PTR_ERR(iwm->dbg.dbgdir); | ||
339 | if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) { | ||
340 | IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result); | ||
341 | goto error; | ||
342 | } | ||
343 | |||
344 | iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir); | ||
345 | result = PTR_ERR(iwm->dbg.rxdir); | ||
346 | if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) { | ||
347 | IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result); | ||
348 | goto error; | ||
349 | } | ||
350 | |||
351 | iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir); | ||
352 | result = PTR_ERR(iwm->dbg.txdir); | ||
353 | if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) { | ||
354 | IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result); | ||
355 | goto error; | ||
356 | } | ||
357 | |||
358 | iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir); | ||
359 | result = PTR_ERR(iwm->dbg.busdir); | ||
360 | if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) { | ||
361 | IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result); | ||
362 | goto error; | ||
363 | } | ||
364 | |||
365 | if (iwm->bus_ops->debugfs_init) { | ||
366 | result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir); | ||
367 | if (result < 0) { | ||
368 | IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result); | ||
369 | goto error; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | |||
374 | iwm->dbg.dbg_level = IWM_DL_NONE; | ||
375 | iwm->dbg.dbg_level_dentry = | ||
376 | debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm, | ||
377 | &fops_iwm_dbg_level); | ||
378 | result = PTR_ERR(iwm->dbg.dbg_level_dentry); | ||
379 | if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) { | ||
380 | IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result); | ||
381 | goto error; | ||
382 | } | ||
383 | |||
384 | |||
385 | iwm->dbg.dbg_modules = IWM_DM_DEFAULT; | ||
386 | iwm->dbg.dbg_modules_dentry = | ||
387 | debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm, | ||
388 | &fops_iwm_dbg_modules); | ||
389 | result = PTR_ERR(iwm->dbg.dbg_modules_dentry); | ||
390 | if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) { | ||
391 | IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result); | ||
392 | goto error; | ||
393 | } | ||
394 | |||
395 | for (i = 0; i < __IWM_DM_NR; i++) | ||
396 | add_dbg_module(iwm->dbg, iwm_debug_module[i].name, | ||
397 | iwm_debug_module[i].id, IWM_DL_DEFAULT); | ||
398 | |||
399 | iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200, | ||
400 | iwm->dbg.txdir, iwm, | ||
401 | &iwm_debugfs_txq_fops); | ||
402 | result = PTR_ERR(iwm->dbg.txq_dentry); | ||
403 | if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) { | ||
404 | IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result); | ||
405 | goto error; | ||
406 | } | ||
407 | |||
408 | iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200, | ||
409 | iwm->dbg.txdir, iwm, | ||
410 | &iwm_debugfs_tx_credit_fops); | ||
411 | result = PTR_ERR(iwm->dbg.tx_credit_dentry); | ||
412 | if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) { | ||
413 | IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result); | ||
414 | goto error; | ||
415 | } | ||
416 | |||
417 | iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200, | ||
418 | iwm->dbg.rxdir, iwm, | ||
419 | &iwm_debugfs_rx_ticket_fops); | ||
420 | result = PTR_ERR(iwm->dbg.rx_ticket_dentry); | ||
421 | if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) { | ||
422 | IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result); | ||
423 | goto error; | ||
424 | } | ||
425 | |||
426 | return 0; | ||
427 | |||
428 | error: | ||
429 | return result; | ||
430 | } | ||
431 | |||
432 | void iwm_debugfs_exit(struct iwm_priv *iwm) | ||
433 | { | ||
434 | int i; | ||
435 | |||
436 | for (i = 0; i < __IWM_DM_NR; i++) | ||
437 | debugfs_remove(iwm->dbg.dbg_module_dentries[i]); | ||
438 | |||
439 | debugfs_remove(iwm->dbg.dbg_modules_dentry); | ||
440 | debugfs_remove(iwm->dbg.dbg_level_dentry); | ||
441 | debugfs_remove(iwm->dbg.txq_dentry); | ||
442 | debugfs_remove(iwm->dbg.tx_credit_dentry); | ||
443 | debugfs_remove(iwm->dbg.rx_ticket_dentry); | ||
444 | if (iwm->bus_ops->debugfs_exit) | ||
445 | iwm->bus_ops->debugfs_exit(iwm); | ||
446 | |||
447 | debugfs_remove(iwm->dbg.busdir); | ||
448 | debugfs_remove(iwm->dbg.dbgdir); | ||
449 | debugfs_remove(iwm->dbg.txdir); | ||
450 | debugfs_remove(iwm->dbg.rxdir); | ||
451 | debugfs_remove(iwm->dbg.devdir); | ||
452 | debugfs_remove(iwm->dbg.rootdir); | ||
453 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c new file mode 100644 index 000000000000..0f34b84fd2eb --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | |||
41 | #include "iwm.h" | ||
42 | #include "umac.h" | ||
43 | #include "commands.h" | ||
44 | #include "eeprom.h" | ||
45 | |||
46 | static struct iwm_eeprom_entry eeprom_map[] = { | ||
47 | [IWM_EEPROM_SIG] = | ||
48 | {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN}, | ||
49 | |||
50 | [IWM_EEPROM_VERSION] = | ||
51 | {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN}, | ||
52 | |||
53 | [IWM_EEPROM_OEM_HW_VERSION] = | ||
54 | {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF, | ||
55 | IWM_EEPROM_OEM_HW_VERSION_LEN}, | ||
56 | |||
57 | [IWM_EEPROM_MAC_VERSION] = | ||
58 | {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN}, | ||
59 | |||
60 | [IWM_EEPROM_CARD_ID] = | ||
61 | {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN}, | ||
62 | |||
63 | [IWM_EEPROM_RADIO_CONF] = | ||
64 | {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN}, | ||
65 | |||
66 | [IWM_EEPROM_SKU_CAP] = | ||
67 | {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, | ||
68 | |||
69 | [IWM_EEPROM_CALIB_RXIQ_OFFSET] = | ||
70 | {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, | ||
71 | |||
72 | [IWM_EEPROM_CALIB_RXIQ] = | ||
73 | {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN}, | ||
74 | }; | ||
75 | |||
76 | |||
77 | static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id) | ||
78 | { | ||
79 | int ret; | ||
80 | u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0; | ||
81 | u32 addr; | ||
82 | struct iwm_udma_wifi_cmd udma_cmd; | ||
83 | struct iwm_umac_cmd umac_cmd; | ||
84 | struct iwm_umac_cmd_eeprom_proxy eeprom_cmd; | ||
85 | |||
86 | if (eeprom_id > (IWM_EEPROM_LAST - 1)) | ||
87 | return -EINVAL; | ||
88 | |||
89 | entry_size = eeprom_map[eeprom_id].length; | ||
90 | |||
91 | if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) { | ||
92 | /* indirect data */ | ||
93 | u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA + | ||
94 | IWM_EEPROM_INDIRECT_OFFSET; | ||
95 | |||
96 | eeprom_map[eeprom_id].offset = | ||
97 | *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1; | ||
98 | } | ||
99 | |||
100 | addr = eeprom_map[eeprom_id].offset; | ||
101 | |||
102 | udma_cmd.eop = 1; | ||
103 | udma_cmd.credit_group = 0x4; | ||
104 | udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD; | ||
105 | udma_cmd.lmac_offset = 0; | ||
106 | |||
107 | umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY; | ||
108 | umac_cmd.resp = 1; | ||
109 | |||
110 | while (entry_size > 0) { | ||
111 | chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN); | ||
112 | |||
113 | eeprom_cmd.hdr.type = | ||
114 | cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ); | ||
115 | eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset); | ||
116 | eeprom_cmd.hdr.len = cpu_to_le32(chunk_size); | ||
117 | |||
118 | ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, | ||
119 | &umac_cmd, &eeprom_cmd, | ||
120 | sizeof(struct iwm_umac_cmd_eeprom_proxy)); | ||
121 | if (ret < 0) { | ||
122 | IWM_ERR(iwm, "Couldn't read eeprom\n"); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY, | ||
127 | IWM_SRC_UMAC, 2*HZ); | ||
128 | if (ret < 0) { | ||
129 | IWM_ERR(iwm, "Did not get any eeprom answer\n"); | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | data_offset += chunk_size; | ||
134 | addr_offset += chunk_size; | ||
135 | entry_size -= chunk_size; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) | ||
142 | { | ||
143 | if (!iwm->eeprom) | ||
144 | return ERR_PTR(-ENODEV); | ||
145 | |||
146 | return iwm->eeprom + eeprom_map[eeprom_id].offset; | ||
147 | } | ||
148 | |||
149 | int iwm_eeprom_init(struct iwm_priv *iwm) | ||
150 | { | ||
151 | int i, ret = 0; | ||
152 | char name[32]; | ||
153 | |||
154 | iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL); | ||
155 | if (!iwm->eeprom) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { | ||
159 | #ifdef CONFIG_IWM_B0_HW_SUPPORT | ||
160 | if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) | ||
161 | break; | ||
162 | #endif | ||
163 | ret = iwm_eeprom_read(iwm, i); | ||
164 | if (ret < 0) { | ||
165 | IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", | ||
166 | i, eeprom_map[i].name); | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n"); | ||
172 | for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { | ||
173 | memset(name, 0, 32); | ||
174 | sprintf(name, "%s: ", eeprom_map[i].name); | ||
175 | |||
176 | IWM_HEXDUMP(iwm, DBG, BOOT, name, | ||
177 | iwm->eeprom + eeprom_map[i].offset, | ||
178 | eeprom_map[i].length); | ||
179 | } | ||
180 | |||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | void iwm_eeprom_exit(struct iwm_priv *iwm) | ||
185 | { | ||
186 | kfree(iwm->eeprom); | ||
187 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h new file mode 100644 index 000000000000..cdb31a6a1f5f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_EEPROM_H__ | ||
40 | #define __IWM_EEPROM_H__ | ||
41 | |||
42 | enum { | ||
43 | IWM_EEPROM_SIG = 0, | ||
44 | IWM_EEPROM_FIRST = IWM_EEPROM_SIG, | ||
45 | IWM_EEPROM_VERSION, | ||
46 | IWM_EEPROM_OEM_HW_VERSION, | ||
47 | IWM_EEPROM_MAC_VERSION, | ||
48 | IWM_EEPROM_CARD_ID, | ||
49 | IWM_EEPROM_RADIO_CONF, | ||
50 | IWM_EEPROM_SKU_CAP, | ||
51 | |||
52 | IWM_EEPROM_INDIRECT_OFFSET, | ||
53 | IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, | ||
54 | |||
55 | IWM_EEPROM_INDIRECT_DATA, | ||
56 | IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA, | ||
57 | |||
58 | IWM_EEPROM_LAST, | ||
59 | }; | ||
60 | |||
61 | #define IWM_EEPROM_SIG_OFF 0x00 | ||
62 | #define IWM_EEPROM_VERSION_OFF (0x54 << 1) | ||
63 | #define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) | ||
64 | #define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) | ||
65 | #define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) | ||
66 | #define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) | ||
67 | #define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) | ||
68 | #define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) | ||
69 | |||
70 | #define IWM_EEPROM_SIG_LEN 4 | ||
71 | #define IWM_EEPROM_VERSION_LEN 2 | ||
72 | #define IWM_EEPROM_OEM_HW_VERSION_LEN 2 | ||
73 | #define IWM_EEPROM_MAC_VERSION_LEN 1 | ||
74 | #define IWM_EEPROM_CARD_ID_LEN 2 | ||
75 | #define IWM_EEPROM_RADIO_CONF_LEN 2 | ||
76 | #define IWM_EEPROM_SKU_CAP_LEN 2 | ||
77 | #define IWM_EEPROM_INDIRECT_LEN 2 | ||
78 | |||
79 | #define IWM_MAX_EEPROM_DATA_LEN 240 | ||
80 | #define IWM_EEPROM_LEN 0x800 | ||
81 | |||
82 | #define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610 | ||
83 | #define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700 | ||
84 | #define IWM_EEPROM_CURRENT_VERSION 0x0612 | ||
85 | |||
86 | #define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4) | ||
87 | #define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) | ||
88 | #define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) | ||
89 | |||
90 | enum { | ||
91 | IWM_EEPROM_CALIB_CAL_HDR, | ||
92 | IWM_EEPROM_CALIB_TX_POWER, | ||
93 | IWM_EEPROM_CALIB_XTAL, | ||
94 | IWM_EEPROM_CALIB_TEMPERATURE, | ||
95 | IWM_EEPROM_CALIB_RX_BB_FILTER, | ||
96 | IWM_EEPROM_CALIB_RX_IQ, | ||
97 | IWM_EEPROM_CALIB_MAX, | ||
98 | }; | ||
99 | |||
100 | #define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \ | ||
101 | (IWM_EEPROM_CALIB_RX_IQ << 1)) | ||
102 | #define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq) | ||
103 | |||
104 | struct iwm_eeprom_entry { | ||
105 | char *name; | ||
106 | u32 offset; | ||
107 | u32 length; | ||
108 | }; | ||
109 | |||
110 | int iwm_eeprom_init(struct iwm_priv *iwm); | ||
111 | void iwm_eeprom_exit(struct iwm_priv *iwm); | ||
112 | u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); | ||
113 | |||
114 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c new file mode 100644 index 000000000000..db4ba0864730 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/firmware.h> | ||
41 | |||
42 | #include "iwm.h" | ||
43 | #include "bus.h" | ||
44 | #include "hal.h" | ||
45 | #include "umac.h" | ||
46 | #include "debug.h" | ||
47 | #include "fw.h" | ||
48 | #include "commands.h" | ||
49 | |||
50 | static const char fw_barker[] = "*WESTOPFORNOONE*"; | ||
51 | |||
52 | /* | ||
53 | * @op_code: Op code we're looking for. | ||
54 | * @index: There can be several instances of the same opcode within | ||
55 | * the firmware. Index specifies which one we're looking for. | ||
56 | */ | ||
57 | static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, | ||
58 | u16 op_code, u32 index) | ||
59 | { | ||
60 | int offset = -EINVAL, fw_offset; | ||
61 | u32 op_index = 0; | ||
62 | const u8 *fw_ptr; | ||
63 | struct iwm_fw_hdr_rec *rec; | ||
64 | |||
65 | fw_offset = 0; | ||
66 | fw_ptr = fw->data; | ||
67 | |||
68 | /* We first need to look for the firmware barker */ | ||
69 | if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) { | ||
70 | IWM_ERR(iwm, "No barker string in this FW\n"); | ||
71 | return -EINVAL; | ||
72 | } | ||
73 | |||
74 | if (fw->size < IWM_HDR_LEN) { | ||
75 | IWM_ERR(iwm, "FW is too small (%d)\n", fw->size); | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | fw_offset += IWM_HDR_BARKER_LEN; | ||
80 | |||
81 | while (fw_offset < fw->size) { | ||
82 | rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset); | ||
83 | |||
84 | IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n", | ||
85 | rec->op_code, rec->len, fw_offset); | ||
86 | |||
87 | if (rec->op_code == IWM_HDR_REC_OP_INVALID) { | ||
88 | IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n"); | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | if (rec->op_code == op_code) { | ||
93 | if (op_index == index) { | ||
94 | fw_offset += sizeof(struct iwm_fw_hdr_rec); | ||
95 | offset = fw_offset; | ||
96 | goto out; | ||
97 | } | ||
98 | op_index++; | ||
99 | } | ||
100 | |||
101 | fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len; | ||
102 | } | ||
103 | |||
104 | out: | ||
105 | return offset; | ||
106 | } | ||
107 | |||
108 | static int iwm_load_firmware_chunk(struct iwm_priv *iwm, | ||
109 | const struct firmware *fw, | ||
110 | struct iwm_fw_img_desc *img_desc) | ||
111 | { | ||
112 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
113 | u32 chunk_size; | ||
114 | const u8 *chunk_ptr; | ||
115 | int ret = 0; | ||
116 | |||
117 | IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n", | ||
118 | img_desc->length, img_desc->address); | ||
119 | |||
120 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
121 | target_cmd.handle_by_hw = 1; | ||
122 | target_cmd.op2 = 0; | ||
123 | target_cmd.resp = 0; | ||
124 | target_cmd.eop = 1; | ||
125 | |||
126 | chunk_size = img_desc->length; | ||
127 | chunk_ptr = fw->data + img_desc->offset; | ||
128 | |||
129 | while (chunk_size > 0) { | ||
130 | u32 tmp_chunk_size; | ||
131 | |||
132 | tmp_chunk_size = min_t(u32, chunk_size, | ||
133 | IWM_MAX_NONWIFI_CMD_BUFF_SIZE); | ||
134 | |||
135 | target_cmd.addr = cpu_to_le32(img_desc->address + | ||
136 | (chunk_ptr - fw->data - img_desc->offset)); | ||
137 | target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size); | ||
138 | |||
139 | IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n", | ||
140 | tmp_chunk_size, target_cmd.addr); | ||
141 | |||
142 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr); | ||
143 | if (ret < 0) { | ||
144 | IWM_ERR(iwm, "Couldn't load FW chunk\n"); | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | chunk_size -= tmp_chunk_size; | ||
149 | chunk_ptr += tmp_chunk_size; | ||
150 | } | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | /* | ||
155 | * To load a fw image to the target, we basically go through the | ||
156 | * fw, looking for OP_MEM_DESC records. Once we found one, we | ||
157 | * pass it to iwm_load_firmware_chunk(). | ||
158 | * The OP_MEM_DESC records contain the actuall memory chunk to be | ||
159 | * sent, but also the destination address. | ||
160 | */ | ||
161 | static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) | ||
162 | { | ||
163 | const struct firmware *fw; | ||
164 | struct iwm_fw_img_desc *img_desc; | ||
165 | struct iwm_fw_img_ver *ver; | ||
166 | int ret = 0, fw_offset; | ||
167 | u32 opcode_idx = 0, build_date; | ||
168 | char *build_tag; | ||
169 | |||
170 | ret = request_firmware(&fw, img_name, iwm_to_dev(iwm)); | ||
171 | if (ret) { | ||
172 | IWM_ERR(iwm, "Request firmware failed"); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name); | ||
177 | |||
178 | while (1) { | ||
179 | fw_offset = iwm_fw_op_offset(iwm, fw, | ||
180 | IWM_HDR_REC_OP_MEM_DESC, | ||
181 | opcode_idx); | ||
182 | if (fw_offset < 0) | ||
183 | break; | ||
184 | |||
185 | img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset); | ||
186 | ret = iwm_load_firmware_chunk(iwm, fw, img_desc); | ||
187 | if (ret < 0) | ||
188 | goto err_release_fw; | ||
189 | opcode_idx++; | ||
190 | }; | ||
191 | |||
192 | /* Read firmware version */ | ||
193 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); | ||
194 | if (fw_offset < 0) | ||
195 | goto err_release_fw; | ||
196 | |||
197 | ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset); | ||
198 | |||
199 | /* Read build tag */ | ||
200 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0); | ||
201 | if (fw_offset < 0) | ||
202 | goto err_release_fw; | ||
203 | |||
204 | build_tag = (char *)(fw->data + fw_offset); | ||
205 | |||
206 | /* Read build date */ | ||
207 | fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0); | ||
208 | if (fw_offset < 0) | ||
209 | goto err_release_fw; | ||
210 | |||
211 | build_date = *(u32 *)(fw->data + fw_offset); | ||
212 | |||
213 | IWM_INFO(iwm, "%s:\n", img_name); | ||
214 | IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor); | ||
215 | IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag); | ||
216 | IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n", | ||
217 | IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), | ||
218 | IWM_BUILD_DAY(build_date)); | ||
219 | |||
220 | |||
221 | err_release_fw: | ||
222 | release_firmware(fw); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | static int iwm_load_umac(struct iwm_priv *iwm) | ||
228 | { | ||
229 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
230 | int ret; | ||
231 | |||
232 | ret = iwm_load_img(iwm, iwm->bus_ops->umac_name); | ||
233 | if (ret < 0) | ||
234 | return ret; | ||
235 | |||
236 | /* We've loaded the UMAC, we can tell the target to jump there */ | ||
237 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP; | ||
238 | target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR); | ||
239 | target_cmd.op1_sz = 0; | ||
240 | target_cmd.op2 = 0; | ||
241 | target_cmd.handle_by_hw = 0; | ||
242 | target_cmd.resp = 1 ; | ||
243 | target_cmd.eop = 1; | ||
244 | |||
245 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); | ||
246 | if (ret < 0) | ||
247 | IWM_ERR(iwm, "Couldn't send JMP command\n"); | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) | ||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | ret = iwm_load_img(iwm, img_name); | ||
257 | if (ret < 0) | ||
258 | return ret; | ||
259 | |||
260 | return iwm_send_umac_reset(iwm, | ||
261 | cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * We currently have to load 3 FWs: | ||
266 | * 1) The UMAC (Upper MAC). | ||
267 | * 2) The calibration LMAC (Lower MAC). | ||
268 | * We then send the calibration init command, so that the device can | ||
269 | * run a first calibration round. | ||
270 | * 3) The operational LMAC, which replaces the calibration one when it's | ||
271 | * done with the first calibration round. | ||
272 | * | ||
273 | * Once those 3 FWs have been loaded, we send the periodic calibration | ||
274 | * command, and then the device is available for regular 802.11 operations. | ||
275 | */ | ||
276 | int iwm_load_fw(struct iwm_priv *iwm) | ||
277 | { | ||
278 | int ret; | ||
279 | |||
280 | /* We first start downloading the UMAC */ | ||
281 | ret = iwm_load_umac(iwm); | ||
282 | if (ret < 0) { | ||
283 | IWM_ERR(iwm, "UMAC loading failed\n"); | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | /* Handle UMAC_ALIVE notification */ | ||
288 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC, | ||
289 | WAIT_NOTIF_TIMEOUT); | ||
290 | if (ret) { | ||
291 | IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret); | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | /* UMAC is alive, we can download the calibration LMAC */ | ||
296 | ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name); | ||
297 | if (ret) { | ||
298 | IWM_ERR(iwm, "Calibration LMAC loading failed\n"); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | /* Handle UMAC_INIT_COMPLETE notification */ | ||
303 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, | ||
304 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
305 | if (ret) { | ||
306 | IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration " | ||
307 | "LMAC: %d\n", ret); | ||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | /* Read EEPROM data */ | ||
312 | ret = iwm_eeprom_init(iwm); | ||
313 | if (ret < 0) { | ||
314 | IWM_ERR(iwm, "Couldn't init eeprom array\n"); | ||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | #ifdef CONFIG_IWM_B0_HW_SUPPORT | ||
319 | if (iwm->conf.hw_b0) { | ||
320 | clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); | ||
321 | clear_bit(PHY_CALIBRATE_RX_IQ_CMD, | ||
322 | &iwm->conf.periodic_calib_map); | ||
323 | } | ||
324 | #endif | ||
325 | /* Read RX IQ calibration result from EEPROM */ | ||
326 | if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { | ||
327 | iwm_store_rxiq_calib_result(iwm); | ||
328 | set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); | ||
329 | } | ||
330 | |||
331 | iwm_send_prio_table(iwm); | ||
332 | iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); | ||
333 | |||
334 | while (iwm->calib_done_map != iwm->conf.init_calib_map) { | ||
335 | ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, | ||
336 | IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); | ||
337 | if (ret) { | ||
338 | IWM_ERR(iwm, "Wait for calibration result timeout\n"); | ||
339 | goto out; | ||
340 | } | ||
341 | IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " | ||
342 | "0x%lx, requested calibrations: 0x%lx\n", | ||
343 | iwm->calib_done_map, iwm->conf.init_calib_map); | ||
344 | } | ||
345 | |||
346 | /* Handle LMAC CALIBRATION_COMPLETE notification */ | ||
347 | ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION, | ||
348 | IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); | ||
349 | if (ret) { | ||
350 | IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n"); | ||
351 | goto out; | ||
352 | } | ||
353 | |||
354 | IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map); | ||
355 | |||
356 | iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1); | ||
357 | |||
358 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, | ||
359 | WAIT_NOTIF_TIMEOUT); | ||
360 | if (ret) { | ||
361 | IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | /* Download the operational LMAC */ | ||
366 | ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name); | ||
367 | if (ret) { | ||
368 | IWM_ERR(iwm, "LMAC loading failed\n"); | ||
369 | goto out; | ||
370 | } | ||
371 | |||
372 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, | ||
373 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
374 | if (ret) { | ||
375 | IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret); | ||
376 | goto out; | ||
377 | } | ||
378 | |||
379 | iwm_send_prio_table(iwm); | ||
380 | iwm_send_calib_results(iwm); | ||
381 | iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); | ||
382 | |||
383 | return 0; | ||
384 | |||
385 | out: | ||
386 | iwm_eeprom_exit(iwm); | ||
387 | return ret; | ||
388 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h new file mode 100644 index 000000000000..c70a3b40dad3 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/fw.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_FW_H__ | ||
40 | #define __IWM_FW_H__ | ||
41 | |||
42 | /** | ||
43 | * struct iwm_fw_hdr_rec - An iwm firmware image is a | ||
44 | * concatenation of various records. Each of them is | ||
45 | * defined by an ID (aka op code), a length, and the | ||
46 | * actual data. | ||
47 | * @op_code: The record ID, see IWM_HDR_REC_OP_* | ||
48 | * | ||
49 | * @len: The record payload length | ||
50 | * | ||
51 | * @buf: The record payload | ||
52 | */ | ||
53 | struct iwm_fw_hdr_rec { | ||
54 | u16 op_code; | ||
55 | u16 len; | ||
56 | u8 buf[0]; | ||
57 | }; | ||
58 | |||
59 | /* Header's definitions */ | ||
60 | #define IWM_HDR_LEN (512) | ||
61 | #define IWM_HDR_BARKER_LEN (16) | ||
62 | |||
63 | /* Header's opcodes */ | ||
64 | #define IWM_HDR_REC_OP_INVALID (0x00) | ||
65 | #define IWM_HDR_REC_OP_BUILD_DATE (0x01) | ||
66 | #define IWM_HDR_REC_OP_BUILD_TAG (0x02) | ||
67 | #define IWM_HDR_REC_OP_SW_VER (0x03) | ||
68 | #define IWM_HDR_REC_OP_HW_SKU (0x04) | ||
69 | #define IWM_HDR_REC_OP_BUILD_OPT (0x05) | ||
70 | #define IWM_HDR_REC_OP_MEM_DESC (0x06) | ||
71 | #define IWM_HDR_REC_USERDEFS (0x07) | ||
72 | |||
73 | /* Header's records length (in bytes) */ | ||
74 | #define IWM_HDR_REC_LEN_BUILD_DATE (4) | ||
75 | #define IWM_HDR_REC_LEN_BUILD_TAG (64) | ||
76 | #define IWM_HDR_REC_LEN_SW_VER (4) | ||
77 | #define IWM_HDR_REC_LEN_HW_SKU (4) | ||
78 | #define IWM_HDR_REC_LEN_BUILD_OPT (4) | ||
79 | #define IWM_HDR_REC_LEN_MEM_DESC (12) | ||
80 | #define IWM_HDR_REC_LEN_USERDEF (64) | ||
81 | |||
82 | #define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff) | ||
83 | #define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff) | ||
84 | #define IWM_BUILD_DAY(date) (date & 0xff) | ||
85 | |||
86 | struct iwm_fw_img_desc { | ||
87 | u32 offset; | ||
88 | u32 address; | ||
89 | u32 length; | ||
90 | }; | ||
91 | |||
92 | struct iwm_fw_img_ver { | ||
93 | u8 minor; | ||
94 | u8 major; | ||
95 | u16 reserved; | ||
96 | }; | ||
97 | |||
98 | int iwm_load_fw(struct iwm_priv *iwm); | ||
99 | |||
100 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c new file mode 100644 index 000000000000..ee127fe4f43f --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.c | |||
@@ -0,0 +1,464 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * Hardware Abstraction Layer for iwm. | ||
41 | * | ||
42 | * This file mostly defines an abstraction API for | ||
43 | * sending various commands to the target. | ||
44 | * | ||
45 | * We have 2 types of commands: wifi and non-wifi ones. | ||
46 | * | ||
47 | * - wifi commands: | ||
48 | * They are used for sending LMAC and UMAC commands, | ||
49 | * and thus are the most commonly used ones. | ||
50 | * There are 2 different wifi command types, the regular | ||
51 | * one and the LMAC one. The former is used to send | ||
52 | * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h) | ||
53 | * while the latter is used for sending commands to the | ||
54 | * LMAC. If you look at LMAC commands you'll se that they | ||
55 | * are actually regular iwlwifi target commands encapsulated | ||
56 | * into a special UMAC command called UMAC passthrough. | ||
57 | * This is due to the fact the the host talks exclusively | ||
58 | * to the UMAC and so there needs to be a special UMAC | ||
59 | * command for talking to the LMAC. | ||
60 | * This is how a wifi command is layed out: | ||
61 | * ------------------------ | ||
62 | * | iwm_udma_out_wifi_hdr | | ||
63 | * ------------------------ | ||
64 | * | SW meta_data (32 bits) | | ||
65 | * ------------------------ | ||
66 | * | iwm_dev_cmd_hdr | | ||
67 | * ------------------------ | ||
68 | * | payload | | ||
69 | * | .... | | ||
70 | * | ||
71 | * - non-wifi, or general commands: | ||
72 | * Those commands are handled by the device's bootrom, | ||
73 | * and are typically sent when the UMAC and the LMAC | ||
74 | * are not yet available. | ||
75 | * * This is how a non-wifi command is layed out: | ||
76 | * --------------------------- | ||
77 | * | iwm_udma_out_nonwifi_hdr | | ||
78 | * --------------------------- | ||
79 | * | payload | | ||
80 | * | .... | | ||
81 | |||
82 | * | ||
83 | * All the commands start with a UDMA header, which is | ||
84 | * basically a 32 bits field. The 4 LSB there define | ||
85 | * an opcode that allows the target to differentiate | ||
86 | * between wifi (opcode is 0xf) and non-wifi commands | ||
87 | * (opcode is [0..0xe]). | ||
88 | * | ||
89 | * When a command (wifi or non-wifi) is supposed to receive | ||
90 | * an answer, we queue the command buffer. When we do receive | ||
91 | * a command response from the UMAC, we go through the list | ||
92 | * of pending command, and pass both the command and the answer | ||
93 | * to the rx handler. Each command is sent with a unique | ||
94 | * sequence id, and the answer is sent with the same one. This | ||
95 | * is how we're supposed to match an answer with its command. | ||
96 | * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi() | ||
97 | * for the implementation details. | ||
98 | */ | ||
99 | #include <linux/kernel.h> | ||
100 | #include <linux/netdevice.h> | ||
101 | |||
102 | #include "iwm.h" | ||
103 | #include "bus.h" | ||
104 | #include "hal.h" | ||
105 | #include "umac.h" | ||
106 | #include "debug.h" | ||
107 | |||
108 | static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, | ||
109 | struct iwm_nonwifi_cmd *cmd, | ||
110 | struct iwm_udma_nonwifi_cmd *udma_cmd) | ||
111 | { | ||
112 | INIT_LIST_HEAD(&cmd->pending); | ||
113 | |||
114 | spin_lock(&iwm->cmd_lock); | ||
115 | |||
116 | cmd->resp_received = 0; | ||
117 | |||
118 | cmd->seq_num = iwm->nonwifi_seq_num; | ||
119 | udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
120 | |||
121 | cmd->seq_num = iwm->nonwifi_seq_num++; | ||
122 | iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; | ||
123 | |||
124 | if (udma_cmd->resp) | ||
125 | list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd); | ||
126 | |||
127 | spin_unlock(&iwm->cmd_lock); | ||
128 | |||
129 | cmd->buf.start = cmd->buf.payload; | ||
130 | cmd->buf.len = 0; | ||
131 | |||
132 | memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); | ||
133 | } | ||
134 | |||
135 | u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) | ||
136 | { | ||
137 | u16 seq_num = iwm->wifi_seq_num; | ||
138 | |||
139 | iwm->wifi_seq_num++; | ||
140 | iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX; | ||
141 | |||
142 | return seq_num; | ||
143 | } | ||
144 | |||
145 | static void iwm_wifi_cmd_init(struct iwm_priv *iwm, | ||
146 | struct iwm_wifi_cmd *cmd, | ||
147 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
148 | struct iwm_umac_cmd *umac_cmd, | ||
149 | struct iwm_lmac_cmd *lmac_cmd, | ||
150 | u16 payload_size) | ||
151 | { | ||
152 | INIT_LIST_HEAD(&cmd->pending); | ||
153 | |||
154 | spin_lock(&iwm->cmd_lock); | ||
155 | |||
156 | cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm); | ||
157 | umac_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
158 | |||
159 | if (umac_cmd->resp) | ||
160 | list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd); | ||
161 | |||
162 | spin_unlock(&iwm->cmd_lock); | ||
163 | |||
164 | cmd->buf.start = cmd->buf.payload; | ||
165 | cmd->buf.len = 0; | ||
166 | |||
167 | if (lmac_cmd) { | ||
168 | cmd->buf.start -= sizeof(struct iwm_lmac_hdr); | ||
169 | |||
170 | lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num); | ||
171 | lmac_cmd->count = cpu_to_le16(payload_size); | ||
172 | |||
173 | memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd)); | ||
174 | |||
175 | umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr)); | ||
176 | } else | ||
177 | umac_cmd->count = 0; | ||
178 | |||
179 | umac_cmd->count = cpu_to_le16(payload_size + | ||
180 | le16_to_cpu(umac_cmd->count)); | ||
181 | udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) + | ||
182 | le16_to_cpu(umac_cmd->count)); | ||
183 | |||
184 | memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); | ||
185 | memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd)); | ||
186 | } | ||
187 | |||
188 | void iwm_cmd_flush(struct iwm_priv *iwm) | ||
189 | { | ||
190 | struct iwm_wifi_cmd *wcmd, *wnext; | ||
191 | struct iwm_nonwifi_cmd *nwcmd, *nwnext; | ||
192 | |||
193 | list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) { | ||
194 | list_del(&wcmd->pending); | ||
195 | kfree(wcmd); | ||
196 | } | ||
197 | |||
198 | list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd, | ||
199 | pending) { | ||
200 | list_del(&nwcmd->pending); | ||
201 | kfree(nwcmd); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num) | ||
206 | { | ||
207 | struct iwm_wifi_cmd *cmd, *next; | ||
208 | |||
209 | list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending) | ||
210 | if (cmd->seq_num == seq_num) { | ||
211 | list_del(&cmd->pending); | ||
212 | return cmd; | ||
213 | } | ||
214 | |||
215 | return NULL; | ||
216 | } | ||
217 | |||
218 | struct iwm_nonwifi_cmd * | ||
219 | iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode) | ||
220 | { | ||
221 | struct iwm_nonwifi_cmd *cmd, *next; | ||
222 | |||
223 | list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) | ||
224 | if ((cmd->seq_num == seq_num) && | ||
225 | (cmd->udma_cmd.opcode == cmd_opcode) && | ||
226 | (cmd->resp_received)) { | ||
227 | list_del(&cmd->pending); | ||
228 | return cmd; | ||
229 | } | ||
230 | |||
231 | return NULL; | ||
232 | } | ||
233 | |||
234 | static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm, | ||
235 | struct iwm_udma_out_nonwifi_hdr *hdr, | ||
236 | struct iwm_udma_nonwifi_cmd *cmd) | ||
237 | { | ||
238 | memset(hdr, 0, sizeof(*hdr)); | ||
239 | |||
240 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode); | ||
241 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp); | ||
242 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1); | ||
243 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW, | ||
244 | cmd->handle_by_hw); | ||
245 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); | ||
246 | SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM, | ||
247 | le16_to_cpu(cmd->seq_num)); | ||
248 | |||
249 | hdr->addr = cmd->addr; | ||
250 | hdr->op1_sz = cmd->op1_sz; | ||
251 | hdr->op2 = cmd->op2; | ||
252 | } | ||
253 | |||
254 | static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm, | ||
255 | struct iwm_nonwifi_cmd *cmd) | ||
256 | { | ||
257 | struct iwm_udma_out_nonwifi_hdr *udma_hdr; | ||
258 | struct iwm_nonwifi_cmd_buff *buf; | ||
259 | struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd; | ||
260 | |||
261 | buf = &cmd->buf; | ||
262 | |||
263 | buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr); | ||
264 | buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr); | ||
265 | |||
266 | udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start); | ||
267 | |||
268 | iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd); | ||
269 | |||
270 | IWM_DBG_CMD(iwm, DBG, | ||
271 | "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, " | ||
272 | "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, " | ||
273 | "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp, | ||
274 | udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr, | ||
275 | udma_cmd->op1_sz, udma_cmd->op2); | ||
276 | |||
277 | return iwm_bus_send_chunk(iwm, buf->start, buf->len); | ||
278 | } | ||
279 | |||
280 | void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop) | ||
281 | { | ||
282 | struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf; | ||
283 | |||
284 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop); | ||
285 | } | ||
286 | |||
287 | void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, | ||
288 | struct iwm_udma_out_wifi_hdr *hdr, | ||
289 | struct iwm_udma_wifi_cmd *cmd) | ||
290 | { | ||
291 | memset(hdr, 0, sizeof(*hdr)); | ||
292 | |||
293 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI); | ||
294 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop); | ||
295 | SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); | ||
296 | |||
297 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT, | ||
298 | le16_to_cpu(cmd->count)); | ||
299 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group); | ||
300 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid); | ||
301 | SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset); | ||
302 | } | ||
303 | |||
304 | void iwm_build_umac_hdr(struct iwm_priv *iwm, | ||
305 | struct iwm_umac_fw_cmd_hdr *hdr, | ||
306 | struct iwm_umac_cmd *cmd) | ||
307 | { | ||
308 | memset(hdr, 0, sizeof(*hdr)); | ||
309 | |||
310 | SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT, | ||
311 | le16_to_cpu(cmd->count)); | ||
312 | SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color); | ||
313 | SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp); | ||
314 | |||
315 | hdr->cmd.cmd = cmd->id; | ||
316 | hdr->cmd.seq_num = cmd->seq_num; | ||
317 | } | ||
318 | |||
319 | static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm, | ||
320 | struct iwm_wifi_cmd *cmd) | ||
321 | { | ||
322 | struct iwm_umac_wifi_out_hdr *umac_hdr; | ||
323 | struct iwm_wifi_cmd_buff *buf; | ||
324 | struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd; | ||
325 | struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd; | ||
326 | int ret; | ||
327 | |||
328 | buf = &cmd->buf; | ||
329 | |||
330 | buf->start -= sizeof(struct iwm_umac_wifi_out_hdr); | ||
331 | buf->len += sizeof(struct iwm_umac_wifi_out_hdr); | ||
332 | |||
333 | umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start); | ||
334 | |||
335 | iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd); | ||
336 | iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd); | ||
337 | |||
338 | IWM_DBG_CMD(iwm, DBG, | ||
339 | "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, " | ||
340 | "eop = 0x%x, count = 0x%x, credit_group = 0x%x, " | ||
341 | "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n", | ||
342 | UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id, | ||
343 | udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group, | ||
344 | udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num); | ||
345 | |||
346 | if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH) | ||
347 | IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n", | ||
348 | cmd->lmac_cmd.id); | ||
349 | |||
350 | ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len); | ||
351 | |||
352 | /* We keep sending UMAC reset regardless of the command credits. | ||
353 | * The UMAC is supposed to be reset anyway and the Tx credits are | ||
354 | * reinitialized afterwards. If we are lucky, the reset could | ||
355 | * still be done even though we have run out of credits for the | ||
356 | * command pool at this moment.*/ | ||
357 | if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) { | ||
358 | IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n", | ||
359 | umac_cmd->id); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | return iwm_bus_send_chunk(iwm, buf->start, buf->len); | ||
364 | } | ||
365 | |||
366 | /* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */ | ||
367 | int iwm_hal_send_target_cmd(struct iwm_priv *iwm, | ||
368 | struct iwm_udma_nonwifi_cmd *udma_cmd, | ||
369 | const void *payload) | ||
370 | { | ||
371 | struct iwm_nonwifi_cmd *cmd; | ||
372 | int ret; | ||
373 | |||
374 | cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); | ||
375 | if (!cmd) { | ||
376 | IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n"); | ||
377 | return -ENOMEM; | ||
378 | } | ||
379 | |||
380 | iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); | ||
381 | |||
382 | if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || | ||
383 | cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { | ||
384 | cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz); | ||
385 | memcpy(&cmd->buf.payload, payload, cmd->buf.len); | ||
386 | } | ||
387 | |||
388 | ret = iwm_send_udma_nonwifi_cmd(iwm, cmd); | ||
389 | |||
390 | if (!udma_cmd->resp) | ||
391 | kfree(cmd); | ||
392 | |||
393 | if (ret < 0) | ||
394 | return ret; | ||
395 | |||
396 | return cmd->seq_num; | ||
397 | } | ||
398 | |||
399 | static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, | ||
400 | struct iwm_lmac_cmd *cmd) | ||
401 | { | ||
402 | memset(hdr, 0, sizeof(*hdr)); | ||
403 | |||
404 | hdr->id = cmd->id; | ||
405 | hdr->flags = 0; /* Is this ever used? */ | ||
406 | hdr->seq_num = cmd->seq_num; | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. | ||
411 | * Sending command to the LMAC is equivalent to sending a | ||
412 | * regular UMAC command with the LMAC passtrough or the LMAC | ||
413 | * wrapper UMAC command IDs. | ||
414 | */ | ||
415 | int iwm_hal_send_host_cmd(struct iwm_priv *iwm, | ||
416 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
417 | struct iwm_umac_cmd *umac_cmd, | ||
418 | struct iwm_lmac_cmd *lmac_cmd, | ||
419 | const void *payload, u16 payload_size) | ||
420 | { | ||
421 | struct iwm_wifi_cmd *cmd; | ||
422 | struct iwm_lmac_hdr *hdr; | ||
423 | int lmac_hdr_len = 0; | ||
424 | int ret; | ||
425 | |||
426 | cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL); | ||
427 | if (!cmd) { | ||
428 | IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n"); | ||
429 | return -ENOMEM; | ||
430 | } | ||
431 | |||
432 | iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size); | ||
433 | |||
434 | if (lmac_cmd) { | ||
435 | hdr = (struct iwm_lmac_hdr *)(cmd->buf.start); | ||
436 | |||
437 | iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd); | ||
438 | lmac_hdr_len = sizeof(struct iwm_lmac_hdr); | ||
439 | } | ||
440 | |||
441 | memcpy(cmd->buf.payload, payload, payload_size); | ||
442 | cmd->buf.len = le16_to_cpu(umac_cmd->count); | ||
443 | |||
444 | ret = iwm_send_udma_wifi_cmd(iwm, cmd); | ||
445 | |||
446 | /* We free the cmd if we're not expecting any response */ | ||
447 | if (!umac_cmd->resp) | ||
448 | kfree(cmd); | ||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * iwm_hal_send_umac_cmd(): This is a special case for | ||
454 | * iwm_hal_send_host_cmd() to send direct UMAC cmd (without | ||
455 | * LMAC involved). | ||
456 | */ | ||
457 | int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, | ||
458 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
459 | struct iwm_umac_cmd *umac_cmd, | ||
460 | const void *payload, u16 payload_size) | ||
461 | { | ||
462 | return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL, | ||
463 | payload, payload_size); | ||
464 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h new file mode 100644 index 000000000000..0adfdc85765d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/hal.h | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef _IWM_HAL_H_ | ||
40 | #define _IWM_HAL_H_ | ||
41 | |||
42 | #include "umac.h" | ||
43 | |||
44 | #define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED) | ||
45 | #define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED) | ||
46 | #define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED) | ||
47 | |||
48 | #define SET_VAL8(s, name, val) \ | ||
49 | do { \ | ||
50 | s = (s & ~(name##_SEED << name##_POS)) | \ | ||
51 | ((val & name##_SEED) << name##_POS); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define SET_VAL16(s, name, val) \ | ||
55 | do { \ | ||
56 | s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ | ||
57 | ((val & name##_SEED) << name##_POS)); \ | ||
58 | } while (0) | ||
59 | |||
60 | #define SET_VAL32(s, name, val) \ | ||
61 | do { \ | ||
62 | s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ | ||
63 | ((val & name##_SEED) << name##_POS)); \ | ||
64 | } while (0) | ||
65 | |||
66 | |||
67 | #define UDMA_UMAC_INIT { .eop = 1, \ | ||
68 | .credit_group = 0x4, \ | ||
69 | .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ | ||
70 | .lmac_offset = 0 } | ||
71 | #define UDMA_LMAC_INIT { .eop = 1, \ | ||
72 | .credit_group = 0x4, \ | ||
73 | .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ | ||
74 | .lmac_offset = 4 } | ||
75 | |||
76 | |||
77 | /* UDMA IN OP CODE -- cmd bits [3:0] */ | ||
78 | #define UDMA_IN_OPCODE_MASK 0xF | ||
79 | |||
80 | #define UDMA_IN_OPCODE_GENERAL_RESP 0x0 | ||
81 | #define UDMA_IN_OPCODE_READ_RESP 0x1 | ||
82 | #define UDMA_IN_OPCODE_WRITE_RESP 0x2 | ||
83 | #define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5 | ||
84 | #define UDMA_IN_OPCODE_PERS_READ_RESP 0x6 | ||
85 | #define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7 | ||
86 | #define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8 | ||
87 | #define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9 | ||
88 | #define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA | ||
89 | #define UDMA_IN_OPCODE_SW_MSG 0xB | ||
90 | #define UDMA_IN_OPCODE_WIFI 0xF | ||
91 | #define UDMA_IN_OPCODE_WIFI_LMAC 0x1F | ||
92 | #define UDMA_IN_OPCODE_WIFI_UMAC 0x2F | ||
93 | |||
94 | /* HW API: udma_hdi_nonwifi API (OUT and IN) */ | ||
95 | |||
96 | /* iwm_udma_nonwifi_cmd request response -- bits [9:9] */ | ||
97 | #define UDMA_HDI_OUT_NW_CMD_RESP_POS 9 | ||
98 | #define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1 | ||
99 | |||
100 | /* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */ | ||
101 | #define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11 | ||
102 | #define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1 | ||
103 | |||
104 | /* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */ | ||
105 | #define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12 | ||
106 | #define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF | ||
107 | |||
108 | /* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */ | ||
109 | #define UDMA_IN_NW_HW_SEQ_NUM_POS 12 | ||
110 | #define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF | ||
111 | |||
112 | /* UDMA IN Non-WIFI HW signature -- bits [16:31] */ | ||
113 | #define UDMA_IN_NW_HW_SIG_POS 16 | ||
114 | #define UDMA_IN_NW_HW_SIG_SEED 0xFFFF | ||
115 | |||
116 | /* fixed signature */ | ||
117 | #define UDMA_IN_NW_HW_SIG 0xCBBC | ||
118 | |||
119 | /* UDMA IN Non-WIFI HW block length -- bits [32:35] */ | ||
120 | #define UDMA_IN_NW_HW_LENGTH_SEED 0xF | ||
121 | #define UDMA_IN_NW_HW_LENGTH_POS 32 | ||
122 | |||
123 | /* End of HW API: udma_hdi_nonwifi API (OUT and IN) */ | ||
124 | |||
125 | #define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032 | ||
126 | #define IWM_MAX_WIFI_HEADERS_SIZE 32 | ||
127 | #define IWM_MAX_NONWIFI_HEADERS_SIZE 16 | ||
128 | #define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ | ||
129 | IWM_MAX_NONWIFI_HEADERS_SIZE) | ||
130 | #define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ | ||
131 | IWM_MAX_WIFI_HEADERS_SIZE) | ||
132 | |||
133 | #define IWM_HAL_CONCATENATE_BUF_SIZE 8192 | ||
134 | |||
135 | struct iwm_wifi_cmd_buff { | ||
136 | u16 len; | ||
137 | u8 *start; | ||
138 | u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE]; | ||
139 | u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE]; | ||
140 | }; | ||
141 | |||
142 | struct iwm_nonwifi_cmd_buff { | ||
143 | u16 len; | ||
144 | u8 *start; | ||
145 | u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE]; | ||
146 | u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE]; | ||
147 | }; | ||
148 | |||
149 | struct iwm_udma_nonwifi_cmd { | ||
150 | u8 opcode; | ||
151 | u8 eop; | ||
152 | u8 resp; | ||
153 | u8 handle_by_hw; | ||
154 | __le32 addr; | ||
155 | __le32 op1_sz; | ||
156 | __le32 op2; | ||
157 | __le16 seq_num; | ||
158 | }; | ||
159 | |||
160 | struct iwm_udma_wifi_cmd { | ||
161 | __le16 count; | ||
162 | u8 eop; | ||
163 | u8 credit_group; | ||
164 | u8 ra_tid; | ||
165 | u8 lmac_offset; | ||
166 | }; | ||
167 | |||
168 | struct iwm_umac_cmd { | ||
169 | u8 id; | ||
170 | __le16 count; | ||
171 | u8 resp; | ||
172 | __le16 seq_num; | ||
173 | u8 color; | ||
174 | }; | ||
175 | |||
176 | struct iwm_lmac_cmd { | ||
177 | u8 id; | ||
178 | __le16 count; | ||
179 | u8 resp; | ||
180 | __le16 seq_num; | ||
181 | }; | ||
182 | |||
183 | struct iwm_nonwifi_cmd { | ||
184 | u16 seq_num; | ||
185 | bool resp_received; | ||
186 | struct list_head pending; | ||
187 | struct iwm_udma_nonwifi_cmd udma_cmd; | ||
188 | struct iwm_umac_cmd umac_cmd; | ||
189 | struct iwm_lmac_cmd lmac_cmd; | ||
190 | struct iwm_nonwifi_cmd_buff buf; | ||
191 | u32 flags; | ||
192 | }; | ||
193 | |||
194 | struct iwm_wifi_cmd { | ||
195 | u16 seq_num; | ||
196 | struct list_head pending; | ||
197 | struct iwm_udma_wifi_cmd udma_cmd; | ||
198 | struct iwm_umac_cmd umac_cmd; | ||
199 | struct iwm_lmac_cmd lmac_cmd; | ||
200 | struct iwm_wifi_cmd_buff buf; | ||
201 | u32 flags; | ||
202 | }; | ||
203 | |||
204 | void iwm_cmd_flush(struct iwm_priv *iwm); | ||
205 | |||
206 | struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, | ||
207 | u16 seq_num); | ||
208 | struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, | ||
209 | u8 seq_num, u8 cmd_opcode); | ||
210 | |||
211 | |||
212 | int iwm_hal_send_target_cmd(struct iwm_priv *iwm, | ||
213 | struct iwm_udma_nonwifi_cmd *ucmd, | ||
214 | const void *payload); | ||
215 | |||
216 | int iwm_hal_send_host_cmd(struct iwm_priv *iwm, | ||
217 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
218 | struct iwm_umac_cmd *umac_cmd, | ||
219 | struct iwm_lmac_cmd *lmac_cmd, | ||
220 | const void *payload, u16 payload_size); | ||
221 | |||
222 | int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, | ||
223 | struct iwm_udma_wifi_cmd *udma_cmd, | ||
224 | struct iwm_umac_cmd *umac_cmd, | ||
225 | const void *payload, u16 payload_size); | ||
226 | |||
227 | u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm); | ||
228 | |||
229 | void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop); | ||
230 | void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, | ||
231 | struct iwm_udma_out_wifi_hdr *hdr, | ||
232 | struct iwm_udma_wifi_cmd *cmd); | ||
233 | void iwm_build_umac_hdr(struct iwm_priv *iwm, | ||
234 | struct iwm_umac_fw_cmd_hdr *hdr, | ||
235 | struct iwm_umac_cmd *cmd); | ||
236 | #endif /* _IWM_HAL_H_ */ | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h new file mode 100644 index 000000000000..3b29681792bb --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_H__ | ||
40 | #define __IWM_H__ | ||
41 | |||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/wireless.h> | ||
44 | #include <net/cfg80211.h> | ||
45 | |||
46 | #include "debug.h" | ||
47 | #include "hal.h" | ||
48 | #include "umac.h" | ||
49 | #include "lmac.h" | ||
50 | #include "eeprom.h" | ||
51 | |||
52 | #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" | ||
53 | #define IWM_AUTHOR "<ilw@linux.intel.com>" | ||
54 | |||
55 | #define CONFIG_IWM_B0_HW_SUPPORT 1 | ||
56 | |||
57 | #define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX | ||
58 | #define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA | ||
59 | #define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW | ||
60 | #define IWM_SRC_NUM 3 | ||
61 | |||
62 | #define IWM_POWER_INDEX_MIN 0 | ||
63 | #define IWM_POWER_INDEX_MAX 5 | ||
64 | #define IWM_POWER_INDEX_DEFAULT 3 | ||
65 | |||
66 | struct iwm_conf { | ||
67 | u32 sdio_ior_timeout; | ||
68 | unsigned long init_calib_map; | ||
69 | unsigned long periodic_calib_map; | ||
70 | bool reset_on_fatal_err; | ||
71 | bool auto_connect; | ||
72 | bool wimax_not_present; | ||
73 | bool enable_qos; | ||
74 | u32 mode; | ||
75 | |||
76 | u32 power_index; | ||
77 | u32 frag_threshold; | ||
78 | u32 rts_threshold; | ||
79 | bool cts_to_self; | ||
80 | |||
81 | u32 assoc_timeout; | ||
82 | u32 roam_timeout; | ||
83 | u32 wireless_mode; | ||
84 | u32 coexist_mode; | ||
85 | |||
86 | u8 ibss_band; | ||
87 | u8 ibss_channel; | ||
88 | |||
89 | u8 mac_addr[ETH_ALEN]; | ||
90 | #ifdef CONFIG_IWM_B0_HW_SUPPORT | ||
91 | bool hw_b0; | ||
92 | #endif | ||
93 | }; | ||
94 | |||
95 | enum { | ||
96 | COEX_MODE_SA = 1, | ||
97 | COEX_MODE_XOR, | ||
98 | COEX_MODE_CM, | ||
99 | COEX_MODE_MAX, | ||
100 | }; | ||
101 | |||
102 | struct iwm_if_ops; | ||
103 | struct iwm_wifi_cmd; | ||
104 | |||
105 | struct pool_entry { | ||
106 | int id; /* group id */ | ||
107 | int sid; /* super group id */ | ||
108 | int min_pages; /* min capacity in pages */ | ||
109 | int max_pages; /* max capacity in pages */ | ||
110 | int alloc_pages; /* allocated # of pages. incresed by driver */ | ||
111 | int total_freed_pages; /* total freed # of pages. incresed by UMAC */ | ||
112 | }; | ||
113 | |||
114 | struct spool_entry { | ||
115 | int id; | ||
116 | int max_pages; | ||
117 | int alloc_pages; | ||
118 | }; | ||
119 | |||
120 | struct iwm_tx_credit { | ||
121 | spinlock_t lock; | ||
122 | int pool_nr; | ||
123 | unsigned long full_pools_map; /* bitmap for # of filled tx pools */ | ||
124 | struct pool_entry pools[IWM_MACS_OUT_GROUPS]; | ||
125 | struct spool_entry spools[IWM_MACS_OUT_SGROUPS]; | ||
126 | }; | ||
127 | |||
128 | struct iwm_notif { | ||
129 | struct list_head pending; | ||
130 | u32 cmd_id; | ||
131 | void *cmd; | ||
132 | u8 src; | ||
133 | void *buf; | ||
134 | unsigned long buf_size; | ||
135 | }; | ||
136 | |||
137 | struct iwm_sta_info { | ||
138 | u8 addr[ETH_ALEN]; | ||
139 | bool valid; | ||
140 | bool qos; | ||
141 | u8 color; | ||
142 | }; | ||
143 | |||
144 | struct iwm_tx_info { | ||
145 | u8 sta; | ||
146 | u8 color; | ||
147 | u8 tid; | ||
148 | }; | ||
149 | |||
150 | struct iwm_rx_info { | ||
151 | unsigned long rx_size; | ||
152 | unsigned long rx_buf_size; | ||
153 | }; | ||
154 | |||
155 | #define IWM_NUM_KEYS 4 | ||
156 | |||
157 | struct iwm_umac_key_hdr { | ||
158 | u8 mac[ETH_ALEN]; | ||
159 | u8 key_idx; | ||
160 | u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */ | ||
161 | } __attribute__ ((packed)); | ||
162 | |||
163 | struct iwm_key { | ||
164 | struct iwm_umac_key_hdr hdr; | ||
165 | u8 in_use; | ||
166 | u8 alg; | ||
167 | u32 flags; | ||
168 | u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; | ||
169 | u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; | ||
170 | u8 key_len; | ||
171 | u8 key[32]; | ||
172 | }; | ||
173 | |||
174 | #define IWM_RX_ID_HASH 0xff | ||
175 | #define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) | ||
176 | |||
177 | #define IWM_STA_TABLE_NUM 16 | ||
178 | #define IWM_TX_LIST_SIZE 64 | ||
179 | #define IWM_RX_LIST_SIZE 256 | ||
180 | |||
181 | #define IWM_SCAN_ID_MAX 0xff | ||
182 | |||
183 | #define IWM_STATUS_READY 0 | ||
184 | #define IWM_STATUS_SCANNING 1 | ||
185 | #define IWM_STATUS_SCAN_ABORTING 2 | ||
186 | #define IWM_STATUS_ASSOCIATING 3 | ||
187 | #define IWM_STATUS_ASSOCIATED 4 | ||
188 | |||
189 | #define IWM_RADIO_RFKILL_OFF 0 | ||
190 | #define IWM_RADIO_RFKILL_HW 1 | ||
191 | #define IWM_RADIO_RFKILL_SW 2 | ||
192 | |||
193 | struct iwm_tx_queue { | ||
194 | int id; | ||
195 | struct sk_buff_head queue; | ||
196 | struct workqueue_struct *wq; | ||
197 | struct work_struct worker; | ||
198 | u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; | ||
199 | int concat_count; | ||
200 | u8 *concat_ptr; | ||
201 | }; | ||
202 | |||
203 | /* Queues 0 ~ 3 for AC data, 5 for iPAN */ | ||
204 | #define IWM_TX_QUEUES 5 | ||
205 | #define IWM_TX_DATA_QUEUES 4 | ||
206 | #define IWM_TX_CMD_QUEUE 4 | ||
207 | |||
208 | struct iwm_bss_info { | ||
209 | struct list_head node; | ||
210 | struct cfg80211_bss *cfg_bss; | ||
211 | struct iwm_umac_notif_bss_info *bss; | ||
212 | }; | ||
213 | |||
214 | typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf, | ||
215 | unsigned long buf_size, struct iwm_wifi_cmd *cmd); | ||
216 | |||
217 | #define IWM_WATCHDOG_PERIOD (6 * HZ) | ||
218 | |||
219 | struct iwm_priv { | ||
220 | struct wireless_dev *wdev; | ||
221 | struct iwm_if_ops *bus_ops; | ||
222 | |||
223 | struct iwm_conf conf; | ||
224 | |||
225 | unsigned long status; | ||
226 | unsigned long radio; | ||
227 | |||
228 | struct list_head pending_notif; | ||
229 | wait_queue_head_t notif_queue; | ||
230 | |||
231 | wait_queue_head_t nonwifi_queue; | ||
232 | |||
233 | unsigned long calib_done_map; | ||
234 | struct { | ||
235 | u8 *buf; | ||
236 | u32 size; | ||
237 | } calib_res[CALIBRATION_CMD_NUM]; | ||
238 | |||
239 | struct iwm_umac_profile *umac_profile; | ||
240 | bool umac_profile_active; | ||
241 | |||
242 | u8 bssid[ETH_ALEN]; | ||
243 | u8 channel; | ||
244 | u16 rate; | ||
245 | |||
246 | struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; | ||
247 | struct list_head bss_list; | ||
248 | |||
249 | void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX]) | ||
250 | (struct iwm_priv *priv, u8 *buf, unsigned long buf_size); | ||
251 | |||
252 | const iwm_handler *umac_handlers; | ||
253 | const iwm_handler *lmac_handlers; | ||
254 | DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM); | ||
255 | DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM); | ||
256 | DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM); | ||
257 | |||
258 | struct list_head wifi_pending_cmd; | ||
259 | struct list_head nonwifi_pending_cmd; | ||
260 | u16 wifi_seq_num; | ||
261 | u8 nonwifi_seq_num; | ||
262 | spinlock_t cmd_lock; | ||
263 | |||
264 | u32 core_enabled; | ||
265 | |||
266 | u8 scan_id; | ||
267 | struct cfg80211_scan_request *scan_request; | ||
268 | |||
269 | struct sk_buff_head rx_list; | ||
270 | struct list_head rx_tickets; | ||
271 | struct list_head rx_packets[IWM_RX_ID_HASH]; | ||
272 | struct workqueue_struct *rx_wq; | ||
273 | struct work_struct rx_worker; | ||
274 | |||
275 | struct iwm_tx_credit tx_credit; | ||
276 | struct iwm_tx_queue txq[IWM_TX_QUEUES]; | ||
277 | |||
278 | struct iwm_key keys[IWM_NUM_KEYS]; | ||
279 | struct iwm_key *default_key; | ||
280 | |||
281 | wait_queue_head_t mlme_queue; | ||
282 | |||
283 | struct iw_statistics wstats; | ||
284 | struct delayed_work stats_request; | ||
285 | |||
286 | struct iwm_debugfs dbg; | ||
287 | |||
288 | u8 *eeprom; | ||
289 | struct timer_list watchdog; | ||
290 | struct work_struct reset_worker; | ||
291 | struct rfkill *rfkill; | ||
292 | |||
293 | char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); | ||
294 | }; | ||
295 | |||
296 | static inline void *iwm_private(struct iwm_priv *iwm) | ||
297 | { | ||
298 | BUG_ON(!iwm); | ||
299 | return &iwm->private; | ||
300 | } | ||
301 | |||
302 | #define hw_to_iwm(h) (h->iwm) | ||
303 | #define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy)) | ||
304 | #define iwm_to_wiphy(i) (i->wdev->wiphy) | ||
305 | #define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w)) | ||
306 | #define iwm_to_wdev(i) (i->wdev) | ||
307 | #define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w)) | ||
308 | #define iwm_to_ndev(i) (i->wdev->netdev) | ||
309 | #define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr)) | ||
310 | #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) | ||
311 | #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) | ||
312 | |||
313 | extern const struct iw_handler_def iwm_iw_handler_def; | ||
314 | |||
315 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, | ||
316 | struct iwm_if_ops *if_ops); | ||
317 | void iwm_if_free(struct iwm_priv *iwm); | ||
318 | int iwm_mode_to_nl80211_iftype(int mode); | ||
319 | int iwm_priv_init(struct iwm_priv *iwm); | ||
320 | void iwm_reset(struct iwm_priv *iwm); | ||
321 | void iwm_tx_credit_init_pools(struct iwm_priv *iwm, | ||
322 | struct iwm_umac_notif_alive *alive); | ||
323 | int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); | ||
324 | int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, | ||
325 | u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size); | ||
326 | int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout); | ||
327 | void iwm_init_default_profile(struct iwm_priv *iwm, | ||
328 | struct iwm_umac_profile *profile); | ||
329 | void iwm_link_on(struct iwm_priv *iwm); | ||
330 | void iwm_link_off(struct iwm_priv *iwm); | ||
331 | int iwm_up(struct iwm_priv *iwm); | ||
332 | int iwm_down(struct iwm_priv *iwm); | ||
333 | |||
334 | /* TX API */ | ||
335 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); | ||
336 | void iwm_tx_worker(struct work_struct *work); | ||
337 | int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); | ||
338 | |||
339 | /* RX API */ | ||
340 | void iwm_rx_setup_handlers(struct iwm_priv *iwm); | ||
341 | int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size); | ||
342 | int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, | ||
343 | struct iwm_wifi_cmd *cmd); | ||
344 | void iwm_rx_free(struct iwm_priv *iwm); | ||
345 | |||
346 | /* RF Kill API */ | ||
347 | int iwm_rfkill_init(struct iwm_priv *iwm); | ||
348 | void iwm_rfkill_exit(struct iwm_priv *iwm); | ||
349 | |||
350 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h new file mode 100644 index 000000000000..db2e5eea1895 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h | |||
@@ -0,0 +1,457 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_LMAC_H__ | ||
40 | #define __IWM_LMAC_H__ | ||
41 | |||
42 | struct iwm_lmac_hdr { | ||
43 | u8 id; | ||
44 | u8 flags; | ||
45 | __le16 seq_num; | ||
46 | } __attribute__ ((packed)); | ||
47 | |||
48 | /* LMAC commands */ | ||
49 | #define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1 | ||
50 | |||
51 | struct iwm_lmac_cal_cfg_elt { | ||
52 | __le32 enable; /* 1 means LMAC needs to do something */ | ||
53 | __le32 start; /* 1 to start calibration, 0 to stop */ | ||
54 | __le32 send_res; /* 1 for sending back results */ | ||
55 | __le32 apply_res; /* 1 for applying calibration results to HW */ | ||
56 | __le32 reserved; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | struct iwm_lmac_cal_cfg_status { | ||
60 | struct iwm_lmac_cal_cfg_elt init; | ||
61 | struct iwm_lmac_cal_cfg_elt periodic; | ||
62 | __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */ | ||
63 | } __attribute__ ((packed)); | ||
64 | |||
65 | struct iwm_lmac_cal_cfg_cmd { | ||
66 | struct iwm_lmac_cal_cfg_status ucode_cfg; | ||
67 | struct iwm_lmac_cal_cfg_status driver_cfg; | ||
68 | __le32 reserved; | ||
69 | } __attribute__ ((packed)); | ||
70 | |||
71 | struct iwm_lmac_cal_cfg_resp { | ||
72 | __le32 status; | ||
73 | } __attribute__ ((packed)); | ||
74 | |||
75 | #define IWM_CARD_STATE_SW_HW_ENABLED 0x00 | ||
76 | #define IWM_CARD_STATE_HW_DISABLED 0x01 | ||
77 | #define IWM_CARD_STATE_SW_DISABLED 0x02 | ||
78 | #define IWM_CARD_STATE_CTKILL_DISABLED 0x04 | ||
79 | #define IWM_CARD_STATE_IS_RXON 0x10 | ||
80 | |||
81 | struct iwm_lmac_card_state { | ||
82 | __le32 flags; | ||
83 | } __attribute__ ((packed)); | ||
84 | |||
85 | /** | ||
86 | * COEX_PRIORITY_TABLE_CMD | ||
87 | * | ||
88 | * Priority entry for each state | ||
89 | * Will keep two tables, for STA and WIPAN | ||
90 | */ | ||
91 | enum { | ||
92 | /* UN-ASSOCIATION PART */ | ||
93 | COEX_UNASSOC_IDLE = 0, | ||
94 | COEX_UNASSOC_MANUAL_SCAN, | ||
95 | COEX_UNASSOC_AUTO_SCAN, | ||
96 | |||
97 | /* CALIBRATION */ | ||
98 | COEX_CALIBRATION, | ||
99 | COEX_PERIODIC_CALIBRATION, | ||
100 | |||
101 | /* CONNECTION */ | ||
102 | COEX_CONNECTION_ESTAB, | ||
103 | |||
104 | /* ASSOCIATION PART */ | ||
105 | COEX_ASSOCIATED_IDLE, | ||
106 | COEX_ASSOC_MANUAL_SCAN, | ||
107 | COEX_ASSOC_AUTO_SCAN, | ||
108 | COEX_ASSOC_ACTIVE_LEVEL, | ||
109 | |||
110 | /* RF ON/OFF */ | ||
111 | COEX_RF_ON, | ||
112 | COEX_RF_OFF, | ||
113 | COEX_STAND_ALONE_DEBUG, | ||
114 | |||
115 | /* IPNN */ | ||
116 | COEX_IPAN_ASSOC_LEVEL, | ||
117 | |||
118 | /* RESERVED */ | ||
119 | COEX_RSRVD1, | ||
120 | COEX_RSRVD2, | ||
121 | |||
122 | COEX_EVENTS_NUM | ||
123 | }; | ||
124 | |||
125 | #define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1 | ||
126 | #define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2 | ||
127 | #define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4 | ||
128 | |||
129 | struct coex_event { | ||
130 | u8 req_prio; | ||
131 | u8 win_med_prio; | ||
132 | u8 reserved; | ||
133 | u8 flags; | ||
134 | } __attribute__ ((packed)); | ||
135 | |||
136 | #define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1 | ||
137 | #define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4 | ||
138 | #define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8 | ||
139 | #define COEX_FLAGS_COEX_ENABLE_MSK 0x80 | ||
140 | |||
141 | struct iwm_coex_prio_table_cmd { | ||
142 | u8 flags; | ||
143 | u8 reserved[3]; | ||
144 | struct coex_event sta_prio[COEX_EVENTS_NUM]; | ||
145 | } __attribute__ ((packed)); | ||
146 | |||
147 | /* Coexistence definitions | ||
148 | * | ||
149 | * Constants to fill in the Priorities' Tables | ||
150 | * RP - Requested Priority | ||
151 | * WP - Win Medium Priority: priority assigned when the contention has been won | ||
152 | * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and | ||
153 | * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | ||
154 | */ | ||
155 | |||
156 | #define COEX_UNASSOC_IDLE_FLAGS 0 | ||
157 | #define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
158 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
159 | #define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
160 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
161 | #define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
162 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
163 | #define COEX_PERIODIC_CALIBRATION_FLAGS 0 | ||
164 | /* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX | ||
165 | * disconnect from network. */ | ||
166 | #define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
167 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
168 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
169 | #define COEX_ASSOCIATED_IDLE_FLAGS 0 | ||
170 | #define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
171 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
172 | #define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
173 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
174 | #define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 | ||
175 | #define COEX_RF_ON_FLAGS 0 | ||
176 | #define COEX_RF_OFF_FLAGS 0 | ||
177 | #define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
178 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) | ||
179 | #define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
180 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
181 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
182 | #define COEX_RSRVD1_FLAGS 0 | ||
183 | #define COEX_RSRVD2_FLAGS 0 | ||
184 | /* XOR_RF_ON is the event wrapping all radio ownership. We need | ||
185 | * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */ | ||
186 | #define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ | ||
187 | COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ | ||
188 | COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) | ||
189 | |||
190 | /* LMAC OP CODES */ | ||
191 | #define REPLY_PAD 0x0 | ||
192 | #define REPLY_ALIVE 0x1 | ||
193 | #define REPLY_ERROR 0x2 | ||
194 | #define REPLY_ECHO 0x3 | ||
195 | #define REPLY_HALT 0x6 | ||
196 | |||
197 | /* RXON state commands */ | ||
198 | #define REPLY_RX_ON 0x10 | ||
199 | #define REPLY_RX_ON_ASSOC 0x11 | ||
200 | #define REPLY_RX_OFF 0x12 | ||
201 | #define REPLY_QOS_PARAM 0x13 | ||
202 | #define REPLY_RX_ON_TIMING 0x14 | ||
203 | #define REPLY_INTERNAL_QOS_PARAM 0x15 | ||
204 | #define REPLY_RX_INT_TIMEOUT_CNFG 0x16 | ||
205 | #define REPLY_NULL 0x17 | ||
206 | |||
207 | /* Multi-Station support */ | ||
208 | #define REPLY_ADD_STA 0x18 | ||
209 | #define REPLY_REMOVE_STA 0x19 | ||
210 | #define REPLY_RESET_ALL_STA 0x1a | ||
211 | |||
212 | /* RX, TX */ | ||
213 | #define REPLY_ALM_RX 0x1b | ||
214 | #define REPLY_TX 0x1c | ||
215 | #define REPLY_TXFIFO_FLUSH 0x1e | ||
216 | |||
217 | /* MISC commands */ | ||
218 | #define REPLY_MGMT_MCAST_KEY 0x1f | ||
219 | #define REPLY_WEPKEY 0x20 | ||
220 | #define REPLY_INIT_IV 0x21 | ||
221 | #define REPLY_WRITE_MIB 0x22 | ||
222 | #define REPLY_READ_MIB 0x23 | ||
223 | #define REPLY_RADIO_FE 0x24 | ||
224 | #define REPLY_TXFIFO_CFG 0x25 | ||
225 | #define REPLY_WRITE_READ 0x26 | ||
226 | #define REPLY_INSTALL_SEC_KEY 0x27 | ||
227 | |||
228 | |||
229 | #define REPLY_RATE_SCALE 0x47 | ||
230 | #define REPLY_LEDS_CMD 0x48 | ||
231 | #define REPLY_TX_LINK_QUALITY_CMD 0x4e | ||
232 | #define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f | ||
233 | #define REPLY_WRITE2REG_CMD 0x50 | ||
234 | |||
235 | /* winfi-wifi coexistence */ | ||
236 | #define COEX_PRIORITY_TABLE_CMD 0x5a | ||
237 | #define COEX_MEDIUM_NOTIFICATION 0x5b | ||
238 | #define COEX_EVENT_CMD 0x5c | ||
239 | |||
240 | /* more Protocol and Protocol-test commands */ | ||
241 | #define REPLY_MAX_SLEEP_TIME_CMD 0x61 | ||
242 | #define CALIBRATION_CFG_CMD 0x65 | ||
243 | #define CALIBRATION_RES_NOTIFICATION 0x66 | ||
244 | #define CALIBRATION_COMPLETE_NOTIFICATION 0x67 | ||
245 | |||
246 | /* Measurements */ | ||
247 | #define REPLY_QUIET_CMD 0x71 | ||
248 | #define REPLY_CHANNEL_SWITCH 0x72 | ||
249 | #define CHANNEL_SWITCH_NOTIFICATION 0x73 | ||
250 | |||
251 | #define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74 | ||
252 | #define SPECTRUM_MEASURE_NOTIFICATION 0x75 | ||
253 | #define REPLY_MEASUREMENT_ABORT_CMD 0x76 | ||
254 | |||
255 | /* Power Management */ | ||
256 | #define POWER_TABLE_CMD 0x77 | ||
257 | #define SAVE_RESTORE_ADRESS_CMD 0x78 | ||
258 | #define REPLY_WATERMARK_CMD 0x79 | ||
259 | #define PM_DEBUG_STATISTIC_NOTIFIC 0x7B | ||
260 | #define PD_FLUSH_N_NOTIFICATION 0x7C | ||
261 | |||
262 | /* Scan commands and notifications */ | ||
263 | #define REPLY_SCAN_REQUEST_CMD 0x80 | ||
264 | #define REPLY_SCAN_ABORT_CMD 0x81 | ||
265 | #define SCAN_START_NOTIFICATION 0x82 | ||
266 | #define SCAN_RESULTS_NOTIFICATION 0x83 | ||
267 | #define SCAN_COMPLETE_NOTIFICATION 0x84 | ||
268 | |||
269 | /* Continuous TX commands */ | ||
270 | #define REPLY_CONT_TX_CMD 0x85 | ||
271 | #define END_OF_CONT_TX_NOTIFICATION 0x86 | ||
272 | |||
273 | /* Timer/Eeprom commands */ | ||
274 | #define TIMER_CMD 0x87 | ||
275 | #define EEPROM_WRITE_CMD 0x88 | ||
276 | |||
277 | /* PAPD commands */ | ||
278 | #define FEEDBACK_REQUEST_NOTIFICATION 0x8b | ||
279 | #define REPLY_CW_CMD 0x8c | ||
280 | |||
281 | /* IBSS/AP commands Continue */ | ||
282 | #define BEACON_NOTIFICATION 0x90 | ||
283 | #define REPLY_TX_BEACON 0x91 | ||
284 | #define REPLY_REQUEST_ATIM 0x93 | ||
285 | #define WHO_IS_AWAKE_NOTIFICATION 0x94 | ||
286 | #define TX_PWR_DBM_LIMIT_CMD 0x95 | ||
287 | #define QUIET_NOTIFICATION 0x96 | ||
288 | #define TX_PWR_TABLE_CMD 0x97 | ||
289 | #define TX_ANT_CONFIGURATION_CMD 0x98 | ||
290 | #define MEASURE_ABORT_NOTIFICATION 0x99 | ||
291 | #define REPLY_CALIBRATION_TUNE 0x9a | ||
292 | |||
293 | /* bt config command */ | ||
294 | #define REPLY_BT_CONFIG 0x9b | ||
295 | #define REPLY_STATISTICS_CMD 0x9c | ||
296 | #define STATISTICS_NOTIFICATION 0x9d | ||
297 | |||
298 | /* RF-KILL commands and notifications */ | ||
299 | #define REPLY_CARD_STATE_CMD 0xa0 | ||
300 | #define CARD_STATE_NOTIFICATION 0xa1 | ||
301 | |||
302 | /* Missed beacons notification */ | ||
303 | #define MISSED_BEACONS_NOTIFICATION 0xa2 | ||
304 | #define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3 | ||
305 | |||
306 | #define REPLY_CT_KILL_CONFIG_CMD 0xa4 | ||
307 | |||
308 | /* HD commands and notifications */ | ||
309 | #define REPLY_HD_PARAMS_CMD 0xa6 | ||
310 | #define HD_PARAMS_NOTIFICATION 0xa7 | ||
311 | #define SENSITIVITY_CMD 0xa8 | ||
312 | #define U_APSD_PARAMS_CMD 0xa9 | ||
313 | #define NOISY_PLATFORM_CMD 0xaa | ||
314 | #define ILLEGAL_CMD 0xac | ||
315 | #define REPLY_PHY_CALIBRATION_CMD 0xb0 | ||
316 | #define REPLAY_RX_GAIN_CALIB_CMD 0xb1 | ||
317 | |||
318 | /* WiPAN commands */ | ||
319 | #define REPLY_WIPAN_PARAMS_CMD 0xb2 | ||
320 | #define REPLY_WIPAN_RX_ON_CMD 0xb3 | ||
321 | #define REPLY_WIPAN_RX_ON_TIMING 0xb4 | ||
322 | #define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5 | ||
323 | #define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6 | ||
324 | #define REPLY_WIPAN_QOS_PARAM 0xb7 | ||
325 | #define WIPAN_REPLY_WEPKEY 0xb8 | ||
326 | |||
327 | /* BeamForming commands */ | ||
328 | #define BEAMFORMER_CFG_CMD 0xba | ||
329 | #define BEAMFORMEE_NOTIFICATION 0xbb | ||
330 | |||
331 | /* TGn new Commands */ | ||
332 | #define REPLY_RX_PHY_CMD 0xc0 | ||
333 | #define REPLY_RX_MPDU_CMD 0xc1 | ||
334 | #define REPLY_MULTICAST_HASH 0xc2 | ||
335 | #define REPLY_KDR_RX 0xc3 | ||
336 | #define REPLY_RX_DSP_EXT_INFO 0xc4 | ||
337 | #define REPLY_COMPRESSED_BA 0xc5 | ||
338 | |||
339 | /* PNC commands */ | ||
340 | #define PNC_CONFIG_CMD 0xc8 | ||
341 | #define PNC_UPDATE_TABLE_CMD 0xc9 | ||
342 | #define XVT_GENERAL_CTRL_CMD 0xca | ||
343 | #define REPLY_LEGACY_RADIO_FE 0xdd | ||
344 | |||
345 | /* WoWLAN commands */ | ||
346 | #define WOWLAN_PATTERNS 0xe0 | ||
347 | #define WOWLAN_WAKEUP_FILTER 0xe1 | ||
348 | #define WOWLAN_TSC_RSC_PARAM 0xe2 | ||
349 | #define WOWLAN_TKIP_PARAM 0xe3 | ||
350 | #define WOWLAN_KEK_KCK_MATERIAL 0xe4 | ||
351 | #define WOWLAN_GET_STATUSES 0xe5 | ||
352 | #define WOWLAN_TX_POWER_PER_DB 0xe6 | ||
353 | #define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES | ||
354 | |||
355 | #define REPLY_DEBUG_CMD 0xf0 | ||
356 | #define REPLY_DSP_DEBUG_CMD 0xf1 | ||
357 | #define REPLY_DEBUG_MONITOR_CMD 0xf2 | ||
358 | #define REPLY_DEBUG_XVT_CMD 0xf3 | ||
359 | #define REPLY_DEBUG_DC_CALIB 0xf4 | ||
360 | #define REPLY_DYNAMIC_BP 0xf5 | ||
361 | |||
362 | /* General purpose Commands */ | ||
363 | #define REPLY_GP1_CMD 0xfa | ||
364 | #define REPLY_GP2_CMD 0xfb | ||
365 | #define REPLY_GP3_CMD 0xfc | ||
366 | #define REPLY_GP4_CMD 0xfd | ||
367 | #define REPLY_REPLAY_WRAPPER 0xfe | ||
368 | #define REPLY_FRAME_DURATION_CALC_CMD 0xff | ||
369 | |||
370 | #define LMAC_COMMAND_ID_MAX 0xff | ||
371 | #define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1) | ||
372 | |||
373 | |||
374 | /* Calibration */ | ||
375 | |||
376 | enum { | ||
377 | PHY_CALIBRATE_DC_CMD = 0, | ||
378 | PHY_CALIBRATE_LO_CMD = 1, | ||
379 | PHY_CALIBRATE_RX_BB_CMD = 2, | ||
380 | PHY_CALIBRATE_TX_IQ_CMD = 3, | ||
381 | PHY_CALIBRATE_RX_IQ_CMD = 4, | ||
382 | PHY_CALIBRATION_NOISE_CMD = 5, | ||
383 | PHY_CALIBRATE_AGC_TABLE_CMD = 6, | ||
384 | PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7, | ||
385 | PHY_CALIBRATE_OPCODES_NUM, | ||
386 | SHILOH_PHY_CALIBRATE_DC_CMD = 8, | ||
387 | SHILOH_PHY_CALIBRATE_LO_CMD = 9, | ||
388 | SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10, | ||
389 | SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11, | ||
390 | SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12, | ||
391 | SHILOH_PHY_CALIBRATION_NOISE_CMD = 13, | ||
392 | SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14, | ||
393 | SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, | ||
394 | SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16, | ||
395 | SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17, | ||
396 | CALIBRATION_CMD_NUM, | ||
397 | }; | ||
398 | |||
399 | struct iwm_lmac_calib_hdr { | ||
400 | u8 opcode; | ||
401 | u8 first_grp; | ||
402 | u8 grp_num; | ||
403 | u8 all_data_valid; | ||
404 | } __attribute__ ((packed)); | ||
405 | |||
406 | #define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7 | ||
407 | #define IWM_CALIB_FREQ_GROUPS_NR 5 | ||
408 | #define IWM_CALIB_DC_MODES_NR 12 | ||
409 | |||
410 | struct iwm_calib_rxiq_entry { | ||
411 | u16 ptam_postdist_ars; | ||
412 | u16 ptam_postdist_arc; | ||
413 | } __attribute__ ((packed)); | ||
414 | |||
415 | struct iwm_calib_rxiq_group { | ||
416 | struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR]; | ||
417 | } __attribute__ ((packed)); | ||
418 | |||
419 | struct iwm_lmac_calib_rxiq { | ||
420 | struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR]; | ||
421 | } __attribute__ ((packed)); | ||
422 | |||
423 | struct iwm_calib_rxiq { | ||
424 | struct iwm_lmac_calib_hdr hdr; | ||
425 | struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR]; | ||
426 | } __attribute__ ((packed)); | ||
427 | |||
428 | #define LMAC_STA_ID_SEED 0x0f | ||
429 | #define LMAC_STA_ID_POS 0 | ||
430 | |||
431 | #define LMAC_STA_COLOR_SEED 0x7 | ||
432 | #define LMAC_STA_COLOR_POS 4 | ||
433 | |||
434 | struct iwm_lmac_power_report { | ||
435 | u8 pa_status; | ||
436 | u8 pa_integ_res_A[3]; | ||
437 | u8 pa_integ_res_B[3]; | ||
438 | u8 pa_integ_res_C[3]; | ||
439 | } __attribute__ ((packed)); | ||
440 | |||
441 | struct iwm_lmac_tx_resp { | ||
442 | u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */ | ||
443 | u8 bt_kill_cnt; | ||
444 | __le16 retry_cnt; | ||
445 | __le32 initial_tx_rate; | ||
446 | __le16 wireless_media_time; | ||
447 | struct iwm_lmac_power_report power_report; | ||
448 | __le32 tfd_info; | ||
449 | __le16 seq_ctl; | ||
450 | __le16 byte_cnt; | ||
451 | u8 tlc_rate_info; | ||
452 | u8 ra_tid; | ||
453 | __le16 frame_ctl; | ||
454 | __le32 status; | ||
455 | } __attribute__ ((packed)); | ||
456 | |||
457 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c new file mode 100644 index 000000000000..6a2640f16b6d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/main.c | |||
@@ -0,0 +1,680 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/ieee80211.h> | ||
42 | #include <linux/wireless.h> | ||
43 | |||
44 | #include "iwm.h" | ||
45 | #include "debug.h" | ||
46 | #include "bus.h" | ||
47 | #include "umac.h" | ||
48 | #include "commands.h" | ||
49 | #include "hal.h" | ||
50 | #include "fw.h" | ||
51 | #include "rx.h" | ||
52 | |||
53 | static struct iwm_conf def_iwm_conf = { | ||
54 | |||
55 | .sdio_ior_timeout = 5000, | ||
56 | .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | | ||
57 | BIT(PHY_CALIBRATE_LO_CMD) | | ||
58 | BIT(PHY_CALIBRATE_TX_IQ_CMD) | | ||
59 | BIT(PHY_CALIBRATE_RX_IQ_CMD), | ||
60 | .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | | ||
61 | BIT(PHY_CALIBRATE_LO_CMD) | | ||
62 | BIT(PHY_CALIBRATE_TX_IQ_CMD) | | ||
63 | BIT(PHY_CALIBRATE_RX_IQ_CMD) | | ||
64 | BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), | ||
65 | .reset_on_fatal_err = 1, | ||
66 | .auto_connect = 1, | ||
67 | .wimax_not_present = 0, | ||
68 | .enable_qos = 1, | ||
69 | .mode = UMAC_MODE_BSS, | ||
70 | |||
71 | /* UMAC configuration */ | ||
72 | .power_index = 0, | ||
73 | .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, | ||
74 | .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, | ||
75 | .cts_to_self = 0, | ||
76 | |||
77 | .assoc_timeout = 2, | ||
78 | .roam_timeout = 10, | ||
79 | .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G, | ||
80 | .coexist_mode = COEX_MODE_CM, | ||
81 | |||
82 | /* IBSS */ | ||
83 | .ibss_band = UMAC_BAND_2GHZ, | ||
84 | .ibss_channel = 1, | ||
85 | |||
86 | .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, | ||
87 | }; | ||
88 | |||
89 | static int modparam_reset; | ||
90 | module_param_named(reset, modparam_reset, bool, 0644); | ||
91 | MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); | ||
92 | |||
93 | int iwm_mode_to_nl80211_iftype(int mode) | ||
94 | { | ||
95 | switch (mode) { | ||
96 | case UMAC_MODE_BSS: | ||
97 | return NL80211_IFTYPE_STATION; | ||
98 | case UMAC_MODE_IBSS: | ||
99 | return NL80211_IFTYPE_ADHOC; | ||
100 | default: | ||
101 | return NL80211_IFTYPE_UNSPECIFIED; | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static void iwm_statistics_request(struct work_struct *work) | ||
108 | { | ||
109 | struct iwm_priv *iwm = | ||
110 | container_of(work, struct iwm_priv, stats_request.work); | ||
111 | |||
112 | iwm_send_umac_stats_req(iwm, 0); | ||
113 | } | ||
114 | |||
115 | static void iwm_reset_worker(struct work_struct *work) | ||
116 | { | ||
117 | struct iwm_priv *iwm; | ||
118 | struct iwm_umac_profile *profile = NULL; | ||
119 | int uninitialized_var(ret), retry = 0; | ||
120 | |||
121 | iwm = container_of(work, struct iwm_priv, reset_worker); | ||
122 | |||
123 | if (iwm->umac_profile_active) { | ||
124 | profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); | ||
125 | if (profile) | ||
126 | memcpy(profile, iwm->umac_profile, sizeof(*profile)); | ||
127 | else | ||
128 | IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); | ||
129 | } | ||
130 | |||
131 | iwm_down(iwm); | ||
132 | |||
133 | while (retry++ < 3) { | ||
134 | ret = iwm_up(iwm); | ||
135 | if (!ret) | ||
136 | break; | ||
137 | |||
138 | schedule_timeout_uninterruptible(10 * HZ); | ||
139 | } | ||
140 | |||
141 | if (ret) { | ||
142 | IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); | ||
143 | |||
144 | kfree(profile); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | if (profile) { | ||
149 | IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n"); | ||
150 | memcpy(iwm->umac_profile, profile, sizeof(*profile)); | ||
151 | iwm_send_mlme_profile(iwm); | ||
152 | kfree(profile); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | static void iwm_watchdog(unsigned long data) | ||
157 | { | ||
158 | struct iwm_priv *iwm = (struct iwm_priv *)data; | ||
159 | |||
160 | IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); | ||
161 | |||
162 | if (modparam_reset) | ||
163 | schedule_work(&iwm->reset_worker); | ||
164 | } | ||
165 | |||
166 | int iwm_priv_init(struct iwm_priv *iwm) | ||
167 | { | ||
168 | int i; | ||
169 | char name[32]; | ||
170 | |||
171 | iwm->status = 0; | ||
172 | INIT_LIST_HEAD(&iwm->pending_notif); | ||
173 | init_waitqueue_head(&iwm->notif_queue); | ||
174 | init_waitqueue_head(&iwm->nonwifi_queue); | ||
175 | init_waitqueue_head(&iwm->mlme_queue); | ||
176 | memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); | ||
177 | spin_lock_init(&iwm->tx_credit.lock); | ||
178 | INIT_LIST_HEAD(&iwm->wifi_pending_cmd); | ||
179 | INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd); | ||
180 | iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE; | ||
181 | iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE; | ||
182 | spin_lock_init(&iwm->cmd_lock); | ||
183 | iwm->scan_id = 1; | ||
184 | INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); | ||
185 | INIT_WORK(&iwm->reset_worker, iwm_reset_worker); | ||
186 | INIT_LIST_HEAD(&iwm->bss_list); | ||
187 | |||
188 | skb_queue_head_init(&iwm->rx_list); | ||
189 | INIT_LIST_HEAD(&iwm->rx_tickets); | ||
190 | for (i = 0; i < IWM_RX_ID_HASH; i++) | ||
191 | INIT_LIST_HEAD(&iwm->rx_packets[i]); | ||
192 | |||
193 | INIT_WORK(&iwm->rx_worker, iwm_rx_worker); | ||
194 | |||
195 | iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx"); | ||
196 | if (!iwm->rx_wq) | ||
197 | return -EAGAIN; | ||
198 | |||
199 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
200 | INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker); | ||
201 | snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i); | ||
202 | iwm->txq[i].id = i; | ||
203 | iwm->txq[i].wq = create_singlethread_workqueue(name); | ||
204 | if (!iwm->txq[i].wq) | ||
205 | return -EAGAIN; | ||
206 | |||
207 | skb_queue_head_init(&iwm->txq[i].queue); | ||
208 | } | ||
209 | |||
210 | for (i = 0; i < IWM_NUM_KEYS; i++) | ||
211 | memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); | ||
212 | |||
213 | iwm->default_key = NULL; | ||
214 | |||
215 | init_timer(&iwm->watchdog); | ||
216 | iwm->watchdog.function = iwm_watchdog; | ||
217 | iwm->watchdog.data = (unsigned long)iwm; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * We reset all the structures, and we reset the UMAC. | ||
224 | * After calling this routine, you're expected to reload | ||
225 | * the firmware. | ||
226 | */ | ||
227 | void iwm_reset(struct iwm_priv *iwm) | ||
228 | { | ||
229 | struct iwm_notif *notif, *next; | ||
230 | |||
231 | if (test_bit(IWM_STATUS_READY, &iwm->status)) | ||
232 | iwm_target_reset(iwm); | ||
233 | |||
234 | iwm->status = 0; | ||
235 | iwm->scan_id = 1; | ||
236 | |||
237 | list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { | ||
238 | list_del(¬if->pending); | ||
239 | kfree(notif->buf); | ||
240 | kfree(notif); | ||
241 | } | ||
242 | |||
243 | iwm_cmd_flush(iwm); | ||
244 | |||
245 | flush_workqueue(iwm->rx_wq); | ||
246 | |||
247 | iwm_link_off(iwm); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * Notification code: | ||
252 | * | ||
253 | * We're faced with the following issue: Any host command can | ||
254 | * have an answer or not, and if there's an answer to expect, | ||
255 | * it can be treated synchronously or asynchronously. | ||
256 | * To work around the synchronous answer case, we implemented | ||
257 | * our notification mechanism. | ||
258 | * When a code path needs to wait for a command response | ||
259 | * synchronously, it calls notif_handle(), which waits for the | ||
260 | * right notification to show up, and then process it. Before | ||
261 | * starting to wait, it registered as a waiter for this specific | ||
262 | * answer (by toggling a bit in on of the handler_map), so that | ||
263 | * the rx code knows that it needs to send a notification to the | ||
264 | * waiting processes. It does so by calling iwm_notif_send(), | ||
265 | * which adds the notification to the pending notifications list, | ||
266 | * and then wakes the waiting processes up. | ||
267 | */ | ||
268 | int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, | ||
269 | u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size) | ||
270 | { | ||
271 | struct iwm_notif *notif; | ||
272 | |||
273 | notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL); | ||
274 | if (!notif) { | ||
275 | IWM_ERR(iwm, "Couldn't alloc memory for notification\n"); | ||
276 | return -ENOMEM; | ||
277 | } | ||
278 | |||
279 | INIT_LIST_HEAD(¬if->pending); | ||
280 | notif->cmd = cmd; | ||
281 | notif->cmd_id = cmd_id; | ||
282 | notif->src = source; | ||
283 | notif->buf = kzalloc(buf_size, GFP_KERNEL); | ||
284 | if (!notif->buf) { | ||
285 | IWM_ERR(iwm, "Couldn't alloc notification buffer\n"); | ||
286 | kfree(notif); | ||
287 | return -ENOMEM; | ||
288 | } | ||
289 | notif->buf_size = buf_size; | ||
290 | memcpy(notif->buf, buf, buf_size); | ||
291 | list_add_tail(¬if->pending, &iwm->pending_notif); | ||
292 | |||
293 | wake_up_interruptible(&iwm->notif_queue); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd, | ||
299 | u8 source) | ||
300 | { | ||
301 | struct iwm_notif *notif, *next; | ||
302 | |||
303 | list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { | ||
304 | if ((notif->cmd_id == cmd) && (notif->src == source)) { | ||
305 | list_del(¬if->pending); | ||
306 | return notif; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | return NULL; | ||
311 | } | ||
312 | |||
313 | static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd, | ||
314 | u8 source, long timeout) | ||
315 | { | ||
316 | int ret; | ||
317 | struct iwm_notif *notif; | ||
318 | unsigned long *map = NULL; | ||
319 | |||
320 | switch (source) { | ||
321 | case IWM_SRC_LMAC: | ||
322 | map = &iwm->lmac_handler_map[0]; | ||
323 | break; | ||
324 | case IWM_SRC_UMAC: | ||
325 | map = &iwm->umac_handler_map[0]; | ||
326 | break; | ||
327 | case IWM_SRC_UDMA: | ||
328 | map = &iwm->udma_handler_map[0]; | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | set_bit(cmd, map); | ||
333 | |||
334 | ret = wait_event_interruptible_timeout(iwm->notif_queue, | ||
335 | ((notif = iwm_notif_find(iwm, cmd, source)) != NULL), | ||
336 | timeout); | ||
337 | clear_bit(cmd, map); | ||
338 | |||
339 | if (!ret) | ||
340 | return NULL; | ||
341 | |||
342 | return notif; | ||
343 | } | ||
344 | |||
345 | int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout) | ||
346 | { | ||
347 | int ret; | ||
348 | struct iwm_notif *notif; | ||
349 | |||
350 | notif = iwm_notif_wait(iwm, cmd, source, timeout); | ||
351 | if (!notif) | ||
352 | return -ETIME; | ||
353 | |||
354 | ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd); | ||
355 | kfree(notif->buf); | ||
356 | kfree(notif); | ||
357 | |||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static int iwm_config_boot_params(struct iwm_priv *iwm) | ||
362 | { | ||
363 | struct iwm_udma_nonwifi_cmd target_cmd; | ||
364 | int ret; | ||
365 | |||
366 | /* check Wimax is off and config debug monitor */ | ||
367 | if (iwm->conf.wimax_not_present) { | ||
368 | u32 data1 = 0x1f; | ||
369 | u32 addr1 = 0x606BE258; | ||
370 | |||
371 | u32 data2_set = 0x0; | ||
372 | u32 data2_clr = 0x1; | ||
373 | u32 addr2 = 0x606BE100; | ||
374 | |||
375 | u32 data3 = 0x1; | ||
376 | u32 addr3 = 0x606BEC00; | ||
377 | |||
378 | target_cmd.resp = 0; | ||
379 | target_cmd.handle_by_hw = 0; | ||
380 | target_cmd.eop = 1; | ||
381 | |||
382 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
383 | target_cmd.addr = cpu_to_le32(addr1); | ||
384 | target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); | ||
385 | target_cmd.op2 = 0; | ||
386 | |||
387 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); | ||
388 | if (ret < 0) { | ||
389 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE; | ||
394 | target_cmd.addr = cpu_to_le32(addr2); | ||
395 | target_cmd.op1_sz = cpu_to_le32(data2_set); | ||
396 | target_cmd.op2 = cpu_to_le32(data2_clr); | ||
397 | |||
398 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); | ||
399 | if (ret < 0) { | ||
400 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; | ||
405 | target_cmd.addr = cpu_to_le32(addr3); | ||
406 | target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); | ||
407 | target_cmd.op2 = 0; | ||
408 | |||
409 | ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3); | ||
410 | if (ret < 0) { | ||
411 | IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); | ||
412 | return ret; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | void iwm_init_default_profile(struct iwm_priv *iwm, | ||
420 | struct iwm_umac_profile *profile) | ||
421 | { | ||
422 | memset(profile, 0, sizeof(struct iwm_umac_profile)); | ||
423 | |||
424 | profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; | ||
425 | profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; | ||
426 | profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE; | ||
427 | profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE; | ||
428 | |||
429 | if (iwm->conf.enable_qos) | ||
430 | profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED); | ||
431 | |||
432 | profile->wireless_mode = iwm->conf.wireless_mode; | ||
433 | profile->mode = cpu_to_le32(iwm->conf.mode); | ||
434 | |||
435 | profile->ibss.atim = 0; | ||
436 | profile->ibss.beacon_interval = 100; | ||
437 | profile->ibss.join_only = 0; | ||
438 | profile->ibss.band = iwm->conf.ibss_band; | ||
439 | profile->ibss.channel = iwm->conf.ibss_channel; | ||
440 | } | ||
441 | |||
442 | void iwm_link_on(struct iwm_priv *iwm) | ||
443 | { | ||
444 | netif_carrier_on(iwm_to_ndev(iwm)); | ||
445 | netif_tx_wake_all_queues(iwm_to_ndev(iwm)); | ||
446 | |||
447 | iwm_send_umac_stats_req(iwm, 0); | ||
448 | } | ||
449 | |||
450 | void iwm_link_off(struct iwm_priv *iwm) | ||
451 | { | ||
452 | struct iw_statistics *wstats = &iwm->wstats; | ||
453 | int i; | ||
454 | |||
455 | netif_tx_stop_all_queues(iwm_to_ndev(iwm)); | ||
456 | netif_carrier_off(iwm_to_ndev(iwm)); | ||
457 | |||
458 | for (i = 0; i < IWM_TX_QUEUES; i++) { | ||
459 | skb_queue_purge(&iwm->txq[i].queue); | ||
460 | |||
461 | iwm->txq[i].concat_count = 0; | ||
462 | iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; | ||
463 | |||
464 | flush_workqueue(iwm->txq[i].wq); | ||
465 | } | ||
466 | |||
467 | iwm_rx_free(iwm); | ||
468 | |||
469 | cancel_delayed_work(&iwm->stats_request); | ||
470 | memset(wstats, 0, sizeof(struct iw_statistics)); | ||
471 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | ||
472 | |||
473 | del_timer_sync(&iwm->watchdog); | ||
474 | } | ||
475 | |||
476 | static void iwm_bss_list_clean(struct iwm_priv *iwm) | ||
477 | { | ||
478 | struct iwm_bss_info *bss, *next; | ||
479 | |||
480 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { | ||
481 | list_del(&bss->node); | ||
482 | kfree(bss->bss); | ||
483 | kfree(bss); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | static int iwm_channels_init(struct iwm_priv *iwm) | ||
488 | { | ||
489 | int ret; | ||
490 | |||
491 | #ifdef CONFIG_IWM_B0_HW_SUPPORT | ||
492 | if (iwm->conf.hw_b0) { | ||
493 | IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); | ||
494 | return 0; | ||
495 | } | ||
496 | #endif | ||
497 | |||
498 | ret = iwm_send_umac_channel_list(iwm); | ||
499 | if (ret) { | ||
500 | IWM_ERR(iwm, "Send channel list failed\n"); | ||
501 | return ret; | ||
502 | } | ||
503 | |||
504 | ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST, | ||
505 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
506 | if (ret) { | ||
507 | IWM_ERR(iwm, "Didn't get a channel list notification\n"); | ||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | int iwm_up(struct iwm_priv *iwm) | ||
515 | { | ||
516 | int ret; | ||
517 | struct iwm_notif *notif_reboot, *notif_ack = NULL; | ||
518 | |||
519 | ret = iwm_bus_enable(iwm); | ||
520 | if (ret) { | ||
521 | IWM_ERR(iwm, "Couldn't enable function\n"); | ||
522 | return ret; | ||
523 | } | ||
524 | |||
525 | iwm_rx_setup_handlers(iwm); | ||
526 | |||
527 | /* Wait for initial BARKER_REBOOT from hardware */ | ||
528 | notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION, | ||
529 | IWM_SRC_UDMA, 2 * HZ); | ||
530 | if (!notif_reboot) { | ||
531 | IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n"); | ||
532 | goto err_disable; | ||
533 | } | ||
534 | |||
535 | /* We send the barker back */ | ||
536 | ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16); | ||
537 | if (ret) { | ||
538 | IWM_ERR(iwm, "REBOOT barker response failed\n"); | ||
539 | kfree(notif_reboot); | ||
540 | goto err_disable; | ||
541 | } | ||
542 | |||
543 | kfree(notif_reboot->buf); | ||
544 | kfree(notif_reboot); | ||
545 | |||
546 | /* Wait for ACK_BARKER from hardware */ | ||
547 | notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION, | ||
548 | IWM_SRC_UDMA, 2 * HZ); | ||
549 | if (!notif_ack) { | ||
550 | IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n"); | ||
551 | goto err_disable; | ||
552 | } | ||
553 | |||
554 | kfree(notif_ack->buf); | ||
555 | kfree(notif_ack); | ||
556 | |||
557 | /* We start to config static boot parameters */ | ||
558 | ret = iwm_config_boot_params(iwm); | ||
559 | if (ret) { | ||
560 | IWM_ERR(iwm, "Config boot parameters failed\n"); | ||
561 | goto err_disable; | ||
562 | } | ||
563 | |||
564 | ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr); | ||
565 | if (ret) { | ||
566 | IWM_ERR(iwm, "MAC reading failed\n"); | ||
567 | goto err_disable; | ||
568 | } | ||
569 | |||
570 | /* We can load the FWs */ | ||
571 | ret = iwm_load_fw(iwm); | ||
572 | if (ret) { | ||
573 | IWM_ERR(iwm, "FW loading failed\n"); | ||
574 | goto err_disable; | ||
575 | } | ||
576 | |||
577 | /* We configure the UMAC and enable the wifi module */ | ||
578 | ret = iwm_send_umac_config(iwm, | ||
579 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | | ||
580 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) | | ||
581 | cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN)); | ||
582 | if (ret) { | ||
583 | IWM_ERR(iwm, "UMAC config failed\n"); | ||
584 | goto err_fw; | ||
585 | } | ||
586 | |||
587 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, | ||
588 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
589 | if (ret) { | ||
590 | IWM_ERR(iwm, "Didn't get a wifi core status notification\n"); | ||
591 | goto err_fw; | ||
592 | } | ||
593 | |||
594 | if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | | ||
595 | UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { | ||
596 | IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n", | ||
597 | iwm->core_enabled); | ||
598 | ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, | ||
599 | IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); | ||
600 | if (ret) { | ||
601 | IWM_ERR(iwm, "Didn't get a core status notification\n"); | ||
602 | goto err_fw; | ||
603 | } | ||
604 | |||
605 | if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | | ||
606 | UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { | ||
607 | IWM_ERR(iwm, "Not all cores enabled: 0x%x\n", | ||
608 | iwm->core_enabled); | ||
609 | goto err_fw; | ||
610 | } else { | ||
611 | IWM_INFO(iwm, "All cores enabled\n"); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), | ||
616 | GFP_KERNEL); | ||
617 | if (!iwm->umac_profile) { | ||
618 | IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); | ||
619 | goto err_fw; | ||
620 | } | ||
621 | |||
622 | iwm_init_default_profile(iwm, iwm->umac_profile); | ||
623 | |||
624 | ret = iwm_channels_init(iwm); | ||
625 | if (ret < 0) { | ||
626 | IWM_ERR(iwm, "Couldn't init channels\n"); | ||
627 | goto err_profile; | ||
628 | } | ||
629 | |||
630 | /* Set the READY bit to indicate interface is brought up successfully */ | ||
631 | set_bit(IWM_STATUS_READY, &iwm->status); | ||
632 | |||
633 | return 0; | ||
634 | |||
635 | err_profile: | ||
636 | kfree(iwm->umac_profile); | ||
637 | iwm->umac_profile = NULL; | ||
638 | |||
639 | err_fw: | ||
640 | iwm_eeprom_exit(iwm); | ||
641 | |||
642 | err_disable: | ||
643 | ret = iwm_bus_disable(iwm); | ||
644 | if (ret < 0) | ||
645 | IWM_ERR(iwm, "Couldn't disable function\n"); | ||
646 | |||
647 | return -EIO; | ||
648 | } | ||
649 | |||
650 | int iwm_down(struct iwm_priv *iwm) | ||
651 | { | ||
652 | int ret; | ||
653 | |||
654 | /* The interface is already down */ | ||
655 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
656 | return 0; | ||
657 | |||
658 | if (iwm->scan_request) { | ||
659 | cfg80211_scan_done(iwm->scan_request, true); | ||
660 | iwm->scan_request = NULL; | ||
661 | } | ||
662 | |||
663 | clear_bit(IWM_STATUS_READY, &iwm->status); | ||
664 | |||
665 | iwm_eeprom_exit(iwm); | ||
666 | kfree(iwm->umac_profile); | ||
667 | iwm->umac_profile = NULL; | ||
668 | iwm_bss_list_clean(iwm); | ||
669 | |||
670 | iwm->default_key = NULL; | ||
671 | iwm->core_enabled = 0; | ||
672 | |||
673 | ret = iwm_bus_disable(iwm); | ||
674 | if (ret < 0) { | ||
675 | IWM_ERR(iwm, "Couldn't disable function\n"); | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | return 0; | ||
680 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c new file mode 100644 index 000000000000..eec7201e91a8 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This is the netdev related hooks for iwm. | ||
26 | * | ||
27 | * Some interesting code paths: | ||
28 | * | ||
29 | * iwm_open() (Called at netdev interface bringup time) | ||
30 | * -> iwm_up() (main.c) | ||
31 | * -> iwm_bus_enable() | ||
32 | * -> if_sdio_enable() (In case of an SDIO bus) | ||
33 | * -> sdio_enable_func() | ||
34 | * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) | ||
35 | * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) | ||
36 | * -> iwm_load_fw() (fw.c) | ||
37 | * -> iwm_load_umac() | ||
38 | * -> iwm_load_lmac() (Calibration LMAC) | ||
39 | * -> iwm_load_lmac() (Operational LMAC) | ||
40 | * -> iwm_send_umac_config() | ||
41 | * | ||
42 | * iwm_stop() (Called at netdev interface bringdown time) | ||
43 | * -> iwm_down() | ||
44 | * -> iwm_bus_disable() | ||
45 | * -> if_sdio_disable() (In case of an SDIO bus) | ||
46 | * -> sdio_disable_func() | ||
47 | */ | ||
48 | #include <linux/netdevice.h> | ||
49 | |||
50 | #include "iwm.h" | ||
51 | #include "cfg80211.h" | ||
52 | #include "debug.h" | ||
53 | |||
54 | static int iwm_open(struct net_device *ndev) | ||
55 | { | ||
56 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
57 | int ret = 0; | ||
58 | |||
59 | if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | ||
60 | ret = iwm_up(iwm); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static int iwm_stop(struct net_device *ndev) | ||
66 | { | ||
67 | struct iwm_priv *iwm = ndev_to_iwm(ndev); | ||
68 | int ret = 0; | ||
69 | |||
70 | if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | ||
71 | ret = iwm_down(iwm); | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * iwm AC to queue mapping | ||
78 | * | ||
79 | * AC_VO -> queue 3 | ||
80 | * AC_VI -> queue 2 | ||
81 | * AC_BE -> queue 1 | ||
82 | * AC_BK -> queue 0 | ||
83 | */ | ||
84 | static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; | ||
85 | |||
86 | static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) | ||
87 | { | ||
88 | skb->priority = cfg80211_classify8021d(skb); | ||
89 | |||
90 | return iwm_1d_to_queue[skb->priority]; | ||
91 | } | ||
92 | |||
93 | static const struct net_device_ops iwm_netdev_ops = { | ||
94 | .ndo_open = iwm_open, | ||
95 | .ndo_stop = iwm_stop, | ||
96 | .ndo_start_xmit = iwm_xmit_frame, | ||
97 | .ndo_select_queue = iwm_select_queue, | ||
98 | }; | ||
99 | |||
100 | void *iwm_if_alloc(int sizeof_bus, struct device *dev, | ||
101 | struct iwm_if_ops *if_ops) | ||
102 | { | ||
103 | struct net_device *ndev; | ||
104 | struct wireless_dev *wdev; | ||
105 | struct iwm_priv *iwm; | ||
106 | int ret = 0; | ||
107 | |||
108 | wdev = iwm_wdev_alloc(sizeof_bus, dev); | ||
109 | if (!wdev) { | ||
110 | dev_err(dev, "no memory for wireless device instance\n"); | ||
111 | return ERR_PTR(-ENOMEM); | ||
112 | } | ||
113 | |||
114 | iwm = wdev_to_iwm(wdev); | ||
115 | iwm->bus_ops = if_ops; | ||
116 | iwm->wdev = wdev; | ||
117 | iwm_priv_init(iwm); | ||
118 | wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); | ||
119 | |||
120 | ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, | ||
121 | IWM_TX_QUEUES); | ||
122 | if (!ndev) { | ||
123 | dev_err(dev, "no memory for network device instance\n"); | ||
124 | goto out_wdev; | ||
125 | } | ||
126 | |||
127 | ndev->netdev_ops = &iwm_netdev_ops; | ||
128 | ndev->wireless_handlers = &iwm_iw_handler_def; | ||
129 | ndev->ieee80211_ptr = wdev; | ||
130 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | ||
131 | ret = register_netdev(ndev); | ||
132 | if (ret < 0) { | ||
133 | dev_err(dev, "Failed to register netdev: %d\n", ret); | ||
134 | goto out_ndev; | ||
135 | } | ||
136 | |||
137 | wdev->netdev = ndev; | ||
138 | |||
139 | ret = iwm_rfkill_init(iwm); | ||
140 | if (ret) { | ||
141 | dev_err(dev, "Failed to init rfkill\n"); | ||
142 | goto out_rfkill; | ||
143 | } | ||
144 | |||
145 | return iwm; | ||
146 | |||
147 | out_rfkill: | ||
148 | unregister_netdev(ndev); | ||
149 | |||
150 | out_ndev: | ||
151 | free_netdev(ndev); | ||
152 | |||
153 | out_wdev: | ||
154 | iwm_wdev_free(iwm); | ||
155 | return ERR_PTR(ret); | ||
156 | } | ||
157 | |||
158 | void iwm_if_free(struct iwm_priv *iwm) | ||
159 | { | ||
160 | int i; | ||
161 | |||
162 | if (!iwm_to_ndev(iwm)) | ||
163 | return; | ||
164 | |||
165 | iwm_rfkill_exit(iwm); | ||
166 | unregister_netdev(iwm_to_ndev(iwm)); | ||
167 | free_netdev(iwm_to_ndev(iwm)); | ||
168 | iwm_wdev_free(iwm); | ||
169 | destroy_workqueue(iwm->rx_wq); | ||
170 | for (i = 0; i < IWM_TX_QUEUES; i++) | ||
171 | destroy_workqueue(iwm->txq[i].wq); | ||
172 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c new file mode 100644 index 000000000000..4ca8b495f82d --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rfkill.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/rfkill.h> | ||
25 | |||
26 | #include "iwm.h" | ||
27 | |||
28 | static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state) | ||
29 | { | ||
30 | struct iwm_priv *iwm = data; | ||
31 | |||
32 | switch (state) { | ||
33 | case RFKILL_STATE_UNBLOCKED: | ||
34 | if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio)) | ||
35 | return -EBUSY; | ||
36 | |||
37 | if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) && | ||
38 | (iwm_to_ndev(iwm)->flags & IFF_UP)) | ||
39 | iwm_up(iwm); | ||
40 | |||
41 | break; | ||
42 | case RFKILL_STATE_SOFT_BLOCKED: | ||
43 | if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) | ||
44 | iwm_down(iwm); | ||
45 | |||
46 | break; | ||
47 | default: | ||
48 | break; | ||
49 | } | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | int iwm_rfkill_init(struct iwm_priv *iwm) | ||
55 | { | ||
56 | int ret; | ||
57 | |||
58 | iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN); | ||
59 | if (!iwm->rfkill) { | ||
60 | IWM_ERR(iwm, "Unable to allocate rfkill device\n"); | ||
61 | return -ENOMEM; | ||
62 | } | ||
63 | |||
64 | iwm->rfkill->name = KBUILD_MODNAME; | ||
65 | iwm->rfkill->data = iwm; | ||
66 | iwm->rfkill->state = RFKILL_STATE_UNBLOCKED; | ||
67 | iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle; | ||
68 | |||
69 | ret = rfkill_register(iwm->rfkill); | ||
70 | if (ret) { | ||
71 | IWM_ERR(iwm, "Failed to register rfkill device\n"); | ||
72 | goto fail; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | fail: | ||
77 | rfkill_free(iwm->rfkill); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | void iwm_rfkill_exit(struct iwm_priv *iwm) | ||
82 | { | ||
83 | if (iwm->rfkill) | ||
84 | rfkill_unregister(iwm->rfkill); | ||
85 | |||
86 | rfkill_free(iwm->rfkill); | ||
87 | iwm->rfkill = NULL; | ||
88 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c new file mode 100644 index 000000000000..d73cf96c6dc6 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.c | |||
@@ -0,0 +1,1431 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/netdevice.h> | ||
41 | #include <linux/etherdevice.h> | ||
42 | #include <linux/wireless.h> | ||
43 | #include <linux/ieee80211.h> | ||
44 | #include <linux/if_arp.h> | ||
45 | #include <linux/list.h> | ||
46 | #include <net/iw_handler.h> | ||
47 | |||
48 | #include "iwm.h" | ||
49 | #include "debug.h" | ||
50 | #include "hal.h" | ||
51 | #include "umac.h" | ||
52 | #include "lmac.h" | ||
53 | #include "commands.h" | ||
54 | #include "rx.h" | ||
55 | #include "cfg80211.h" | ||
56 | #include "eeprom.h" | ||
57 | |||
58 | static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) | ||
59 | { | ||
60 | if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || | ||
61 | (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) | ||
68 | { | ||
69 | return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), | ||
70 | 16); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Notification handlers: | ||
75 | * | ||
76 | * For every possible notification we can receive from the | ||
77 | * target, we have a handler. | ||
78 | * When we get a target notification, and there is no one | ||
79 | * waiting for it, it's just processed through the rx code | ||
80 | * path: | ||
81 | * | ||
82 | * iwm_rx_handle() | ||
83 | * -> iwm_rx_handle_umac() | ||
84 | * -> iwm_rx_handle_wifi() | ||
85 | * -> iwm_rx_handle_resp() | ||
86 | * -> iwm_ntf_*() | ||
87 | * | ||
88 | * OR | ||
89 | * | ||
90 | * -> iwm_rx_handle_non_wifi() | ||
91 | * | ||
92 | * If there are processes waiting for this notification, then | ||
93 | * iwm_rx_handle_wifi() just wakes those processes up and they | ||
94 | * grab the pending notification. | ||
95 | */ | ||
96 | static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, | ||
97 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
98 | { | ||
99 | struct iwm_umac_notif_error *error; | ||
100 | struct iwm_fw_error_hdr *fw_err; | ||
101 | |||
102 | error = (struct iwm_umac_notif_error *)buf; | ||
103 | fw_err = &error->err; | ||
104 | |||
105 | |||
106 | IWM_ERR(iwm, "%cMAC FW ERROR:\n", | ||
107 | (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); | ||
108 | IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); | ||
109 | IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); | ||
110 | IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); | ||
111 | IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); | ||
112 | IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); | ||
113 | IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); | ||
114 | IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); | ||
115 | IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); | ||
116 | IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); | ||
117 | IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); | ||
118 | IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); | ||
119 | IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); | ||
120 | IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, | ||
126 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
127 | { | ||
128 | struct iwm_umac_notif_alive *alive_resp = | ||
129 | (struct iwm_umac_notif_alive *)(buf); | ||
130 | u16 status = le16_to_cpu(alive_resp->status); | ||
131 | |||
132 | if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { | ||
133 | IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); | ||
134 | return -EIO; | ||
135 | } | ||
136 | |||
137 | iwm_tx_credit_init_pools(iwm, alive_resp); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, | ||
143 | unsigned long buf_size, | ||
144 | struct iwm_wifi_cmd *cmd) | ||
145 | { | ||
146 | struct iwm_umac_notif_init_complete *init_complete = | ||
147 | (struct iwm_umac_notif_init_complete *)(buf); | ||
148 | u16 status = le16_to_cpu(init_complete->status); | ||
149 | |||
150 | if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { | ||
151 | IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); | ||
152 | set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); | ||
153 | } else { | ||
154 | IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); | ||
155 | clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, | ||
162 | unsigned long buf_size, | ||
163 | struct iwm_wifi_cmd *cmd) | ||
164 | { | ||
165 | int pool_nr, total_freed_pages; | ||
166 | unsigned long pool_map; | ||
167 | int i, id; | ||
168 | struct iwm_umac_notif_page_dealloc *dealloc = | ||
169 | (struct iwm_umac_notif_page_dealloc *)buf; | ||
170 | |||
171 | pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); | ||
172 | pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); | ||
173 | |||
174 | IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " | ||
175 | "update map 0x%lx\n", pool_nr, pool_map); | ||
176 | |||
177 | spin_lock(&iwm->tx_credit.lock); | ||
178 | |||
179 | for (i = 0; i < pool_nr; i++) { | ||
180 | id = GET_VAL32(dealloc->grp_info[i], | ||
181 | UMAC_DEALLOC_NTFY_GROUP_NUM); | ||
182 | if (test_bit(id, &pool_map)) { | ||
183 | total_freed_pages = GET_VAL32(dealloc->grp_info[i], | ||
184 | UMAC_DEALLOC_NTFY_PAGE_CNT); | ||
185 | iwm_tx_credit_inc(iwm, id, total_freed_pages); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | spin_unlock(&iwm->tx_credit.lock); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, | ||
195 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
196 | { | ||
197 | IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, | ||
203 | unsigned long buf_size, | ||
204 | struct iwm_wifi_cmd *cmd) | ||
205 | { | ||
206 | IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, | ||
212 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
213 | { | ||
214 | struct iwm_lmac_tx_resp *tx_resp; | ||
215 | struct iwm_umac_wifi_in_hdr *hdr; | ||
216 | |||
217 | tx_resp = (struct iwm_lmac_tx_resp *) | ||
218 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
219 | hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
220 | |||
221 | IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); | ||
222 | |||
223 | IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", | ||
224 | le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); | ||
225 | IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); | ||
226 | IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", | ||
227 | le16_to_cpu(tx_resp->retry_cnt)); | ||
228 | IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); | ||
229 | IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", | ||
230 | le16_to_cpu(tx_resp->byte_cnt)); | ||
231 | IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | |||
237 | static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, | ||
238 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
239 | { | ||
240 | u8 opcode; | ||
241 | u8 *calib_buf; | ||
242 | struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) | ||
243 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
244 | |||
245 | opcode = hdr->opcode; | ||
246 | |||
247 | BUG_ON(opcode >= CALIBRATION_CMD_NUM || | ||
248 | opcode < PHY_CALIBRATE_OPCODES_NUM); | ||
249 | |||
250 | IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", | ||
251 | opcode); | ||
252 | |||
253 | buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); | ||
254 | calib_buf = iwm->calib_res[opcode].buf; | ||
255 | |||
256 | if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { | ||
257 | kfree(calib_buf); | ||
258 | calib_buf = kzalloc(buf_size, GFP_KERNEL); | ||
259 | if (!calib_buf) { | ||
260 | IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); | ||
261 | return -ENOMEM; | ||
262 | } | ||
263 | iwm->calib_res[opcode].buf = calib_buf; | ||
264 | iwm->calib_res[opcode].size = buf_size; | ||
265 | } | ||
266 | |||
267 | memcpy(calib_buf, hdr, buf_size); | ||
268 | set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, | ||
274 | unsigned long buf_size, | ||
275 | struct iwm_wifi_cmd *cmd) | ||
276 | { | ||
277 | IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, | ||
283 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
284 | { | ||
285 | struct iwm_lmac_cal_cfg_resp *cal_resp; | ||
286 | |||
287 | cal_resp = (struct iwm_lmac_cal_cfg_resp *) | ||
288 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
289 | |||
290 | IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", | ||
291 | le32_to_cpu(cal_resp->status)); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, | ||
297 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
298 | { | ||
299 | struct iwm_umac_notif_wifi_status *status = | ||
300 | (struct iwm_umac_notif_wifi_status *)buf; | ||
301 | |||
302 | iwm->core_enabled |= le16_to_cpu(status->status); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static struct iwm_rx_ticket_node * | ||
308 | iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) | ||
309 | { | ||
310 | struct iwm_rx_ticket_node *ticket_node; | ||
311 | |||
312 | ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); | ||
313 | if (!ticket_node) { | ||
314 | IWM_ERR(iwm, "Couldn't allocate ticket node\n"); | ||
315 | return ERR_PTR(-ENOMEM); | ||
316 | } | ||
317 | |||
318 | ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL); | ||
319 | if (!ticket_node->ticket) { | ||
320 | IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); | ||
321 | kfree(ticket_node); | ||
322 | return ERR_PTR(-ENOMEM); | ||
323 | } | ||
324 | |||
325 | memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket)); | ||
326 | INIT_LIST_HEAD(&ticket_node->node); | ||
327 | |||
328 | return ticket_node; | ||
329 | } | ||
330 | |||
331 | static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) | ||
332 | { | ||
333 | kfree(ticket_node->ticket); | ||
334 | kfree(ticket_node); | ||
335 | } | ||
336 | |||
337 | static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) | ||
338 | { | ||
339 | u8 id_hash = IWM_RX_ID_GET_HASH(id); | ||
340 | struct list_head *packet_list; | ||
341 | struct iwm_rx_packet *packet, *next; | ||
342 | |||
343 | packet_list = &iwm->rx_packets[id_hash]; | ||
344 | |||
345 | list_for_each_entry_safe(packet, next, packet_list, node) | ||
346 | if (packet->id == id) | ||
347 | return packet; | ||
348 | |||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, | ||
353 | u32 size, u16 id) | ||
354 | { | ||
355 | struct iwm_rx_packet *packet; | ||
356 | |||
357 | packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); | ||
358 | if (!packet) { | ||
359 | IWM_ERR(iwm, "Couldn't allocate packet\n"); | ||
360 | return ERR_PTR(-ENOMEM); | ||
361 | } | ||
362 | |||
363 | packet->skb = dev_alloc_skb(size); | ||
364 | if (!packet->skb) { | ||
365 | IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); | ||
366 | kfree(packet); | ||
367 | return ERR_PTR(-ENOMEM); | ||
368 | } | ||
369 | |||
370 | packet->pkt_size = size; | ||
371 | |||
372 | skb_put(packet->skb, size); | ||
373 | memcpy(packet->skb->data, buf, size); | ||
374 | INIT_LIST_HEAD(&packet->node); | ||
375 | packet->id = id; | ||
376 | |||
377 | return packet; | ||
378 | } | ||
379 | |||
380 | void iwm_rx_free(struct iwm_priv *iwm) | ||
381 | { | ||
382 | struct iwm_rx_ticket_node *ticket, *nt; | ||
383 | struct iwm_rx_packet *packet, *np; | ||
384 | int i; | ||
385 | |||
386 | list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { | ||
387 | list_del(&ticket->node); | ||
388 | iwm_rx_ticket_node_free(ticket); | ||
389 | } | ||
390 | |||
391 | for (i = 0; i < IWM_RX_ID_HASH; i++) { | ||
392 | list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], | ||
393 | node) { | ||
394 | list_del(&packet->node); | ||
395 | kfree_skb(packet->skb); | ||
396 | kfree(packet); | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, | ||
402 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
403 | { | ||
404 | struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = | ||
405 | (struct iwm_umac_notif_rx_ticket *)buf; | ||
406 | struct iwm_rx_ticket *ticket = | ||
407 | (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; | ||
408 | int i, schedule_rx = 0; | ||
409 | |||
410 | for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { | ||
411 | struct iwm_rx_ticket_node *ticket_node; | ||
412 | |||
413 | switch (le16_to_cpu(ticket->action)) { | ||
414 | case IWM_RX_TICKET_RELEASE: | ||
415 | case IWM_RX_TICKET_DROP: | ||
416 | /* We can push the packet to the stack */ | ||
417 | ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); | ||
418 | if (IS_ERR(ticket_node)) | ||
419 | return PTR_ERR(ticket_node); | ||
420 | |||
421 | IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", | ||
422 | ticket->id); | ||
423 | list_add_tail(&ticket_node->node, &iwm->rx_tickets); | ||
424 | |||
425 | /* | ||
426 | * We received an Rx ticket, most likely there's | ||
427 | * a packet pending for it, it's not worth going | ||
428 | * through the packet hash list to double check. | ||
429 | * Let's just fire the rx worker.. | ||
430 | */ | ||
431 | schedule_rx = 1; | ||
432 | |||
433 | break; | ||
434 | |||
435 | default: | ||
436 | IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", | ||
437 | ticket->action); | ||
438 | } | ||
439 | |||
440 | ticket++; | ||
441 | } | ||
442 | |||
443 | if (schedule_rx) | ||
444 | queue_work(iwm->rx_wq, &iwm->rx_worker); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, | ||
450 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
451 | { | ||
452 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
453 | struct iwm_rx_packet *packet; | ||
454 | u16 id, buf_offset; | ||
455 | u32 packet_size; | ||
456 | |||
457 | IWM_DBG_NTF(iwm, DBG, "\n"); | ||
458 | |||
459 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
460 | id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); | ||
461 | buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); | ||
462 | packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); | ||
463 | |||
464 | IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", | ||
465 | wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); | ||
466 | IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); | ||
467 | IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); | ||
468 | |||
469 | packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); | ||
470 | if (IS_ERR(packet)) | ||
471 | return PTR_ERR(packet); | ||
472 | |||
473 | list_add_tail(&packet->node, &iwm->rx_packets[IWM_RX_ID_GET_HASH(id)]); | ||
474 | |||
475 | /* We might (unlikely) have received the packet _after_ the ticket */ | ||
476 | queue_work(iwm->rx_wq, &iwm->rx_worker); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | /* MLME handlers */ | ||
482 | static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, | ||
483 | unsigned long buf_size, | ||
484 | struct iwm_wifi_cmd *cmd) | ||
485 | { | ||
486 | struct iwm_umac_notif_assoc_start *start; | ||
487 | |||
488 | start = (struct iwm_umac_notif_assoc_start *)buf; | ||
489 | |||
490 | set_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | ||
491 | |||
492 | IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", | ||
493 | start->bssid, le32_to_cpu(start->roam_reason)); | ||
494 | |||
495 | wake_up_interruptible(&iwm->mlme_queue); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, | ||
501 | unsigned long buf_size, | ||
502 | struct iwm_wifi_cmd *cmd) | ||
503 | { | ||
504 | struct iwm_umac_notif_assoc_complete *complete = | ||
505 | (struct iwm_umac_notif_assoc_complete *)buf; | ||
506 | union iwreq_data wrqu; | ||
507 | |||
508 | IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", | ||
509 | complete->bssid, complete->status); | ||
510 | |||
511 | memset(&wrqu, 0, sizeof(wrqu)); | ||
512 | |||
513 | clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | ||
514 | |||
515 | switch (le32_to_cpu(complete->status)) { | ||
516 | case UMAC_ASSOC_COMPLETE_SUCCESS: | ||
517 | set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
518 | memcpy(iwm->bssid, complete->bssid, ETH_ALEN); | ||
519 | iwm->channel = complete->channel; | ||
520 | |||
521 | iwm_link_on(iwm); | ||
522 | |||
523 | memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); | ||
524 | break; | ||
525 | case UMAC_ASSOC_COMPLETE_FAILURE: | ||
526 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
527 | memset(iwm->bssid, 0, ETH_ALEN); | ||
528 | iwm->channel = 0; | ||
529 | |||
530 | iwm_link_off(iwm); | ||
531 | default: | ||
532 | break; | ||
533 | } | ||
534 | |||
535 | if (iwm->conf.mode == UMAC_MODE_IBSS) { | ||
536 | cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
541 | wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, | ||
547 | unsigned long buf_size, | ||
548 | struct iwm_wifi_cmd *cmd) | ||
549 | { | ||
550 | struct iwm_umac_notif_profile_invalidate *invalid; | ||
551 | |||
552 | invalid = (struct iwm_umac_notif_profile_invalidate *)buf; | ||
553 | |||
554 | IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", | ||
555 | le32_to_cpu(invalid->reason)); | ||
556 | |||
557 | clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); | ||
558 | clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); | ||
559 | |||
560 | iwm->umac_profile_active = 0; | ||
561 | memset(iwm->bssid, 0, ETH_ALEN); | ||
562 | iwm->channel = 0; | ||
563 | |||
564 | iwm_link_off(iwm); | ||
565 | |||
566 | wake_up_interruptible(&iwm->mlme_queue); | ||
567 | |||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, | ||
572 | unsigned long buf_size, | ||
573 | struct iwm_wifi_cmd *cmd) | ||
574 | { | ||
575 | int ret; | ||
576 | struct iwm_umac_notif_scan_complete *scan_complete = | ||
577 | (struct iwm_umac_notif_scan_complete *)buf; | ||
578 | u32 result = le32_to_cpu(scan_complete->result); | ||
579 | |||
580 | IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", | ||
581 | le32_to_cpu(scan_complete->type), | ||
582 | le32_to_cpu(scan_complete->result), | ||
583 | scan_complete->seq_num); | ||
584 | |||
585 | if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { | ||
586 | IWM_ERR(iwm, "Scan complete while device not scanning\n"); | ||
587 | return -EIO; | ||
588 | } | ||
589 | if (!iwm->scan_request) | ||
590 | return 0; | ||
591 | |||
592 | ret = iwm_cfg80211_inform_bss(iwm); | ||
593 | |||
594 | cfg80211_scan_done(iwm->scan_request, | ||
595 | (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); | ||
596 | iwm->scan_request = NULL; | ||
597 | |||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, | ||
602 | unsigned long buf_size, | ||
603 | struct iwm_wifi_cmd *cmd) | ||
604 | { | ||
605 | struct iwm_umac_notif_sta_info *umac_sta = | ||
606 | (struct iwm_umac_notif_sta_info *)buf; | ||
607 | struct iwm_sta_info *sta; | ||
608 | int i; | ||
609 | |||
610 | switch (le32_to_cpu(umac_sta->opcode)) { | ||
611 | case UMAC_OPCODE_ADD_MODIFY: | ||
612 | sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; | ||
613 | |||
614 | IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " | ||
615 | "addr = %pM, qos = %d\n", | ||
616 | sta->valid ? "Modify" : "Add", | ||
617 | GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), | ||
618 | GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), | ||
619 | umac_sta->mac_addr, | ||
620 | umac_sta->flags & UMAC_STA_FLAG_QOS); | ||
621 | |||
622 | sta->valid = 1; | ||
623 | sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; | ||
624 | sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); | ||
625 | memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); | ||
626 | break; | ||
627 | case UMAC_OPCODE_REMOVE: | ||
628 | IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " | ||
629 | "addr = %pM\n", | ||
630 | GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), | ||
631 | GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), | ||
632 | umac_sta->mac_addr); | ||
633 | |||
634 | sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; | ||
635 | |||
636 | if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) | ||
637 | sta->valid = 0; | ||
638 | |||
639 | break; | ||
640 | case UMAC_OPCODE_CLEAR_ALL: | ||
641 | for (i = 0; i < IWM_STA_TABLE_NUM; i++) | ||
642 | iwm->sta_table[i].valid = 0; | ||
643 | |||
644 | break; | ||
645 | default: | ||
646 | break; | ||
647 | } | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, | ||
653 | unsigned long buf_size, | ||
654 | struct iwm_wifi_cmd *cmd) | ||
655 | { | ||
656 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
657 | struct ieee80211_mgmt *mgmt; | ||
658 | struct iwm_umac_notif_bss_info *umac_bss = | ||
659 | (struct iwm_umac_notif_bss_info *)buf; | ||
660 | struct ieee80211_channel *channel; | ||
661 | struct ieee80211_supported_band *band; | ||
662 | struct iwm_bss_info *bss, *next; | ||
663 | s32 signal; | ||
664 | int freq; | ||
665 | u16 frame_len = le16_to_cpu(umac_bss->frame_len); | ||
666 | size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; | ||
667 | |||
668 | mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); | ||
669 | |||
670 | IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); | ||
671 | IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); | ||
672 | IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", | ||
673 | le32_to_cpu(umac_bss->timestamp)); | ||
674 | IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", | ||
675 | le16_to_cpu(umac_bss->table_idx)); | ||
676 | IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); | ||
677 | IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); | ||
678 | IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); | ||
679 | IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); | ||
680 | |||
681 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) | ||
682 | if (bss->bss->table_idx == umac_bss->table_idx) | ||
683 | break; | ||
684 | |||
685 | if (&bss->node != &iwm->bss_list) { | ||
686 | /* Remove the old BSS entry, we will add it back later. */ | ||
687 | list_del(&bss->node); | ||
688 | kfree(bss->bss); | ||
689 | } else { | ||
690 | /* New BSS entry */ | ||
691 | |||
692 | bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); | ||
693 | if (!bss) { | ||
694 | IWM_ERR(iwm, "Couldn't allocate bss_info\n"); | ||
695 | return -ENOMEM; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | bss->bss = kzalloc(bss_len, GFP_KERNEL); | ||
700 | if (!bss) { | ||
701 | kfree(bss); | ||
702 | IWM_ERR(iwm, "Couldn't allocate bss\n"); | ||
703 | return -ENOMEM; | ||
704 | } | ||
705 | |||
706 | INIT_LIST_HEAD(&bss->node); | ||
707 | memcpy(bss->bss, umac_bss, bss_len); | ||
708 | |||
709 | if (umac_bss->band == UMAC_BAND_2GHZ) | ||
710 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
711 | else if (umac_bss->band == UMAC_BAND_5GHZ) | ||
712 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
713 | else { | ||
714 | IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); | ||
715 | goto err; | ||
716 | } | ||
717 | |||
718 | freq = ieee80211_channel_to_frequency(umac_bss->channel); | ||
719 | channel = ieee80211_get_channel(wiphy, freq); | ||
720 | signal = umac_bss->rssi * 100; | ||
721 | |||
722 | bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, | ||
723 | mgmt, frame_len, | ||
724 | signal, GFP_KERNEL); | ||
725 | if (!bss->cfg_bss) | ||
726 | goto err; | ||
727 | |||
728 | list_add_tail(&bss->node, &iwm->bss_list); | ||
729 | |||
730 | return 0; | ||
731 | err: | ||
732 | kfree(bss->bss); | ||
733 | kfree(bss); | ||
734 | |||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, | ||
739 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
740 | { | ||
741 | struct iwm_umac_notif_bss_removed *bss_rm = | ||
742 | (struct iwm_umac_notif_bss_removed *)buf; | ||
743 | struct iwm_bss_info *bss, *next; | ||
744 | u16 table_idx; | ||
745 | int i; | ||
746 | |||
747 | for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { | ||
748 | table_idx = (le16_to_cpu(bss_rm->entries[i]) | ||
749 | & IWM_BSS_REMOVE_INDEX_MSK); | ||
750 | list_for_each_entry_safe(bss, next, &iwm->bss_list, node) | ||
751 | if (bss->bss->table_idx == cpu_to_le16(table_idx)) { | ||
752 | struct ieee80211_mgmt *mgmt; | ||
753 | |||
754 | mgmt = (struct ieee80211_mgmt *) | ||
755 | (bss->bss->frame_buf); | ||
756 | IWM_DBG_MLME(iwm, ERR, | ||
757 | "BSS removed: %pM\n", | ||
758 | mgmt->bssid); | ||
759 | list_del(&bss->node); | ||
760 | kfree(bss->bss); | ||
761 | kfree(bss); | ||
762 | } | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, | ||
769 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
770 | { | ||
771 | struct iwm_umac_notif_mgt_frame *mgt_frame = | ||
772 | (struct iwm_umac_notif_mgt_frame *)buf; | ||
773 | struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; | ||
774 | u8 *ie; | ||
775 | unsigned int event; | ||
776 | union iwreq_data wrqu; | ||
777 | |||
778 | IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, | ||
779 | le16_to_cpu(mgt_frame->len)); | ||
780 | |||
781 | if (ieee80211_is_assoc_req(mgt->frame_control)) { | ||
782 | ie = mgt->u.assoc_req.variable;; | ||
783 | event = IWEVASSOCREQIE; | ||
784 | } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { | ||
785 | ie = mgt->u.reassoc_req.variable;; | ||
786 | event = IWEVASSOCREQIE; | ||
787 | } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { | ||
788 | ie = mgt->u.assoc_resp.variable;; | ||
789 | event = IWEVASSOCRESPIE; | ||
790 | } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { | ||
791 | ie = mgt->u.reassoc_resp.variable;; | ||
792 | event = IWEVASSOCRESPIE; | ||
793 | } else { | ||
794 | IWM_ERR(iwm, "Unsupported management frame"); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); | ||
799 | |||
800 | IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); | ||
801 | wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, | ||
807 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
808 | { | ||
809 | struct iwm_umac_notif_wifi_if *notif = | ||
810 | (struct iwm_umac_notif_wifi_if *)buf; | ||
811 | |||
812 | switch (notif->status) { | ||
813 | case WIFI_IF_NTFY_ASSOC_START: | ||
814 | return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); | ||
815 | case WIFI_IF_NTFY_ASSOC_COMPLETE: | ||
816 | return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); | ||
817 | case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: | ||
818 | return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); | ||
819 | case WIFI_IF_NTFY_CONNECTION_TERMINATED: | ||
820 | IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); | ||
821 | break; | ||
822 | case WIFI_IF_NTFY_SCAN_COMPLETE: | ||
823 | return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); | ||
824 | case WIFI_IF_NTFY_STA_TABLE_CHANGE: | ||
825 | return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); | ||
826 | case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: | ||
827 | IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); | ||
828 | break; | ||
829 | case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: | ||
830 | return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); | ||
831 | case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: | ||
832 | return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); | ||
833 | break; | ||
834 | case WIFI_IF_NTFY_MGMT_FRAME: | ||
835 | return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); | ||
836 | case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: | ||
837 | case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: | ||
838 | case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: | ||
839 | case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: | ||
840 | case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: | ||
841 | case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: | ||
842 | case WIFI_DBG_IF_NTFY_CNCT_ATC_START: | ||
843 | case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: | ||
844 | case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: | ||
845 | case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: | ||
846 | IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", | ||
847 | notif->status); | ||
848 | break; | ||
849 | default: | ||
850 | IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); | ||
851 | break; | ||
852 | } | ||
853 | |||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | #define IWM_STATS_UPDATE_INTERVAL (2 * HZ) | ||
858 | |||
859 | static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, | ||
860 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
861 | { | ||
862 | struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; | ||
863 | struct iw_statistics *wstats = &iwm->wstats; | ||
864 | u16 max_rate = 0; | ||
865 | int i; | ||
866 | |||
867 | IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); | ||
868 | |||
869 | if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
870 | for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { | ||
871 | max_rate = max_t(u16, max_rate, | ||
872 | max(le16_to_cpu(stats->tx_rate[i]), | ||
873 | le16_to_cpu(stats->rx_rate[i]))); | ||
874 | } | ||
875 | /* UMAC passes rate info multiplies by 2 */ | ||
876 | iwm->rate = max_rate >> 1; | ||
877 | } | ||
878 | |||
879 | wstats->status = 0; | ||
880 | |||
881 | wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); | ||
882 | wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); | ||
883 | wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); | ||
884 | wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); | ||
885 | |||
886 | wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); | ||
887 | |||
888 | /* according to cfg80211 */ | ||
889 | if (stats->rssi_dbm < -110) | ||
890 | wstats->qual.qual = 0; | ||
891 | else if (stats->rssi_dbm > -40) | ||
892 | wstats->qual.qual = 70; | ||
893 | else | ||
894 | wstats->qual.qual = stats->rssi_dbm + 110; | ||
895 | |||
896 | wstats->qual.level = stats->rssi_dbm; | ||
897 | wstats->qual.noise = stats->noise_dbm; | ||
898 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
899 | |||
900 | schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); | ||
901 | |||
902 | mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); | ||
903 | |||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, | ||
908 | unsigned long buf_size, | ||
909 | struct iwm_wifi_cmd *cmd) | ||
910 | { | ||
911 | struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = | ||
912 | (struct iwm_umac_cmd_eeprom_proxy *) | ||
913 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
914 | struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; | ||
915 | u32 hdr_offset = le32_to_cpu(hdr->offset); | ||
916 | u32 hdr_len = le32_to_cpu(hdr->len); | ||
917 | u32 hdr_type = le32_to_cpu(hdr->type); | ||
918 | |||
919 | IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", | ||
920 | hdr_type, hdr_len, hdr_offset); | ||
921 | |||
922 | if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) | ||
923 | return -EINVAL; | ||
924 | |||
925 | #ifdef CONFIG_IWM_B0_HW_SUPPORT | ||
926 | if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { | ||
927 | if (eeprom_proxy->buf[0] == 0xff) | ||
928 | iwm->conf.hw_b0 = 1; | ||
929 | } | ||
930 | #endif | ||
931 | |||
932 | switch (hdr_type) { | ||
933 | case IWM_UMAC_CMD_EEPROM_TYPE_READ: | ||
934 | memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); | ||
935 | break; | ||
936 | case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: | ||
937 | default: | ||
938 | return -ENOTSUPP; | ||
939 | } | ||
940 | |||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, | ||
945 | unsigned long buf_size, | ||
946 | struct iwm_wifi_cmd *cmd) | ||
947 | { | ||
948 | struct iwm_umac_cmd_get_channel_list *ch_list = | ||
949 | (struct iwm_umac_cmd_get_channel_list *) | ||
950 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
951 | struct wiphy *wiphy = iwm_to_wiphy(iwm); | ||
952 | struct ieee80211_supported_band *band; | ||
953 | int i; | ||
954 | |||
955 | band = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
956 | |||
957 | for (i = 0; i < band->n_channels; i++) { | ||
958 | unsigned long ch_mask_0 = | ||
959 | le32_to_cpu(ch_list->ch[0].channels_mask); | ||
960 | unsigned long ch_mask_2 = | ||
961 | le32_to_cpu(ch_list->ch[2].channels_mask); | ||
962 | |||
963 | if (!test_bit(i, &ch_mask_0)) | ||
964 | band->channels[i].flags |= IEEE80211_CHAN_DISABLED; | ||
965 | |||
966 | if (!test_bit(i, &ch_mask_2)) | ||
967 | band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; | ||
968 | } | ||
969 | |||
970 | band = wiphy->bands[IEEE80211_BAND_5GHZ]; | ||
971 | |||
972 | for (i = 0; i < min(band->n_channels, 32); i++) { | ||
973 | unsigned long ch_mask_1 = | ||
974 | le32_to_cpu(ch_list->ch[1].channels_mask); | ||
975 | unsigned long ch_mask_3 = | ||
976 | le32_to_cpu(ch_list->ch[3].channels_mask); | ||
977 | |||
978 | if (!test_bit(i, &ch_mask_1)) | ||
979 | band->channels[i].flags |= IEEE80211_CHAN_DISABLED; | ||
980 | |||
981 | if (!test_bit(i, &ch_mask_3)) | ||
982 | band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; | ||
983 | } | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, | ||
989 | unsigned long buf_size, | ||
990 | struct iwm_wifi_cmd *cmd) | ||
991 | { | ||
992 | struct iwm_umac_wifi_if *hdr = | ||
993 | (struct iwm_umac_wifi_if *)cmd->buf.payload; | ||
994 | |||
995 | IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " | ||
996 | "oid is %d\n", hdr->oid); | ||
997 | |||
998 | switch (hdr->oid) { | ||
999 | case UMAC_WIFI_IF_CMD_SET_PROFILE: | ||
1000 | iwm->umac_profile_active = 1; | ||
1001 | wake_up_interruptible(&iwm->mlme_queue); | ||
1002 | break; | ||
1003 | default: | ||
1004 | break; | ||
1005 | } | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, | ||
1011 | unsigned long buf_size, struct iwm_wifi_cmd *cmd) | ||
1012 | { | ||
1013 | struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) | ||
1014 | (buf + sizeof(struct iwm_umac_wifi_in_hdr)); | ||
1015 | u32 flags = le32_to_cpu(state->flags); | ||
1016 | |||
1017 | IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", | ||
1018 | flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", | ||
1019 | flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); | ||
1020 | |||
1021 | if (flags & IWM_CARD_STATE_HW_DISABLED) | ||
1022 | set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); | ||
1023 | else | ||
1024 | clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); | ||
1025 | |||
1026 | return 0; | ||
1027 | } | ||
1028 | |||
1029 | static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, | ||
1030 | unsigned long buf_size) | ||
1031 | { | ||
1032 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
1033 | struct iwm_wifi_cmd *cmd; | ||
1034 | u8 source, cmd_id; | ||
1035 | u16 seq_num; | ||
1036 | u32 count; | ||
1037 | u8 resp; | ||
1038 | |||
1039 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
1040 | cmd_id = wifi_hdr->sw_hdr.cmd.cmd; | ||
1041 | |||
1042 | source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
1043 | if (source >= IWM_SRC_NUM) { | ||
1044 | IWM_CRIT(iwm, "invalid source %d\n", source); | ||
1045 | return -EINVAL; | ||
1046 | } | ||
1047 | |||
1048 | count = (GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT)); | ||
1049 | count += sizeof(struct iwm_umac_wifi_in_hdr) - | ||
1050 | sizeof(struct iwm_dev_cmd_hdr); | ||
1051 | if (count > buf_size) { | ||
1052 | IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); | ||
1053 | return -EINVAL; | ||
1054 | } | ||
1055 | |||
1056 | resp = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_STATUS); | ||
1057 | |||
1058 | seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); | ||
1059 | |||
1060 | IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", | ||
1061 | cmd_id, source, seq_num); | ||
1062 | |||
1063 | /* | ||
1064 | * If this is a response to a previously sent command, there must | ||
1065 | * be a pending command for this sequence number. | ||
1066 | */ | ||
1067 | cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); | ||
1068 | |||
1069 | /* Notify the caller only for sync commands. */ | ||
1070 | switch (source) { | ||
1071 | case UMAC_HDI_IN_SOURCE_FHRX: | ||
1072 | if (iwm->lmac_handlers[cmd_id] && | ||
1073 | test_bit(cmd_id, &iwm->lmac_handler_map[0])) | ||
1074 | return iwm_notif_send(iwm, cmd, cmd_id, source, | ||
1075 | buf, count); | ||
1076 | break; | ||
1077 | case UMAC_HDI_IN_SOURCE_FW: | ||
1078 | if (iwm->umac_handlers[cmd_id] && | ||
1079 | test_bit(cmd_id, &iwm->umac_handler_map[0])) | ||
1080 | return iwm_notif_send(iwm, cmd, cmd_id, source, | ||
1081 | buf, count); | ||
1082 | break; | ||
1083 | case UMAC_HDI_IN_SOURCE_UDMA: | ||
1084 | break; | ||
1085 | } | ||
1086 | |||
1087 | return iwm_rx_handle_resp(iwm, buf, count, cmd); | ||
1088 | } | ||
1089 | |||
1090 | int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, | ||
1091 | struct iwm_wifi_cmd *cmd) | ||
1092 | { | ||
1093 | u8 source, cmd_id; | ||
1094 | struct iwm_umac_wifi_in_hdr *wifi_hdr; | ||
1095 | int ret = 0; | ||
1096 | |||
1097 | wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; | ||
1098 | cmd_id = wifi_hdr->sw_hdr.cmd.cmd; | ||
1099 | |||
1100 | source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); | ||
1101 | |||
1102 | IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); | ||
1103 | |||
1104 | switch (source) { | ||
1105 | case UMAC_HDI_IN_SOURCE_FHRX: | ||
1106 | if (iwm->lmac_handlers[cmd_id]) | ||
1107 | ret = iwm->lmac_handlers[cmd_id] | ||
1108 | (iwm, buf, buf_size, cmd); | ||
1109 | break; | ||
1110 | case UMAC_HDI_IN_SOURCE_FW: | ||
1111 | if (iwm->umac_handlers[cmd_id]) | ||
1112 | ret = iwm->umac_handlers[cmd_id] | ||
1113 | (iwm, buf, buf_size, cmd); | ||
1114 | break; | ||
1115 | case UMAC_HDI_IN_SOURCE_UDMA: | ||
1116 | ret = -EINVAL; | ||
1117 | break; | ||
1118 | } | ||
1119 | |||
1120 | kfree(cmd); | ||
1121 | |||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, | ||
1126 | unsigned long buf_size) | ||
1127 | { | ||
1128 | u8 seq_num; | ||
1129 | struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; | ||
1130 | struct iwm_nonwifi_cmd *cmd, *next; | ||
1131 | |||
1132 | seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); | ||
1133 | |||
1134 | /* | ||
1135 | * We received a non wifi answer. | ||
1136 | * Let's check if there's a pending command for it, and if so | ||
1137 | * replace the command payload with the buffer, and then wake the | ||
1138 | * callers up. | ||
1139 | * That means we only support synchronised non wifi command response | ||
1140 | * schemes. | ||
1141 | */ | ||
1142 | list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending) | ||
1143 | if (cmd->seq_num == seq_num) { | ||
1144 | cmd->resp_received = 1; | ||
1145 | cmd->buf.len = buf_size; | ||
1146 | memcpy(cmd->buf.hdr, buf, buf_size); | ||
1147 | wake_up_interruptible(&iwm->nonwifi_queue); | ||
1148 | } | ||
1149 | |||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, | ||
1154 | unsigned long buf_size) | ||
1155 | { | ||
1156 | int ret = 0; | ||
1157 | u8 op_code; | ||
1158 | unsigned long buf_offset = 0; | ||
1159 | struct iwm_udma_in_hdr *hdr; | ||
1160 | |||
1161 | /* | ||
1162 | * To allow for a more efficient bus usage, UMAC | ||
1163 | * messages are encapsulated into UDMA ones. This | ||
1164 | * way we can have several UMAC messages in one bus | ||
1165 | * transfer. | ||
1166 | * A UDMA frame size is always aligned on 16 bytes, | ||
1167 | * and a UDMA frame must not start with a UMAC_PAD_TERMINAL | ||
1168 | * word. This is how we parse a bus frame into several | ||
1169 | * UDMA ones. | ||
1170 | */ | ||
1171 | while (buf_offset < buf_size) { | ||
1172 | |||
1173 | hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); | ||
1174 | |||
1175 | if (iwm_rx_check_udma_hdr(hdr) < 0) { | ||
1176 | IWM_DBG_RX(iwm, DBG, "End of frame\n"); | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); | ||
1181 | |||
1182 | IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); | ||
1183 | |||
1184 | if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { | ||
1185 | ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, | ||
1186 | buf_size - buf_offset); | ||
1187 | } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { | ||
1188 | if (GET_VAL32(hdr->cmd, | ||
1189 | UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != | ||
1190 | UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { | ||
1191 | IWM_ERR(iwm, "Incorrect hw signature\n"); | ||
1192 | return -EINVAL; | ||
1193 | } | ||
1194 | ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, | ||
1195 | buf_size - buf_offset); | ||
1196 | } else { | ||
1197 | IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); | ||
1198 | ret |= -EINVAL; | ||
1199 | } | ||
1200 | |||
1201 | buf_offset += iwm_rx_resp_size(hdr); | ||
1202 | } | ||
1203 | |||
1204 | return ret; | ||
1205 | } | ||
1206 | |||
1207 | int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) | ||
1208 | { | ||
1209 | struct iwm_udma_in_hdr *hdr; | ||
1210 | |||
1211 | hdr = (struct iwm_udma_in_hdr *)buf; | ||
1212 | |||
1213 | switch (le32_to_cpu(hdr->cmd)) { | ||
1214 | case UMAC_REBOOT_BARKER: | ||
1215 | return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, | ||
1216 | IWM_SRC_UDMA, buf, buf_size); | ||
1217 | case UMAC_ACK_BARKER: | ||
1218 | return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, | ||
1219 | IWM_SRC_UDMA, NULL, 0); | ||
1220 | default: | ||
1221 | IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); | ||
1222 | return iwm_rx_handle_umac(iwm, buf, buf_size); | ||
1223 | } | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | static const iwm_handler iwm_umac_handlers[] = | ||
1229 | { | ||
1230 | [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, | ||
1231 | [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, | ||
1232 | [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, | ||
1233 | [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, | ||
1234 | [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, | ||
1235 | [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, | ||
1236 | [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, | ||
1237 | [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, | ||
1238 | [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, | ||
1239 | [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, | ||
1240 | [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, | ||
1241 | [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, | ||
1242 | [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, | ||
1243 | }; | ||
1244 | |||
1245 | static const iwm_handler iwm_lmac_handlers[] = | ||
1246 | { | ||
1247 | [REPLY_TX] = iwm_ntf_tx, | ||
1248 | [REPLY_ALIVE] = iwm_ntf_lmac_version, | ||
1249 | [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, | ||
1250 | [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, | ||
1251 | [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, | ||
1252 | [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, | ||
1253 | [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, | ||
1254 | }; | ||
1255 | |||
1256 | void iwm_rx_setup_handlers(struct iwm_priv *iwm) | ||
1257 | { | ||
1258 | iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; | ||
1259 | iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; | ||
1260 | } | ||
1261 | |||
1262 | static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) | ||
1263 | { | ||
1264 | struct ieee80211_hdr *hdr; | ||
1265 | unsigned int hdr_len; | ||
1266 | |||
1267 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1268 | |||
1269 | if (!ieee80211_has_protected(hdr->frame_control)) | ||
1270 | return; | ||
1271 | |||
1272 | hdr_len = ieee80211_hdrlen(hdr->frame_control); | ||
1273 | if (hdr_total_len <= hdr_len) | ||
1274 | return; | ||
1275 | |||
1276 | memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); | ||
1277 | skb_pull(skb, (hdr_total_len - hdr_len)); | ||
1278 | } | ||
1279 | |||
1280 | static void iwm_rx_adjust_packet(struct iwm_priv *iwm, | ||
1281 | struct iwm_rx_packet *packet, | ||
1282 | struct iwm_rx_ticket_node *ticket_node) | ||
1283 | { | ||
1284 | u32 payload_offset = 0, payload_len; | ||
1285 | struct iwm_rx_ticket *ticket = ticket_node->ticket; | ||
1286 | struct iwm_rx_mpdu_hdr *mpdu_hdr; | ||
1287 | struct ieee80211_hdr *hdr; | ||
1288 | |||
1289 | mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; | ||
1290 | payload_offset += sizeof(struct iwm_rx_mpdu_hdr); | ||
1291 | /* Padding is 0 or 2 bytes */ | ||
1292 | payload_len = le16_to_cpu(mpdu_hdr->len) + | ||
1293 | (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); | ||
1294 | payload_len -= ticket->tail_len; | ||
1295 | |||
1296 | IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " | ||
1297 | "ticket offset:%d ticket tail len:%d\n", | ||
1298 | payload_len, payload_offset, ticket->payload_offset, | ||
1299 | ticket->tail_len); | ||
1300 | |||
1301 | IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); | ||
1302 | |||
1303 | skb_pull(packet->skb, payload_offset); | ||
1304 | skb_trim(packet->skb, payload_len); | ||
1305 | |||
1306 | iwm_remove_iv(packet->skb, ticket->payload_offset); | ||
1307 | |||
1308 | hdr = (struct ieee80211_hdr *) packet->skb->data; | ||
1309 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
1310 | /* UMAC handed QOS_DATA frame with 2 padding bytes appended | ||
1311 | * to the qos_ctl field in IEEE 802.11 headers. */ | ||
1312 | memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, | ||
1313 | packet->skb->data, | ||
1314 | ieee80211_hdrlen(hdr->frame_control) - | ||
1315 | IEEE80211_QOS_CTL_LEN); | ||
1316 | hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, | ||
1317 | IEEE80211_QOS_CTL_LEN + 2); | ||
1318 | hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | ||
1319 | } | ||
1320 | |||
1321 | IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", | ||
1322 | packet->skb->data, packet->skb->len); | ||
1323 | } | ||
1324 | |||
1325 | static void classify8023(struct sk_buff *skb) | ||
1326 | { | ||
1327 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1328 | |||
1329 | if (ieee80211_is_data_qos(hdr->frame_control)) { | ||
1330 | u8 *qc = ieee80211_get_qos_ctl(hdr); | ||
1331 | /* frame has qos control */ | ||
1332 | skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; | ||
1333 | } else { | ||
1334 | skb->priority = 0; | ||
1335 | } | ||
1336 | } | ||
1337 | |||
1338 | static void iwm_rx_process_packet(struct iwm_priv *iwm, | ||
1339 | struct iwm_rx_packet *packet, | ||
1340 | struct iwm_rx_ticket_node *ticket_node) | ||
1341 | { | ||
1342 | int ret; | ||
1343 | struct sk_buff *skb = packet->skb; | ||
1344 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
1345 | struct net_device *ndev = iwm_to_ndev(iwm); | ||
1346 | |||
1347 | IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); | ||
1348 | |||
1349 | switch (le16_to_cpu(ticket_node->ticket->action)) { | ||
1350 | case IWM_RX_TICKET_RELEASE: | ||
1351 | IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); | ||
1352 | classify8023(skb); | ||
1353 | iwm_rx_adjust_packet(iwm, packet, ticket_node); | ||
1354 | ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); | ||
1355 | if (ret < 0) { | ||
1356 | IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " | ||
1357 | "%d\n", ret); | ||
1358 | break; | ||
1359 | } | ||
1360 | |||
1361 | IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); | ||
1362 | |||
1363 | skb->dev = iwm_to_ndev(iwm); | ||
1364 | skb->protocol = eth_type_trans(skb, ndev); | ||
1365 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1366 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1367 | |||
1368 | ndev->stats.rx_packets++; | ||
1369 | ndev->stats.rx_bytes += skb->len; | ||
1370 | |||
1371 | if (netif_rx(skb) == NET_RX_DROP) { | ||
1372 | IWM_ERR(iwm, "Packet dropped\n"); | ||
1373 | ndev->stats.rx_dropped++; | ||
1374 | } | ||
1375 | break; | ||
1376 | case IWM_RX_TICKET_DROP: | ||
1377 | IWM_DBG_RX(iwm, DBG, "DROP packet\n"); | ||
1378 | kfree_skb(packet->skb); | ||
1379 | break; | ||
1380 | default: | ||
1381 | IWM_ERR(iwm, "Unknow ticket action: %d\n", | ||
1382 | le16_to_cpu(ticket_node->ticket->action)); | ||
1383 | kfree_skb(packet->skb); | ||
1384 | } | ||
1385 | |||
1386 | kfree(packet); | ||
1387 | iwm_rx_ticket_node_free(ticket_node); | ||
1388 | } | ||
1389 | |||
1390 | /* | ||
1391 | * Rx data processing: | ||
1392 | * | ||
1393 | * We're receiving Rx packet from the LMAC, and Rx ticket from | ||
1394 | * the UMAC. | ||
1395 | * To forward a target data packet upstream (i.e. to the | ||
1396 | * kernel network stack), we must have received an Rx ticket | ||
1397 | * that tells us we're allowed to release this packet (ticket | ||
1398 | * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, | ||
1399 | * among other things, where valid data actually starts in the Rx | ||
1400 | * packet. | ||
1401 | */ | ||
1402 | void iwm_rx_worker(struct work_struct *work) | ||
1403 | { | ||
1404 | struct iwm_priv *iwm; | ||
1405 | struct iwm_rx_ticket_node *ticket, *next; | ||
1406 | |||
1407 | iwm = container_of(work, struct iwm_priv, rx_worker); | ||
1408 | |||
1409 | /* | ||
1410 | * We go through the tickets list and if there is a pending | ||
1411 | * packet for it, we push it upstream. | ||
1412 | * We stop whenever a ticket is missing its packet, as we're | ||
1413 | * supposed to send the packets in order. | ||
1414 | */ | ||
1415 | list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { | ||
1416 | struct iwm_rx_packet *packet = | ||
1417 | iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); | ||
1418 | |||
1419 | if (!packet) { | ||
1420 | IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " | ||
1421 | "to be handled first\n", | ||
1422 | le16_to_cpu(ticket->ticket->id)); | ||
1423 | return; | ||
1424 | } | ||
1425 | |||
1426 | list_del(&ticket->node); | ||
1427 | list_del(&packet->node); | ||
1428 | iwm_rx_process_packet(iwm, packet, ticket); | ||
1429 | } | ||
1430 | } | ||
1431 | |||
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h new file mode 100644 index 000000000000..da0db91cee59 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/rx.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_RX_H__ | ||
40 | #define __IWM_RX_H__ | ||
41 | |||
42 | #include <linux/skbuff.h> | ||
43 | |||
44 | #include "umac.h" | ||
45 | |||
46 | struct iwm_rx_ticket_node { | ||
47 | struct list_head node; | ||
48 | struct iwm_rx_ticket *ticket; | ||
49 | }; | ||
50 | |||
51 | struct iwm_rx_packet { | ||
52 | struct list_head node; | ||
53 | u16 id; | ||
54 | struct sk_buff *skb; | ||
55 | unsigned long pkt_size; | ||
56 | }; | ||
57 | |||
58 | void iwm_rx_worker(struct work_struct *work); | ||
59 | |||
60 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c new file mode 100644 index 000000000000..edc0a0091058 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * This is the SDIO bus specific hooks for iwm. | ||
41 | * It also is the module's entry point. | ||
42 | * | ||
43 | * Interesting code paths: | ||
44 | * iwm_sdio_probe() (Called by an SDIO bus scan) | ||
45 | * -> iwm_if_alloc() (netdev.c) | ||
46 | * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy) | ||
47 | * -> wiphy_new() | ||
48 | * -> wiphy_register() | ||
49 | * -> alloc_netdev_mq() | ||
50 | * -> register_netdev() | ||
51 | * | ||
52 | * iwm_sdio_remove() | ||
53 | * -> iwm_if_free() (netdev.c) | ||
54 | * -> unregister_netdev() | ||
55 | * -> iwm_wdev_free() (cfg80211.c) | ||
56 | * -> wiphy_unregister() | ||
57 | * -> wiphy_free() | ||
58 | * | ||
59 | * iwm_sdio_isr() (called in process context from the SDIO core code) | ||
60 | * -> queue_work(.., isr_worker) | ||
61 | * -- [async] --> iwm_sdio_isr_worker() | ||
62 | * -> iwm_rx_handle() | ||
63 | */ | ||
64 | |||
65 | #include <linux/kernel.h> | ||
66 | #include <linux/netdevice.h> | ||
67 | #include <linux/debugfs.h> | ||
68 | #include <linux/mmc/sdio.h> | ||
69 | #include <linux/mmc/sdio_func.h> | ||
70 | |||
71 | #include "iwm.h" | ||
72 | #include "debug.h" | ||
73 | #include "bus.h" | ||
74 | #include "sdio.h" | ||
75 | |||
76 | static void iwm_sdio_isr_worker(struct work_struct *work) | ||
77 | { | ||
78 | struct iwm_sdio_priv *hw; | ||
79 | struct iwm_priv *iwm; | ||
80 | struct iwm_rx_info *rx_info; | ||
81 | struct sk_buff *skb; | ||
82 | u8 *rx_buf; | ||
83 | unsigned long rx_size; | ||
84 | |||
85 | hw = container_of(work, struct iwm_sdio_priv, isr_worker); | ||
86 | iwm = hw_to_iwm(hw); | ||
87 | |||
88 | while (!skb_queue_empty(&iwm->rx_list)) { | ||
89 | skb = skb_dequeue(&iwm->rx_list); | ||
90 | rx_info = skb_to_rx_info(skb); | ||
91 | rx_size = rx_info->rx_size; | ||
92 | rx_buf = skb->data; | ||
93 | |||
94 | IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size); | ||
95 | if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0) | ||
96 | IWM_WARN(iwm, "RX error\n"); | ||
97 | |||
98 | kfree_skb(skb); | ||
99 | } | ||
100 | } | ||
101 | |||
102 | static void iwm_sdio_isr(struct sdio_func *func) | ||
103 | { | ||
104 | struct iwm_priv *iwm; | ||
105 | struct iwm_sdio_priv *hw; | ||
106 | struct iwm_rx_info *rx_info; | ||
107 | struct sk_buff *skb; | ||
108 | unsigned long buf_size, read_size; | ||
109 | int ret; | ||
110 | u8 val; | ||
111 | |||
112 | hw = sdio_get_drvdata(func); | ||
113 | iwm = hw_to_iwm(hw); | ||
114 | |||
115 | buf_size = hw->blk_size; | ||
116 | |||
117 | /* We're checking the status */ | ||
118 | val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); | ||
119 | if (val == 0 || ret < 0) { | ||
120 | IWM_ERR(iwm, "Wrong INTR_STATUS\n"); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | /* See if we have free buffers */ | ||
125 | if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { | ||
126 | IWM_ERR(iwm, "No buffer for more Rx frames\n"); | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | /* We first read the transaction size */ | ||
131 | read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); | ||
132 | read_size = read_size << 8; | ||
133 | |||
134 | if (ret < 0) { | ||
135 | IWM_ERR(iwm, "Couldn't read the xfer size\n"); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | /* We need to clear the INT register */ | ||
140 | sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); | ||
141 | if (ret < 0) { | ||
142 | IWM_ERR(iwm, "Couldn't clear the INT register\n"); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | while (buf_size < read_size) | ||
147 | buf_size <<= 1; | ||
148 | |||
149 | skb = dev_alloc_skb(buf_size); | ||
150 | if (!skb) { | ||
151 | IWM_ERR(iwm, "Couldn't alloc RX skb\n"); | ||
152 | return; | ||
153 | } | ||
154 | rx_info = skb_to_rx_info(skb); | ||
155 | rx_info->rx_size = read_size; | ||
156 | rx_info->rx_buf_size = buf_size; | ||
157 | |||
158 | /* Now we can read the actual buffer */ | ||
159 | ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), | ||
160 | IWM_SDIO_DATA_ADDR, read_size); | ||
161 | |||
162 | /* The skb is put on a driver's specific Rx SKB list */ | ||
163 | skb_queue_tail(&iwm->rx_list, skb); | ||
164 | |||
165 | /* We can now schedule the actual worker */ | ||
166 | queue_work(hw->isr_wq, &hw->isr_worker); | ||
167 | } | ||
168 | |||
169 | static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw) | ||
170 | { | ||
171 | struct iwm_priv *iwm = hw_to_iwm(hw); | ||
172 | |||
173 | flush_workqueue(hw->isr_wq); | ||
174 | |||
175 | skb_queue_purge(&iwm->rx_list); | ||
176 | } | ||
177 | |||
178 | /* Bus ops */ | ||
179 | static int if_sdio_enable(struct iwm_priv *iwm) | ||
180 | { | ||
181 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
182 | int ret; | ||
183 | |||
184 | sdio_claim_host(hw->func); | ||
185 | |||
186 | ret = sdio_enable_func(hw->func); | ||
187 | if (ret) { | ||
188 | IWM_ERR(iwm, "Couldn't enable the device: is TOP driver " | ||
189 | "loaded and functional?\n"); | ||
190 | goto release_host; | ||
191 | } | ||
192 | |||
193 | iwm_reset(iwm); | ||
194 | |||
195 | ret = sdio_claim_irq(hw->func, iwm_sdio_isr); | ||
196 | if (ret) { | ||
197 | IWM_ERR(iwm, "Failed to claim irq: %d\n", ret); | ||
198 | goto release_host; | ||
199 | } | ||
200 | |||
201 | sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret); | ||
202 | if (ret < 0) { | ||
203 | IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret); | ||
204 | goto release_irq; | ||
205 | } | ||
206 | |||
207 | sdio_release_host(hw->func); | ||
208 | |||
209 | IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n"); | ||
210 | |||
211 | return 0; | ||
212 | |||
213 | release_irq: | ||
214 | sdio_release_irq(hw->func); | ||
215 | release_host: | ||
216 | sdio_release_host(hw->func); | ||
217 | |||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static int if_sdio_disable(struct iwm_priv *iwm) | ||
222 | { | ||
223 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
224 | int ret; | ||
225 | |||
226 | iwm_reset(iwm); | ||
227 | |||
228 | sdio_claim_host(hw->func); | ||
229 | sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); | ||
230 | if (ret < 0) | ||
231 | IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret); | ||
232 | |||
233 | sdio_release_irq(hw->func); | ||
234 | sdio_disable_func(hw->func); | ||
235 | sdio_release_host(hw->func); | ||
236 | |||
237 | iwm_sdio_rx_free(hw); | ||
238 | |||
239 | IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) | ||
245 | { | ||
246 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
247 | int aligned_count = ALIGN(count, hw->blk_size); | ||
248 | int ret; | ||
249 | |||
250 | if ((unsigned long)buf & 0x3) { | ||
251 | IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf); | ||
252 | /* TODO: Is this a hardware limitation? use get_unligned */ | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | sdio_claim_host(hw->func); | ||
257 | ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf, | ||
258 | aligned_count); | ||
259 | sdio_release_host(hw->func); | ||
260 | |||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | /* debugfs hooks */ | ||
265 | static int iwm_debugfs_sdio_open(struct inode *inode, struct file *filp) | ||
266 | { | ||
267 | filp->private_data = inode->i_private; | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, | ||
272 | size_t count, loff_t *ppos) | ||
273 | { | ||
274 | struct iwm_priv *iwm = filp->private_data; | ||
275 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
276 | char *buf; | ||
277 | u8 cccr; | ||
278 | int buf_len = 4096, ret; | ||
279 | size_t len = 0; | ||
280 | |||
281 | if (*ppos != 0) | ||
282 | return 0; | ||
283 | if (count < sizeof(buf)) | ||
284 | return -ENOSPC; | ||
285 | |||
286 | buf = kzalloc(buf_len, GFP_KERNEL); | ||
287 | if (!buf) | ||
288 | return -ENOMEM; | ||
289 | |||
290 | sdio_claim_host(hw->func); | ||
291 | |||
292 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret); | ||
293 | if (ret) { | ||
294 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n"); | ||
295 | goto err; | ||
296 | } | ||
297 | len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr); | ||
298 | |||
299 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret); | ||
300 | if (ret) { | ||
301 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n"); | ||
302 | goto err; | ||
303 | } | ||
304 | len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr); | ||
305 | |||
306 | |||
307 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret); | ||
308 | if (ret) { | ||
309 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n"); | ||
310 | goto err; | ||
311 | } | ||
312 | len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr); | ||
313 | |||
314 | |||
315 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret); | ||
316 | if (ret) { | ||
317 | IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n"); | ||
318 | goto err; | ||
319 | } | ||
320 | len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr); | ||
321 | |||
322 | |||
323 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret); | ||
324 | if (ret) { | ||
325 | IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n"); | ||
326 | goto err; | ||
327 | } | ||
328 | len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr); | ||
329 | |||
330 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret); | ||
331 | if (ret) { | ||
332 | IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n"); | ||
333 | goto err; | ||
334 | } | ||
335 | len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr); | ||
336 | |||
337 | |||
338 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret); | ||
339 | if (ret) { | ||
340 | IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n"); | ||
341 | goto err; | ||
342 | } | ||
343 | len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr); | ||
344 | |||
345 | cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret); | ||
346 | if (ret) { | ||
347 | IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n"); | ||
348 | goto err; | ||
349 | } | ||
350 | len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr); | ||
351 | |||
352 | ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); | ||
353 | err: | ||
354 | sdio_release_host(hw->func); | ||
355 | |||
356 | kfree(buf); | ||
357 | |||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static const struct file_operations iwm_debugfs_sdio_fops = { | ||
362 | .owner = THIS_MODULE, | ||
363 | .open = iwm_debugfs_sdio_open, | ||
364 | .read = iwm_debugfs_sdio_read, | ||
365 | }; | ||
366 | |||
367 | static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) | ||
368 | { | ||
369 | int result; | ||
370 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
371 | |||
372 | hw->cccr_dentry = debugfs_create_file("cccr", 0200, | ||
373 | parent_dir, iwm, | ||
374 | &iwm_debugfs_sdio_fops); | ||
375 | result = PTR_ERR(hw->cccr_dentry); | ||
376 | if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) { | ||
377 | IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result); | ||
378 | return result; | ||
379 | } | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static void if_sdio_debugfs_exit(struct iwm_priv *iwm) | ||
385 | { | ||
386 | struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); | ||
387 | |||
388 | debugfs_remove(hw->cccr_dentry); | ||
389 | } | ||
390 | |||
391 | static struct iwm_if_ops if_sdio_ops = { | ||
392 | .enable = if_sdio_enable, | ||
393 | .disable = if_sdio_disable, | ||
394 | .send_chunk = if_sdio_send_chunk, | ||
395 | .debugfs_init = if_sdio_debugfs_init, | ||
396 | .debugfs_exit = if_sdio_debugfs_exit, | ||
397 | .umac_name = "iwmc3200wifi-umac-sdio.bin", | ||
398 | .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin", | ||
399 | .lmac_name = "iwmc3200wifi-lmac-sdio.bin", | ||
400 | }; | ||
401 | |||
402 | static int iwm_sdio_probe(struct sdio_func *func, | ||
403 | const struct sdio_device_id *id) | ||
404 | { | ||
405 | struct iwm_priv *iwm; | ||
406 | struct iwm_sdio_priv *hw; | ||
407 | struct device *dev = &func->dev; | ||
408 | int ret; | ||
409 | |||
410 | /* check if TOP has already initialized the card */ | ||
411 | sdio_claim_host(func); | ||
412 | ret = sdio_enable_func(func); | ||
413 | if (ret) { | ||
414 | dev_err(dev, "wait for TOP to enable the device\n"); | ||
415 | sdio_release_host(func); | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE); | ||
420 | |||
421 | sdio_disable_func(func); | ||
422 | sdio_release_host(func); | ||
423 | |||
424 | if (ret < 0) { | ||
425 | dev_err(dev, "Failed to set block size: %d\n", ret); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops); | ||
430 | if (IS_ERR(iwm)) { | ||
431 | dev_err(dev, "allocate SDIO interface failed\n"); | ||
432 | return PTR_ERR(iwm); | ||
433 | } | ||
434 | |||
435 | hw = iwm_private(iwm); | ||
436 | hw->iwm = iwm; | ||
437 | |||
438 | ret = iwm_debugfs_init(iwm); | ||
439 | if (ret < 0) { | ||
440 | IWM_ERR(iwm, "Debugfs registration failed\n"); | ||
441 | goto if_free; | ||
442 | } | ||
443 | |||
444 | sdio_set_drvdata(func, hw); | ||
445 | |||
446 | hw->func = func; | ||
447 | hw->blk_size = IWM_SDIO_BLK_SIZE; | ||
448 | |||
449 | hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio"); | ||
450 | if (!hw->isr_wq) { | ||
451 | ret = -ENOMEM; | ||
452 | goto debugfs_exit; | ||
453 | } | ||
454 | |||
455 | INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); | ||
456 | |||
457 | dev_info(dev, "IWM SDIO probe\n"); | ||
458 | |||
459 | return 0; | ||
460 | |||
461 | debugfs_exit: | ||
462 | iwm_debugfs_exit(iwm); | ||
463 | if_free: | ||
464 | iwm_if_free(iwm); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | static void iwm_sdio_remove(struct sdio_func *func) | ||
469 | { | ||
470 | struct iwm_sdio_priv *hw = sdio_get_drvdata(func); | ||
471 | struct iwm_priv *iwm = hw_to_iwm(hw); | ||
472 | struct device *dev = &func->dev; | ||
473 | |||
474 | iwm_debugfs_exit(iwm); | ||
475 | iwm_if_free(iwm); | ||
476 | destroy_workqueue(hw->isr_wq); | ||
477 | |||
478 | sdio_set_drvdata(func, NULL); | ||
479 | |||
480 | dev_info(dev, "IWM SDIO remove\n"); | ||
481 | |||
482 | return; | ||
483 | } | ||
484 | |||
485 | static const struct sdio_device_id iwm_sdio_ids[] = { | ||
486 | { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, | ||
487 | { /* end: all zeroes */ }, | ||
488 | }; | ||
489 | MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); | ||
490 | |||
491 | static struct sdio_driver iwm_sdio_driver = { | ||
492 | .name = "iwm_sdio", | ||
493 | .id_table = iwm_sdio_ids, | ||
494 | .probe = iwm_sdio_probe, | ||
495 | .remove = iwm_sdio_remove, | ||
496 | }; | ||
497 | |||
498 | static int __init iwm_sdio_init_module(void) | ||
499 | { | ||
500 | int ret; | ||
501 | |||
502 | ret = sdio_register_driver(&iwm_sdio_driver); | ||
503 | |||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | static void __exit iwm_sdio_exit_module(void) | ||
508 | { | ||
509 | sdio_unregister_driver(&iwm_sdio_driver); | ||
510 | } | ||
511 | |||
512 | module_init(iwm_sdio_init_module); | ||
513 | module_exit(iwm_sdio_exit_module); | ||
514 | |||
515 | MODULE_LICENSE("GPL"); | ||
516 | MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR); | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h new file mode 100644 index 000000000000..b3c156b08dda --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_SDIO_H__ | ||
40 | #define __IWM_SDIO_H__ | ||
41 | |||
42 | #define SDIO_VENDOR_ID_INTEL 0x89 | ||
43 | #define SDIO_DEVICE_ID_IWM 0x1403 | ||
44 | |||
45 | #define IWM_SDIO_DATA_ADDR 0x0 | ||
46 | #define IWM_SDIO_INTR_ENABLE_ADDR 0x14 | ||
47 | #define IWM_SDIO_INTR_STATUS_ADDR 0x13 | ||
48 | #define IWM_SDIO_INTR_CLEAR_ADDR 0x13 | ||
49 | #define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C | ||
50 | |||
51 | #define IWM_SDIO_BLK_SIZE 256 | ||
52 | |||
53 | #define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private) | ||
54 | |||
55 | struct iwm_sdio_priv { | ||
56 | struct sdio_func *func; | ||
57 | struct iwm_priv *iwm; | ||
58 | |||
59 | struct workqueue_struct *isr_wq; | ||
60 | struct work_struct isr_worker; | ||
61 | |||
62 | struct dentry *cccr_dentry; | ||
63 | |||
64 | unsigned int blk_size; | ||
65 | }; | ||
66 | |||
67 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c new file mode 100644 index 000000000000..e3b4f7902daf --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/tx.c | |||
@@ -0,0 +1,492 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * iwm Tx theory of operation: | ||
41 | * | ||
42 | * 1) We receive a 802.3 frame from the stack | ||
43 | * 2) We convert it to a 802.11 frame [iwm_xmit_frame] | ||
44 | * 3) We queue it to its corresponding tx queue [iwm_xmit_frame] | ||
45 | * 4) We schedule the tx worker. There is one worker per tx | ||
46 | * queue. [iwm_xmit_frame] | ||
47 | * 5) The tx worker is scheduled | ||
48 | * 6) We go through every queued skb on the tx queue, and for each | ||
49 | * and every one of them: [iwm_tx_worker] | ||
50 | * a) We check if we have enough Tx credits (see below for a Tx | ||
51 | * credits description) for the frame length. [iwm_tx_worker] | ||
52 | * b) If we do, we aggregate the Tx frame into a UDMA one, by | ||
53 | * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker] | ||
54 | * c) When we run out of credits, or when we reach the maximum | ||
55 | * concatenation size, we actually send the concatenated UDMA | ||
56 | * frame. [iwm_tx_worker] | ||
57 | * | ||
58 | * When we run out of Tx credits, the skbs are filling the tx queue, | ||
59 | * and eventually we will stop the netdev queue. [iwm_tx_worker] | ||
60 | * The tx queue is emptied as we're getting new tx credits, by | ||
61 | * scheduling the tx_worker. [iwm_tx_credit_inc] | ||
62 | * The netdev queue is started again when we have enough tx credits, | ||
63 | * and when our tx queue has some reasonable amout of space available | ||
64 | * (i.e. half of the max size). [iwm_tx_worker] | ||
65 | */ | ||
66 | |||
67 | #include <linux/skbuff.h> | ||
68 | #include <linux/netdevice.h> | ||
69 | #include <linux/ieee80211.h> | ||
70 | |||
71 | #include "iwm.h" | ||
72 | #include "debug.h" | ||
73 | #include "commands.h" | ||
74 | #include "hal.h" | ||
75 | #include "umac.h" | ||
76 | #include "bus.h" | ||
77 | |||
78 | #define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff | ||
79 | |||
80 | #define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \ | ||
81 | (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0)) | ||
82 | |||
83 | #define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1) | ||
84 | #define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1) | ||
85 | |||
86 | /* require to hold tx_credit lock */ | ||
87 | static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id) | ||
88 | { | ||
89 | struct pool_entry *pool = &tx_credit->pools[id]; | ||
90 | struct spool_entry *spool = &tx_credit->spools[pool->sid]; | ||
91 | int spool_pages; | ||
92 | |||
93 | /* number of pages can be taken from spool by this pool */ | ||
94 | spool_pages = spool->max_pages - spool->alloc_pages + | ||
95 | max(pool->min_pages - pool->alloc_pages, 0); | ||
96 | |||
97 | return min(pool->max_pages - pool->alloc_pages, spool_pages); | ||
98 | } | ||
99 | |||
100 | static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb) | ||
101 | { | ||
102 | u32 npages = BYTES_TO_PAGES(nb); | ||
103 | |||
104 | if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id)) | ||
105 | return 1; | ||
106 | |||
107 | set_bit(id, &iwm->tx_credit.full_pools_map); | ||
108 | |||
109 | IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n", | ||
110 | pool_id_to_queue(id), | ||
111 | iwm_tx_credit_get(&iwm->tx_credit, id)); | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages) | ||
117 | { | ||
118 | struct pool_entry *pool; | ||
119 | struct spool_entry *spool; | ||
120 | int freed_pages; | ||
121 | int queue; | ||
122 | |||
123 | BUG_ON(id >= IWM_MACS_OUT_GROUPS); | ||
124 | |||
125 | pool = &iwm->tx_credit.pools[id]; | ||
126 | spool = &iwm->tx_credit.spools[pool->sid]; | ||
127 | |||
128 | freed_pages = total_freed_pages - pool->total_freed_pages; | ||
129 | IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id); | ||
130 | |||
131 | if (!freed_pages) { | ||
132 | IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n"); | ||
133 | return; | ||
134 | } else if (freed_pages < 0) | ||
135 | freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1; | ||
136 | |||
137 | if (pool->alloc_pages > pool->min_pages) { | ||
138 | int spool_pages = pool->alloc_pages - pool->min_pages; | ||
139 | spool_pages = min(spool_pages, freed_pages); | ||
140 | spool->alloc_pages -= spool_pages; | ||
141 | } | ||
142 | |||
143 | pool->alloc_pages -= freed_pages; | ||
144 | pool->total_freed_pages = total_freed_pages; | ||
145 | |||
146 | IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " | ||
147 | "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, | ||
148 | pool->total_freed_pages, pool->sid, spool->alloc_pages); | ||
149 | |||
150 | if (test_bit(id, &iwm->tx_credit.full_pools_map) && | ||
151 | (pool->alloc_pages < pool->max_pages / 2)) { | ||
152 | clear_bit(id, &iwm->tx_credit.full_pools_map); | ||
153 | |||
154 | queue = pool_id_to_queue(id); | ||
155 | |||
156 | IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available " | ||
157 | "credit: %d\n", queue, | ||
158 | iwm_tx_credit_get(&iwm->tx_credit, id)); | ||
159 | queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages) | ||
164 | { | ||
165 | struct pool_entry *pool; | ||
166 | struct spool_entry *spool; | ||
167 | int spool_pages; | ||
168 | |||
169 | IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n", | ||
170 | alloc_pages, id); | ||
171 | |||
172 | BUG_ON(id >= IWM_MACS_OUT_GROUPS); | ||
173 | |||
174 | pool = &iwm->tx_credit.pools[id]; | ||
175 | spool = &iwm->tx_credit.spools[pool->sid]; | ||
176 | |||
177 | spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages; | ||
178 | |||
179 | if (pool->alloc_pages >= pool->min_pages) | ||
180 | spool->alloc_pages += alloc_pages; | ||
181 | else if (spool_pages > 0) | ||
182 | spool->alloc_pages += spool_pages; | ||
183 | |||
184 | pool->alloc_pages += alloc_pages; | ||
185 | |||
186 | IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " | ||
187 | "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, | ||
188 | pool->total_freed_pages, pool->sid, spool->alloc_pages); | ||
189 | } | ||
190 | |||
191 | int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) | ||
192 | { | ||
193 | u32 npages = BYTES_TO_PAGES(nb); | ||
194 | int ret = 0; | ||
195 | |||
196 | spin_lock(&iwm->tx_credit.lock); | ||
197 | |||
198 | if (!iwm_tx_credit_ok(iwm, id, nb)) { | ||
199 | IWM_DBG_TX(iwm, DBG, "No credit avaliable for pool[%d]\n", id); | ||
200 | ret = -ENOSPC; | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | iwm_tx_credit_dec(iwm, id, npages); | ||
205 | |||
206 | out: | ||
207 | spin_unlock(&iwm->tx_credit.lock); | ||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Since we're on an SDIO or USB bus, we are not sharing memory | ||
213 | * for storing to be transmitted frames. The host needs to push | ||
214 | * them upstream. As a consequence there needs to be a way for | ||
215 | * the target to let us know if it can actually take more TX frames | ||
216 | * or not. This is what Tx credits are for. | ||
217 | * | ||
218 | * For each Tx HW queue, we have a Tx pool, and then we have one | ||
219 | * unique super pool (spool), which is actually a global pool of | ||
220 | * all the UMAC pages. | ||
221 | * For each Tx pool we have a min_pages, a max_pages fields, and a | ||
222 | * alloc_pages fields. The alloc_pages tracks the number of pages | ||
223 | * currently allocated from the tx pool. | ||
224 | * Here are the rules to check if given a tx frame we have enough | ||
225 | * tx credits for it: | ||
226 | * 1) We translate the frame length into a number of UMAC pages. | ||
227 | * Let's call them n_pages. | ||
228 | * 2) For the corresponding tx pool, we check if n_pages + | ||
229 | * pool->alloc_pages is higher than pool->min_pages. min_pages | ||
230 | * represent a set of pre-allocated pages on the tx pool. If | ||
231 | * that's the case, then we need to allocate those pages from | ||
232 | * the spool. We can do so until we reach spool->max_pages. | ||
233 | * 3) Each tx pool is not allowed to allocate more than pool->max_pages | ||
234 | * from the spool, so once we're over min_pages, we can allocate | ||
235 | * pages from the spool, but not more than max_pages. | ||
236 | * | ||
237 | * When the tx code path needs to send a tx frame, it checks first | ||
238 | * if it has enough tx credits, following those rules. [iwm_tx_credit_get] | ||
239 | * If it does, it then updates the pool and spool counters and | ||
240 | * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec] | ||
241 | * On the other side, when the UMAC is done transmitting frames, it | ||
242 | * will send a credit update notification to the host. This is when | ||
243 | * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc, | ||
244 | * called from rx.c:iwm_ntf_tx_credit_update] | ||
245 | * | ||
246 | */ | ||
247 | void iwm_tx_credit_init_pools(struct iwm_priv *iwm, | ||
248 | struct iwm_umac_notif_alive *alive) | ||
249 | { | ||
250 | int i, sid, pool_pages; | ||
251 | |||
252 | spin_lock(&iwm->tx_credit.lock); | ||
253 | |||
254 | iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count); | ||
255 | iwm->tx_credit.full_pools_map = 0; | ||
256 | memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry)); | ||
257 | |||
258 | IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr); | ||
259 | |||
260 | for (i = 0; i < iwm->tx_credit.pool_nr; i++) { | ||
261 | __le32 page_grp_state = alive->page_grp_state[i]; | ||
262 | |||
263 | iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state, | ||
264 | UMAC_ALIVE_PAGE_STS_GRP_NUM); | ||
265 | iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state, | ||
266 | UMAC_ALIVE_PAGE_STS_SGRP_NUM); | ||
267 | iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state, | ||
268 | UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE); | ||
269 | iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state, | ||
270 | UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE); | ||
271 | iwm->tx_credit.pools[i].alloc_pages = 0; | ||
272 | iwm->tx_credit.pools[i].total_freed_pages = 0; | ||
273 | |||
274 | sid = iwm->tx_credit.pools[i].sid; | ||
275 | pool_pages = iwm->tx_credit.pools[i].min_pages; | ||
276 | |||
277 | if (iwm->tx_credit.spools[sid].max_pages == 0) { | ||
278 | iwm->tx_credit.spools[sid].id = sid; | ||
279 | iwm->tx_credit.spools[sid].max_pages = | ||
280 | GET_VAL32(page_grp_state, | ||
281 | UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE); | ||
282 | iwm->tx_credit.spools[sid].alloc_pages = 0; | ||
283 | } | ||
284 | |||
285 | iwm->tx_credit.spools[sid].alloc_pages += pool_pages; | ||
286 | |||
287 | IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity " | ||
288 | "min: %d, max: %d, pool alloc: %d, total_free: %d, " | ||
289 | "super poll alloc: %d\n", | ||
290 | i, iwm->tx_credit.pools[i].id, | ||
291 | iwm->tx_credit.pools[i].sid, | ||
292 | iwm->tx_credit.pools[i].min_pages, | ||
293 | iwm->tx_credit.pools[i].max_pages, | ||
294 | iwm->tx_credit.pools[i].alloc_pages, | ||
295 | iwm->tx_credit.pools[i].total_freed_pages, | ||
296 | iwm->tx_credit.spools[sid].alloc_pages); | ||
297 | } | ||
298 | |||
299 | spin_unlock(&iwm->tx_credit.lock); | ||
300 | } | ||
301 | |||
302 | #define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr) | ||
303 | |||
304 | static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, | ||
305 | int pool_id, u8 *buf) | ||
306 | { | ||
307 | struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf; | ||
308 | struct iwm_udma_wifi_cmd udma_cmd; | ||
309 | struct iwm_umac_cmd umac_cmd; | ||
310 | struct iwm_tx_info *tx_info = skb_to_tx_info(skb); | ||
311 | |||
312 | udma_cmd.count = cpu_to_le16(skb->len + | ||
313 | sizeof(struct iwm_umac_fw_cmd_hdr)); | ||
314 | /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be | ||
315 | * called later to set EOP for the last packet. */ | ||
316 | udma_cmd.eop = 0; | ||
317 | udma_cmd.credit_group = pool_id; | ||
318 | udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; | ||
319 | udma_cmd.lmac_offset = 0; | ||
320 | |||
321 | umac_cmd.id = REPLY_TX; | ||
322 | umac_cmd.count = cpu_to_le16(skb->len); | ||
323 | umac_cmd.color = tx_info->color; | ||
324 | umac_cmd.resp = 0; | ||
325 | umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm)); | ||
326 | |||
327 | iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd); | ||
328 | iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd); | ||
329 | |||
330 | memcpy(buf + sizeof(*hdr), skb->data, skb->len); | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, | ||
336 | struct iwm_tx_queue *txq) | ||
337 | { | ||
338 | int ret; | ||
339 | |||
340 | if (!txq->concat_count) | ||
341 | return 0; | ||
342 | |||
343 | IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n", | ||
344 | txq->id, txq->concat_count); | ||
345 | |||
346 | /* mark EOP for the last packet */ | ||
347 | iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1); | ||
348 | |||
349 | ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count); | ||
350 | |||
351 | txq->concat_count = 0; | ||
352 | txq->concat_ptr = txq->concat_buf; | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | #define CONFIG_IWM_TX_CONCATENATED 1 | ||
358 | |||
359 | void iwm_tx_worker(struct work_struct *work) | ||
360 | { | ||
361 | struct iwm_priv *iwm; | ||
362 | struct iwm_tx_info *tx_info = NULL; | ||
363 | struct sk_buff *skb; | ||
364 | int cmdlen, ret; | ||
365 | struct iwm_tx_queue *txq; | ||
366 | int pool_id; | ||
367 | |||
368 | txq = container_of(work, struct iwm_tx_queue, worker); | ||
369 | iwm = container_of(txq, struct iwm_priv, txq[txq->id]); | ||
370 | |||
371 | pool_id = queue_to_pool_id(txq->id); | ||
372 | |||
373 | while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && | ||
374 | !skb_queue_empty(&txq->queue)) { | ||
375 | |||
376 | skb = skb_dequeue(&txq->queue); | ||
377 | tx_info = skb_to_tx_info(skb); | ||
378 | cmdlen = IWM_UDMA_HDR_LEN + skb->len; | ||
379 | |||
380 | IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " | ||
381 | "%d, color: %d\n", txq->id, skb, tx_info->sta, | ||
382 | tx_info->color); | ||
383 | |||
384 | #if !CONFIG_IWM_TX_CONCATENATED | ||
385 | /* temporarily keep this to comparing the performance */ | ||
386 | ret = iwm_send_packet(iwm, skb, pool_id); | ||
387 | #else | ||
388 | |||
389 | if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) | ||
390 | iwm_tx_send_concat_packets(iwm, txq); | ||
391 | |||
392 | ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen); | ||
393 | if (ret) { | ||
394 | IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " | ||
395 | "%d, Tx worker stopped\n", txq->id); | ||
396 | skb_queue_head(&txq->queue, skb); | ||
397 | break; | ||
398 | } | ||
399 | |||
400 | txq->concat_ptr = txq->concat_buf + txq->concat_count; | ||
401 | iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); | ||
402 | txq->concat_count += ALIGN(cmdlen, 16); | ||
403 | #endif | ||
404 | kfree_skb(skb); | ||
405 | } | ||
406 | |||
407 | iwm_tx_send_concat_packets(iwm, txq); | ||
408 | |||
409 | if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) && | ||
410 | !test_bit(pool_id, &iwm->tx_credit.full_pools_map) && | ||
411 | (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) { | ||
412 | IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id); | ||
413 | netif_wake_subqueue(iwm_to_ndev(iwm), txq->id); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | ||
418 | { | ||
419 | struct iwm_priv *iwm = ndev_to_iwm(netdev); | ||
420 | struct net_device *ndev = iwm_to_ndev(iwm); | ||
421 | struct wireless_dev *wdev = iwm_to_wdev(iwm); | ||
422 | u8 *dst_addr; | ||
423 | struct iwm_tx_info *tx_info; | ||
424 | struct iwm_tx_queue *txq; | ||
425 | struct iwm_sta_info *sta_info; | ||
426 | u8 sta_id; | ||
427 | u16 queue; | ||
428 | int ret; | ||
429 | |||
430 | if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
431 | IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " | ||
432 | "not associated\n"); | ||
433 | netif_tx_stop_all_queues(netdev); | ||
434 | goto drop; | ||
435 | } | ||
436 | |||
437 | queue = skb_get_queue_mapping(skb); | ||
438 | BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */ | ||
439 | |||
440 | txq = &iwm->txq[queue]; | ||
441 | |||
442 | /* No free space for Tx, tx_worker is too slow */ | ||
443 | if (skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) { | ||
444 | IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); | ||
445 | netif_stop_subqueue(netdev, queue); | ||
446 | return NETDEV_TX_BUSY; | ||
447 | } | ||
448 | |||
449 | ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype, | ||
450 | iwm->bssid, 0); | ||
451 | if (ret) { | ||
452 | IWM_ERR(iwm, "build wifi header failed\n"); | ||
453 | goto drop; | ||
454 | } | ||
455 | |||
456 | dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1; | ||
457 | |||
458 | for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) { | ||
459 | sta_info = &iwm->sta_table[sta_id]; | ||
460 | if (sta_info->valid && | ||
461 | !memcmp(dst_addr, sta_info->addr, ETH_ALEN)) | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | if (sta_id == IWM_STA_TABLE_NUM) { | ||
466 | IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n", | ||
467 | dst_addr); | ||
468 | goto drop; | ||
469 | } | ||
470 | |||
471 | tx_info = skb_to_tx_info(skb); | ||
472 | tx_info->sta = sta_id; | ||
473 | tx_info->color = sta_info->color; | ||
474 | /* UMAC uses TID 8 (vs. 0) for non QoS packets */ | ||
475 | if (sta_info->qos) | ||
476 | tx_info->tid = skb->priority; | ||
477 | else | ||
478 | tx_info->tid = IWM_UMAC_MGMT_TID; | ||
479 | |||
480 | skb_queue_tail(&iwm->txq[queue].queue, skb); | ||
481 | |||
482 | queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); | ||
483 | |||
484 | ndev->stats.tx_packets++; | ||
485 | ndev->stats.tx_bytes += skb->len; | ||
486 | return NETDEV_TX_OK; | ||
487 | |||
488 | drop: | ||
489 | ndev->stats.tx_dropped++; | ||
490 | dev_kfree_skb_any(skb); | ||
491 | return NETDEV_TX_OK; | ||
492 | } | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h new file mode 100644 index 000000000000..4a95cce1f0a6 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/umac.h | |||
@@ -0,0 +1,744 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * | ||
10 | * * Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * * Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in | ||
14 | * the documentation and/or other materials provided with the | ||
15 | * distribution. | ||
16 | * * Neither the name of Intel Corporation nor the names of its | ||
17 | * contributors may be used to endorse or promote products derived | ||
18 | * from this software without specific prior written permission. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
31 | * | ||
32 | * | ||
33 | * Intel Corporation <ilw@linux.intel.com> | ||
34 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
35 | * Zhu Yi <yi.zhu@intel.com> | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #ifndef __IWM_UMAC_H__ | ||
40 | #define __IWM_UMAC_H__ | ||
41 | |||
42 | struct iwm_udma_in_hdr { | ||
43 | __le32 cmd; | ||
44 | __le32 size; | ||
45 | } __attribute__ ((packed)); | ||
46 | |||
47 | struct iwm_udma_out_nonwifi_hdr { | ||
48 | __le32 cmd; | ||
49 | __le32 addr; | ||
50 | __le32 op1_sz; | ||
51 | __le32 op2; | ||
52 | } __attribute__ ((packed)); | ||
53 | |||
54 | struct iwm_udma_out_wifi_hdr { | ||
55 | __le32 cmd; | ||
56 | __le32 meta_data; | ||
57 | } __attribute__ ((packed)); | ||
58 | |||
59 | /* Sequence numbering */ | ||
60 | #define UMAC_WIFI_SEQ_NUM_BASE 1 | ||
61 | #define UMAC_WIFI_SEQ_NUM_MAX 0x4000 | ||
62 | #define UMAC_NONWIFI_SEQ_NUM_BASE 1 | ||
63 | #define UMAC_NONWIFI_SEQ_NUM_MAX 0x10 | ||
64 | |||
65 | /* MAC address address */ | ||
66 | #define WICO_MAC_ADDRESS_ADDR 0x604008F8 | ||
67 | |||
68 | /* RA / TID */ | ||
69 | #define UMAC_HDI_ACT_TBL_IDX_TID_POS 0 | ||
70 | #define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF | ||
71 | |||
72 | #define UMAC_HDI_ACT_TBL_IDX_RA_POS 4 | ||
73 | #define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF | ||
74 | |||
75 | #define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF | ||
76 | #define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9 | ||
77 | #define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA | ||
78 | |||
79 | #define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \ | ||
80 | ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ | ||
81 | (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) | ||
82 | #define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \ | ||
83 | ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ | ||
84 | (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) | ||
85 | |||
86 | /* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ | ||
87 | #define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 | ||
88 | #define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF | ||
89 | |||
90 | /* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */ | ||
91 | #define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4 | ||
92 | #define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF | ||
93 | |||
94 | /* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */ | ||
95 | #define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8 | ||
96 | #define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF | ||
97 | |||
98 | /* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */ | ||
99 | #define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16 | ||
100 | #define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF | ||
101 | |||
102 | /* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */ | ||
103 | #define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24 | ||
104 | #define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF | ||
105 | |||
106 | /* Barkers */ | ||
107 | #define UMAC_REBOOT_BARKER 0xdeadbeef | ||
108 | #define UMAC_ACK_BARKER 0xfeedbabe | ||
109 | #define UMAC_PAD_TERMINAL 0xadadadad | ||
110 | |||
111 | /* UMAC JMP address */ | ||
112 | #define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000 | ||
113 | |||
114 | /* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */ | ||
115 | #define UMAC_HDI_OUT_CMD_OPCODE_POS 0 | ||
116 | #define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF | ||
117 | |||
118 | /* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */ | ||
119 | #define UMAC_HDI_OUT_CMD_EOT_POS 10 | ||
120 | #define UMAC_HDI_OUT_CMD_EOT_SEED 0x1 | ||
121 | |||
122 | /* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */ | ||
123 | #define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11 | ||
124 | #define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1 | ||
125 | |||
126 | /* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ | ||
127 | #define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 | ||
128 | #define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF | ||
129 | |||
130 | /* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */ | ||
131 | #define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16 | ||
132 | #define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF | ||
133 | |||
134 | /* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */ | ||
135 | #define UMAC_HDI_OUT_BYTE_COUNT_POS 0 | ||
136 | #define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF | ||
137 | |||
138 | /* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */ | ||
139 | #define UMAC_HDI_OUT_CREDIT_GRP_POS 12 | ||
140 | #define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF | ||
141 | |||
142 | /* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */ | ||
143 | #define UMAC_HDI_OUT_RATID_POS 16 | ||
144 | #define UMAC_HDI_OUT_RATID_SEED 0xFF | ||
145 | |||
146 | /* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */ | ||
147 | #define UMAC_HDI_OUT_LMAC_OFFSET_POS 24 | ||
148 | #define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF | ||
149 | |||
150 | /* Signature */ | ||
151 | #define UMAC_HDI_OUT_SIGNATURE 0xCBBC | ||
152 | |||
153 | /* buffer alignment */ | ||
154 | #define UMAC_HDI_BUF_ALIGN_MSK 0xF | ||
155 | |||
156 | /* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */ | ||
157 | #define UMAC_HDI_IN_CMD_OPCODE_POS 0 | ||
158 | #define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF | ||
159 | |||
160 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */ | ||
161 | #define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4 | ||
162 | #define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7 | ||
163 | |||
164 | /* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */ | ||
165 | #define UMAC_HDI_IN_CMD_SOURCE_POS 4 | ||
166 | #define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3 | ||
167 | |||
168 | /* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */ | ||
169 | #define UMAC_HDI_IN_CMD_EOT_POS 6 | ||
170 | #define UMAC_HDI_IN_CMD_EOT_SEED 0x1 | ||
171 | |||
172 | /* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */ | ||
173 | #define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7 | ||
174 | #define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1 | ||
175 | |||
176 | /* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */ | ||
177 | #define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8 | ||
178 | #define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1 | ||
179 | |||
180 | /* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */ | ||
181 | #define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9 | ||
182 | #define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF | ||
183 | |||
184 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ | ||
185 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 | ||
186 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF | ||
187 | |||
188 | /* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */ | ||
189 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16 | ||
190 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF | ||
191 | |||
192 | /* Fixed Non-WiFi signature */ | ||
193 | #define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC | ||
194 | |||
195 | /* IN NTFY op-codes */ | ||
196 | #define UMAC_NOTIFY_OPCODE_ALIVE 0xA1 | ||
197 | #define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2 | ||
198 | #define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3 | ||
199 | #define UMAC_NOTIFY_OPCODE_ERROR 0xA4 | ||
200 | #define UMAC_NOTIFY_OPCODE_DEBUG 0xA5 | ||
201 | #define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0 | ||
202 | #define UMAC_NOTIFY_OPCODE_STATS 0xB1 | ||
203 | #define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3 | ||
204 | #define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4 | ||
205 | #define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\ | ||
206 | UMAC_NOTIFY_OPCODE_ALIVE + 1) | ||
207 | #define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE) | ||
208 | |||
209 | /* HDI OUT OP CODE */ | ||
210 | #define UMAC_HDI_OUT_OPCODE_PING 0x0 | ||
211 | #define UMAC_HDI_OUT_OPCODE_READ 0x1 | ||
212 | #define UMAC_HDI_OUT_OPCODE_WRITE 0x2 | ||
213 | #define UMAC_HDI_OUT_OPCODE_JUMP 0x3 | ||
214 | #define UMAC_HDI_OUT_OPCODE_REBOOT 0x4 | ||
215 | #define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5 | ||
216 | #define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6 | ||
217 | #define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7 | ||
218 | /* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */ | ||
219 | #define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB | ||
220 | #define UMAC_HDI_OUT_OPCODE_WIFI 0xF | ||
221 | |||
222 | /* HDI IN OP CODE -- Non WiFi*/ | ||
223 | #define UMAC_HDI_IN_OPCODE_PING 0x0 | ||
224 | #define UMAC_HDI_IN_OPCODE_READ 0x1 | ||
225 | #define UMAC_HDI_IN_OPCODE_WRITE 0x2 | ||
226 | #define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5 | ||
227 | #define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6 | ||
228 | #define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7 | ||
229 | #define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8 | ||
230 | #define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9 | ||
231 | #define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA | ||
232 | #define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB | ||
233 | #define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \ | ||
234 | (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1) | ||
235 | #define UMAC_HDI_IN_OPCODE_WIFI 0xF | ||
236 | |||
237 | /* HDI IN SOURCE */ | ||
238 | #define UMAC_HDI_IN_SOURCE_FHRX 0x0 | ||
239 | #define UMAC_HDI_IN_SOURCE_UDMA 0x1 | ||
240 | #define UMAC_HDI_IN_SOURCE_FW 0x2 | ||
241 | #define UMAC_HDI_IN_SOURCE_RESERVED 0x3 | ||
242 | |||
243 | /* OUT CMD op-codes */ | ||
244 | #define UMAC_CMD_OPCODE_ECHO 0x01 | ||
245 | #define UMAC_CMD_OPCODE_HALT 0x02 | ||
246 | #define UMAC_CMD_OPCODE_RESET 0x03 | ||
247 | #define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09 | ||
248 | #define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A | ||
249 | #define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B | ||
250 | #define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C | ||
251 | #define UMAC_CMD_OPCODE_TX_ECHO 0x0D | ||
252 | #define UMAC_CMD_OPCODE_DBG_MON 0x0E | ||
253 | #define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F | ||
254 | #define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10 | ||
255 | #define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11 | ||
256 | #define UMAC_CMD_OPCODE_GET_PARAM 0x12 | ||
257 | #define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13 | ||
258 | #define UMAC_CMD_OPCODE_TARGET 0x14 | ||
259 | #define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15 | ||
260 | #define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 | ||
261 | #define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 | ||
262 | #define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 | ||
263 | #define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA | ||
264 | #define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB | ||
265 | #define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC | ||
266 | #define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD | ||
267 | #define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE | ||
268 | #define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF | ||
269 | |||
270 | /* UMAC WiFi interface op-codes */ | ||
271 | #define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11 | ||
272 | #define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12 | ||
273 | #define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13 | ||
274 | #define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14 | ||
275 | #define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15 | ||
276 | #define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16 | ||
277 | #define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17 | ||
278 | #define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18 | ||
279 | #define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19 | ||
280 | #define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A | ||
281 | #define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B | ||
282 | #define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C | ||
283 | #define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E | ||
284 | #define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 | ||
285 | |||
286 | /* UMAC WiFi interface ports */ | ||
287 | #define UMAC_WIFI_IF_FLG_PORT_DEF 0x00 | ||
288 | #define UMAC_WIFI_IF_FLG_PORT_PAN 0x01 | ||
289 | #define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF | ||
290 | |||
291 | /* UMAC WiFi interface actions */ | ||
292 | #define UMAC_WIFI_IF_FLG_ACT_GET 0x10 | ||
293 | #define UMAC_WIFI_IF_FLG_ACT_SET 0x20 | ||
294 | |||
295 | /* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */ | ||
296 | #define UMAC_FW_CMD_BYTE_COUNT_POS 0 | ||
297 | #define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF | ||
298 | |||
299 | /* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */ | ||
300 | #define UMAC_FW_CMD_STATUS_POS 12 | ||
301 | #define UMAC_FW_CMD_STATUS_SEED 0xF | ||
302 | |||
303 | /* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */ | ||
304 | #define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16 | ||
305 | #define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1 | ||
306 | |||
307 | /* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */ | ||
308 | #define UMAC_FW_CMD_TX_FW_CMD_POS 17 | ||
309 | #define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1 | ||
310 | |||
311 | /* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */ | ||
312 | #define UMAC_FW_CMD_TX_PLAINTEXT_POS 18 | ||
313 | #define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1 | ||
314 | |||
315 | /* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */ | ||
316 | #define UMAC_FW_CMD_TX_STA_COLOR_POS 20 | ||
317 | #define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7 | ||
318 | |||
319 | /* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */ | ||
320 | #define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24 | ||
321 | #define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF | ||
322 | |||
323 | /* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */ | ||
324 | #define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5 | ||
325 | #define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1 | ||
326 | |||
327 | /* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */ | ||
328 | #define UMAC_DEV_CMD_FLAGS_ABORT_POS 6 | ||
329 | #define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1 | ||
330 | |||
331 | /* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */ | ||
332 | #define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7 | ||
333 | #define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1 | ||
334 | |||
335 | /* Rx */ | ||
336 | /* Rx actions */ | ||
337 | #define IWM_RX_TICKET_DROP 0x0 | ||
338 | #define IWM_RX_TICKET_RELEASE 0x1 | ||
339 | #define IWM_RX_TICKET_SNIFFER 0x2 | ||
340 | #define IWM_RX_TICKET_ENQUEUE 0x3 | ||
341 | |||
342 | /* Rx flags */ | ||
343 | #define IWM_RX_TICKET_PAD_SIZE_MSK 0x2 | ||
344 | #define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4 | ||
345 | #define IWM_RX_TICKET_AMSDU_MSK 0x8 | ||
346 | #define IWM_RX_TICKET_DROP_REASON_POS 4 | ||
347 | #define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << RX_TICKET_FLAGS_DROP_REASON_POS) | ||
348 | |||
349 | #define IWM_RX_DROP_NO_DROP 0x0 | ||
350 | #define IWM_RX_DROP_BAD_CRC 0x1 | ||
351 | /* L2P no address match */ | ||
352 | #define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2 | ||
353 | /* Multicast address not in list */ | ||
354 | #define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3 | ||
355 | /* Control frames are not sent to the driver */ | ||
356 | #define IWM_RX_DROP_CTL_FRAME 0x4 | ||
357 | /* Our frame is back */ | ||
358 | #define IWM_RX_DROP_OUR_TX 0x5 | ||
359 | /* Association class filtering */ | ||
360 | #define IWM_RX_DROP_CLASS_FILTER 0x6 | ||
361 | /* Duplicated frame */ | ||
362 | #define IWM_RX_DROP_DUPLICATE_FILTER 0x7 | ||
363 | /* Decryption error */ | ||
364 | #define IWM_RX_DROP_SEC_ERR 0x8 | ||
365 | /* Unencrypted frame while encryption is on */ | ||
366 | #define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9 | ||
367 | /* Replay check failure */ | ||
368 | #define IWM_RX_DROP_SEC_REPLAY_ERR 0xa | ||
369 | /* uCode and FW key color mismatch, check before replay */ | ||
370 | #define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb | ||
371 | #define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc | ||
372 | /* No fragmentations Db is found */ | ||
373 | #define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd | ||
374 | /* Fragmention Db has seqCtl mismatch Vs. non-1st frag */ | ||
375 | #define IWM_RX_DROP_FRAG_ERR 0xe | ||
376 | #define IWM_RX_DROP_FRAG_LOST 0xf | ||
377 | #define IWM_RX_DROP_FRAG_COMPLETE 0x10 | ||
378 | /* Should be handled by UMAC */ | ||
379 | #define IWM_RX_DROP_MANAGEMENT 0x11 | ||
380 | /* STA not found by UMAC */ | ||
381 | #define IWM_RX_DROP_NO_STATION 0x12 | ||
382 | /* NULL or QoS NULL */ | ||
383 | #define IWM_RX_DROP_NULL_DATA 0x13 | ||
384 | #define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14 | ||
385 | #define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15 | ||
386 | |||
387 | struct iwm_rx_ticket { | ||
388 | __le16 action; | ||
389 | __le16 id; | ||
390 | __le16 flags; | ||
391 | u8 payload_offset; /* includes: MAC header, pad, IV */ | ||
392 | u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */ | ||
393 | } __attribute__ ((packed)); | ||
394 | |||
395 | struct iwm_rx_mpdu_hdr { | ||
396 | __le16 len; | ||
397 | __le16 reserved; | ||
398 | } __attribute__ ((packed)); | ||
399 | |||
400 | /* UMAC SW WIFI API */ | ||
401 | |||
402 | struct iwm_dev_cmd_hdr { | ||
403 | u8 cmd; | ||
404 | u8 flags; | ||
405 | __le16 seq_num; | ||
406 | } __attribute__ ((packed)); | ||
407 | |||
408 | struct iwm_umac_fw_cmd_hdr { | ||
409 | __le32 meta_data; | ||
410 | struct iwm_dev_cmd_hdr cmd; | ||
411 | } __attribute__ ((packed)); | ||
412 | |||
413 | struct iwm_umac_wifi_out_hdr { | ||
414 | struct iwm_udma_out_wifi_hdr hw_hdr; | ||
415 | struct iwm_umac_fw_cmd_hdr sw_hdr; | ||
416 | } __attribute__ ((packed)); | ||
417 | |||
418 | struct iwm_umac_nonwifi_out_hdr { | ||
419 | struct iwm_udma_out_nonwifi_hdr hw_hdr; | ||
420 | } __attribute__ ((packed)); | ||
421 | |||
422 | struct iwm_umac_wifi_in_hdr { | ||
423 | struct iwm_udma_in_hdr hw_hdr; | ||
424 | struct iwm_umac_fw_cmd_hdr sw_hdr; | ||
425 | } __attribute__ ((packed)); | ||
426 | |||
427 | struct iwm_umac_nonwifi_in_hdr { | ||
428 | struct iwm_udma_in_hdr hw_hdr; | ||
429 | __le32 time_stamp; | ||
430 | } __attribute__ ((packed)); | ||
431 | |||
432 | #define IWM_UMAC_PAGE_SIZE 0x200 | ||
433 | |||
434 | /* Notify structures */ | ||
435 | struct iwm_fw_version { | ||
436 | u8 minor; | ||
437 | u8 major; | ||
438 | __le16 id; | ||
439 | }; | ||
440 | |||
441 | struct iwm_fw_build { | ||
442 | u8 type; | ||
443 | u8 subtype; | ||
444 | u8 platform; | ||
445 | u8 opt; | ||
446 | }; | ||
447 | |||
448 | struct iwm_fw_alive_hdr { | ||
449 | struct iwm_fw_version ver; | ||
450 | struct iwm_fw_build build; | ||
451 | __le32 os_build; | ||
452 | __le32 log_hdr_addr; | ||
453 | __le32 log_buf_addr; | ||
454 | __le32 sys_timer_addr; | ||
455 | }; | ||
456 | |||
457 | #define WAIT_NOTIF_TIMEOUT (2 * HZ) | ||
458 | #define SCAN_COMPLETE_TIMEOUT (3 * HZ) | ||
459 | |||
460 | #define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD | ||
461 | #define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE | ||
462 | |||
463 | #define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD | ||
464 | #define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE | ||
465 | |||
466 | #define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40 | ||
467 | #define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80 | ||
468 | |||
469 | #define IWM_MACS_OUT_GROUPS 6 | ||
470 | #define IWM_MACS_OUT_SGROUPS 1 | ||
471 | |||
472 | |||
473 | #define WIFI_IF_NTFY_ASSOC_START 0x80 | ||
474 | #define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81 | ||
475 | #define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82 | ||
476 | #define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83 | ||
477 | #define WIFI_IF_NTFY_SCAN_COMPLETE 0x84 | ||
478 | #define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85 | ||
479 | #define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86 | ||
480 | #define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87 | ||
481 | #define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88 | ||
482 | #define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89 | ||
483 | #define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A | ||
484 | #define WIFI_IF_NTFY_MGMT_FRAME 0x8B | ||
485 | |||
486 | /* DEBUG INDICATIONS */ | ||
487 | #define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0 | ||
488 | #define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1 | ||
489 | #define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2 | ||
490 | #define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3 | ||
491 | #define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4 | ||
492 | #define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5 | ||
493 | #define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6 | ||
494 | #define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7 | ||
495 | #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 | ||
496 | #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 | ||
497 | |||
498 | /* Notification structures */ | ||
499 | struct iwm_umac_notif_wifi_if { | ||
500 | struct iwm_umac_wifi_in_hdr hdr; | ||
501 | u8 status; | ||
502 | u8 flags; | ||
503 | __le16 buf_size; | ||
504 | } __attribute__ ((packed)); | ||
505 | |||
506 | #define UMAC_ROAM_REASON_FIRST_SELECTION 0x1 | ||
507 | #define UMAC_ROAM_REASON_AP_DEAUTH 0x2 | ||
508 | #define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3 | ||
509 | #define UMAC_ROAM_REASON_RSSI 0x4 | ||
510 | #define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5 | ||
511 | #define UMAC_ROAM_REASON_IBSS_COALESCING 0x6 | ||
512 | |||
513 | struct iwm_umac_notif_assoc_start { | ||
514 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
515 | __le32 roam_reason; | ||
516 | u8 bssid[ETH_ALEN]; | ||
517 | u8 reserved[2]; | ||
518 | } __attribute__ ((packed)); | ||
519 | |||
520 | #define UMAC_ASSOC_COMPLETE_SUCCESS 0x0 | ||
521 | #define UMAC_ASSOC_COMPLETE_FAILURE 0x1 | ||
522 | |||
523 | struct iwm_umac_notif_assoc_complete { | ||
524 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
525 | __le32 status; | ||
526 | u8 bssid[ETH_ALEN]; | ||
527 | u8 band; | ||
528 | u8 channel; | ||
529 | } __attribute__ ((packed)); | ||
530 | |||
531 | #define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0 | ||
532 | #define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1 | ||
533 | #define UMAC_PROFILE_INVALID_REQUEST 0x2 | ||
534 | #define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3 | ||
535 | |||
536 | struct iwm_umac_notif_profile_invalidate { | ||
537 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
538 | __le32 reason; | ||
539 | } __attribute__ ((packed)); | ||
540 | |||
541 | #define UMAC_SCAN_RESULT_SUCCESS 0x0 | ||
542 | #define UMAC_SCAN_RESULT_ABORTED 0x1 | ||
543 | #define UMAC_SCAN_RESULT_REJECTED 0x2 | ||
544 | #define UMAC_SCAN_RESULT_FAILED 0x3 | ||
545 | |||
546 | struct iwm_umac_notif_scan_complete { | ||
547 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
548 | __le32 type; | ||
549 | __le32 result; | ||
550 | u8 seq_num; | ||
551 | } __attribute__ ((packed)); | ||
552 | |||
553 | #define UMAC_OPCODE_ADD_MODIFY 0x0 | ||
554 | #define UMAC_OPCODE_REMOVE 0x1 | ||
555 | #define UMAC_OPCODE_CLEAR_ALL 0x2 | ||
556 | |||
557 | #define UMAC_STA_FLAG_QOS 0x1 | ||
558 | |||
559 | struct iwm_umac_notif_sta_info { | ||
560 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
561 | __le32 opcode; | ||
562 | u8 mac_addr[ETH_ALEN]; | ||
563 | u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */ | ||
564 | u8 flags; | ||
565 | } __attribute__ ((packed)); | ||
566 | |||
567 | #define UMAC_BAND_2GHZ 0 | ||
568 | #define UMAC_BAND_5GHZ 1 | ||
569 | |||
570 | #define UMAC_CHANNEL_WIDTH_20MHZ 0 | ||
571 | #define UMAC_CHANNEL_WIDTH_40MHZ 1 | ||
572 | |||
573 | struct iwm_umac_notif_bss_info { | ||
574 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
575 | __le32 type; | ||
576 | __le32 timestamp; | ||
577 | __le16 table_idx; | ||
578 | __le16 frame_len; | ||
579 | u8 band; | ||
580 | u8 channel; | ||
581 | s8 rssi; | ||
582 | u8 reserved; | ||
583 | u8 frame_buf[1]; | ||
584 | } __attribute__ ((packed)); | ||
585 | |||
586 | #define IWM_BSS_REMOVE_INDEX_MSK 0x0fff | ||
587 | #define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00 | ||
588 | |||
589 | #define IWM_BSS_REMOVE_FLG_AGE 0x1000 | ||
590 | #define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000 | ||
591 | #define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000 | ||
592 | |||
593 | struct iwm_umac_notif_bss_removed { | ||
594 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
595 | __le32 count; | ||
596 | __le16 entries[0]; | ||
597 | } __attribute__ ((packed)); | ||
598 | |||
599 | struct iwm_umac_notif_mgt_frame { | ||
600 | struct iwm_umac_notif_wifi_if mlme_hdr; | ||
601 | __le16 len; | ||
602 | u8 frame[1]; | ||
603 | } __attribute__ ((packed)); | ||
604 | |||
605 | struct iwm_umac_notif_alive { | ||
606 | struct iwm_umac_wifi_in_hdr hdr; | ||
607 | __le16 status; | ||
608 | __le16 reserved1; | ||
609 | struct iwm_fw_alive_hdr alive_data; | ||
610 | __le16 reserved2; | ||
611 | __le16 page_grp_count; | ||
612 | __le32 page_grp_state[IWM_MACS_OUT_GROUPS]; | ||
613 | } __attribute__ ((packed)); | ||
614 | |||
615 | struct iwm_umac_notif_init_complete { | ||
616 | __le16 status; | ||
617 | __le16 reserved; | ||
618 | } __attribute__ ((packed)); | ||
619 | |||
620 | /* error categories */ | ||
621 | enum { | ||
622 | UMAC_SYS_ERR_CAT_NONE = 0, | ||
623 | UMAC_SYS_ERR_CAT_BOOT, | ||
624 | UMAC_SYS_ERR_CAT_UMAC, | ||
625 | UMAC_SYS_ERR_CAT_UAXM, | ||
626 | UMAC_SYS_ERR_CAT_LMAC, | ||
627 | UMAC_SYS_ERR_CAT_MAX | ||
628 | }; | ||
629 | |||
630 | struct iwm_fw_error_hdr { | ||
631 | __le32 category; | ||
632 | __le32 status; | ||
633 | __le32 pc; | ||
634 | __le32 blink1; | ||
635 | __le32 blink2; | ||
636 | __le32 ilink1; | ||
637 | __le32 ilink2; | ||
638 | __le32 data1; | ||
639 | __le32 data2; | ||
640 | __le32 line_num; | ||
641 | __le32 umac_status; | ||
642 | __le32 lmac_status; | ||
643 | __le32 sdio_status; | ||
644 | } __attribute__ ((packed)); | ||
645 | |||
646 | struct iwm_umac_notif_error { | ||
647 | struct iwm_umac_wifi_in_hdr hdr; | ||
648 | struct iwm_fw_error_hdr err; | ||
649 | } __attribute__ ((packed)); | ||
650 | |||
651 | #define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0 | ||
652 | #define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff | ||
653 | #define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8 | ||
654 | #define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff | ||
655 | #define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0 | ||
656 | #define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff | ||
657 | #define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24 | ||
658 | #define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf | ||
659 | |||
660 | struct iwm_umac_notif_page_dealloc { | ||
661 | struct iwm_umac_wifi_in_hdr hdr; | ||
662 | __le32 changes; | ||
663 | __le32 grp_info[IWM_MACS_OUT_GROUPS]; | ||
664 | } __attribute__ ((packed)); | ||
665 | |||
666 | struct iwm_umac_notif_wifi_status { | ||
667 | struct iwm_umac_wifi_in_hdr hdr; | ||
668 | __le16 status; | ||
669 | __le16 reserved; | ||
670 | } __attribute__ ((packed)); | ||
671 | |||
672 | struct iwm_umac_notif_rx_ticket { | ||
673 | struct iwm_umac_wifi_in_hdr hdr; | ||
674 | u8 num_tickets; | ||
675 | u8 reserved[3]; | ||
676 | struct iwm_rx_ticket tickets[1]; | ||
677 | } __attribute__ ((packed)); | ||
678 | |||
679 | /* Tx/Rx rates window (number of max of last update window per second) */ | ||
680 | #define UMAC_NTF_RATE_SAMPLE_NR 4 | ||
681 | |||
682 | #define IWM_UMAC_MGMT_TID 8 | ||
683 | #define IWM_UMAC_TID_NR 8 | ||
684 | |||
685 | struct iwm_umac_notif_stats { | ||
686 | struct iwm_umac_wifi_in_hdr hdr; | ||
687 | __le32 flags; | ||
688 | __le32 timestamp; | ||
689 | __le16 tid_load[IWM_UMAC_TID_NR + 2]; /* 1 non-QoS + 1 dword align */ | ||
690 | __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; | ||
691 | __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; | ||
692 | s32 rssi_dbm; | ||
693 | s32 noise_dbm; | ||
694 | __le32 supp_rates; | ||
695 | __le32 missed_beacons; | ||
696 | __le32 rx_beacons; | ||
697 | __le32 rx_dir_pkts; | ||
698 | __le32 rx_nondir_pkts; | ||
699 | __le32 rx_multicast; | ||
700 | __le32 rx_errors; | ||
701 | __le32 rx_drop_other_bssid; | ||
702 | __le32 rx_drop_decode; | ||
703 | __le32 rx_drop_reassembly; | ||
704 | __le32 rx_drop_bad_len; | ||
705 | __le32 rx_drop_overflow; | ||
706 | __le32 rx_drop_crc; | ||
707 | __le32 rx_drop_missed; | ||
708 | __le32 tx_dir_pkts; | ||
709 | __le32 tx_nondir_pkts; | ||
710 | __le32 tx_failure; | ||
711 | __le32 tx_errors; | ||
712 | __le32 tx_drop_max_retry; | ||
713 | __le32 tx_err_abort; | ||
714 | __le32 tx_err_carrier; | ||
715 | __le32 rx_bytes; | ||
716 | __le32 tx_bytes; | ||
717 | __le32 tx_power; | ||
718 | __le32 tx_max_power; | ||
719 | __le32 roam_threshold; | ||
720 | __le32 ap_assoc_nr; | ||
721 | __le32 scan_full; | ||
722 | __le32 scan_abort; | ||
723 | __le32 ap_nr; | ||
724 | __le32 roam_nr; | ||
725 | __le32 roam_missed_beacons; | ||
726 | __le32 roam_rssi; | ||
727 | __le32 roam_unassoc; | ||
728 | __le32 roam_deauth; | ||
729 | __le32 roam_ap_loadblance; | ||
730 | } __attribute__ ((packed)); | ||
731 | |||
732 | /* WiFi interface wrapper header */ | ||
733 | struct iwm_umac_wifi_if { | ||
734 | u8 oid; | ||
735 | u8 flags; | ||
736 | __le16 buf_size; | ||
737 | } __attribute__ ((packed)); | ||
738 | |||
739 | #define IWM_SEQ_NUM_HOST_MSK 0x0000 | ||
740 | #define IWM_SEQ_NUM_UMAC_MSK 0x4000 | ||
741 | #define IWM_SEQ_NUM_LMAC_MSK 0x8000 | ||
742 | #define IWM_SEQ_NUM_MSK 0xC000 | ||
743 | |||
744 | #endif | ||
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c new file mode 100644 index 000000000000..584c94d0f399 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/wext.c | |||
@@ -0,0 +1,723 @@ | |||
1 | /* | ||
2 | * Intel Wireless Multicomm 3200 WiFi driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> | ||
5 | * Samuel Ortiz <samuel.ortiz@intel.com> | ||
6 | * Zhu Yi <yi.zhu@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/wireless.h> | ||
27 | #include <linux/if_arp.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <net/cfg80211.h> | ||
30 | #include <net/iw_handler.h> | ||
31 | |||
32 | #include "iwm.h" | ||
33 | #include "umac.h" | ||
34 | #include "commands.h" | ||
35 | #include "debug.h" | ||
36 | |||
37 | static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) | ||
38 | { | ||
39 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
40 | struct iw_statistics *wstats = &iwm->wstats; | ||
41 | |||
42 | if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
43 | memset(wstats, 0, sizeof(struct iw_statistics)); | ||
44 | wstats->qual.updated = IW_QUAL_ALL_INVALID; | ||
45 | } | ||
46 | |||
47 | return wstats; | ||
48 | } | ||
49 | |||
50 | static int iwm_wext_siwfreq(struct net_device *dev, | ||
51 | struct iw_request_info *info, | ||
52 | struct iw_freq *freq, char *extra) | ||
53 | { | ||
54 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
55 | |||
56 | if (freq->flags == IW_FREQ_AUTO) | ||
57 | return 0; | ||
58 | |||
59 | /* frequency/channel can only be set in IBSS mode */ | ||
60 | if (iwm->conf.mode != UMAC_MODE_IBSS) | ||
61 | return -EOPNOTSUPP; | ||
62 | |||
63 | return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); | ||
64 | } | ||
65 | |||
66 | static int iwm_wext_giwfreq(struct net_device *dev, | ||
67 | struct iw_request_info *info, | ||
68 | struct iw_freq *freq, char *extra) | ||
69 | { | ||
70 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
71 | |||
72 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
73 | return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); | ||
74 | |||
75 | freq->e = 0; | ||
76 | freq->m = iwm->channel; | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, | ||
82 | struct sockaddr *ap_addr, char *extra) | ||
83 | { | ||
84 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
85 | |||
86 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
87 | return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); | ||
88 | |||
89 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
90 | return -EIO; | ||
91 | |||
92 | if (is_zero_ether_addr(ap_addr->sa_data) || | ||
93 | is_broadcast_ether_addr(ap_addr->sa_data)) { | ||
94 | IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", | ||
95 | iwm->umac_profile->bssid[0]); | ||
96 | memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); | ||
97 | iwm->umac_profile->bss_num = 0; | ||
98 | } else { | ||
99 | IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", | ||
100 | ap_addr->sa_data); | ||
101 | memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, | ||
102 | ETH_ALEN); | ||
103 | iwm->umac_profile->bss_num = 1; | ||
104 | } | ||
105 | |||
106 | if (iwm->umac_profile_active) { | ||
107 | if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) | ||
108 | return 0; | ||
109 | |||
110 | iwm_invalidate_mlme_profile(iwm); | ||
111 | } | ||
112 | |||
113 | if (iwm->umac_profile->ssid.ssid_len) | ||
114 | return iwm_send_mlme_profile(iwm); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, | ||
120 | struct sockaddr *ap_addr, char *extra) | ||
121 | { | ||
122 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
123 | |||
124 | switch (iwm->conf.mode) { | ||
125 | case UMAC_MODE_IBSS: | ||
126 | return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); | ||
127 | case UMAC_MODE_BSS: | ||
128 | if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { | ||
129 | ap_addr->sa_family = ARPHRD_ETHER; | ||
130 | memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); | ||
131 | } else | ||
132 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | ||
133 | break; | ||
134 | default: | ||
135 | return -EOPNOTSUPP; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int iwm_wext_siwessid(struct net_device *dev, | ||
142 | struct iw_request_info *info, | ||
143 | struct iw_point *data, char *ssid) | ||
144 | { | ||
145 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
146 | size_t len = data->length; | ||
147 | int ret; | ||
148 | |||
149 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
150 | return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); | ||
151 | |||
152 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
153 | return -EIO; | ||
154 | |||
155 | if (len > 0 && ssid[len - 1] == '\0') | ||
156 | len--; | ||
157 | |||
158 | if (iwm->umac_profile_active) { | ||
159 | if (iwm->umac_profile->ssid.ssid_len == len && | ||
160 | !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) | ||
161 | return 0; | ||
162 | |||
163 | ret = iwm_invalidate_mlme_profile(iwm); | ||
164 | if (ret < 0) { | ||
165 | IWM_ERR(iwm, "Couldn't invalidate profile\n"); | ||
166 | return ret; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | iwm->umac_profile->ssid.ssid_len = len; | ||
171 | memcpy(iwm->umac_profile->ssid.ssid, ssid, len); | ||
172 | |||
173 | return iwm_send_mlme_profile(iwm); | ||
174 | } | ||
175 | |||
176 | static int iwm_wext_giwessid(struct net_device *dev, | ||
177 | struct iw_request_info *info, | ||
178 | struct iw_point *data, char *ssid) | ||
179 | { | ||
180 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
181 | |||
182 | if (iwm->conf.mode == UMAC_MODE_IBSS) | ||
183 | return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); | ||
184 | |||
185 | if (!test_bit(IWM_STATUS_READY, &iwm->status)) | ||
186 | return -EIO; | ||
187 | |||
188 | data->length = iwm->umac_profile->ssid.ssid_len; | ||
189 | if (data->length) { | ||
190 | memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); | ||
191 | data->flags = 1; | ||
192 | } else | ||
193 | data->flags = 0; | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static struct iwm_key * | ||
199 | iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, | ||
200 | struct iw_encode_ext *ext, u8 alg) | ||
201 | { | ||
202 | struct iwm_key *key = &iwm->keys[key_idx]; | ||
203 | |||
204 | memset(key, 0, sizeof(struct iwm_key)); | ||
205 | memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); | ||
206 | key->hdr.key_idx = key_idx; | ||
207 | if (is_broadcast_ether_addr(ext->addr.sa_data)) | ||
208 | key->hdr.multicast = 1; | ||
209 | |||
210 | key->in_use = in_use; | ||
211 | key->flags = ext->ext_flags; | ||
212 | key->alg = alg; | ||
213 | key->key_len = ext->key_len; | ||
214 | memcpy(key->key, ext->key, ext->key_len); | ||
215 | |||
216 | return key; | ||
217 | } | ||
218 | |||
219 | static int iwm_wext_giwrate(struct net_device *dev, | ||
220 | struct iw_request_info *info, | ||
221 | struct iw_param *rate, char *extra) | ||
222 | { | ||
223 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
224 | |||
225 | rate->value = iwm->rate * 1000000; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int iwm_wext_siwencode(struct net_device *dev, | ||
231 | struct iw_request_info *info, | ||
232 | struct iw_point *erq, char *key_buf) | ||
233 | { | ||
234 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
235 | struct iwm_key *uninitialized_var(key); | ||
236 | int idx, i, uninitialized_var(alg), remove = 0, ret; | ||
237 | |||
238 | IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); | ||
239 | IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); | ||
240 | |||
241 | if (!iwm->umac_profile) { | ||
242 | IWM_ERR(iwm, "UMAC profile not allocated yet\n"); | ||
243 | return -ENODEV; | ||
244 | } | ||
245 | |||
246 | if (erq->length == WLAN_KEY_LEN_WEP40) { | ||
247 | alg = UMAC_CIPHER_TYPE_WEP_40; | ||
248 | iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; | ||
249 | iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; | ||
250 | } else if (erq->length == WLAN_KEY_LEN_WEP104) { | ||
251 | alg = UMAC_CIPHER_TYPE_WEP_104; | ||
252 | iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; | ||
253 | iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; | ||
254 | } | ||
255 | |||
256 | if (erq->flags & IW_ENCODE_RESTRICTED) | ||
257 | iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
258 | else | ||
259 | iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; | ||
260 | |||
261 | idx = erq->flags & IW_ENCODE_INDEX; | ||
262 | if (idx == 0) { | ||
263 | if (iwm->default_key) | ||
264 | for (i = 0; i < IWM_NUM_KEYS; i++) { | ||
265 | if (iwm->default_key == &iwm->keys[i]) { | ||
266 | idx = i; | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | else | ||
271 | iwm->default_key = &iwm->keys[idx]; | ||
272 | } else if (idx < 1 || idx > 4) { | ||
273 | return -EINVAL; | ||
274 | } else | ||
275 | idx--; | ||
276 | |||
277 | if (erq->flags & IW_ENCODE_DISABLED) | ||
278 | remove = 1; | ||
279 | else if (erq->length == 0) { | ||
280 | if (!iwm->keys[idx].in_use) | ||
281 | return -EINVAL; | ||
282 | iwm->default_key = &iwm->keys[idx]; | ||
283 | } | ||
284 | |||
285 | if (erq->length) { | ||
286 | key = &iwm->keys[idx]; | ||
287 | memset(key, 0, sizeof(struct iwm_key)); | ||
288 | memset(key->hdr.mac, 0xff, ETH_ALEN); | ||
289 | key->hdr.key_idx = idx; | ||
290 | key->hdr.multicast = 1; | ||
291 | key->in_use = !remove; | ||
292 | key->alg = alg; | ||
293 | key->key_len = erq->length; | ||
294 | memcpy(key->key, key_buf, erq->length); | ||
295 | |||
296 | IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", | ||
297 | idx, !!iwm->default_key); | ||
298 | } | ||
299 | |||
300 | if (remove) { | ||
301 | if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { | ||
302 | int j; | ||
303 | for (j = 0; j < IWM_NUM_KEYS; j++) | ||
304 | if (iwm->keys[j].in_use) { | ||
305 | struct iwm_key *k = &iwm->keys[j]; | ||
306 | |||
307 | k->in_use = 0; | ||
308 | ret = iwm_set_key(iwm, remove, 0, k); | ||
309 | if (ret < 0) | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | iwm->umac_profile->sec.ucast_cipher = | ||
314 | UMAC_CIPHER_TYPE_NONE; | ||
315 | iwm->umac_profile->sec.mcast_cipher = | ||
316 | UMAC_CIPHER_TYPE_NONE; | ||
317 | iwm->umac_profile->sec.auth_type = | ||
318 | UMAC_AUTH_TYPE_OPEN; | ||
319 | |||
320 | return 0; | ||
321 | } else { | ||
322 | key->in_use = 0; | ||
323 | return iwm_set_key(iwm, remove, 0, key); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * If we havent set a profile yet, we cant set keys. | ||
329 | * Keys will be pushed after we're associated. | ||
330 | */ | ||
331 | if (!iwm->umac_profile_active) | ||
332 | return 0; | ||
333 | |||
334 | /* | ||
335 | * If there is a current active profile, but no | ||
336 | * default key, it's not worth trying to associate again. | ||
337 | */ | ||
338 | if (!iwm->default_key) | ||
339 | return 0; | ||
340 | |||
341 | /* | ||
342 | * Here we have an active profile, but a key setting changed. | ||
343 | * We thus have to invalidate the current profile, and push the | ||
344 | * new one. Keys will be pushed when association takes place. | ||
345 | */ | ||
346 | ret = iwm_invalidate_mlme_profile(iwm); | ||
347 | if (ret < 0) { | ||
348 | IWM_ERR(iwm, "Couldn't invalidate profile\n"); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | return iwm_send_mlme_profile(iwm); | ||
353 | } | ||
354 | |||
355 | static int iwm_wext_giwencode(struct net_device *dev, | ||
356 | struct iw_request_info *info, | ||
357 | struct iw_point *erq, char *key) | ||
358 | { | ||
359 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
360 | int idx, i; | ||
361 | |||
362 | idx = erq->flags & IW_ENCODE_INDEX; | ||
363 | if (idx < 1 || idx > 4) { | ||
364 | idx = -1; | ||
365 | if (!iwm->default_key) { | ||
366 | erq->length = 0; | ||
367 | erq->flags |= IW_ENCODE_NOKEY; | ||
368 | return 0; | ||
369 | } else | ||
370 | for (i = 0; i < IWM_NUM_KEYS; i++) { | ||
371 | if (iwm->default_key == &iwm->keys[i]) { | ||
372 | idx = i; | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | if (idx < 0) | ||
377 | return -EINVAL; | ||
378 | } else | ||
379 | idx--; | ||
380 | |||
381 | erq->flags = idx + 1; | ||
382 | |||
383 | if (!iwm->keys[idx].in_use) { | ||
384 | erq->length = 0; | ||
385 | erq->flags |= IW_ENCODE_DISABLED; | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | memcpy(key, iwm->keys[idx].key, | ||
390 | min_t(int, erq->length, iwm->keys[idx].key_len)); | ||
391 | erq->length = iwm->keys[idx].key_len; | ||
392 | erq->flags |= IW_ENCODE_ENABLED; | ||
393 | |||
394 | if (iwm->umac_profile->mode == UMAC_MODE_BSS) { | ||
395 | switch (iwm->umac_profile->sec.auth_type) { | ||
396 | case UMAC_AUTH_TYPE_OPEN: | ||
397 | erq->flags |= IW_ENCODE_OPEN; | ||
398 | break; | ||
399 | default: | ||
400 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
401 | break; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) | ||
409 | { | ||
410 | if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) | ||
411 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; | ||
412 | else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) | ||
413 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; | ||
414 | else | ||
415 | iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int iwm_wext_siwpower(struct net_device *dev, | ||
421 | struct iw_request_info *info, | ||
422 | struct iw_param *wrq, char *extra) | ||
423 | { | ||
424 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
425 | u32 power_index; | ||
426 | |||
427 | if (wrq->disabled) { | ||
428 | power_index = IWM_POWER_INDEX_MIN; | ||
429 | goto set; | ||
430 | } else | ||
431 | power_index = IWM_POWER_INDEX_DEFAULT; | ||
432 | |||
433 | switch (wrq->flags & IW_POWER_MODE) { | ||
434 | case IW_POWER_ON: | ||
435 | case IW_POWER_MODE: | ||
436 | case IW_POWER_ALL_R: | ||
437 | break; | ||
438 | default: | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | set: | ||
443 | if (power_index == iwm->conf.power_index) | ||
444 | return 0; | ||
445 | |||
446 | iwm->conf.power_index = power_index; | ||
447 | |||
448 | return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, | ||
449 | CFG_POWER_INDEX, iwm->conf.power_index); | ||
450 | } | ||
451 | |||
452 | static int iwm_wext_giwpower(struct net_device *dev, | ||
453 | struct iw_request_info *info, | ||
454 | union iwreq_data *wrqu, char *extra) | ||
455 | { | ||
456 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
457 | |||
458 | wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) | ||
464 | { | ||
465 | u8 *auth_type = &iwm->umac_profile->sec.auth_type; | ||
466 | |||
467 | if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) | ||
468 | *auth_type = UMAC_AUTH_TYPE_8021X; | ||
469 | else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { | ||
470 | if (iwm->umac_profile->sec.flags & | ||
471 | (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) | ||
472 | *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; | ||
473 | else | ||
474 | *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
475 | } else { | ||
476 | IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) | ||
484 | { | ||
485 | u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : | ||
486 | &iwm->umac_profile->sec.mcast_cipher; | ||
487 | |||
488 | switch (cipher) { | ||
489 | case IW_AUTH_CIPHER_NONE: | ||
490 | *profile_cipher = UMAC_CIPHER_TYPE_NONE; | ||
491 | break; | ||
492 | case IW_AUTH_CIPHER_WEP40: | ||
493 | *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; | ||
494 | break; | ||
495 | case IW_AUTH_CIPHER_TKIP: | ||
496 | *profile_cipher = UMAC_CIPHER_TYPE_TKIP; | ||
497 | break; | ||
498 | case IW_AUTH_CIPHER_CCMP: | ||
499 | *profile_cipher = UMAC_CIPHER_TYPE_CCMP; | ||
500 | break; | ||
501 | case IW_AUTH_CIPHER_WEP104: | ||
502 | *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; | ||
503 | break; | ||
504 | default: | ||
505 | IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); | ||
506 | return -ENOTSUPP; | ||
507 | } | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) | ||
513 | { | ||
514 | u8 *auth_type = &iwm->umac_profile->sec.auth_type; | ||
515 | |||
516 | switch (auth_alg) { | ||
517 | case IW_AUTH_ALG_OPEN_SYSTEM: | ||
518 | *auth_type = UMAC_AUTH_TYPE_OPEN; | ||
519 | break; | ||
520 | case IW_AUTH_ALG_SHARED_KEY: | ||
521 | if (iwm->umac_profile->sec.flags & | ||
522 | (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { | ||
523 | if (*auth_type == UMAC_AUTH_TYPE_8021X) | ||
524 | return -EINVAL; | ||
525 | *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; | ||
526 | } else { | ||
527 | *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; | ||
528 | } | ||
529 | break; | ||
530 | case IW_AUTH_ALG_LEAP: | ||
531 | default: | ||
532 | IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); | ||
533 | return -ENOTSUPP; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int iwm_wext_siwauth(struct net_device *dev, | ||
540 | struct iw_request_info *info, | ||
541 | struct iw_param *data, char *extra) | ||
542 | { | ||
543 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
544 | int ret; | ||
545 | |||
546 | if ((data->flags) & | ||
547 | (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | | ||
548 | IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { | ||
549 | /* We need to invalidate the current profile */ | ||
550 | if (iwm->umac_profile_active) { | ||
551 | ret = iwm_invalidate_mlme_profile(iwm); | ||
552 | if (ret < 0) { | ||
553 | IWM_ERR(iwm, "Couldn't invalidate profile\n"); | ||
554 | return ret; | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | |||
559 | switch (data->flags & IW_AUTH_INDEX) { | ||
560 | case IW_AUTH_WPA_VERSION: | ||
561 | return iwm_set_wpa_version(iwm, data->value); | ||
562 | break; | ||
563 | case IW_AUTH_CIPHER_PAIRWISE: | ||
564 | return iwm_set_cipher(iwm, data->value, 1); | ||
565 | break; | ||
566 | case IW_AUTH_CIPHER_GROUP: | ||
567 | return iwm_set_cipher(iwm, data->value, 0); | ||
568 | break; | ||
569 | case IW_AUTH_KEY_MGMT: | ||
570 | return iwm_set_key_mgt(iwm, data->value); | ||
571 | break; | ||
572 | case IW_AUTH_80211_AUTH_ALG: | ||
573 | return iwm_set_auth_alg(iwm, data->value); | ||
574 | break; | ||
575 | default: | ||
576 | return -ENOTSUPP; | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int iwm_wext_giwauth(struct net_device *dev, | ||
583 | struct iw_request_info *info, | ||
584 | struct iw_param *data, char *extra) | ||
585 | { | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int iwm_wext_siwencodeext(struct net_device *dev, | ||
590 | struct iw_request_info *info, | ||
591 | struct iw_point *erq, char *extra) | ||
592 | { | ||
593 | struct iwm_priv *iwm = ndev_to_iwm(dev); | ||
594 | struct iwm_key *key; | ||
595 | struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; | ||
596 | int uninitialized_var(alg), idx, i, remove = 0; | ||
597 | |||
598 | IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); | ||
599 | IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); | ||
600 | IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); | ||
601 | IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); | ||
602 | IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); | ||
603 | |||
604 | switch (ext->alg) { | ||
605 | case IW_ENCODE_ALG_NONE: | ||
606 | remove = 1; | ||
607 | break; | ||
608 | case IW_ENCODE_ALG_WEP: | ||
609 | if (ext->key_len == WLAN_KEY_LEN_WEP40) | ||
610 | alg = UMAC_CIPHER_TYPE_WEP_40; | ||
611 | else if (ext->key_len == WLAN_KEY_LEN_WEP104) | ||
612 | alg = UMAC_CIPHER_TYPE_WEP_104; | ||
613 | else { | ||
614 | IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); | ||
615 | return -EINVAL; | ||
616 | } | ||
617 | |||
618 | break; | ||
619 | case IW_ENCODE_ALG_TKIP: | ||
620 | alg = UMAC_CIPHER_TYPE_TKIP; | ||
621 | break; | ||
622 | case IW_ENCODE_ALG_CCMP: | ||
623 | alg = UMAC_CIPHER_TYPE_CCMP; | ||
624 | break; | ||
625 | default: | ||
626 | return -EOPNOTSUPP; | ||
627 | } | ||
628 | |||
629 | idx = erq->flags & IW_ENCODE_INDEX; | ||
630 | |||
631 | if (idx == 0) { | ||
632 | if (iwm->default_key) | ||
633 | for (i = 0; i < IWM_NUM_KEYS; i++) { | ||
634 | if (iwm->default_key == &iwm->keys[i]) { | ||
635 | idx = i; | ||
636 | break; | ||
637 | } | ||
638 | } | ||
639 | } else if (idx < 1 || idx > 4) { | ||
640 | return -EINVAL; | ||
641 | } else | ||
642 | idx--; | ||
643 | |||
644 | if (erq->flags & IW_ENCODE_DISABLED) | ||
645 | remove = 1; | ||
646 | else if ((erq->length == 0) || | ||
647 | (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { | ||
648 | iwm->default_key = &iwm->keys[idx]; | ||
649 | if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) | ||
650 | return iwm_set_tx_key(iwm, idx); | ||
651 | } | ||
652 | |||
653 | key = iwm_key_init(iwm, idx, !remove, ext, alg); | ||
654 | |||
655 | return iwm_set_key(iwm, remove, !iwm->default_key, key); | ||
656 | } | ||
657 | |||
658 | static const iw_handler iwm_handlers[] = | ||
659 | { | ||
660 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
661 | (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ | ||
662 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
663 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
664 | (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ | ||
665 | (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ | ||
666 | (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ | ||
667 | (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ | ||
668 | (iw_handler) NULL, /* SIOCSIWSENS */ | ||
669 | (iw_handler) NULL, /* SIOCGIWSENS */ | ||
670 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | ||
671 | (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ | ||
672 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | ||
673 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | ||
674 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | ||
675 | (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ | ||
676 | (iw_handler) NULL, /* SIOCSIWSPY */ | ||
677 | (iw_handler) NULL, /* SIOCGIWSPY */ | ||
678 | (iw_handler) NULL, /* SIOCSIWTHRSPY */ | ||
679 | (iw_handler) NULL, /* SIOCGIWTHRSPY */ | ||
680 | (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ | ||
681 | (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ | ||
682 | (iw_handler) NULL, /* SIOCSIWMLME */ | ||
683 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | ||
684 | (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ | ||
685 | (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ | ||
686 | (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ | ||
687 | (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ | ||
688 | (iw_handler) NULL, /* SIOCSIWNICKN */ | ||
689 | (iw_handler) NULL, /* SIOCGIWNICKN */ | ||
690 | (iw_handler) NULL, /* -- hole -- */ | ||
691 | (iw_handler) NULL, /* -- hole -- */ | ||
692 | (iw_handler) NULL, /* SIOCSIWRATE */ | ||
693 | (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ | ||
694 | (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ | ||
695 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ | ||
696 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ | ||
697 | (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ | ||
698 | (iw_handler) NULL, /* SIOCSIWTXPOW */ | ||
699 | (iw_handler) NULL, /* SIOCGIWTXPOW */ | ||
700 | (iw_handler) NULL, /* SIOCSIWRETRY */ | ||
701 | (iw_handler) NULL, /* SIOCGIWRETRY */ | ||
702 | (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ | ||
703 | (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ | ||
704 | (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ | ||
705 | (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ | ||
706 | (iw_handler) NULL, /* -- hole -- */ | ||
707 | (iw_handler) NULL, /* -- hole -- */ | ||
708 | (iw_handler) NULL, /* SIOCSIWGENIE */ | ||
709 | (iw_handler) NULL, /* SIOCGIWGENIE */ | ||
710 | (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ | ||
711 | (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ | ||
712 | (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ | ||
713 | (iw_handler) NULL, /* SIOCGIWENCODEEXT */ | ||
714 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
715 | (iw_handler) NULL, /* -- hole -- */ | ||
716 | }; | ||
717 | |||
718 | const struct iw_handler_def iwm_iw_handler_def = { | ||
719 | .num_standard = ARRAY_SIZE(iwm_handlers), | ||
720 | .standard = (iw_handler *) iwm_handlers, | ||
721 | .get_wireless_stats = iwm_get_wireless_stats, | ||
722 | }; | ||
723 | |||
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index cbaafa653b6a..a4455ec7c354 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -321,6 +321,8 @@ struct lbs_private { | |||
321 | 321 | ||
322 | u32 monitormode; | 322 | u32 monitormode; |
323 | u8 fw_ready; | 323 | u8 fw_ready; |
324 | u8 fn_init_required; | ||
325 | u8 fn_shutdown_required; | ||
324 | }; | 326 | }; |
325 | 327 | ||
326 | extern struct cmd_confirm_sleep confirm_sleep; | 328 | extern struct cmd_confirm_sleep confirm_sleep; |
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 8ff8ac9d817e..fe8f0cb737bc 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -86,6 +86,8 @@ | |||
86 | #define CMD_MESH_CONFIG_OLD 0x00a3 | 86 | #define CMD_MESH_CONFIG_OLD 0x00a3 |
87 | #define CMD_MESH_CONFIG 0x00ac | 87 | #define CMD_MESH_CONFIG 0x00ac |
88 | #define CMD_SET_BOOT2_VER 0x00a5 | 88 | #define CMD_SET_BOOT2_VER 0x00a5 |
89 | #define CMD_FUNC_INIT 0x00a9 | ||
90 | #define CMD_FUNC_SHUTDOWN 0x00aa | ||
89 | #define CMD_802_11_BEACON_CTRL 0x00b0 | 91 | #define CMD_802_11_BEACON_CTRL 0x00b0 |
90 | 92 | ||
91 | /* For the IEEE Power Save */ | 93 | /* For the IEEE Power Save */ |
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 55864c10f9f1..a7e3fc119b70 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -61,26 +61,30 @@ struct if_sdio_model { | |||
61 | int model; | 61 | int model; |
62 | const char *helper; | 62 | const char *helper; |
63 | const char *firmware; | 63 | const char *firmware; |
64 | struct if_sdio_card *card; | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | static struct if_sdio_model if_sdio_models[] = { | 67 | static struct if_sdio_model if_sdio_models[] = { |
67 | { | 68 | { |
68 | /* 8385 */ | 69 | /* 8385 */ |
69 | .model = 0x04, | 70 | .model = IF_SDIO_MODEL_8385, |
70 | .helper = "sd8385_helper.bin", | 71 | .helper = "sd8385_helper.bin", |
71 | .firmware = "sd8385.bin", | 72 | .firmware = "sd8385.bin", |
73 | .card = NULL, | ||
72 | }, | 74 | }, |
73 | { | 75 | { |
74 | /* 8686 */ | 76 | /* 8686 */ |
75 | .model = 0x0B, | 77 | .model = IF_SDIO_MODEL_8686, |
76 | .helper = "sd8686_helper.bin", | 78 | .helper = "sd8686_helper.bin", |
77 | .firmware = "sd8686.bin", | 79 | .firmware = "sd8686.bin", |
80 | .card = NULL, | ||
78 | }, | 81 | }, |
79 | { | 82 | { |
80 | /* 8688 */ | 83 | /* 8688 */ |
81 | .model = 0x10, | 84 | .model = IF_SDIO_MODEL_8688, |
82 | .helper = "sd8688_helper.bin", | 85 | .helper = "sd8688_helper.bin", |
83 | .firmware = "sd8688.bin", | 86 | .firmware = "sd8688.bin", |
87 | .card = NULL, | ||
84 | }, | 88 | }, |
85 | }; | 89 | }; |
86 | 90 | ||
@@ -96,6 +100,7 @@ struct if_sdio_card { | |||
96 | 100 | ||
97 | int model; | 101 | int model; |
98 | unsigned long ioport; | 102 | unsigned long ioport; |
103 | unsigned int scratch_reg; | ||
99 | 104 | ||
100 | const char *helper; | 105 | const char *helper; |
101 | const char *firmware; | 106 | const char *firmware; |
@@ -107,25 +112,29 @@ struct if_sdio_card { | |||
107 | 112 | ||
108 | struct workqueue_struct *workqueue; | 113 | struct workqueue_struct *workqueue; |
109 | struct work_struct packet_worker; | 114 | struct work_struct packet_worker; |
115 | |||
116 | u8 rx_unit; | ||
110 | }; | 117 | }; |
111 | 118 | ||
112 | /********************************************************************/ | 119 | /********************************************************************/ |
113 | /* I/O */ | 120 | /* I/O */ |
114 | /********************************************************************/ | 121 | /********************************************************************/ |
115 | 122 | ||
123 | /* | ||
124 | * For SD8385/SD8686, this function reads firmware status after | ||
125 | * the image is downloaded, or reads RX packet length when | ||
126 | * interrupt (with IF_SDIO_H_INT_UPLD bit set) is received. | ||
127 | * For SD8688, this function reads firmware status only. | ||
128 | */ | ||
116 | static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) | 129 | static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) |
117 | { | 130 | { |
118 | int ret, reg; | 131 | int ret; |
119 | u16 scratch; | 132 | u16 scratch; |
120 | 133 | ||
121 | if (card->model == 0x04) | 134 | scratch = sdio_readb(card->func, card->scratch_reg, &ret); |
122 | reg = IF_SDIO_SCRATCH_OLD; | ||
123 | else | ||
124 | reg = IF_SDIO_SCRATCH; | ||
125 | |||
126 | scratch = sdio_readb(card->func, reg, &ret); | ||
127 | if (!ret) | 135 | if (!ret) |
128 | scratch |= sdio_readb(card->func, reg + 1, &ret) << 8; | 136 | scratch |= sdio_readb(card->func, card->scratch_reg + 1, |
137 | &ret) << 8; | ||
129 | 138 | ||
130 | if (err) | 139 | if (err) |
131 | *err = ret; | 140 | *err = ret; |
@@ -136,6 +145,46 @@ static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err) | |||
136 | return scratch; | 145 | return scratch; |
137 | } | 146 | } |
138 | 147 | ||
148 | static u8 if_sdio_read_rx_unit(struct if_sdio_card *card) | ||
149 | { | ||
150 | int ret; | ||
151 | u8 rx_unit; | ||
152 | |||
153 | rx_unit = sdio_readb(card->func, IF_SDIO_RX_UNIT, &ret); | ||
154 | |||
155 | if (ret) | ||
156 | rx_unit = 0; | ||
157 | |||
158 | return rx_unit; | ||
159 | } | ||
160 | |||
161 | static u16 if_sdio_read_rx_len(struct if_sdio_card *card, int *err) | ||
162 | { | ||
163 | int ret; | ||
164 | u16 rx_len; | ||
165 | |||
166 | switch (card->model) { | ||
167 | case IF_SDIO_MODEL_8385: | ||
168 | case IF_SDIO_MODEL_8686: | ||
169 | rx_len = if_sdio_read_scratch(card, &ret); | ||
170 | break; | ||
171 | case IF_SDIO_MODEL_8688: | ||
172 | default: /* for newer chipsets */ | ||
173 | rx_len = sdio_readb(card->func, IF_SDIO_RX_LEN, &ret); | ||
174 | if (!ret) | ||
175 | rx_len <<= card->rx_unit; | ||
176 | else | ||
177 | rx_len = 0xffff; /* invalid length */ | ||
178 | |||
179 | break; | ||
180 | } | ||
181 | |||
182 | if (err) | ||
183 | *err = ret; | ||
184 | |||
185 | return rx_len; | ||
186 | } | ||
187 | |||
139 | static int if_sdio_handle_cmd(struct if_sdio_card *card, | 188 | static int if_sdio_handle_cmd(struct if_sdio_card *card, |
140 | u8 *buffer, unsigned size) | 189 | u8 *buffer, unsigned size) |
141 | { | 190 | { |
@@ -216,7 +265,7 @@ static int if_sdio_handle_event(struct if_sdio_card *card, | |||
216 | 265 | ||
217 | lbs_deb_enter(LBS_DEB_SDIO); | 266 | lbs_deb_enter(LBS_DEB_SDIO); |
218 | 267 | ||
219 | if (card->model == 0x04) { | 268 | if (card->model == IF_SDIO_MODEL_8385) { |
220 | event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); | 269 | event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); |
221 | if (ret) | 270 | if (ret) |
222 | goto out; | 271 | goto out; |
@@ -254,7 +303,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card) | |||
254 | 303 | ||
255 | lbs_deb_enter(LBS_DEB_SDIO); | 304 | lbs_deb_enter(LBS_DEB_SDIO); |
256 | 305 | ||
257 | size = if_sdio_read_scratch(card, &ret); | 306 | size = if_sdio_read_rx_len(card, &ret); |
258 | if (ret) | 307 | if (ret) |
259 | goto out; | 308 | goto out; |
260 | 309 | ||
@@ -497,7 +546,6 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) | |||
497 | ret = 0; | 546 | ret = 0; |
498 | 547 | ||
499 | release: | 548 | release: |
500 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | ||
501 | sdio_release_host(card->func); | 549 | sdio_release_host(card->func); |
502 | kfree(chunk_buffer); | 550 | kfree(chunk_buffer); |
503 | release_fw: | 551 | release_fw: |
@@ -633,7 +681,6 @@ static int if_sdio_prog_real(struct if_sdio_card *card) | |||
633 | ret = 0; | 681 | ret = 0; |
634 | 682 | ||
635 | release: | 683 | release: |
636 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | ||
637 | sdio_release_host(card->func); | 684 | sdio_release_host(card->func); |
638 | kfree(chunk_buffer); | 685 | kfree(chunk_buffer); |
639 | release_fw: | 686 | release_fw: |
@@ -662,6 +709,8 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) | |||
662 | if (ret) | 709 | if (ret) |
663 | goto out; | 710 | goto out; |
664 | 711 | ||
712 | lbs_deb_sdio("firmware status = %#x\n", scratch); | ||
713 | |||
665 | if (scratch == IF_SDIO_FIRMWARE_OK) { | 714 | if (scratch == IF_SDIO_FIRMWARE_OK) { |
666 | lbs_deb_sdio("firmware already loaded\n"); | 715 | lbs_deb_sdio("firmware already loaded\n"); |
667 | goto success; | 716 | goto success; |
@@ -676,6 +725,9 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card) | |||
676 | goto out; | 725 | goto out; |
677 | 726 | ||
678 | success: | 727 | success: |
728 | sdio_claim_host(card->func); | ||
729 | sdio_set_block_size(card->func, IF_SDIO_BLOCK_SIZE); | ||
730 | sdio_release_host(card->func); | ||
679 | ret = 0; | 731 | ret = 0; |
680 | 732 | ||
681 | out: | 733 | out: |
@@ -829,10 +881,10 @@ static int if_sdio_probe(struct sdio_func *func, | |||
829 | if (sscanf(func->card->info[i], | 881 | if (sscanf(func->card->info[i], |
830 | "ID: %x", &model) == 1) | 882 | "ID: %x", &model) == 1) |
831 | break; | 883 | break; |
832 | if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { | 884 | if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { |
833 | model = 4; | 885 | model = IF_SDIO_MODEL_8385; |
834 | break; | 886 | break; |
835 | } | 887 | } |
836 | } | 888 | } |
837 | 889 | ||
838 | if (i == func->card->num_info) { | 890 | if (i == func->card->num_info) { |
@@ -846,6 +898,20 @@ static int if_sdio_probe(struct sdio_func *func, | |||
846 | 898 | ||
847 | card->func = func; | 899 | card->func = func; |
848 | card->model = model; | 900 | card->model = model; |
901 | |||
902 | switch (card->model) { | ||
903 | case IF_SDIO_MODEL_8385: | ||
904 | card->scratch_reg = IF_SDIO_SCRATCH_OLD; | ||
905 | break; | ||
906 | case IF_SDIO_MODEL_8686: | ||
907 | card->scratch_reg = IF_SDIO_SCRATCH; | ||
908 | break; | ||
909 | case IF_SDIO_MODEL_8688: | ||
910 | default: /* for newer chipsets */ | ||
911 | card->scratch_reg = IF_SDIO_FW_STATUS; | ||
912 | break; | ||
913 | } | ||
914 | |||
849 | spin_lock_init(&card->lock); | 915 | spin_lock_init(&card->lock); |
850 | card->workqueue = create_workqueue("libertas_sdio"); | 916 | card->workqueue = create_workqueue("libertas_sdio"); |
851 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); | 917 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); |
@@ -861,6 +927,8 @@ static int if_sdio_probe(struct sdio_func *func, | |||
861 | goto free; | 927 | goto free; |
862 | } | 928 | } |
863 | 929 | ||
930 | if_sdio_models[i].card = card; | ||
931 | |||
864 | card->helper = if_sdio_models[i].helper; | 932 | card->helper = if_sdio_models[i].helper; |
865 | card->firmware = if_sdio_models[i].firmware; | 933 | card->firmware = if_sdio_models[i].firmware; |
866 | 934 | ||
@@ -923,15 +991,32 @@ static int if_sdio_probe(struct sdio_func *func, | |||
923 | 991 | ||
924 | priv->fw_ready = 1; | 992 | priv->fw_ready = 1; |
925 | 993 | ||
994 | sdio_claim_host(func); | ||
995 | |||
996 | /* | ||
997 | * Get rx_unit if the chip is SD8688 or newer. | ||
998 | * SD8385 & SD8686 do not have rx_unit. | ||
999 | */ | ||
1000 | if ((card->model != IF_SDIO_MODEL_8385) | ||
1001 | && (card->model != IF_SDIO_MODEL_8686)) | ||
1002 | card->rx_unit = if_sdio_read_rx_unit(card); | ||
1003 | else | ||
1004 | card->rx_unit = 0; | ||
1005 | |||
926 | /* | 1006 | /* |
927 | * Enable interrupts now that everything is set up | 1007 | * Enable interrupts now that everything is set up |
928 | */ | 1008 | */ |
929 | sdio_claim_host(func); | ||
930 | sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); | 1009 | sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); |
931 | sdio_release_host(func); | 1010 | sdio_release_host(func); |
932 | if (ret) | 1011 | if (ret) |
933 | goto reclaim; | 1012 | goto reclaim; |
934 | 1013 | ||
1014 | /* | ||
1015 | * FUNC_INIT is required for SD8688 WLAN/BT multiple functions | ||
1016 | */ | ||
1017 | priv->fn_init_required = | ||
1018 | (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; | ||
1019 | |||
935 | ret = lbs_start_card(priv); | 1020 | ret = lbs_start_card(priv); |
936 | if (ret) | 1021 | if (ret) |
937 | goto err_activate_card; | 1022 | goto err_activate_card; |
@@ -972,23 +1057,30 @@ static void if_sdio_remove(struct sdio_func *func) | |||
972 | { | 1057 | { |
973 | struct if_sdio_card *card; | 1058 | struct if_sdio_card *card; |
974 | struct if_sdio_packet *packet; | 1059 | struct if_sdio_packet *packet; |
1060 | int ret; | ||
975 | 1061 | ||
976 | lbs_deb_enter(LBS_DEB_SDIO); | 1062 | lbs_deb_enter(LBS_DEB_SDIO); |
977 | 1063 | ||
978 | card = sdio_get_drvdata(func); | 1064 | card = sdio_get_drvdata(func); |
979 | 1065 | ||
1066 | lbs_stop_card(card->priv); | ||
1067 | |||
980 | card->priv->surpriseremoved = 1; | 1068 | card->priv->surpriseremoved = 1; |
981 | 1069 | ||
982 | lbs_deb_sdio("call remove card\n"); | 1070 | lbs_deb_sdio("call remove card\n"); |
983 | lbs_stop_card(card->priv); | ||
984 | lbs_remove_card(card->priv); | 1071 | lbs_remove_card(card->priv); |
985 | 1072 | ||
986 | flush_workqueue(card->workqueue); | 1073 | flush_workqueue(card->workqueue); |
987 | destroy_workqueue(card->workqueue); | 1074 | destroy_workqueue(card->workqueue); |
988 | 1075 | ||
989 | sdio_claim_host(func); | 1076 | sdio_claim_host(func); |
1077 | |||
1078 | /* Disable interrupts */ | ||
1079 | sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret); | ||
1080 | |||
990 | sdio_release_irq(func); | 1081 | sdio_release_irq(func); |
991 | sdio_disable_func(func); | 1082 | sdio_disable_func(func); |
1083 | |||
992 | sdio_release_host(func); | 1084 | sdio_release_host(func); |
993 | 1085 | ||
994 | while (card->packets) { | 1086 | while (card->packets) { |
@@ -1031,8 +1123,23 @@ static int __init if_sdio_init_module(void) | |||
1031 | 1123 | ||
1032 | static void __exit if_sdio_exit_module(void) | 1124 | static void __exit if_sdio_exit_module(void) |
1033 | { | 1125 | { |
1126 | int i; | ||
1127 | struct if_sdio_card *card; | ||
1128 | |||
1034 | lbs_deb_enter(LBS_DEB_SDIO); | 1129 | lbs_deb_enter(LBS_DEB_SDIO); |
1035 | 1130 | ||
1131 | for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) { | ||
1132 | card = if_sdio_models[i].card; | ||
1133 | |||
1134 | /* | ||
1135 | * FUNC_SHUTDOWN is required for SD8688 WLAN/BT | ||
1136 | * multiple functions | ||
1137 | */ | ||
1138 | if (card && card->priv) | ||
1139 | card->priv->fn_shutdown_required = | ||
1140 | (card->model == IF_SDIO_MODEL_8688) ? 1 : 0; | ||
1141 | } | ||
1142 | |||
1036 | sdio_unregister_driver(&if_sdio_driver); | 1143 | sdio_unregister_driver(&if_sdio_driver); |
1037 | 1144 | ||
1038 | lbs_deb_leave(LBS_DEB_SDIO); | 1145 | lbs_deb_leave(LBS_DEB_SDIO); |
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index 37ada2c29aa9..60c9b2fcef03 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h | |||
@@ -12,6 +12,10 @@ | |||
12 | #ifndef _LBS_IF_SDIO_H | 12 | #ifndef _LBS_IF_SDIO_H |
13 | #define _LBS_IF_SDIO_H | 13 | #define _LBS_IF_SDIO_H |
14 | 14 | ||
15 | #define IF_SDIO_MODEL_8385 0x04 | ||
16 | #define IF_SDIO_MODEL_8686 0x0b | ||
17 | #define IF_SDIO_MODEL_8688 0x10 | ||
18 | |||
15 | #define IF_SDIO_IOPORT 0x00 | 19 | #define IF_SDIO_IOPORT 0x00 |
16 | 20 | ||
17 | #define IF_SDIO_H_INT_MASK 0x04 | 21 | #define IF_SDIO_H_INT_MASK 0x04 |
@@ -38,8 +42,12 @@ | |||
38 | 42 | ||
39 | #define IF_SDIO_SCRATCH 0x34 | 43 | #define IF_SDIO_SCRATCH 0x34 |
40 | #define IF_SDIO_SCRATCH_OLD 0x80fe | 44 | #define IF_SDIO_SCRATCH_OLD 0x80fe |
45 | #define IF_SDIO_FW_STATUS 0x40 | ||
41 | #define IF_SDIO_FIRMWARE_OK 0xfedc | 46 | #define IF_SDIO_FIRMWARE_OK 0xfedc |
42 | 47 | ||
48 | #define IF_SDIO_RX_LEN 0x42 | ||
49 | #define IF_SDIO_RX_UNIT 0x43 | ||
50 | |||
43 | #define IF_SDIO_EVENT 0x80fc | 51 | #define IF_SDIO_EVENT 0x80fc |
44 | 52 | ||
45 | #define IF_SDIO_BLOCK_SIZE 256 | 53 | #define IF_SDIO_BLOCK_SIZE 256 |
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index dccd01fd1f10..5fa55fe1f860 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c | |||
@@ -814,6 +814,13 @@ static void if_spi_e2h(struct if_spi_card *card) | |||
814 | if (err) | 814 | if (err) |
815 | goto out; | 815 | goto out; |
816 | 816 | ||
817 | /* re-enable the card event interrupt */ | ||
818 | spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, | ||
819 | ~IF_SPI_HICU_CARD_EVENT); | ||
820 | |||
821 | /* generate a card interrupt */ | ||
822 | spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_HOST_EVENT); | ||
823 | |||
817 | spin_lock_irqsave(&priv->driver_lock, flags); | 824 | spin_lock_irqsave(&priv->driver_lock, flags); |
818 | lbs_queue_event(priv, cause & 0xff); | 825 | lbs_queue_event(priv, cause & 0xff); |
819 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 826 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 89575e448015..a58a12352672 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -1002,9 +1002,17 @@ static int lbs_setup_firmware(struct lbs_private *priv) | |||
1002 | { | 1002 | { |
1003 | int ret = -1; | 1003 | int ret = -1; |
1004 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; | 1004 | s16 curlevel = 0, minlevel = 0, maxlevel = 0; |
1005 | struct cmd_header cmd; | ||
1005 | 1006 | ||
1006 | lbs_deb_enter(LBS_DEB_FW); | 1007 | lbs_deb_enter(LBS_DEB_FW); |
1007 | 1008 | ||
1009 | if (priv->fn_init_required) { | ||
1010 | memset(&cmd, 0, sizeof(cmd)); | ||
1011 | if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), | ||
1012 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1013 | lbs_pr_alert("CMD_FUNC_INIT command failed\n"); | ||
1014 | } | ||
1015 | |||
1008 | /* Read MAC address from firmware */ | 1016 | /* Read MAC address from firmware */ |
1009 | memset(priv->current_addr, 0xff, ETH_ALEN); | 1017 | memset(priv->current_addr, 0xff, ETH_ALEN); |
1010 | ret = lbs_update_hw_spec(priv); | 1018 | ret = lbs_update_hw_spec(priv); |
@@ -1192,6 +1200,9 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) | |||
1192 | priv->mesh_open = 0; | 1200 | priv->mesh_open = 0; |
1193 | priv->infra_open = 0; | 1201 | priv->infra_open = 0; |
1194 | 1202 | ||
1203 | priv->fn_init_required = 0; | ||
1204 | priv->fn_shutdown_required = 0; | ||
1205 | |||
1195 | /* Setup the OS Interface to our functions */ | 1206 | /* Setup the OS Interface to our functions */ |
1196 | dev->netdev_ops = &lbs_netdev_ops; | 1207 | dev->netdev_ops = &lbs_netdev_ops; |
1197 | dev->watchdog_timeo = 5 * HZ; | 1208 | dev->watchdog_timeo = 5 * HZ; |
@@ -1373,11 +1384,20 @@ void lbs_stop_card(struct lbs_private *priv) | |||
1373 | struct net_device *dev; | 1384 | struct net_device *dev; |
1374 | struct cmd_ctrl_node *cmdnode; | 1385 | struct cmd_ctrl_node *cmdnode; |
1375 | unsigned long flags; | 1386 | unsigned long flags; |
1387 | struct cmd_header cmd; | ||
1376 | 1388 | ||
1377 | lbs_deb_enter(LBS_DEB_MAIN); | 1389 | lbs_deb_enter(LBS_DEB_MAIN); |
1378 | 1390 | ||
1379 | if (!priv) | 1391 | if (!priv) |
1380 | goto out; | 1392 | goto out; |
1393 | |||
1394 | if (priv->fn_shutdown_required) { | ||
1395 | memset(&cmd, 0, sizeof(cmd)); | ||
1396 | if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd), | ||
1397 | lbs_cmd_copyback, (unsigned long) &cmd)) | ||
1398 | lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n"); | ||
1399 | } | ||
1400 | |||
1381 | dev = priv->dev; | 1401 | dev = priv->dev; |
1382 | 1402 | ||
1383 | netif_stop_queue(dev); | 1403 | netif_stop_queue(dev); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 61a4ad7cc1c2..574b8bb121e1 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -291,6 +291,14 @@ struct mac80211_hwsim_data { | |||
291 | bool ps_poll_pending; | 291 | bool ps_poll_pending; |
292 | struct dentry *debugfs; | 292 | struct dentry *debugfs; |
293 | struct dentry *debugfs_ps; | 293 | struct dentry *debugfs_ps; |
294 | |||
295 | /* | ||
296 | * Only radios in the same group can communicate together (the | ||
297 | * channel has to match too). Each bit represents a group. A | ||
298 | * radio can be in more then one group. | ||
299 | */ | ||
300 | u64 group; | ||
301 | struct dentry *debugfs_group; | ||
294 | }; | 302 | }; |
295 | 303 | ||
296 | 304 | ||
@@ -412,7 +420,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
412 | 420 | ||
413 | if (!data2->started || !data2->radio_enabled || | 421 | if (!data2->started || !data2->radio_enabled || |
414 | !hwsim_ps_rx_ok(data2, skb) || | 422 | !hwsim_ps_rx_ok(data2, skb) || |
415 | data->channel->center_freq != data2->channel->center_freq) | 423 | data->channel->center_freq != data2->channel->center_freq || |
424 | !(data->group & data2->group)) | ||
416 | continue; | 425 | continue; |
417 | 426 | ||
418 | nskb = skb_copy(skb, GFP_ATOMIC); | 427 | nskb = skb_copy(skb, GFP_ATOMIC); |
@@ -720,6 +729,7 @@ static void mac80211_hwsim_free(void) | |||
720 | spin_unlock_bh(&hwsim_radio_lock); | 729 | spin_unlock_bh(&hwsim_radio_lock); |
721 | 730 | ||
722 | list_for_each_entry(data, &tmplist, list) { | 731 | list_for_each_entry(data, &tmplist, list) { |
732 | debugfs_remove(data->debugfs_group); | ||
723 | debugfs_remove(data->debugfs_ps); | 733 | debugfs_remove(data->debugfs_ps); |
724 | debugfs_remove(data->debugfs); | 734 | debugfs_remove(data->debugfs); |
725 | ieee80211_unregister_hw(data->hw); | 735 | ieee80211_unregister_hw(data->hw); |
@@ -872,6 +882,24 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, | |||
872 | "%llu\n"); | 882 | "%llu\n"); |
873 | 883 | ||
874 | 884 | ||
885 | static int hwsim_fops_group_read(void *dat, u64 *val) | ||
886 | { | ||
887 | struct mac80211_hwsim_data *data = dat; | ||
888 | *val = data->group; | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int hwsim_fops_group_write(void *dat, u64 val) | ||
893 | { | ||
894 | struct mac80211_hwsim_data *data = dat; | ||
895 | data->group = val; | ||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, | ||
900 | hwsim_fops_group_read, hwsim_fops_group_write, | ||
901 | "%llx\n"); | ||
902 | |||
875 | static int __init init_mac80211_hwsim(void) | 903 | static int __init init_mac80211_hwsim(void) |
876 | { | 904 | { |
877 | int i, err = 0; | 905 | int i, err = 0; |
@@ -976,6 +1004,8 @@ static int __init init_mac80211_hwsim(void) | |||
976 | 1004 | ||
977 | hw->wiphy->bands[band] = sband; | 1005 | hw->wiphy->bands[band] = sband; |
978 | } | 1006 | } |
1007 | /* By default all radios are belonging to the first group */ | ||
1008 | data->group = 1; | ||
979 | 1009 | ||
980 | /* Work to be done prior to ieee80211_register_hw() */ | 1010 | /* Work to be done prior to ieee80211_register_hw() */ |
981 | switch (regtest) { | 1011 | switch (regtest) { |
@@ -1100,6 +1130,9 @@ static int __init init_mac80211_hwsim(void) | |||
1100 | data->debugfs_ps = debugfs_create_file("ps", 0666, | 1130 | data->debugfs_ps = debugfs_create_file("ps", 0666, |
1101 | data->debugfs, data, | 1131 | data->debugfs, data, |
1102 | &hwsim_fops_ps); | 1132 | &hwsim_fops_ps); |
1133 | data->debugfs_group = debugfs_create_file("group", 0666, | ||
1134 | data->debugfs, data, | ||
1135 | &hwsim_fops_group); | ||
1103 | 1136 | ||
1104 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, | 1137 | setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, |
1105 | (unsigned long) hw); | 1138 | (unsigned long) hw); |
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 59a5e778bb08..83116baeb110 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c | |||
@@ -96,7 +96,7 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address, | |||
96 | spi_message_add_tail(&t[0], &m); | 96 | spi_message_add_tail(&t[0], &m); |
97 | 97 | ||
98 | t[1].tx_buf = buf; | 98 | t[1].tx_buf = buf; |
99 | t[1].len = len; | 99 | t[1].len = len & ~1; |
100 | spi_message_add_tail(&t[1], &m); | 100 | spi_message_add_tail(&t[1], &m); |
101 | 101 | ||
102 | if (len % 2) { | 102 | if (len % 2) { |
@@ -172,8 +172,6 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) | |||
172 | __le32 buffer = p54spi_read32(priv, reg); | 172 | __le32 buffer = p54spi_read32(priv, reg); |
173 | if ((buffer & bits) == bits) | 173 | if ((buffer & bits) == bits) |
174 | return 1; | 174 | return 1; |
175 | |||
176 | msleep(0); | ||
177 | } | 175 | } |
178 | return 0; | 176 | return 0; |
179 | } | 177 | } |
@@ -181,9 +179,6 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) | |||
181 | static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, | 179 | static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, |
182 | const void *buf, size_t len) | 180 | const void *buf, size_t len) |
183 | { | 181 | { |
184 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, | ||
185 | cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); | ||
186 | |||
187 | if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, | 182 | if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, |
188 | cpu_to_le32(HOST_ALLOWED))) { | 183 | cpu_to_le32(HOST_ALLOWED))) { |
189 | dev_err(&priv->spi->dev, "spi_write_dma not allowed " | 184 | dev_err(&priv->spi->dev, "spi_write_dma not allowed " |
@@ -191,6 +186,9 @@ static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, | |||
191 | return -EAGAIN; | 186 | return -EAGAIN; |
192 | } | 187 | } |
193 | 188 | ||
189 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, | ||
190 | cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); | ||
191 | |||
194 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); | 192 | p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); |
195 | p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); | 193 | p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); |
196 | p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); | 194 | p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); |
@@ -327,7 +325,7 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) | |||
327 | p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); | 325 | p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val)); |
328 | } | 326 | } |
329 | 327 | ||
330 | static void p54spi_wakeup(struct p54s_priv *priv) | 328 | static int p54spi_wakeup(struct p54s_priv *priv) |
331 | { | 329 | { |
332 | /* wake the chip */ | 330 | /* wake the chip */ |
333 | p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, | 331 | p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, |
@@ -337,13 +335,11 @@ static void p54spi_wakeup(struct p54s_priv *priv) | |||
337 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, | 335 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, |
338 | cpu_to_le32(SPI_HOST_INT_READY))) { | 336 | cpu_to_le32(SPI_HOST_INT_READY))) { |
339 | dev_err(&priv->spi->dev, "INT_READY timeout\n"); | 337 | dev_err(&priv->spi->dev, "INT_READY timeout\n"); |
340 | goto out; | 338 | return -EBUSY; |
341 | } | 339 | } |
342 | 340 | ||
343 | p54spi_int_ack(priv, SPI_HOST_INT_READY); | 341 | p54spi_int_ack(priv, SPI_HOST_INT_READY); |
344 | 342 | return 0; | |
345 | out: | ||
346 | return; | ||
347 | } | 343 | } |
348 | 344 | ||
349 | static inline void p54spi_sleep(struct p54s_priv *priv) | 345 | static inline void p54spi_sleep(struct p54s_priv *priv) |
@@ -375,31 +371,44 @@ static int p54spi_rx(struct p54s_priv *priv) | |||
375 | { | 371 | { |
376 | struct sk_buff *skb; | 372 | struct sk_buff *skb; |
377 | u16 len; | 373 | u16 len; |
374 | u16 rx_head[2]; | ||
375 | #define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16)) | ||
378 | 376 | ||
379 | p54spi_wakeup(priv); | 377 | if (p54spi_wakeup(priv) < 0) |
380 | 378 | return -EBUSY; | |
381 | /* dummy read to flush SPI DMA controller bug */ | ||
382 | p54spi_read16(priv, SPI_ADRS_GEN_PURP_1); | ||
383 | 379 | ||
384 | len = p54spi_read16(priv, SPI_ADRS_DMA_DATA); | 380 | /* Read data size and first data word in one SPI transaction |
381 | * This is workaround for firmware/DMA bug, | ||
382 | * when first data word gets lost under high load. | ||
383 | */ | ||
384 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head)); | ||
385 | len = rx_head[0]; | ||
385 | 386 | ||
386 | if (len == 0) { | 387 | if (len == 0) { |
387 | dev_err(&priv->spi->dev, "rx request of zero bytes"); | 388 | p54spi_sleep(priv); |
389 | dev_err(&priv->spi->dev, "rx request of zero bytes\n"); | ||
388 | return 0; | 390 | return 0; |
389 | } | 391 | } |
390 | 392 | ||
391 | |||
392 | /* Firmware may insert up to 4 padding bytes after the lmac header, | 393 | /* Firmware may insert up to 4 padding bytes after the lmac header, |
393 | * but it does not amend the size of SPI data transfer. | 394 | * but it does not amend the size of SPI data transfer. |
394 | * Such packets has correct data size in header, thus referencing | 395 | * Such packets has correct data size in header, thus referencing |
395 | * past the end of allocated skb. Reserve extra 4 bytes for this case */ | 396 | * past the end of allocated skb. Reserve extra 4 bytes for this case */ |
396 | skb = dev_alloc_skb(len + 4); | 397 | skb = dev_alloc_skb(len + 4); |
397 | if (!skb) { | 398 | if (!skb) { |
399 | p54spi_sleep(priv); | ||
398 | dev_err(&priv->spi->dev, "could not alloc skb"); | 400 | dev_err(&priv->spi->dev, "could not alloc skb"); |
399 | return 0; | 401 | return -ENOMEM; |
400 | } | 402 | } |
401 | 403 | ||
402 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); | 404 | if (len <= READAHEAD_SZ) { |
405 | memcpy(skb_put(skb, len), rx_head + 1, len); | ||
406 | } else { | ||
407 | memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ); | ||
408 | p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, | ||
409 | skb_put(skb, len - READAHEAD_SZ), | ||
410 | len - READAHEAD_SZ); | ||
411 | } | ||
403 | p54spi_sleep(priv); | 412 | p54spi_sleep(priv); |
404 | /* Put additional bytes to compensate for the possible | 413 | /* Put additional bytes to compensate for the possible |
405 | * alignment-caused truncation */ | 414 | * alignment-caused truncation */ |
@@ -427,7 +436,8 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) | |||
427 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; | 436 | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; |
428 | int ret = 0; | 437 | int ret = 0; |
429 | 438 | ||
430 | p54spi_wakeup(priv); | 439 | if (p54spi_wakeup(priv) < 0) |
440 | return -EBUSY; | ||
431 | 441 | ||
432 | ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); | 442 | ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); |
433 | if (ret < 0) | 443 | if (ret < 0) |
@@ -436,16 +446,16 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) | |||
436 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, | 446 | if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, |
437 | cpu_to_le32(SPI_HOST_INT_WR_READY))) { | 447 | cpu_to_le32(SPI_HOST_INT_WR_READY))) { |
438 | dev_err(&priv->spi->dev, "WR_READY timeout\n"); | 448 | dev_err(&priv->spi->dev, "WR_READY timeout\n"); |
439 | ret = -1; | 449 | ret = -EAGAIN; |
440 | goto out; | 450 | goto out; |
441 | } | 451 | } |
442 | 452 | ||
443 | p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); | 453 | p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); |
444 | p54spi_sleep(priv); | ||
445 | 454 | ||
446 | if (FREE_AFTER_TX(skb)) | 455 | if (FREE_AFTER_TX(skb)) |
447 | p54_free_skb(priv->hw, skb); | 456 | p54_free_skb(priv->hw, skb); |
448 | out: | 457 | out: |
458 | p54spi_sleep(priv); | ||
449 | return ret; | 459 | return ret; |
450 | } | 460 | } |
451 | 461 | ||
@@ -515,8 +525,7 @@ static void p54spi_work(struct work_struct *work) | |||
515 | 525 | ||
516 | mutex_lock(&priv->mutex); | 526 | mutex_lock(&priv->mutex); |
517 | 527 | ||
518 | if (priv->fw_state == FW_STATE_OFF && | 528 | if (priv->fw_state == FW_STATE_OFF) |
519 | priv->fw_state == FW_STATE_RESET) | ||
520 | goto out; | 529 | goto out; |
521 | 530 | ||
522 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | 531 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); |
@@ -543,11 +552,6 @@ static void p54spi_work(struct work_struct *work) | |||
543 | } | 552 | } |
544 | 553 | ||
545 | ret = p54spi_wq_tx(priv); | 554 | ret = p54spi_wq_tx(priv); |
546 | if (ret < 0) | ||
547 | goto out; | ||
548 | |||
549 | ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); | ||
550 | |||
551 | out: | 555 | out: |
552 | mutex_unlock(&priv->mutex); | 556 | mutex_unlock(&priv->mutex); |
553 | } | 557 | } |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 52fc647e6cb6..c254fdf446fd 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Driver for RNDIS based wireless USB devices. | 2 | * Driver for RNDIS based wireless USB devices. |
3 | * | 3 | * |
4 | * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net> | 4 | * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net> |
5 | * Copyright (C) 2008 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 5 | * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -196,6 +196,18 @@ enum ndis_80211_priv_filter { | |||
196 | ndis_80211_priv_8021x_wep | 196 | ndis_80211_priv_8021x_wep |
197 | }; | 197 | }; |
198 | 198 | ||
199 | enum ndis_80211_addkey_bits { | ||
200 | ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28), | ||
201 | ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29), | ||
202 | ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30), | ||
203 | ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31), | ||
204 | }; | ||
205 | |||
206 | enum ndis_80211_addwep_bits { | ||
207 | ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30), | ||
208 | ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31), | ||
209 | }; | ||
210 | |||
199 | struct ndis_80211_ssid { | 211 | struct ndis_80211_ssid { |
200 | __le32 length; | 212 | __le32 length; |
201 | u8 essid[NDIS_802_11_LENGTH_SSID]; | 213 | u8 essid[NDIS_802_11_LENGTH_SSID]; |
@@ -309,7 +321,6 @@ enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, | |||
309 | #define CAP_MODE_80211B 2 | 321 | #define CAP_MODE_80211B 2 |
310 | #define CAP_MODE_80211G 4 | 322 | #define CAP_MODE_80211G 4 |
311 | #define CAP_MODE_MASK 7 | 323 | #define CAP_MODE_MASK 7 |
312 | #define CAP_SUPPORT_TXPOWER 8 | ||
313 | 324 | ||
314 | #define WORK_LINK_UP (1<<0) | 325 | #define WORK_LINK_UP (1<<0) |
315 | #define WORK_LINK_DOWN (1<<1) | 326 | #define WORK_LINK_DOWN (1<<1) |
@@ -394,6 +405,7 @@ struct rndis_wext_private { | |||
394 | int encr_tx_key_index; | 405 | int encr_tx_key_index; |
395 | char encr_keys[4][32]; | 406 | char encr_keys[4][32]; |
396 | int encr_key_len[4]; | 407 | int encr_key_len[4]; |
408 | char encr_key_wpa[4]; | ||
397 | int wpa_version; | 409 | int wpa_version; |
398 | int wpa_keymgmt; | 410 | int wpa_keymgmt; |
399 | int wpa_authalg; | 411 | int wpa_authalg; |
@@ -945,7 +957,7 @@ static int set_infra_mode(struct usbnet *usbdev, int mode) | |||
945 | if (priv->wpa_keymgmt == 0 || | 957 | if (priv->wpa_keymgmt == 0 || |
946 | priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { | 958 | priv->wpa_keymgmt == IW_AUTH_KEY_MGMT_802_1X) { |
947 | for (i = 0; i < 4; i++) { | 959 | for (i = 0; i < 4; i++) { |
948 | if (priv->encr_key_len[i] > 0) | 960 | if (priv->encr_key_len[i] > 0 && !priv->encr_key_wpa[i]) |
949 | add_wep_key(usbdev, priv->encr_keys[i], | 961 | add_wep_key(usbdev, priv->encr_keys[i], |
950 | priv->encr_key_len[i], i); | 962 | priv->encr_key_len[i], i); |
951 | } | 963 | } |
@@ -999,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | |||
999 | memcpy(&ndis_key.material, key, key_len); | 1011 | memcpy(&ndis_key.material, key, key_len); |
1000 | 1012 | ||
1001 | if (index == priv->encr_tx_key_index) { | 1013 | if (index == priv->encr_tx_key_index) { |
1002 | ndis_key.index |= cpu_to_le32(1 << 31); | 1014 | ndis_key.index |= ndis_80211_addwep_transmit_key; |
1003 | ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, | 1015 | ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104, |
1004 | IW_AUTH_CIPHER_NONE); | 1016 | IW_AUTH_CIPHER_NONE); |
1005 | if (ret) | 1017 | if (ret) |
@@ -1016,12 +1028,81 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index) | |||
1016 | } | 1028 | } |
1017 | 1029 | ||
1018 | priv->encr_key_len[index] = key_len; | 1030 | priv->encr_key_len[index] = key_len; |
1031 | priv->encr_key_wpa[index] = 0; | ||
1019 | memcpy(&priv->encr_keys[index], key, key_len); | 1032 | memcpy(&priv->encr_keys[index], key, key_len); |
1020 | 1033 | ||
1021 | return 0; | 1034 | return 0; |
1022 | } | 1035 | } |
1023 | 1036 | ||
1024 | 1037 | ||
1038 | static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len, | ||
1039 | int index, const struct sockaddr *addr, | ||
1040 | const u8 *rx_seq, int alg, int flags) | ||
1041 | { | ||
1042 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | ||
1043 | struct ndis_80211_key ndis_key; | ||
1044 | int ret; | ||
1045 | |||
1046 | if (index < 0 || index >= 4) | ||
1047 | return -EINVAL; | ||
1048 | if (key_len > sizeof(ndis_key.material) || key_len < 0) | ||
1049 | return -EINVAL; | ||
1050 | if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq) | ||
1051 | return -EINVAL; | ||
1052 | if ((flags & ndis_80211_addkey_pairwise_key) && !addr) | ||
1053 | return -EINVAL; | ||
1054 | |||
1055 | devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index, | ||
1056 | !!(flags & ndis_80211_addkey_transmit_key), | ||
1057 | !!(flags & ndis_80211_addkey_pairwise_key), | ||
1058 | !!(flags & ndis_80211_addkey_set_init_recv_seq)); | ||
1059 | |||
1060 | memset(&ndis_key, 0, sizeof(ndis_key)); | ||
1061 | |||
1062 | ndis_key.size = cpu_to_le32(sizeof(ndis_key) - | ||
1063 | sizeof(ndis_key.material) + key_len); | ||
1064 | ndis_key.length = cpu_to_le32(key_len); | ||
1065 | ndis_key.index = cpu_to_le32(index) | flags; | ||
1066 | |||
1067 | if (alg == IW_ENCODE_ALG_TKIP && key_len == 32) { | ||
1068 | /* wpa_supplicant gives us the Michael MIC RX/TX keys in | ||
1069 | * different order than NDIS spec, so swap the order here. */ | ||
1070 | memcpy(ndis_key.material, key, 16); | ||
1071 | memcpy(ndis_key.material + 16, key + 24, 8); | ||
1072 | memcpy(ndis_key.material + 24, key + 16, 8); | ||
1073 | } else | ||
1074 | memcpy(ndis_key.material, key, key_len); | ||
1075 | |||
1076 | if (flags & ndis_80211_addkey_set_init_recv_seq) | ||
1077 | memcpy(ndis_key.rsc, rx_seq, 6); | ||
1078 | |||
1079 | if (flags & ndis_80211_addkey_pairwise_key) { | ||
1080 | /* pairwise key */ | ||
1081 | memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN); | ||
1082 | } else { | ||
1083 | /* group key */ | ||
1084 | if (priv->infra_mode == ndis_80211_infra_adhoc) | ||
1085 | memset(ndis_key.bssid, 0xff, ETH_ALEN); | ||
1086 | else | ||
1087 | get_bssid(usbdev, ndis_key.bssid); | ||
1088 | } | ||
1089 | |||
1090 | ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, | ||
1091 | le32_to_cpu(ndis_key.size)); | ||
1092 | devdbg(usbdev, "add_wpa_key: OID_802_11_ADD_KEY -> %08X", ret); | ||
1093 | if (ret != 0) | ||
1094 | return ret; | ||
1095 | |||
1096 | priv->encr_key_len[index] = key_len; | ||
1097 | priv->encr_key_wpa[index] = 1; | ||
1098 | |||
1099 | if (flags & ndis_80211_addkey_transmit_key) | ||
1100 | priv->encr_tx_key_index = index; | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | |||
1025 | /* remove_key is for both wep and wpa */ | 1106 | /* remove_key is for both wep and wpa */ |
1026 | static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | 1107 | static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) |
1027 | { | 1108 | { |
@@ -1034,6 +1115,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | |||
1034 | return 0; | 1115 | return 0; |
1035 | 1116 | ||
1036 | priv->encr_key_len[index] = 0; | 1117 | priv->encr_key_len[index] = 0; |
1118 | priv->encr_key_wpa[index] = 0; | ||
1037 | memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); | 1119 | memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index])); |
1038 | 1120 | ||
1039 | if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || | 1121 | if (priv->wpa_cipher_pair == IW_AUTH_CIPHER_TKIP || |
@@ -1045,7 +1127,8 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN]) | |||
1045 | if (bssid) { | 1127 | if (bssid) { |
1046 | /* pairwise key */ | 1128 | /* pairwise key */ |
1047 | if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) | 1129 | if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0) |
1048 | remove_key.index |= cpu_to_le32(1 << 30); | 1130 | remove_key.index |= |
1131 | ndis_80211_addkey_pairwise_key; | ||
1049 | memcpy(remove_key.bssid, bssid, | 1132 | memcpy(remove_key.bssid, bssid, |
1050 | sizeof(remove_key.bssid)); | 1133 | sizeof(remove_key.bssid)); |
1051 | } else | 1134 | } else |
@@ -1590,9 +1673,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
1590 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 1673 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
1591 | struct usbnet *usbdev = netdev_priv(dev); | 1674 | struct usbnet *usbdev = netdev_priv(dev); |
1592 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1675 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1593 | struct ndis_80211_key ndis_key; | 1676 | int keyidx, flags; |
1594 | int keyidx, ret; | ||
1595 | u8 *addr; | ||
1596 | 1677 | ||
1597 | keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; | 1678 | keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; |
1598 | 1679 | ||
@@ -1615,58 +1696,16 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, | |||
1615 | ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) | 1696 | ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) |
1616 | return remove_key(usbdev, keyidx, NULL); | 1697 | return remove_key(usbdev, keyidx, NULL); |
1617 | 1698 | ||
1618 | if (ext->key_len > sizeof(ndis_key.material)) | 1699 | flags = 0; |
1619 | return -1; | 1700 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) |
1620 | 1701 | flags |= ndis_80211_addkey_set_init_recv_seq; | |
1621 | memset(&ndis_key, 0, sizeof(ndis_key)); | 1702 | if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) |
1622 | 1703 | flags |= ndis_80211_addkey_pairwise_key; | |
1623 | ndis_key.size = cpu_to_le32(sizeof(ndis_key) - | ||
1624 | sizeof(ndis_key.material) + ext->key_len); | ||
1625 | ndis_key.length = cpu_to_le32(ext->key_len); | ||
1626 | ndis_key.index = cpu_to_le32(keyidx); | ||
1627 | |||
1628 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { | ||
1629 | memcpy(ndis_key.rsc, ext->rx_seq, 6); | ||
1630 | ndis_key.index |= cpu_to_le32(1 << 29); | ||
1631 | } | ||
1632 | |||
1633 | addr = ext->addr.sa_data; | ||
1634 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | ||
1635 | /* group key */ | ||
1636 | if (priv->infra_mode == ndis_80211_infra_adhoc) | ||
1637 | memset(ndis_key.bssid, 0xff, ETH_ALEN); | ||
1638 | else | ||
1639 | get_bssid(usbdev, ndis_key.bssid); | ||
1640 | } else { | ||
1641 | /* pairwise key */ | ||
1642 | ndis_key.index |= cpu_to_le32(1 << 30); | ||
1643 | memcpy(ndis_key.bssid, addr, ETH_ALEN); | ||
1644 | } | ||
1645 | |||
1646 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | ||
1647 | ndis_key.index |= cpu_to_le32(1 << 31); | ||
1648 | |||
1649 | if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { | ||
1650 | /* wpa_supplicant gives us the Michael MIC RX/TX keys in | ||
1651 | * different order than NDIS spec, so swap the order here. */ | ||
1652 | memcpy(ndis_key.material, ext->key, 16); | ||
1653 | memcpy(ndis_key.material + 16, ext->key + 24, 8); | ||
1654 | memcpy(ndis_key.material + 24, ext->key + 16, 8); | ||
1655 | } else | ||
1656 | memcpy(ndis_key.material, ext->key, ext->key_len); | ||
1657 | |||
1658 | ret = rndis_set_oid(usbdev, OID_802_11_ADD_KEY, &ndis_key, | ||
1659 | le32_to_cpu(ndis_key.size)); | ||
1660 | devdbg(usbdev, "SIOCSIWENCODEEXT: OID_802_11_ADD_KEY -> %08X", ret); | ||
1661 | if (ret != 0) | ||
1662 | return ret; | ||
1663 | |||
1664 | priv->encr_key_len[keyidx] = ext->key_len; | ||
1665 | memcpy(&priv->encr_keys[keyidx], ndis_key.material, ext->key_len); | ||
1666 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) | 1704 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) |
1667 | priv->encr_tx_key_index = keyidx; | 1705 | flags |= ndis_80211_addkey_transmit_key; |
1668 | 1706 | ||
1669 | return 0; | 1707 | return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr, |
1708 | ext->rx_seq, ext->alg, flags); | ||
1670 | } | 1709 | } |
1671 | 1710 | ||
1672 | 1711 | ||
@@ -1849,18 +1888,10 @@ static int rndis_iw_get_txpower(struct net_device *dev, | |||
1849 | struct usbnet *usbdev = netdev_priv(dev); | 1888 | struct usbnet *usbdev = netdev_priv(dev); |
1850 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1889 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1851 | __le32 tx_power; | 1890 | __le32 tx_power; |
1852 | int ret = 0, len; | ||
1853 | 1891 | ||
1854 | if (priv->radio_on) { | 1892 | if (priv->radio_on) { |
1855 | if (priv->caps & CAP_SUPPORT_TXPOWER) { | 1893 | /* fake since changing tx_power (by userlevel) not supported */ |
1856 | len = sizeof(tx_power); | 1894 | tx_power = cpu_to_le32(get_bcm4320_power(priv)); |
1857 | ret = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, | ||
1858 | &tx_power, &len); | ||
1859 | if (ret != 0) | ||
1860 | return ret; | ||
1861 | } else | ||
1862 | /* fake incase not supported */ | ||
1863 | tx_power = cpu_to_le32(get_bcm4320_power(priv)); | ||
1864 | 1895 | ||
1865 | wrqu->txpower.flags = IW_TXPOW_MWATT; | 1896 | wrqu->txpower.flags = IW_TXPOW_MWATT; |
1866 | wrqu->txpower.value = le32_to_cpu(tx_power); | 1897 | wrqu->txpower.value = le32_to_cpu(tx_power); |
@@ -1873,7 +1904,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, | |||
1873 | 1904 | ||
1874 | devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); | 1905 | devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value); |
1875 | 1906 | ||
1876 | return ret; | 1907 | return 0; |
1877 | } | 1908 | } |
1878 | 1909 | ||
1879 | 1910 | ||
@@ -1883,7 +1914,6 @@ static int rndis_iw_set_txpower(struct net_device *dev, | |||
1883 | struct usbnet *usbdev = netdev_priv(dev); | 1914 | struct usbnet *usbdev = netdev_priv(dev); |
1884 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 1915 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
1885 | __le32 tx_power = 0; | 1916 | __le32 tx_power = 0; |
1886 | int ret = 0; | ||
1887 | 1917 | ||
1888 | if (!wrqu->txpower.disabled) { | 1918 | if (!wrqu->txpower.disabled) { |
1889 | if (wrqu->txpower.flags == IW_TXPOW_MWATT) | 1919 | if (wrqu->txpower.flags == IW_TXPOW_MWATT) |
@@ -1906,22 +1936,10 @@ static int rndis_iw_set_txpower(struct net_device *dev, | |||
1906 | devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); | 1936 | devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power)); |
1907 | 1937 | ||
1908 | if (le32_to_cpu(tx_power) != 0) { | 1938 | if (le32_to_cpu(tx_power) != 0) { |
1909 | if (priv->caps & CAP_SUPPORT_TXPOWER) { | 1939 | /* txpower unsupported, just turn radio on */ |
1910 | /* turn radio on first */ | 1940 | if (!priv->radio_on) |
1911 | if (!priv->radio_on) | 1941 | return disassociate(usbdev, 1); |
1912 | disassociate(usbdev, 1); | 1942 | return 0; /* all ready on */ |
1913 | |||
1914 | ret = rndis_set_oid(usbdev, OID_802_11_TX_POWER_LEVEL, | ||
1915 | &tx_power, sizeof(tx_power)); | ||
1916 | if (ret != 0) | ||
1917 | ret = -EOPNOTSUPP; | ||
1918 | return ret; | ||
1919 | } else { | ||
1920 | /* txpower unsupported, just turn radio on */ | ||
1921 | if (!priv->radio_on) | ||
1922 | return disassociate(usbdev, 1); | ||
1923 | return 0; /* all ready on */ | ||
1924 | } | ||
1925 | } | 1943 | } |
1926 | 1944 | ||
1927 | /* tx_power == 0, turn off radio */ | 1945 | /* tx_power == 0, turn off radio */ |
@@ -2130,16 +2148,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev) | |||
2130 | __le32 items[8]; | 2148 | __le32 items[8]; |
2131 | } networks_supported; | 2149 | } networks_supported; |
2132 | int len, retval, i, n; | 2150 | int len, retval, i, n; |
2133 | __le32 tx_power; | ||
2134 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 2151 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
2135 | 2152 | ||
2136 | /* determine if supports setting txpower */ | ||
2137 | len = sizeof(tx_power); | ||
2138 | retval = rndis_query_oid(usbdev, OID_802_11_TX_POWER_LEVEL, &tx_power, | ||
2139 | &len); | ||
2140 | if (retval == 0 && le32_to_cpu(tx_power) != 0xFF) | ||
2141 | priv->caps |= CAP_SUPPORT_TXPOWER; | ||
2142 | |||
2143 | /* determine supported modes */ | 2153 | /* determine supported modes */ |
2144 | len = sizeof(networks_supported); | 2154 | len = sizeof(networks_supported); |
2145 | retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, | 2155 | retval = rndis_query_oid(usbdev, OID_802_11_NETWORK_TYPES_SUPPORTED, |
@@ -2275,7 +2285,17 @@ end: | |||
2275 | } | 2285 | } |
2276 | 2286 | ||
2277 | 2287 | ||
2278 | static int bcm4320_early_init(struct usbnet *usbdev) | 2288 | static int bcm4320a_early_init(struct usbnet *usbdev) |
2289 | { | ||
2290 | /* bcm4320a doesn't handle configuration parameters well. Try | ||
2291 | * set any and you get partially zeroed mac and broken device. | ||
2292 | */ | ||
2293 | |||
2294 | return 0; | ||
2295 | } | ||
2296 | |||
2297 | |||
2298 | static int bcm4320b_early_init(struct usbnet *usbdev) | ||
2279 | { | 2299 | { |
2280 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); | 2300 | struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); |
2281 | char buf[8]; | 2301 | char buf[8]; |
@@ -2515,7 +2535,7 @@ static const struct driver_info bcm4320b_info = { | |||
2515 | .rx_fixup = rndis_rx_fixup, | 2535 | .rx_fixup = rndis_rx_fixup, |
2516 | .tx_fixup = rndis_tx_fixup, | 2536 | .tx_fixup = rndis_tx_fixup, |
2517 | .reset = rndis_wext_reset, | 2537 | .reset = rndis_wext_reset, |
2518 | .early_init = bcm4320_early_init, | 2538 | .early_init = bcm4320b_early_init, |
2519 | .link_change = rndis_wext_link_change, | 2539 | .link_change = rndis_wext_link_change, |
2520 | }; | 2540 | }; |
2521 | 2541 | ||
@@ -2528,7 +2548,7 @@ static const struct driver_info bcm4320a_info = { | |||
2528 | .rx_fixup = rndis_rx_fixup, | 2548 | .rx_fixup = rndis_rx_fixup, |
2529 | .tx_fixup = rndis_tx_fixup, | 2549 | .tx_fixup = rndis_tx_fixup, |
2530 | .reset = rndis_wext_reset, | 2550 | .reset = rndis_wext_reset, |
2531 | .early_init = bcm4320_early_init, | 2551 | .early_init = bcm4320a_early_init, |
2532 | .link_change = rndis_wext_link_change, | 2552 | .link_change = rndis_wext_link_change, |
2533 | }; | 2553 | }; |
2534 | 2554 | ||
@@ -2541,7 +2561,7 @@ static const struct driver_info rndis_wext_info = { | |||
2541 | .rx_fixup = rndis_rx_fixup, | 2561 | .rx_fixup = rndis_rx_fixup, |
2542 | .tx_fixup = rndis_tx_fixup, | 2562 | .tx_fixup = rndis_tx_fixup, |
2543 | .reset = rndis_wext_reset, | 2563 | .reset = rndis_wext_reset, |
2544 | .early_init = bcm4320_early_init, | 2564 | .early_init = bcm4320a_early_init, |
2545 | .link_change = rndis_wext_link_change, | 2565 | .link_change = rndis_wext_link_change, |
2546 | }; | 2566 | }; |
2547 | 2567 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 6f39ba662188..0197531bd88c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -335,10 +335,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, | |||
335 | preamble_mask = erp->short_preamble << 3; | 335 | preamble_mask = erp->short_preamble << 3; |
336 | 336 | ||
337 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | 337 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); |
338 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, | 338 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); |
339 | erp->ack_timeout); | ||
340 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, | 339 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, |
341 | erp->ack_consume_time); | 340 | erp->ack_consume_time); |
341 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | ||
342 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | ||
342 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | 343 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); |
343 | 344 | ||
344 | rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); | 345 | rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); |
@@ -371,6 +372,11 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, | |||
371 | rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); | 372 | rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); |
372 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); | 373 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); |
373 | 374 | ||
375 | rt2x00pci_register_read(rt2x00dev, CSR12, ®); | ||
376 | rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); | ||
377 | rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); | ||
378 | rt2x00pci_register_write(rt2x00dev, CSR12, reg); | ||
379 | |||
374 | rt2x00pci_register_read(rt2x00dev, CSR18, ®); | 380 | rt2x00pci_register_read(rt2x00dev, CSR18, ®); |
375 | rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); | 381 | rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); |
376 | rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); | 382 | rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); |
@@ -503,24 +509,6 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, | |||
503 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); | 509 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); |
504 | } | 510 | } |
505 | 511 | ||
506 | static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, | ||
507 | struct rt2x00lib_conf *libconf) | ||
508 | { | ||
509 | u32 reg; | ||
510 | |||
511 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | ||
512 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | ||
513 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | ||
514 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | ||
515 | |||
516 | rt2x00pci_register_read(rt2x00dev, CSR12, ®); | ||
517 | rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, | ||
518 | libconf->conf->beacon_int * 16); | ||
519 | rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, | ||
520 | libconf->conf->beacon_int * 16); | ||
521 | rt2x00pci_register_write(rt2x00dev, CSR12, reg); | ||
522 | } | ||
523 | |||
524 | static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, | 512 | static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev, |
525 | struct rt2x00lib_conf *libconf) | 513 | struct rt2x00lib_conf *libconf) |
526 | { | 514 | { |
@@ -558,8 +546,6 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, | |||
558 | libconf->conf->power_level); | 546 | libconf->conf->power_level); |
559 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 547 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
560 | rt2400pci_config_retry_limit(rt2x00dev, libconf); | 548 | rt2400pci_config_retry_limit(rt2x00dev, libconf); |
561 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
562 | rt2400pci_config_duration(rt2x00dev, libconf); | ||
563 | if (flags & IEEE80211_CONF_CHANGE_PS) | 549 | if (flags & IEEE80211_CONF_CHANGE_PS) |
564 | rt2400pci_config_ps(rt2x00dev, libconf); | 550 | rt2400pci_config_ps(rt2x00dev, libconf); |
565 | } | 551 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 906960f67b6c..f95cb646f85a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -341,10 +341,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, | |||
341 | preamble_mask = erp->short_preamble << 3; | 341 | preamble_mask = erp->short_preamble << 3; |
342 | 342 | ||
343 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | 343 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); |
344 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, | 344 | rt2x00_set_field32(®, TXCSR1_ACK_TIMEOUT, erp->ack_timeout); |
345 | erp->ack_timeout); | ||
346 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, | 345 | rt2x00_set_field32(®, TXCSR1_ACK_CONSUME_TIME, |
347 | erp->ack_consume_time); | 346 | erp->ack_consume_time); |
347 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | ||
348 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | ||
348 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | 349 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); |
349 | 350 | ||
350 | rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); | 351 | rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); |
@@ -377,6 +378,11 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, | |||
377 | rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); | 378 | rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); |
378 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); | 379 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); |
379 | 380 | ||
381 | rt2x00pci_register_read(rt2x00dev, CSR12, ®); | ||
382 | rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, erp->beacon_int * 16); | ||
383 | rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, erp->beacon_int * 16); | ||
384 | rt2x00pci_register_write(rt2x00dev, CSR12, reg); | ||
385 | |||
380 | rt2x00pci_register_read(rt2x00dev, CSR18, ®); | 386 | rt2x00pci_register_read(rt2x00dev, CSR18, ®); |
381 | rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); | 387 | rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); |
382 | rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); | 388 | rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); |
@@ -552,24 +558,6 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, | |||
552 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); | 558 | rt2x00pci_register_write(rt2x00dev, CSR11, reg); |
553 | } | 559 | } |
554 | 560 | ||
555 | static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, | ||
556 | struct rt2x00lib_conf *libconf) | ||
557 | { | ||
558 | u32 reg; | ||
559 | |||
560 | rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); | ||
561 | rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); | ||
562 | rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); | ||
563 | rt2x00pci_register_write(rt2x00dev, TXCSR1, reg); | ||
564 | |||
565 | rt2x00pci_register_read(rt2x00dev, CSR12, ®); | ||
566 | rt2x00_set_field32(®, CSR12_BEACON_INTERVAL, | ||
567 | libconf->conf->beacon_int * 16); | ||
568 | rt2x00_set_field32(®, CSR12_CFP_MAX_DURATION, | ||
569 | libconf->conf->beacon_int * 16); | ||
570 | rt2x00pci_register_write(rt2x00dev, CSR12, reg); | ||
571 | } | ||
572 | |||
573 | static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, | 561 | static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev, |
574 | struct rt2x00lib_conf *libconf) | 562 | struct rt2x00lib_conf *libconf) |
575 | { | 563 | { |
@@ -609,8 +597,6 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, | |||
609 | libconf->conf->power_level); | 597 | libconf->conf->power_level); |
610 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 598 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
611 | rt2500pci_config_retry_limit(rt2x00dev, libconf); | 599 | rt2500pci_config_retry_limit(rt2x00dev, libconf); |
612 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
613 | rt2500pci_config_duration(rt2x00dev, libconf); | ||
614 | if (flags & IEEE80211_CONF_CHANGE_PS) | 600 | if (flags & IEEE80211_CONF_CHANGE_PS) |
615 | rt2500pci_config_ps(rt2x00dev, libconf); | 601 | rt2500pci_config_ps(rt2x00dev, libconf); |
616 | } | 602 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 1debb88bc60e..69f966f1ce54 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -503,6 +503,10 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, | |||
503 | 503 | ||
504 | rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); | 504 | rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); |
505 | 505 | ||
506 | rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); | ||
507 | rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, erp->beacon_int * 4); | ||
508 | rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); | ||
509 | |||
506 | rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); | 510 | rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); |
507 | rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); | 511 | rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); |
508 | rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); | 512 | rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); |
@@ -632,17 +636,6 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, | |||
632 | rt2500usb_rf_write(rt2x00dev, 3, rf3); | 636 | rt2500usb_rf_write(rt2x00dev, 3, rf3); |
633 | } | 637 | } |
634 | 638 | ||
635 | static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, | ||
636 | struct rt2x00lib_conf *libconf) | ||
637 | { | ||
638 | u16 reg; | ||
639 | |||
640 | rt2500usb_register_read(rt2x00dev, TXRX_CSR18, ®); | ||
641 | rt2x00_set_field16(®, TXRX_CSR18_INTERVAL, | ||
642 | libconf->conf->beacon_int * 4); | ||
643 | rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); | ||
644 | } | ||
645 | |||
646 | static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, | 639 | static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev, |
647 | struct rt2x00lib_conf *libconf) | 640 | struct rt2x00lib_conf *libconf) |
648 | { | 641 | { |
@@ -680,8 +673,6 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, | |||
680 | !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) | 673 | !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) |
681 | rt2500usb_config_txpower(rt2x00dev, | 674 | rt2500usb_config_txpower(rt2x00dev, |
682 | libconf->conf->power_level); | 675 | libconf->conf->power_level); |
683 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
684 | rt2500usb_config_duration(rt2x00dev, libconf); | ||
685 | if (flags & IEEE80211_CONF_CHANGE_PS) | 676 | if (flags & IEEE80211_CONF_CHANGE_PS) |
686 | rt2500usb_config_ps(rt2x00dev, libconf); | 677 | rt2500usb_config_ps(rt2x00dev, libconf); |
687 | } | 678 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 257bfb5483c9..142ad34fdc49 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -616,6 +616,11 @@ static void rt2800usb_config_erp(struct rt2x00_dev *rt2x00dev, | |||
616 | rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); | 616 | rt2x00_set_field32(®, XIFS_TIME_CFG_EIFS, erp->eifs); |
617 | rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); | 617 | rt2x00_set_field32(®, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1); |
618 | rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); | 618 | rt2x00usb_register_write(rt2x00dev, XIFS_TIME_CFG, reg); |
619 | |||
620 | rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); | ||
621 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, | ||
622 | erp->beacon_int * 16); | ||
623 | rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||
619 | } | 624 | } |
620 | 625 | ||
621 | static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, | 626 | static void rt2800usb_config_ant(struct rt2x00_dev *rt2x00dev, |
@@ -955,17 +960,6 @@ static void rt2800usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, | |||
955 | rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); | 960 | rt2x00usb_register_write(rt2x00dev, TX_RTY_CFG, reg); |
956 | } | 961 | } |
957 | 962 | ||
958 | static void rt2800usb_config_duration(struct rt2x00_dev *rt2x00dev, | ||
959 | struct rt2x00lib_conf *libconf) | ||
960 | { | ||
961 | u32 reg; | ||
962 | |||
963 | rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, ®); | ||
964 | rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_INTERVAL, | ||
965 | libconf->conf->beacon_int * 16); | ||
966 | rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||
967 | } | ||
968 | |||
969 | static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, | 963 | static void rt2800usb_config_ps(struct rt2x00_dev *rt2x00dev, |
970 | struct rt2x00lib_conf *libconf) | 964 | struct rt2x00lib_conf *libconf) |
971 | { | 965 | { |
@@ -1010,8 +1004,6 @@ static void rt2800usb_config(struct rt2x00_dev *rt2x00dev, | |||
1010 | rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); | 1004 | rt2800usb_config_txpower(rt2x00dev, libconf->conf->power_level); |
1011 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 1005 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
1012 | rt2800usb_config_retry_limit(rt2x00dev, libconf); | 1006 | rt2800usb_config_retry_limit(rt2x00dev, libconf); |
1013 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
1014 | rt2800usb_config_duration(rt2x00dev, libconf); | ||
1015 | if (flags & IEEE80211_CONF_CHANGE_PS) | 1007 | if (flags & IEEE80211_CONF_CHANGE_PS) |
1016 | rt2800usb_config_ps(rt2x00dev, libconf); | 1008 | rt2800usb_config_ps(rt2x00dev, libconf); |
1017 | } | 1009 | } |
@@ -2881,8 +2873,6 @@ static const struct rt2x00_ops rt2800usb_ops = { | |||
2881 | * rt2800usb module information. | 2873 | * rt2800usb module information. |
2882 | */ | 2874 | */ |
2883 | static struct usb_device_id rt2800usb_device_table[] = { | 2875 | static struct usb_device_id rt2800usb_device_table[] = { |
2884 | /* ??? */ | ||
2885 | { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2886 | /* Abocom */ | 2876 | /* Abocom */ |
2887 | { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2877 | { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2888 | { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2878 | { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -2912,6 +2902,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
2912 | { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2902 | { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2913 | { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2903 | { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2914 | { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2904 | { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2905 | { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
2915 | /* Buffalo */ | 2906 | /* Buffalo */ |
2916 | { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2907 | { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, |
2917 | { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, | 2908 | { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) }, |
@@ -3026,6 +3017,10 @@ static struct usb_device_id rt2800usb_device_table[] = { | |||
3026 | { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3017 | { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3027 | /* Sparklan */ | 3018 | /* Sparklan */ |
3028 | { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3019 | { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3020 | /* Sweex */ | ||
3021 | { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3022 | { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3023 | { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||
3029 | /* U-Media*/ | 3024 | /* U-Media*/ |
3030 | { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, | 3025 | { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) }, |
3031 | /* ZCOM */ | 3026 | /* ZCOM */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 419b1b9f998e..2b64a6198698 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -417,6 +417,8 @@ struct rt2x00lib_erp { | |||
417 | short pifs; | 417 | short pifs; |
418 | short difs; | 418 | short difs; |
419 | short eifs; | 419 | short eifs; |
420 | |||
421 | u16 beacon_int; | ||
420 | }; | 422 | }; |
421 | 423 | ||
422 | /* | 424 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 863e399d4fa6..c5bbf0b6e207 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -106,6 +106,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, | |||
106 | } | 106 | } |
107 | 107 | ||
108 | erp.basic_rates = bss_conf->basic_rates; | 108 | erp.basic_rates = bss_conf->basic_rates; |
109 | erp.beacon_int = bss_conf->beacon_int; | ||
109 | 110 | ||
110 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); | 111 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); |
111 | } | 112 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 57ab42cfed34..bc4e81e21841 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c | |||
@@ -33,7 +33,7 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) | |||
33 | { | 33 | { |
34 | switch (key->alg) { | 34 | switch (key->alg) { |
35 | case ALG_WEP: | 35 | case ALG_WEP: |
36 | if (key->keylen == LEN_WEP40) | 36 | if (key->keylen == WLAN_KEY_LEN_WEP40) |
37 | return CIPHER_WEP64; | 37 | return CIPHER_WEP64; |
38 | else | 38 | else |
39 | return CIPHER_WEP128; | 39 | return CIPHER_WEP128; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index f2270845072a..57813e72c808 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -260,7 +260,8 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
260 | * Update TX statistics. | 260 | * Update TX statistics. |
261 | */ | 261 | */ |
262 | rt2x00dev->link.qual.tx_success += | 262 | rt2x00dev->link.qual.tx_success += |
263 | test_bit(TXDONE_SUCCESS, &txdesc->flags); | 263 | test_bit(TXDONE_SUCCESS, &txdesc->flags) || |
264 | test_bit(TXDONE_UNKNOWN, &txdesc->flags); | ||
264 | rt2x00dev->link.qual.tx_failed += | 265 | rt2x00dev->link.qual.tx_failed += |
265 | test_bit(TXDONE_FAILURE, &txdesc->flags); | 266 | test_bit(TXDONE_FAILURE, &txdesc->flags); |
266 | 267 | ||
@@ -278,14 +279,16 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
278 | tx_info->status.rates[1].idx = -1; /* terminate */ | 279 | tx_info->status.rates[1].idx = -1; /* terminate */ |
279 | 280 | ||
280 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { | 281 | if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { |
281 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) | 282 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || |
283 | test_bit(TXDONE_UNKNOWN, &txdesc->flags)) | ||
282 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | 284 | tx_info->flags |= IEEE80211_TX_STAT_ACK; |
283 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) | 285 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) |
284 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; | 286 | rt2x00dev->low_level_stats.dot11ACKFailureCount++; |
285 | } | 287 | } |
286 | 288 | ||
287 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | 289 | if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { |
288 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) | 290 | if (test_bit(TXDONE_SUCCESS, &txdesc->flags) || |
291 | test_bit(TXDONE_UNKNOWN, &txdesc->flags)) | ||
289 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; | 292 | rt2x00dev->low_level_stats.dot11RTSSuccessCount++; |
290 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) | 293 | else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) |
291 | rt2x00dev->low_level_stats.dot11RTSFailureCount++; | 294 | rt2x00dev->low_level_stats.dot11RTSFailureCount++; |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index cb521ee7a8f0..a8bf5c432858 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -603,15 +603,22 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, | |||
603 | 603 | ||
604 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); | 604 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); |
605 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); | 605 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); |
606 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | ||
606 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); | 607 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); |
607 | 608 | ||
608 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); | 609 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); |
610 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); | ||
609 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, | 611 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, |
610 | !!erp->short_preamble); | 612 | !!erp->short_preamble); |
611 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); | 613 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); |
612 | 614 | ||
613 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); | 615 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); |
614 | 616 | ||
617 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); | ||
618 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, | ||
619 | erp->beacon_int * 16); | ||
620 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); | ||
621 | |||
615 | rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); | 622 | rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); |
616 | rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); | 623 | rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); |
617 | rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); | 624 | rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); |
@@ -938,25 +945,6 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, | |||
938 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); | 945 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); |
939 | } | 946 | } |
940 | 947 | ||
941 | static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, | ||
942 | struct rt2x00lib_conf *libconf) | ||
943 | { | ||
944 | u32 reg; | ||
945 | |||
946 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); | ||
947 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | ||
948 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); | ||
949 | |||
950 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); | ||
951 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); | ||
952 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); | ||
953 | |||
954 | rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); | ||
955 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, | ||
956 | libconf->conf->beacon_int * 16); | ||
957 | rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); | ||
958 | } | ||
959 | |||
960 | static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, | 948 | static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev, |
961 | struct rt2x00lib_conf *libconf) | 949 | struct rt2x00lib_conf *libconf) |
962 | { | 950 | { |
@@ -1016,8 +1004,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, | |||
1016 | rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); | 1004 | rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); |
1017 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 1005 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
1018 | rt61pci_config_retry_limit(rt2x00dev, libconf); | 1006 | rt61pci_config_retry_limit(rt2x00dev, libconf); |
1019 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
1020 | rt61pci_config_duration(rt2x00dev, libconf); | ||
1021 | if (flags & IEEE80211_CONF_CHANGE_PS) | 1007 | if (flags & IEEE80211_CONF_CHANGE_PS) |
1022 | rt61pci_config_ps(rt2x00dev, libconf); | 1008 | rt61pci_config_ps(rt2x00dev, libconf); |
1023 | } | 1009 | } |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 270dd4e59f7f..211a3d6bc054 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -566,15 +566,22 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, | |||
566 | 566 | ||
567 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); | 567 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); |
568 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); | 568 | rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); |
569 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | ||
569 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); | 570 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); |
570 | 571 | ||
571 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); | 572 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); |
573 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); | ||
572 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, | 574 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, |
573 | !!erp->short_preamble); | 575 | !!erp->short_preamble); |
574 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); | 576 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); |
575 | 577 | ||
576 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); | 578 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); |
577 | 579 | ||
580 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); | ||
581 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, | ||
582 | erp->beacon_int * 16); | ||
583 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); | ||
584 | |||
578 | rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); | 585 | rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); |
579 | rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); | 586 | rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); |
580 | rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); | 587 | rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); |
@@ -834,25 +841,6 @@ static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, | |||
834 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); | 841 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); |
835 | } | 842 | } |
836 | 843 | ||
837 | static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, | ||
838 | struct rt2x00lib_conf *libconf) | ||
839 | { | ||
840 | u32 reg; | ||
841 | |||
842 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); | ||
843 | rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); | ||
844 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); | ||
845 | |||
846 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); | ||
847 | rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); | ||
848 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); | ||
849 | |||
850 | rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); | ||
851 | rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, | ||
852 | libconf->conf->beacon_int * 16); | ||
853 | rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); | ||
854 | } | ||
855 | |||
856 | static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, | 844 | static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev, |
857 | struct rt2x00lib_conf *libconf) | 845 | struct rt2x00lib_conf *libconf) |
858 | { | 846 | { |
@@ -906,8 +894,6 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, | |||
906 | rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); | 894 | rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); |
907 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) | 895 | if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) |
908 | rt73usb_config_retry_limit(rt2x00dev, libconf); | 896 | rt73usb_config_retry_limit(rt2x00dev, libconf); |
909 | if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) | ||
910 | rt73usb_config_duration(rt2x00dev, libconf); | ||
911 | if (flags & IEEE80211_CONF_CHANGE_PS) | 897 | if (flags & IEEE80211_CONF_CHANGE_PS) |
912 | rt73usb_config_ps(rt2x00dev, libconf); | 898 | rt73usb_config_ps(rt2x00dev, libconf); |
913 | } | 899 | } |
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index f95204632690..b7b0c46adb46 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c | |||
@@ -2509,7 +2509,7 @@ static void strip_dev_setup(struct net_device *dev) | |||
2509 | * netdev_priv(dev) Already holds a pointer to our struct strip | 2509 | * netdev_priv(dev) Already holds a pointer to our struct strip |
2510 | */ | 2510 | */ |
2511 | 2511 | ||
2512 | *(MetricomAddress *) & dev->broadcast = broadcast_address; | 2512 | *(MetricomAddress *)dev->broadcast = broadcast_address; |
2513 | dev->dev_addr[0] = 0; | 2513 | dev->dev_addr[0] = 0; |
2514 | dev->addr_len = sizeof(MetricomAddress); | 2514 | dev->addr_len = sizeof(MetricomAddress); |
2515 | 2515 | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6bdb1704083b..40b07b988224 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -420,9 +420,9 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, | |||
420 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) | 420 | if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) |
421 | cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; | 421 | cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; |
422 | 422 | ||
423 | /* Multicast */ | 423 | /* No ACK expected (multicast, etc.) */ |
424 | if (is_multicast_ether_addr(header->addr1)) | 424 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) |
425 | cs->control |= ZD_CS_MULTICAST; | 425 | cs->control |= ZD_CS_NO_ACK; |
426 | 426 | ||
427 | /* PS-POLL */ | 427 | /* PS-POLL */ |
428 | if (ieee80211_is_pspoll(header->frame_control)) | 428 | if (ieee80211_is_pspoll(header->frame_control)) |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 4c05d3ee4c37..7c2759118d13 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h | |||
@@ -87,7 +87,7 @@ struct zd_ctrlset { | |||
87 | 87 | ||
88 | /* zd_ctrlset control field */ | 88 | /* zd_ctrlset control field */ |
89 | #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 | 89 | #define ZD_CS_NEED_RANDOM_BACKOFF 0x01 |
90 | #define ZD_CS_MULTICAST 0x02 | 90 | #define ZD_CS_NO_ACK 0x02 |
91 | 91 | ||
92 | #define ZD_CS_FRAME_TYPE_MASK 0x0c | 92 | #define ZD_CS_FRAME_TYPE_MASK 0x0c |
93 | #define ZD_CS_DATA_FRAME 0x00 | 93 | #define ZD_CS_DATA_FRAME 0x00 |
diff --git a/drivers/staging/agnx/pci.c b/drivers/staging/agnx/pci.c index 25c0ffd2faa0..43b3fe352616 100644 --- a/drivers/staging/agnx/pci.c +++ b/drivers/staging/agnx/pci.c | |||
@@ -303,14 +303,18 @@ static int agnx_config(struct ieee80211_hw *dev, u32 changed) | |||
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
305 | 305 | ||
306 | static int agnx_config_interface(struct ieee80211_hw *dev, | 306 | static void agnx_bss_info_changed(struct ieee80211_hw *dev, |
307 | struct ieee80211_vif *vif, | 307 | struct ieee80211_vif *vif, |
308 | struct ieee80211_if_conf *conf) | 308 | struct ieee80211_bss_conf *conf, |
309 | u32 changed) | ||
309 | { | 310 | { |
310 | struct agnx_priv *priv = dev->priv; | 311 | struct agnx_priv *priv = dev->priv; |
311 | void __iomem *ctl = priv->ctl; | 312 | void __iomem *ctl = priv->ctl; |
312 | AGNX_TRACE; | 313 | AGNX_TRACE; |
313 | 314 | ||
315 | if (!(changed & BSS_CHANGED_BSSID)) | ||
316 | return; | ||
317 | |||
314 | spin_lock(&priv->lock); | 318 | spin_lock(&priv->lock); |
315 | 319 | ||
316 | if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { | 320 | if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) { |
@@ -323,8 +327,7 @@ static int agnx_config_interface(struct ieee80211_hw *dev, | |||
323 | agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1); | 327 | agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1); |
324 | } | 328 | } |
325 | spin_unlock(&priv->lock); | 329 | spin_unlock(&priv->lock); |
326 | return 0; | 330 | } /* agnx_bss_info_changed */ |
327 | } /* agnx_config_interface */ | ||
328 | 331 | ||
329 | 332 | ||
330 | static void agnx_configure_filter(struct ieee80211_hw *dev, | 333 | static void agnx_configure_filter(struct ieee80211_hw *dev, |
@@ -422,7 +425,7 @@ static struct ieee80211_ops agnx_ops = { | |||
422 | .add_interface = agnx_add_interface, | 425 | .add_interface = agnx_add_interface, |
423 | .remove_interface = agnx_remove_interface, | 426 | .remove_interface = agnx_remove_interface, |
424 | .config = agnx_config, | 427 | .config = agnx_config, |
425 | .config_interface = agnx_config_interface, | 428 | .bss_info_changed = agnx_bss_info_changed, |
426 | .configure_filter = agnx_configure_filter, | 429 | .configure_filter = agnx_configure_filter, |
427 | .get_stats = agnx_get_stats, | 430 | .get_stats = agnx_get_stats, |
428 | .get_tx_stats = agnx_get_tx_stats, | 431 | .get_tx_stats = agnx_get_tx_stats, |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 05c29c01174c..34de8b21f6d4 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -493,6 +493,7 @@ struct ieee80211s_hdr { | |||
493 | /* Mesh flags */ | 493 | /* Mesh flags */ |
494 | #define MESH_FLAGS_AE_A4 0x1 | 494 | #define MESH_FLAGS_AE_A4 0x1 |
495 | #define MESH_FLAGS_AE_A5_A6 0x2 | 495 | #define MESH_FLAGS_AE_A5_A6 0x2 |
496 | #define MESH_FLAGS_AE 0x3 | ||
496 | #define MESH_FLAGS_PS_DEEP 0x4 | 497 | #define MESH_FLAGS_PS_DEEP 0x4 |
497 | 498 | ||
498 | /** | 499 | /** |
@@ -1085,6 +1086,14 @@ enum ieee80211_spectrum_mgmt_actioncode { | |||
1085 | WLAN_ACTION_SPCT_CHL_SWITCH = 4, | 1086 | WLAN_ACTION_SPCT_CHL_SWITCH = 4, |
1086 | }; | 1087 | }; |
1087 | 1088 | ||
1089 | /* Security key length */ | ||
1090 | enum ieee80211_key_len { | ||
1091 | WLAN_KEY_LEN_WEP40 = 5, | ||
1092 | WLAN_KEY_LEN_WEP104 = 13, | ||
1093 | WLAN_KEY_LEN_CCMP = 16, | ||
1094 | WLAN_KEY_LEN_TKIP = 32, | ||
1095 | }; | ||
1096 | |||
1088 | /* | 1097 | /* |
1089 | * IEEE 802.11-2007 7.3.2.9 Country information element | 1098 | * IEEE 802.11-2007 7.3.2.9 Country information element |
1090 | * | 1099 | * |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9e17a83d3432..f20da7d63b1e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -56,9 +56,9 @@ enum ieee80211_band { | |||
56 | * on this channel. | 56 | * on this channel. |
57 | * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. | 57 | * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. |
58 | * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. | 58 | * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. |
59 | * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel | 59 | * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel |
60 | * is not permitted. | 60 | * is not permitted. |
61 | * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel | 61 | * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel |
62 | * is not permitted. | 62 | * is not permitted. |
63 | */ | 63 | */ |
64 | enum ieee80211_channel_flags { | 64 | enum ieee80211_channel_flags { |
@@ -66,10 +66,13 @@ enum ieee80211_channel_flags { | |||
66 | IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, | 66 | IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, |
67 | IEEE80211_CHAN_NO_IBSS = 1<<2, | 67 | IEEE80211_CHAN_NO_IBSS = 1<<2, |
68 | IEEE80211_CHAN_RADAR = 1<<3, | 68 | IEEE80211_CHAN_RADAR = 1<<3, |
69 | IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4, | 69 | IEEE80211_CHAN_NO_HT40PLUS = 1<<4, |
70 | IEEE80211_CHAN_NO_FAT_BELOW = 1<<5, | 70 | IEEE80211_CHAN_NO_HT40MINUS = 1<<5, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | #define IEEE80211_CHAN_NO_HT40 \ | ||
74 | (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) | ||
75 | |||
73 | /** | 76 | /** |
74 | * struct ieee80211_channel - channel definition | 77 | * struct ieee80211_channel - channel definition |
75 | * | 78 | * |
@@ -778,10 +781,11 @@ enum wiphy_params_flags { | |||
778 | * @get_key: get information about the key with the given parameters. | 781 | * @get_key: get information about the key with the given parameters. |
779 | * @mac_addr will be %NULL when requesting information for a group | 782 | * @mac_addr will be %NULL when requesting information for a group |
780 | * key. All pointers given to the @callback function need not be valid | 783 | * key. All pointers given to the @callback function need not be valid |
781 | * after it returns. | 784 | * after it returns. This function should return an error if it is |
785 | * not possible to retrieve the key, -ENOENT if it doesn't exist. | ||
782 | * | 786 | * |
783 | * @del_key: remove a key given the @mac_addr (%NULL for a group key) | 787 | * @del_key: remove a key given the @mac_addr (%NULL for a group key) |
784 | * and @key_index | 788 | * and @key_index, return -ENOENT if the key doesn't exist. |
785 | * | 789 | * |
786 | * @set_default_key: set the default key on an interface | 790 | * @set_default_key: set the default key on an interface |
787 | * | 791 | * |
@@ -994,7 +998,7 @@ struct wiphy { | |||
994 | * know whether it points to a wiphy your driver has registered | 998 | * know whether it points to a wiphy your driver has registered |
995 | * or not. Assign this to something global to your driver to | 999 | * or not. Assign this to something global to your driver to |
996 | * help determine whether you own this wiphy or not. */ | 1000 | * help determine whether you own this wiphy or not. */ |
997 | void *privid; | 1001 | const void *privid; |
998 | 1002 | ||
999 | struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; | 1003 | struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; |
1000 | 1004 | ||
@@ -1070,7 +1074,7 @@ static inline const char *wiphy_name(struct wiphy *wiphy) | |||
1070 | * The returned pointer must be assigned to each netdev's | 1074 | * The returned pointer must be assigned to each netdev's |
1071 | * ieee80211_ptr for proper operation. | 1075 | * ieee80211_ptr for proper operation. |
1072 | */ | 1076 | */ |
1073 | struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv); | 1077 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv); |
1074 | 1078 | ||
1075 | /** | 1079 | /** |
1076 | * wiphy_register - register a wiphy with cfg80211 | 1080 | * wiphy_register - register a wiphy with cfg80211 |
@@ -1240,6 +1244,53 @@ extern int ieee80211_radiotap_iterator_init( | |||
1240 | extern int ieee80211_radiotap_iterator_next( | 1244 | extern int ieee80211_radiotap_iterator_next( |
1241 | struct ieee80211_radiotap_iterator *iterator); | 1245 | struct ieee80211_radiotap_iterator *iterator); |
1242 | 1246 | ||
1247 | extern const unsigned char rfc1042_header[6]; | ||
1248 | extern const unsigned char bridge_tunnel_header[6]; | ||
1249 | |||
1250 | /** | ||
1251 | * ieee80211_get_hdrlen_from_skb - get header length from data | ||
1252 | * | ||
1253 | * Given an skb with a raw 802.11 header at the data pointer this function | ||
1254 | * returns the 802.11 header length in bytes (not including encryption | ||
1255 | * headers). If the data in the sk_buff is too short to contain a valid 802.11 | ||
1256 | * header the function returns 0. | ||
1257 | * | ||
1258 | * @skb: the frame | ||
1259 | */ | ||
1260 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); | ||
1261 | |||
1262 | /** | ||
1263 | * ieee80211_hdrlen - get header length in bytes from frame control | ||
1264 | * @fc: frame control field in little-endian format | ||
1265 | */ | ||
1266 | unsigned int ieee80211_hdrlen(__le16 fc); | ||
1267 | |||
1268 | /** | ||
1269 | * ieee80211_data_to_8023 - convert an 802.11 data frame to 802.3 | ||
1270 | * @skb: the 802.11 data frame | ||
1271 | * @addr: the device MAC address | ||
1272 | * @iftype: the virtual interface type | ||
1273 | */ | ||
1274 | int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | ||
1275 | enum nl80211_iftype iftype); | ||
1276 | |||
1277 | /** | ||
1278 | * ieee80211_data_from_8023 - convert an 802.3 frame to 802.11 | ||
1279 | * @skb: the 802.3 frame | ||
1280 | * @addr: the device MAC address | ||
1281 | * @iftype: the virtual interface type | ||
1282 | * @bssid: the network bssid (used only for iftype STATION and ADHOC) | ||
1283 | * @qos: build 802.11 QoS data frame | ||
1284 | */ | ||
1285 | int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, | ||
1286 | enum nl80211_iftype iftype, u8 *bssid, bool qos); | ||
1287 | |||
1288 | /** | ||
1289 | * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame | ||
1290 | * @skb: the data frame | ||
1291 | */ | ||
1292 | unsigned int cfg80211_classify8021d(struct sk_buff *skb); | ||
1293 | |||
1243 | /* | 1294 | /* |
1244 | * Regulatory helper functions for wiphys | 1295 | * Regulatory helper functions for wiphys |
1245 | */ | 1296 | */ |
@@ -1303,9 +1354,10 @@ extern void wiphy_apply_custom_regulatory( | |||
1303 | * freq_reg_info - get regulatory information for the given frequency | 1354 | * freq_reg_info - get regulatory information for the given frequency |
1304 | * @wiphy: the wiphy for which we want to process this rule for | 1355 | * @wiphy: the wiphy for which we want to process this rule for |
1305 | * @center_freq: Frequency in KHz for which we want regulatory information for | 1356 | * @center_freq: Frequency in KHz for which we want regulatory information for |
1306 | * @bandwidth: the bandwidth requirement you have in KHz, if you do not have one | 1357 | * @desired_bw_khz: the desired max bandwidth you want to use per |
1307 | * you can set this to 0. If this frequency is allowed we then set | 1358 | * channel. Note that this is still 20 MHz if you want to use HT40 |
1308 | * this value to the maximum allowed bandwidth. | 1359 | * as HT40 makes use of two channels for its 40 MHz width bandwidth. |
1360 | * If set to 0 we'll assume you want the standard 20 MHz. | ||
1309 | * @reg_rule: the regulatory rule which we have for this frequency | 1361 | * @reg_rule: the regulatory rule which we have for this frequency |
1310 | * | 1362 | * |
1311 | * Use this function to get the regulatory rule for a specific frequency on | 1363 | * Use this function to get the regulatory rule for a specific frequency on |
@@ -1320,7 +1372,9 @@ extern void wiphy_apply_custom_regulatory( | |||
1320 | * freq_in_rule_band() for our current definition of a band -- this is purely | 1372 | * freq_in_rule_band() for our current definition of a band -- this is purely |
1321 | * subjective and right now its 802.11 specific. | 1373 | * subjective and right now its 802.11 specific. |
1322 | */ | 1374 | */ |
1323 | extern int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, | 1375 | extern int freq_reg_info(struct wiphy *wiphy, |
1376 | u32 center_freq, | ||
1377 | u32 desired_bw_khz, | ||
1324 | const struct ieee80211_reg_rule **reg_rule); | 1378 | const struct ieee80211_reg_rule **reg_rule); |
1325 | 1379 | ||
1326 | /* | 1380 | /* |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d10ed1776fcd..d72346ff3247 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -173,7 +173,6 @@ enum ieee80211_bss_change { | |||
173 | * @timestamp: beacon timestamp | 173 | * @timestamp: beacon timestamp |
174 | * @beacon_int: beacon interval | 174 | * @beacon_int: beacon interval |
175 | * @assoc_capability: capabilities taken from assoc resp | 175 | * @assoc_capability: capabilities taken from assoc resp |
176 | * @ht: BSS's HT configuration | ||
177 | * @basic_rates: bitmap of basic rates, each bit stands for an | 176 | * @basic_rates: bitmap of basic rates, each bit stands for an |
178 | * index into the rate table configured by the driver in | 177 | * index into the rate table configured by the driver in |
179 | * the current band. | 178 | * the current band. |
@@ -673,16 +672,6 @@ enum ieee80211_key_alg { | |||
673 | }; | 672 | }; |
674 | 673 | ||
675 | /** | 674 | /** |
676 | * enum ieee80211_key_len - key length | ||
677 | * @LEN_WEP40: WEP 5-byte long key | ||
678 | * @LEN_WEP104: WEP 13-byte long key | ||
679 | */ | ||
680 | enum ieee80211_key_len { | ||
681 | LEN_WEP40 = 5, | ||
682 | LEN_WEP104 = 13, | ||
683 | }; | ||
684 | |||
685 | /** | ||
686 | * enum ieee80211_key_flags - key flags | 675 | * enum ieee80211_key_flags - key flags |
687 | * | 676 | * |
688 | * These flags are used for communication about keys between the driver | 677 | * These flags are used for communication about keys between the driver |
@@ -1813,24 +1802,6 @@ struct sk_buff * | |||
1813 | ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | 1802 | ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); |
1814 | 1803 | ||
1815 | /** | 1804 | /** |
1816 | * ieee80211_get_hdrlen_from_skb - get header length from data | ||
1817 | * | ||
1818 | * Given an skb with a raw 802.11 header at the data pointer this function | ||
1819 | * returns the 802.11 header length in bytes (not including encryption | ||
1820 | * headers). If the data in the sk_buff is too short to contain a valid 802.11 | ||
1821 | * header the function returns 0. | ||
1822 | * | ||
1823 | * @skb: the frame | ||
1824 | */ | ||
1825 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); | ||
1826 | |||
1827 | /** | ||
1828 | * ieee80211_hdrlen - get header length in bytes from frame control | ||
1829 | * @fc: frame control field in little-endian format | ||
1830 | */ | ||
1831 | unsigned int ieee80211_hdrlen(__le16 fc); | ||
1832 | |||
1833 | /** | ||
1834 | * ieee80211_get_tkip_key - get a TKIP rc4 for skb | 1805 | * ieee80211_get_tkip_key - get a TKIP rc4 for skb |
1835 | * | 1806 | * |
1836 | * This function computes a TKIP rc4 key for an skb. It computes | 1807 | * This function computes a TKIP rc4 key for an skb. It computes |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e7682fe1c590..11c72311f35b 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -52,14 +52,6 @@ static const struct file_operations name## _ops = { \ | |||
52 | 52 | ||
53 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", | 53 | DEBUGFS_READONLY_FILE(frequency, 20, "%d", |
54 | local->hw.conf.channel->center_freq); | 54 | local->hw.conf.channel->center_freq); |
55 | DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", | ||
56 | local->hw.wiphy->rts_threshold); | ||
57 | DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", | ||
58 | local->hw.wiphy->frag_threshold); | ||
59 | DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", | ||
60 | local->hw.wiphy->retry_short); | ||
61 | DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", | ||
62 | local->hw.wiphy->retry_long); | ||
63 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", | 55 | DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", |
64 | local->total_ps_buffered); | 56 | local->total_ps_buffered); |
65 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", | 57 | DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", |
@@ -303,10 +295,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
303 | local->debugfs.keys = debugfs_create_dir("keys", phyd); | 295 | local->debugfs.keys = debugfs_create_dir("keys", phyd); |
304 | 296 | ||
305 | DEBUGFS_ADD(frequency); | 297 | DEBUGFS_ADD(frequency); |
306 | DEBUGFS_ADD(rts_threshold); | ||
307 | DEBUGFS_ADD(fragmentation_threshold); | ||
308 | DEBUGFS_ADD(short_retry_limit); | ||
309 | DEBUGFS_ADD(long_retry_limit); | ||
310 | DEBUGFS_ADD(total_ps_buffered); | 298 | DEBUGFS_ADD(total_ps_buffered); |
311 | DEBUGFS_ADD(wep_iv); | 299 | DEBUGFS_ADD(wep_iv); |
312 | DEBUGFS_ADD(tsf); | 300 | DEBUGFS_ADD(tsf); |
@@ -359,10 +347,6 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
359 | void debugfs_hw_del(struct ieee80211_local *local) | 347 | void debugfs_hw_del(struct ieee80211_local *local) |
360 | { | 348 | { |
361 | DEBUGFS_DEL(frequency); | 349 | DEBUGFS_DEL(frequency); |
362 | DEBUGFS_DEL(rts_threshold); | ||
363 | DEBUGFS_DEL(fragmentation_threshold); | ||
364 | DEBUGFS_DEL(short_retry_limit); | ||
365 | DEBUGFS_DEL(long_retry_limit); | ||
366 | DEBUGFS_DEL(total_ps_buffered); | 350 | DEBUGFS_DEL(total_ps_buffered); |
367 | DEBUGFS_DEL(wep_iv); | 351 | DEBUGFS_DEL(wep_iv); |
368 | DEBUGFS_DEL(tsf); | 352 | DEBUGFS_DEL(tsf); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index c236079ed38a..0b30277eb366 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -535,9 +535,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
535 | bssid = ifibss->bssid; | 535 | bssid = ifibss->bssid; |
536 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, | 536 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, |
537 | ifibss->ssid, ifibss->ssid_len, | 537 | ifibss->ssid, ifibss->ssid_len, |
538 | capability, | ||
539 | WLAN_CAPABILITY_IBSS | | 538 | WLAN_CAPABILITY_IBSS | |
540 | WLAN_CAPABILITY_PRIVACY); | 539 | WLAN_CAPABILITY_PRIVACY, |
540 | capability); | ||
541 | 541 | ||
542 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 542 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
543 | if (bss) | 543 | if (bss) |
@@ -737,6 +737,9 @@ static void ieee80211_ibss_work(struct work_struct *work) | |||
737 | struct ieee80211_if_ibss *ifibss; | 737 | struct ieee80211_if_ibss *ifibss; |
738 | struct sk_buff *skb; | 738 | struct sk_buff *skb; |
739 | 739 | ||
740 | if (WARN_ON(local->suspended)) | ||
741 | return; | ||
742 | |||
740 | if (!netif_running(sdata->dev)) | 743 | if (!netif_running(sdata->dev)) |
741 | return; | 744 | return; |
742 | 745 | ||
@@ -773,10 +776,36 @@ static void ieee80211_ibss_timer(unsigned long data) | |||
773 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 776 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
774 | struct ieee80211_local *local = sdata->local; | 777 | struct ieee80211_local *local = sdata->local; |
775 | 778 | ||
779 | if (local->quiescing) { | ||
780 | ifibss->timer_running = true; | ||
781 | return; | ||
782 | } | ||
783 | |||
776 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | 784 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); |
777 | queue_work(local->hw.workqueue, &ifibss->work); | 785 | queue_work(local->hw.workqueue, &ifibss->work); |
778 | } | 786 | } |
779 | 787 | ||
788 | #ifdef CONFIG_PM | ||
789 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata) | ||
790 | { | ||
791 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
792 | |||
793 | cancel_work_sync(&ifibss->work); | ||
794 | if (del_timer_sync(&ifibss->timer)) | ||
795 | ifibss->timer_running = true; | ||
796 | } | ||
797 | |||
798 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata) | ||
799 | { | ||
800 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
801 | |||
802 | if (ifibss->timer_running) { | ||
803 | add_timer(&ifibss->timer); | ||
804 | ifibss->timer_running = false; | ||
805 | } | ||
806 | } | ||
807 | #endif | ||
808 | |||
780 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | 809 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) |
781 | { | 810 | { |
782 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 811 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9d1514727f6e..c088c46704a3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -293,6 +293,7 @@ struct ieee80211_if_managed { | |||
293 | int auth_tries; /* retries for auth req */ | 293 | int auth_tries; /* retries for auth req */ |
294 | int assoc_tries; /* retries for assoc req */ | 294 | int assoc_tries; /* retries for assoc req */ |
295 | 295 | ||
296 | unsigned long timers_running; /* used for quiesce/restart */ | ||
296 | bool powersave; /* powersave requested for this iface */ | 297 | bool powersave; /* powersave requested for this iface */ |
297 | 298 | ||
298 | unsigned long request; | 299 | unsigned long request; |
@@ -333,6 +334,9 @@ struct ieee80211_if_ibss { | |||
333 | 334 | ||
334 | unsigned long request; | 335 | unsigned long request; |
335 | unsigned long last_scan_completed; | 336 | unsigned long last_scan_completed; |
337 | |||
338 | bool timer_running; | ||
339 | |||
336 | bool fixed_bssid; | 340 | bool fixed_bssid; |
337 | bool fixed_channel; | 341 | bool fixed_channel; |
338 | 342 | ||
@@ -358,6 +362,8 @@ struct ieee80211_if_mesh { | |||
358 | struct timer_list mesh_path_timer; | 362 | struct timer_list mesh_path_timer; |
359 | struct sk_buff_head skb_queue; | 363 | struct sk_buff_head skb_queue; |
360 | 364 | ||
365 | unsigned long timers_running; | ||
366 | |||
361 | bool housekeeping; | 367 | bool housekeeping; |
362 | 368 | ||
363 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 369 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
@@ -609,6 +615,21 @@ struct ieee80211_local { | |||
609 | unsigned int filter_flags; /* FIF_* */ | 615 | unsigned int filter_flags; /* FIF_* */ |
610 | struct iw_statistics wstats; | 616 | struct iw_statistics wstats; |
611 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ | 617 | bool tim_in_locked_section; /* see ieee80211_beacon_get() */ |
618 | |||
619 | /* | ||
620 | * suspended is true if we finished all the suspend _and_ we have | ||
621 | * not yet come up from resume. This is to be used by mac80211 | ||
622 | * to ensure driver sanity during suspend and mac80211's own | ||
623 | * sanity. It can eventually be used for WoW as well. | ||
624 | */ | ||
625 | bool suspended; | ||
626 | |||
627 | /* | ||
628 | * quiescing is true during the suspend process _only_ to | ||
629 | * ease timer cancelling etc. | ||
630 | */ | ||
631 | bool quiescing; | ||
632 | |||
612 | int tx_headroom; /* required headroom for hardware/radiotap */ | 633 | int tx_headroom; /* required headroom for hardware/radiotap */ |
613 | 634 | ||
614 | /* Tasklet and skb queue to process calls from IRQ mode. All frames | 635 | /* Tasklet and skb queue to process calls from IRQ mode. All frames |
@@ -758,10 +779,6 @@ struct ieee80211_local { | |||
758 | struct dentry *rcdir; | 779 | struct dentry *rcdir; |
759 | struct dentry *rcname; | 780 | struct dentry *rcname; |
760 | struct dentry *frequency; | 781 | struct dentry *frequency; |
761 | struct dentry *rts_threshold; | ||
762 | struct dentry *fragmentation_threshold; | ||
763 | struct dentry *short_retry_limit; | ||
764 | struct dentry *long_retry_limit; | ||
765 | struct dentry *total_ps_buffered; | 782 | struct dentry *total_ps_buffered; |
766 | struct dentry *wep_iv; | 783 | struct dentry *wep_iv; |
767 | struct dentry *tsf; | 784 | struct dentry *tsf; |
@@ -938,6 +955,11 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, | |||
938 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); | 955 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); |
939 | int ieee80211_max_network_latency(struct notifier_block *nb, | 956 | int ieee80211_max_network_latency(struct notifier_block *nb, |
940 | unsigned long data, void *dummy); | 957 | unsigned long data, void *dummy); |
958 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
959 | struct ieee80211_channel_sw_ie *sw_elem, | ||
960 | struct ieee80211_bss *bss); | ||
961 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | ||
962 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | ||
941 | 963 | ||
942 | /* IBSS code */ | 964 | /* IBSS code */ |
943 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 965 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -950,6 +972,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
950 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 972 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
951 | struct cfg80211_ibss_params *params); | 973 | struct cfg80211_ibss_params *params); |
952 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 974 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
975 | void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata); | ||
976 | void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata); | ||
953 | 977 | ||
954 | /* scan/BSS handling */ | 978 | /* scan/BSS handling */ |
955 | void ieee80211_scan_work(struct work_struct *work); | 979 | void ieee80211_scan_work(struct work_struct *work); |
@@ -960,6 +984,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
960 | int ieee80211_scan_results(struct ieee80211_local *local, | 984 | int ieee80211_scan_results(struct ieee80211_local *local, |
961 | struct iw_request_info *info, | 985 | struct iw_request_info *info, |
962 | char *buf, size_t len); | 986 | char *buf, size_t len); |
987 | void ieee80211_scan_cancel(struct ieee80211_local *local); | ||
963 | ieee80211_rx_result | 988 | ieee80211_rx_result |
964 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, | 989 | ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, |
965 | struct sk_buff *skb, | 990 | struct sk_buff *skb, |
@@ -1035,14 +1060,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
1035 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1060 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
1036 | struct ieee80211_mgmt *mgmt, | 1061 | struct ieee80211_mgmt *mgmt, |
1037 | size_t len); | 1062 | size_t len); |
1038 | void ieee80211_chswitch_timer(unsigned long data); | ||
1039 | void ieee80211_chswitch_work(struct work_struct *work); | ||
1040 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
1041 | struct ieee80211_channel_sw_ie *sw_elem, | ||
1042 | struct ieee80211_bss *bss); | ||
1043 | void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
1044 | u16 capab_info, u8 *pwr_constr_elem, | ||
1045 | u8 pwr_constr_elem_len); | ||
1046 | 1063 | ||
1047 | /* Suspend/resume and hw reconfiguration */ | 1064 | /* Suspend/resume and hw reconfiguration */ |
1048 | int ieee80211_reconfig(struct ieee80211_local *local); | 1065 | int ieee80211_reconfig(struct ieee80211_local *local); |
@@ -1068,8 +1085,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) | |||
1068 | 1085 | ||
1069 | /* utility functions/constants */ | 1086 | /* utility functions/constants */ |
1070 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1087 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
1071 | extern const unsigned char rfc1042_header[6]; | ||
1072 | extern const unsigned char bridge_tunnel_header[6]; | ||
1073 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | 1088 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, |
1074 | enum nl80211_iftype type); | 1089 | enum nl80211_iftype type); |
1075 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 1090 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 827ea8e6ee0a..ce267565e180 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -320,7 +320,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
320 | case ALG_TKIP: | 320 | case ALG_TKIP: |
321 | key->conf.iv_len = TKIP_IV_LEN; | 321 | key->conf.iv_len = TKIP_IV_LEN; |
322 | key->conf.icv_len = TKIP_ICV_LEN; | 322 | key->conf.icv_len = TKIP_ICV_LEN; |
323 | if (seq && seq_len == 6) { | 323 | if (seq) { |
324 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { | 324 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { |
325 | key->u.tkip.rx[i].iv32 = | 325 | key->u.tkip.rx[i].iv32 = |
326 | get_unaligned_le32(&seq[2]); | 326 | get_unaligned_le32(&seq[2]); |
@@ -332,7 +332,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
332 | case ALG_CCMP: | 332 | case ALG_CCMP: |
333 | key->conf.iv_len = CCMP_HDR_LEN; | 333 | key->conf.iv_len = CCMP_HDR_LEN; |
334 | key->conf.icv_len = CCMP_MIC_LEN; | 334 | key->conf.icv_len = CCMP_MIC_LEN; |
335 | if (seq && seq_len == CCMP_PN_LEN) { | 335 | if (seq) { |
336 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | 336 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) |
337 | for (j = 0; j < CCMP_PN_LEN; j++) | 337 | for (j = 0; j < CCMP_PN_LEN; j++) |
338 | key->u.ccmp.rx_pn[i][j] = | 338 | key->u.ccmp.rx_pn[i][j] = |
@@ -342,7 +342,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
342 | case ALG_AES_CMAC: | 342 | case ALG_AES_CMAC: |
343 | key->conf.iv_len = 0; | 343 | key->conf.iv_len = 0; |
344 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 344 | key->conf.icv_len = sizeof(struct ieee80211_mmie); |
345 | if (seq && seq_len == 6) | 345 | if (seq) |
346 | for (j = 0; j < 6; j++) | 346 | for (j = 0; j < 6; j++) |
347 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; | 347 | key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1]; |
348 | break; | 348 | break; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 76df5eabf268..6b7e92eaab47 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -219,18 +219,26 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
219 | u32 changed) | 219 | u32 changed) |
220 | { | 220 | { |
221 | struct ieee80211_local *local = sdata->local; | 221 | struct ieee80211_local *local = sdata->local; |
222 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
222 | 223 | ||
223 | if (!changed) | 224 | if (!changed) |
224 | return; | 225 | return; |
225 | 226 | ||
226 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 227 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
227 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | 228 | /* |
228 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 229 | * While not associated, claim a BSSID of all-zeroes |
230 | * so that drivers don't do any weird things with the | ||
231 | * BSSID at that time. | ||
232 | */ | ||
233 | if (sdata->vif.bss_conf.assoc) | ||
234 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | ||
235 | else | ||
236 | sdata->vif.bss_conf.bssid = zero; | ||
237 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | ||
229 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 238 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
230 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 239 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
231 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; | 240 | sdata->vif.bss_conf.bssid = sdata->dev->dev_addr; |
232 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 241 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
233 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
234 | sdata->vif.bss_conf.bssid = zero; | 242 | sdata->vif.bss_conf.bssid = zero; |
235 | } else { | 243 | } else { |
236 | WARN_ON(1); | 244 | WARN_ON(1); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9000b01a1671..fc712e60705d 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #define CAPAB_OFFSET 17 | 21 | #define CAPAB_OFFSET 17 |
22 | #define ACCEPT_PLINKS 0x80 | 22 | #define ACCEPT_PLINKS 0x80 |
23 | 23 | ||
24 | #define TMR_RUNNING_HK 0 | ||
25 | #define TMR_RUNNING_MP 1 | ||
26 | |||
24 | int mesh_allocated; | 27 | int mesh_allocated; |
25 | static struct kmem_cache *rm_cache; | 28 | static struct kmem_cache *rm_cache; |
26 | 29 | ||
@@ -45,6 +48,12 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
45 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 48 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
46 | 49 | ||
47 | ifmsh->housekeeping = true; | 50 | ifmsh->housekeeping = true; |
51 | |||
52 | if (local->quiescing) { | ||
53 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
54 | return; | ||
55 | } | ||
56 | |||
48 | queue_work(local->hw.workqueue, &ifmsh->work); | 57 | queue_work(local->hw.workqueue, &ifmsh->work); |
49 | } | 58 | } |
50 | 59 | ||
@@ -343,6 +352,11 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
343 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 352 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
344 | struct ieee80211_local *local = sdata->local; | 353 | struct ieee80211_local *local = sdata->local; |
345 | 354 | ||
355 | if (local->quiescing) { | ||
356 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
357 | return; | ||
358 | } | ||
359 | |||
346 | queue_work(local->hw.workqueue, &ifmsh->work); | 360 | queue_work(local->hw.workqueue, &ifmsh->work); |
347 | } | 361 | } |
348 | 362 | ||
@@ -424,6 +438,32 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
424 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 438 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
425 | } | 439 | } |
426 | 440 | ||
441 | #ifdef CONFIG_PM | ||
442 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
443 | { | ||
444 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
445 | |||
446 | /* might restart the timer but that doesn't matter */ | ||
447 | cancel_work_sync(&ifmsh->work); | ||
448 | |||
449 | /* use atomic bitops in case both timers fire at the same time */ | ||
450 | |||
451 | if (del_timer_sync(&ifmsh->housekeeping_timer)) | ||
452 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | ||
453 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | ||
454 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | ||
455 | } | ||
456 | |||
457 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
458 | { | ||
459 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
460 | |||
461 | if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running)) | ||
462 | add_timer(&ifmsh->housekeeping_timer); | ||
463 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | ||
464 | add_timer(&ifmsh->mesh_path_timer); | ||
465 | } | ||
466 | #endif | ||
427 | 467 | ||
428 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | 468 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) |
429 | { | 469 | { |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index d891d7ddccd7..c7d72819cdd2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -191,12 +191,8 @@ struct mesh_rmc { | |||
191 | #define PLINK_CATEGORY 30 | 191 | #define PLINK_CATEGORY 30 |
192 | #define MESH_PATH_SEL_CATEGORY 32 | 192 | #define MESH_PATH_SEL_CATEGORY 32 |
193 | 193 | ||
194 | /* Mesh Header Flags */ | ||
195 | #define IEEE80211S_FLAGS_AE 0x3 | ||
196 | |||
197 | /* Public interfaces */ | 194 | /* Public interfaces */ |
198 | /* Various */ | 195 | /* Various */ |
199 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); | ||
200 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 196 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
201 | struct ieee80211_sub_if_data *sdata); | 197 | struct ieee80211_sub_if_data *sdata); |
202 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 198 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
@@ -267,6 +263,8 @@ void mesh_path_timer(unsigned long data); | |||
267 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 263 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
268 | void mesh_path_discard_frame(struct sk_buff *skb, | 264 | void mesh_path_discard_frame(struct sk_buff *skb, |
269 | struct ieee80211_sub_if_data *sdata); | 265 | struct ieee80211_sub_if_data *sdata); |
266 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | ||
267 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | ||
270 | 268 | ||
271 | #ifdef CONFIG_MAC80211_MESH | 269 | #ifdef CONFIG_MAC80211_MESH |
272 | extern int mesh_allocated; | 270 | extern int mesh_allocated; |
@@ -294,10 +292,20 @@ static inline void mesh_path_activate(struct mesh_path *mpath) | |||
294 | 292 | ||
295 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); | 293 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); |
296 | 294 | ||
295 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | ||
296 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | ||
297 | void mesh_plink_quiesce(struct sta_info *sta); | ||
298 | void mesh_plink_restart(struct sta_info *sta); | ||
297 | #else | 299 | #else |
298 | #define mesh_allocated 0 | 300 | #define mesh_allocated 0 |
299 | static inline void | 301 | static inline void |
300 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} | 302 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} |
303 | static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | ||
304 | {} | ||
305 | static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | ||
306 | {} | ||
307 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} | ||
308 | static inline void mesh_plink_restart(struct sta_info *sta) {} | ||
301 | #endif | 309 | #endif |
302 | 310 | ||
303 | #endif /* IEEE80211S_H */ | 311 | #endif /* IEEE80211S_H */ |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 60b35accda91..003cb470ac84 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -836,8 +836,14 @@ void mesh_path_timer(unsigned long data) | |||
836 | mpath = rcu_dereference(mpath); | 836 | mpath = rcu_dereference(mpath); |
837 | if (!mpath) | 837 | if (!mpath) |
838 | goto endmpathtimer; | 838 | goto endmpathtimer; |
839 | spin_lock_bh(&mpath->state_lock); | ||
840 | sdata = mpath->sdata; | 839 | sdata = mpath->sdata; |
840 | |||
841 | if (sdata->local->quiescing) { | ||
842 | rcu_read_unlock(); | ||
843 | return; | ||
844 | } | ||
845 | |||
846 | spin_lock_bh(&mpath->state_lock); | ||
841 | if (mpath->flags & MESH_PATH_RESOLVED || | 847 | if (mpath->flags & MESH_PATH_RESOLVED || |
842 | (!(mpath->flags & MESH_PATH_RESOLVING))) | 848 | (!(mpath->flags & MESH_PATH_RESOLVING))) |
843 | mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); | 849 | mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a8bbdeca013a..cb14253587f1 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -266,6 +266,11 @@ static void mesh_plink_timer(unsigned long data) | |||
266 | */ | 266 | */ |
267 | sta = (struct sta_info *) data; | 267 | sta = (struct sta_info *) data; |
268 | 268 | ||
269 | if (sta->sdata->local->quiescing) { | ||
270 | sta->plink_timer_was_running = true; | ||
271 | return; | ||
272 | } | ||
273 | |||
269 | spin_lock_bh(&sta->lock); | 274 | spin_lock_bh(&sta->lock); |
270 | if (sta->ignore_plink_timer) { | 275 | if (sta->ignore_plink_timer) { |
271 | sta->ignore_plink_timer = false; | 276 | sta->ignore_plink_timer = false; |
@@ -322,6 +327,22 @@ static void mesh_plink_timer(unsigned long data) | |||
322 | } | 327 | } |
323 | } | 328 | } |
324 | 329 | ||
330 | #ifdef CONFIG_PM | ||
331 | void mesh_plink_quiesce(struct sta_info *sta) | ||
332 | { | ||
333 | if (del_timer_sync(&sta->plink_timer)) | ||
334 | sta->plink_timer_was_running = true; | ||
335 | } | ||
336 | |||
337 | void mesh_plink_restart(struct sta_info *sta) | ||
338 | { | ||
339 | if (sta->plink_timer_was_running) { | ||
340 | add_timer(&sta->plink_timer); | ||
341 | sta->plink_timer_was_running = false; | ||
342 | } | ||
343 | } | ||
344 | #endif | ||
345 | |||
325 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 346 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
326 | { | 347 | { |
327 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); | 348 | sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae030688771f..509469cb9265 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -33,10 +33,13 @@ | |||
33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 33 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
34 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 34 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_WAIT (HZ / 20) | 36 | #define IEEE80211_PROBE_WAIT (HZ / 5) |
37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) | 37 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 38 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
39 | 39 | ||
40 | #define TMR_RUNNING_TIMER 0 | ||
41 | #define TMR_RUNNING_CHANSW 1 | ||
42 | |||
40 | /* utils */ | 43 | /* utils */ |
41 | static int ecw2cw(int ecw) | 44 | static int ecw2cw(int ecw) |
42 | { | 45 | { |
@@ -121,10 +124,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
121 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | 124 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { |
122 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 125 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
123 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 126 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
124 | channel_type = NL80211_CHAN_HT40PLUS; | 127 | if (!(local->hw.conf.channel->flags & |
128 | IEEE80211_CHAN_NO_HT40PLUS)) | ||
129 | channel_type = NL80211_CHAN_HT40PLUS; | ||
125 | break; | 130 | break; |
126 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 131 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
127 | channel_type = NL80211_CHAN_HT40MINUS; | 132 | if (!(local->hw.conf.channel->flags & |
133 | IEEE80211_CHAN_NO_HT40MINUS)) | ||
134 | channel_type = NL80211_CHAN_HT40MINUS; | ||
128 | break; | 135 | break; |
129 | } | 136 | } |
130 | } | 137 | } |
@@ -349,13 +356,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
349 | 356 | ||
350 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 357 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
351 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 358 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
352 | if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { | 359 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { |
353 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 360 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
354 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 361 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
355 | } | 362 | } |
356 | break; | 363 | break; |
357 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 364 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: |
358 | if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { | 365 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { |
359 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 366 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
360 | cap &= ~IEEE80211_HT_CAP_SGI_40; | 367 | cap &= ~IEEE80211_HT_CAP_SGI_40; |
361 | } | 368 | } |
@@ -482,6 +489,108 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
482 | ieee80211_tx_skb(sdata, skb, 0); | 489 | ieee80211_tx_skb(sdata, skb, 0); |
483 | } | 490 | } |
484 | 491 | ||
492 | /* spectrum management related things */ | ||
493 | static void ieee80211_chswitch_work(struct work_struct *work) | ||
494 | { | ||
495 | struct ieee80211_sub_if_data *sdata = | ||
496 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | ||
497 | struct ieee80211_bss *bss; | ||
498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
499 | |||
500 | if (!netif_running(sdata->dev)) | ||
501 | return; | ||
502 | |||
503 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, | ||
504 | sdata->local->hw.conf.channel->center_freq, | ||
505 | ifmgd->ssid, ifmgd->ssid_len); | ||
506 | if (!bss) | ||
507 | goto exit; | ||
508 | |||
509 | sdata->local->oper_channel = sdata->local->csa_channel; | ||
510 | /* XXX: shouldn't really modify cfg80211-owned data! */ | ||
511 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
512 | bss->cbss.channel = sdata->local->oper_channel; | ||
513 | |||
514 | ieee80211_rx_bss_put(sdata->local, bss); | ||
515 | exit: | ||
516 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
517 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
518 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
519 | } | ||
520 | |||
521 | static void ieee80211_chswitch_timer(unsigned long data) | ||
522 | { | ||
523 | struct ieee80211_sub_if_data *sdata = | ||
524 | (struct ieee80211_sub_if_data *) data; | ||
525 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
526 | |||
527 | if (sdata->local->quiescing) { | ||
528 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
533 | } | ||
534 | |||
535 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
536 | struct ieee80211_channel_sw_ie *sw_elem, | ||
537 | struct ieee80211_bss *bss) | ||
538 | { | ||
539 | struct ieee80211_channel *new_ch; | ||
540 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
541 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | ||
542 | |||
543 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) | ||
544 | return; | ||
545 | |||
546 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | ||
547 | return; | ||
548 | |||
549 | /* Disregard subsequent beacons if we are already running a timer | ||
550 | processing a CSA */ | ||
551 | |||
552 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | ||
553 | return; | ||
554 | |||
555 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
556 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | ||
557 | return; | ||
558 | |||
559 | sdata->local->csa_channel = new_ch; | ||
560 | |||
561 | if (sw_elem->count <= 1) { | ||
562 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
563 | } else { | ||
564 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
565 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
566 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
567 | mod_timer(&ifmgd->chswitch_timer, | ||
568 | jiffies + | ||
569 | msecs_to_jiffies(sw_elem->count * | ||
570 | bss->cbss.beacon_interval)); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
575 | u16 capab_info, u8 *pwr_constr_elem, | ||
576 | u8 pwr_constr_elem_len) | ||
577 | { | ||
578 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | ||
579 | |||
580 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | ||
581 | return; | ||
582 | |||
583 | /* Power constraint IE length should be 1 octet */ | ||
584 | if (pwr_constr_elem_len != 1) | ||
585 | return; | ||
586 | |||
587 | if ((*pwr_constr_elem <= conf->channel->max_power) && | ||
588 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | ||
589 | sdata->local->power_constr_level = *pwr_constr_elem; | ||
590 | ieee80211_hw_config(sdata->local, 0); | ||
591 | } | ||
592 | } | ||
593 | |||
485 | /* powersave */ | 594 | /* powersave */ |
486 | static void ieee80211_enable_ps(struct ieee80211_local *local, | 595 | static void ieee80211_enable_ps(struct ieee80211_local *local, |
487 | struct ieee80211_sub_if_data *sdata) | 596 | struct ieee80211_sub_if_data *sdata) |
@@ -613,6 +722,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
613 | { | 722 | { |
614 | struct ieee80211_local *local = (void *) data; | 723 | struct ieee80211_local *local = (void *) data; |
615 | 724 | ||
725 | if (local->quiescing) | ||
726 | return; | ||
727 | |||
616 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 728 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
617 | } | 729 | } |
618 | 730 | ||
@@ -865,6 +977,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
865 | * changed or not. | 977 | * changed or not. |
866 | */ | 978 | */ |
867 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; | 979 | bss_info_changed |= BSS_CHANGED_BASIC_RATES; |
980 | |||
981 | /* And the BSSID changed - we're associated now */ | ||
982 | bss_info_changed |= BSS_CHANGED_BSSID; | ||
983 | |||
868 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); | 984 | ieee80211_bss_info_change_notify(sdata, bss_info_changed); |
869 | 985 | ||
870 | /* will be same as sdata */ | 986 | /* will be same as sdata */ |
@@ -1064,6 +1180,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1064 | } | 1180 | } |
1065 | 1181 | ||
1066 | ieee80211_hw_config(local, config_changed); | 1182 | ieee80211_hw_config(local, config_changed); |
1183 | |||
1184 | /* And the BSSID changed -- not very interesting here */ | ||
1185 | changed |= BSS_CHANGED_BSSID; | ||
1067 | ieee80211_bss_info_change_notify(sdata, changed); | 1186 | ieee80211_bss_info_change_notify(sdata, changed); |
1068 | 1187 | ||
1069 | rcu_read_lock(); | 1188 | rcu_read_lock(); |
@@ -1270,8 +1389,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
1270 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | 1389 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; |
1271 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | 1390 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, |
1272 | ifmgd->ssid_len, NULL, 0); | 1391 | ifmgd->ssid_len, NULL, 0); |
1392 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT); | ||
1273 | goto unlock; | 1393 | goto unlock; |
1274 | |||
1275 | } | 1394 | } |
1276 | 1395 | ||
1277 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { | 1396 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { |
@@ -1280,15 +1399,16 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
1280 | ifmgd->ssid_len, NULL, 0); | 1399 | ifmgd->ssid_len, NULL, 0); |
1281 | } | 1400 | } |
1282 | 1401 | ||
1402 | if (!disassoc) | ||
1403 | mod_timer(&ifmgd->timer, | ||
1404 | jiffies + IEEE80211_MONITORING_INTERVAL); | ||
1405 | |||
1283 | unlock: | 1406 | unlock: |
1284 | rcu_read_unlock(); | 1407 | rcu_read_unlock(); |
1285 | 1408 | ||
1286 | if (disassoc) | 1409 | if (disassoc) |
1287 | ieee80211_set_disassoc(sdata, true, true, | 1410 | ieee80211_set_disassoc(sdata, true, true, |
1288 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 1411 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1289 | else | ||
1290 | mod_timer(&ifmgd->timer, jiffies + | ||
1291 | IEEE80211_MONITORING_INTERVAL); | ||
1292 | } | 1412 | } |
1293 | 1413 | ||
1294 | 1414 | ||
@@ -1732,7 +1852,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1732 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { | 1852 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { |
1733 | struct ieee80211_channel_sw_ie *sw_elem = | 1853 | struct ieee80211_channel_sw_ie *sw_elem = |
1734 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1854 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1735 | ieee80211_process_chanswitch(sdata, sw_elem, bss); | 1855 | ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); |
1736 | } | 1856 | } |
1737 | 1857 | ||
1738 | ieee80211_rx_bss_put(local, bss); | 1858 | ieee80211_rx_bss_put(local, bss); |
@@ -1820,6 +1940,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1820 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1940 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1821 | return; | 1941 | return; |
1822 | 1942 | ||
1943 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | ||
1944 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1945 | if (net_ratelimit()) { | ||
1946 | printk(KERN_DEBUG "%s: cancelling probereq poll due " | ||
1947 | "to a received beacon\n", sdata->dev->name); | ||
1948 | } | ||
1949 | #endif | ||
1950 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1951 | } | ||
1952 | |||
1823 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); | 1953 | ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); |
1824 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, | 1954 | ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, |
1825 | len - baselen, &elems, | 1955 | len - baselen, &elems, |
@@ -1829,16 +1959,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1829 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, | 1959 | directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, |
1830 | ifmgd->aid); | 1960 | ifmgd->aid); |
1831 | 1961 | ||
1832 | ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim)); | 1962 | if (ncrc != ifmgd->beacon_crc) { |
1963 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, | ||
1964 | true); | ||
1833 | 1965 | ||
1834 | if (ncrc == ifmgd->beacon_crc) | 1966 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1835 | return; | 1967 | elems.wmm_param_len); |
1836 | ifmgd->beacon_crc = ncrc; | 1968 | } |
1837 | |||
1838 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | ||
1839 | |||
1840 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, | ||
1841 | elems.wmm_param_len); | ||
1842 | 1969 | ||
1843 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { | 1970 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { |
1844 | if (directed_tim) { | 1971 | if (directed_tim) { |
@@ -1863,6 +1990,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1863 | } | 1990 | } |
1864 | } | 1991 | } |
1865 | 1992 | ||
1993 | if (ncrc == ifmgd->beacon_crc) | ||
1994 | return; | ||
1995 | ifmgd->beacon_crc = ncrc; | ||
1996 | |||
1866 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1997 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1867 | erp_valid = true; | 1998 | erp_valid = true; |
1868 | erp_value = elems.erp_info[0]; | 1999 | erp_value = elems.erp_info[0]; |
@@ -1997,6 +2128,11 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1997 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2128 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1998 | struct ieee80211_local *local = sdata->local; | 2129 | struct ieee80211_local *local = sdata->local; |
1999 | 2130 | ||
2131 | if (local->quiescing) { | ||
2132 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2133 | return; | ||
2134 | } | ||
2135 | |||
2000 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | 2136 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2001 | queue_work(local->hw.workqueue, &ifmgd->work); | 2137 | queue_work(local->hw.workqueue, &ifmgd->work); |
2002 | } | 2138 | } |
@@ -2129,6 +2265,17 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2129 | 2265 | ||
2130 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2266 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2131 | return; | 2267 | return; |
2268 | |||
2269 | /* | ||
2270 | * Nothing should have been stuffed into the workqueue during | ||
2271 | * the suspend->resume cycle. If this WARN is seen then there | ||
2272 | * is a bug with either the driver suspend or something in | ||
2273 | * mac80211 stuffing into the workqueue which we haven't yet | ||
2274 | * cleared during mac80211's suspend cycle. | ||
2275 | */ | ||
2276 | if (WARN_ON(local->suspended)) | ||
2277 | return; | ||
2278 | |||
2132 | ifmgd = &sdata->u.mgd; | 2279 | ifmgd = &sdata->u.mgd; |
2133 | 2280 | ||
2134 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) | 2281 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
@@ -2196,6 +2343,38 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2196 | } | 2343 | } |
2197 | } | 2344 | } |
2198 | 2345 | ||
2346 | #ifdef CONFIG_PM | ||
2347 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | ||
2348 | { | ||
2349 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2350 | |||
2351 | /* | ||
2352 | * we need to use atomic bitops for the running bits | ||
2353 | * only because both timers might fire at the same | ||
2354 | * time -- the code here is properly synchronised. | ||
2355 | */ | ||
2356 | |||
2357 | cancel_work_sync(&ifmgd->work); | ||
2358 | cancel_work_sync(&ifmgd->beacon_loss_work); | ||
2359 | if (del_timer_sync(&ifmgd->timer)) | ||
2360 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | ||
2361 | |||
2362 | cancel_work_sync(&ifmgd->chswitch_work); | ||
2363 | if (del_timer_sync(&ifmgd->chswitch_timer)) | ||
2364 | set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running); | ||
2365 | } | ||
2366 | |||
2367 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | ||
2368 | { | ||
2369 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2370 | |||
2371 | if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running)) | ||
2372 | add_timer(&ifmgd->timer); | ||
2373 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | ||
2374 | add_timer(&ifmgd->chswitch_timer); | ||
2375 | } | ||
2376 | #endif | ||
2377 | |||
2199 | /* interface setup */ | 2378 | /* interface setup */ |
2200 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 2379 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2201 | { | 2380 | { |
@@ -2310,9 +2489,6 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
2310 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; | 2489 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; |
2311 | } | 2490 | } |
2312 | 2491 | ||
2313 | if (netif_running(sdata->dev)) | ||
2314 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
2315 | |||
2316 | return ieee80211_sta_commit(sdata); | 2492 | return ieee80211_sta_commit(sdata); |
2317 | } | 2493 | } |
2318 | 2494 | ||
@@ -2321,6 +2497,13 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | |||
2321 | { | 2497 | { |
2322 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2323 | 2499 | ||
2500 | if (len == 0 && ifmgd->extra_ie_len == 0) | ||
2501 | return -EALREADY; | ||
2502 | |||
2503 | if (len == ifmgd->extra_ie_len && ifmgd->extra_ie && | ||
2504 | memcmp(ifmgd->extra_ie, ie, len) == 0) | ||
2505 | return -EALREADY; | ||
2506 | |||
2324 | kfree(ifmgd->extra_ie); | 2507 | kfree(ifmgd->extra_ie); |
2325 | if (len == 0) { | 2508 | if (len == 0) { |
2326 | ifmgd->extra_ie = NULL; | 2509 | ifmgd->extra_ie = NULL; |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9d3d89abbb57..7a549f9deb96 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <net/rtnetlink.h> | 2 | #include <net/rtnetlink.h> |
3 | 3 | ||
4 | #include "ieee80211_i.h" | 4 | #include "ieee80211_i.h" |
5 | #include "mesh.h" | ||
5 | #include "driver-ops.h" | 6 | #include "driver-ops.h" |
6 | #include "led.h" | 7 | #include "led.h" |
7 | 8 | ||
@@ -13,11 +14,30 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
13 | struct sta_info *sta; | 14 | struct sta_info *sta; |
14 | unsigned long flags; | 15 | unsigned long flags; |
15 | 16 | ||
17 | ieee80211_scan_cancel(local); | ||
18 | |||
16 | ieee80211_stop_queues_by_reason(hw, | 19 | ieee80211_stop_queues_by_reason(hw, |
17 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 20 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
18 | 21 | ||
22 | /* flush out all packets */ | ||
23 | synchronize_net(); | ||
24 | |||
25 | local->quiescing = true; | ||
26 | /* make quiescing visible to timers everywhere */ | ||
27 | mb(); | ||
28 | |||
19 | flush_workqueue(local->hw.workqueue); | 29 | flush_workqueue(local->hw.workqueue); |
20 | 30 | ||
31 | /* Don't try to run timers while suspended. */ | ||
32 | del_timer_sync(&local->sta_cleanup); | ||
33 | |||
34 | /* | ||
35 | * Note that this particular timer doesn't need to be | ||
36 | * restarted at resume. | ||
37 | */ | ||
38 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
39 | del_timer_sync(&local->dynamic_ps_timer); | ||
40 | |||
21 | /* disable keys */ | 41 | /* disable keys */ |
22 | list_for_each_entry(sdata, &local->interfaces, list) | 42 | list_for_each_entry(sdata, &local->interfaces, list) |
23 | ieee80211_disable_keys(sdata); | 43 | ieee80211_disable_keys(sdata); |
@@ -35,10 +55,20 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
35 | 55 | ||
36 | rcu_read_unlock(); | 56 | rcu_read_unlock(); |
37 | 57 | ||
58 | /* flush again, in case driver queued work */ | ||
59 | flush_workqueue(local->hw.workqueue); | ||
60 | |||
61 | /* stop hardware - this must stop RX */ | ||
62 | if (local->open_count) { | ||
63 | ieee80211_led_radio(local, false); | ||
64 | drv_stop(local); | ||
65 | } | ||
66 | |||
38 | /* remove STAs */ | 67 | /* remove STAs */ |
39 | if (local->ops->sta_notify) { | 68 | spin_lock_irqsave(&local->sta_lock, flags); |
40 | spin_lock_irqsave(&local->sta_lock, flags); | 69 | list_for_each_entry(sta, &local->sta_list, list) { |
41 | list_for_each_entry(sta, &local->sta_list, list) { | 70 | if (local->ops->sta_notify) { |
71 | sdata = sta->sdata; | ||
42 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 72 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
43 | sdata = container_of(sdata->bss, | 73 | sdata = container_of(sdata->bss, |
44 | struct ieee80211_sub_if_data, | 74 | struct ieee80211_sub_if_data, |
@@ -47,29 +77,43 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
47 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, | 77 | drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, |
48 | &sta->sta); | 78 | &sta->sta); |
49 | } | 79 | } |
50 | spin_unlock_irqrestore(&local->sta_lock, flags); | 80 | |
81 | mesh_plink_quiesce(sta); | ||
51 | } | 82 | } |
83 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
52 | 84 | ||
53 | /* remove all interfaces */ | 85 | /* remove all interfaces */ |
54 | list_for_each_entry(sdata, &local->interfaces, list) { | 86 | list_for_each_entry(sdata, &local->interfaces, list) { |
55 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 87 | switch(sdata->vif.type) { |
56 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 88 | case NL80211_IFTYPE_STATION: |
57 | netif_running(sdata->dev)) { | 89 | ieee80211_sta_quiesce(sdata); |
58 | conf.vif = &sdata->vif; | 90 | break; |
59 | conf.type = sdata->vif.type; | 91 | case NL80211_IFTYPE_ADHOC: |
60 | conf.mac_addr = sdata->dev->dev_addr; | 92 | ieee80211_ibss_quiesce(sdata); |
61 | drv_remove_interface(local, &conf); | 93 | break; |
94 | case NL80211_IFTYPE_MESH_POINT: | ||
95 | ieee80211_mesh_quiesce(sdata); | ||
96 | break; | ||
97 | case NL80211_IFTYPE_AP_VLAN: | ||
98 | case NL80211_IFTYPE_MONITOR: | ||
99 | /* don't tell driver about this */ | ||
100 | continue; | ||
101 | default: | ||
102 | break; | ||
62 | } | 103 | } |
63 | } | ||
64 | 104 | ||
65 | /* flush again, in case driver queued work */ | 105 | if (!netif_running(sdata->dev)) |
66 | flush_workqueue(local->hw.workqueue); | 106 | continue; |
67 | 107 | ||
68 | /* stop hardware */ | 108 | conf.vif = &sdata->vif; |
69 | if (local->open_count) { | 109 | conf.type = sdata->vif.type; |
70 | ieee80211_led_radio(local, false); | 110 | conf.mac_addr = sdata->dev->dev_addr; |
71 | drv_stop(local); | 111 | drv_remove_interface(local, &conf); |
72 | } | 112 | } |
113 | |||
114 | local->suspended = true; | ||
115 | local->quiescing = false; | ||
116 | |||
73 | return 0; | 117 | return 0; |
74 | } | 118 | } |
75 | 119 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index f962bd1b16e2..6a9b8e63a6bf 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1247,93 +1247,12 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | static int | 1249 | static int |
1250 | ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | 1250 | __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) |
1251 | { | 1251 | { |
1252 | struct net_device *dev = rx->dev; | 1252 | struct net_device *dev = rx->dev; |
1253 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | ||
1254 | u16 hdrlen, ethertype; | ||
1255 | u8 *payload; | ||
1256 | u8 dst[ETH_ALEN]; | ||
1257 | u8 src[ETH_ALEN] __aligned(2); | ||
1258 | struct sk_buff *skb = rx->skb; | ||
1259 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1253 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1260 | 1254 | ||
1261 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 1255 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); |
1262 | return -1; | ||
1263 | |||
1264 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
1265 | |||
1266 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | ||
1267 | * header | ||
1268 | * IEEE 802.11 address fields: | ||
1269 | * ToDS FromDS Addr1 Addr2 Addr3 Addr4 | ||
1270 | * 0 0 DA SA BSSID n/a | ||
1271 | * 0 1 DA BSSID SA n/a | ||
1272 | * 1 0 BSSID SA DA n/a | ||
1273 | * 1 1 RA TA DA SA | ||
1274 | */ | ||
1275 | memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); | ||
1276 | memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); | ||
1277 | |||
1278 | switch (hdr->frame_control & | ||
1279 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | ||
1280 | case cpu_to_le16(IEEE80211_FCTL_TODS): | ||
1281 | if (unlikely(sdata->vif.type != NL80211_IFTYPE_AP && | ||
1282 | sdata->vif.type != NL80211_IFTYPE_AP_VLAN)) | ||
1283 | return -1; | ||
1284 | break; | ||
1285 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | ||
1286 | if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && | ||
1287 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) | ||
1288 | return -1; | ||
1289 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1290 | struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) | ||
1291 | (skb->data + hdrlen); | ||
1292 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
1293 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { | ||
1294 | memcpy(dst, meshdr->eaddr1, ETH_ALEN); | ||
1295 | memcpy(src, meshdr->eaddr2, ETH_ALEN); | ||
1296 | } | ||
1297 | } | ||
1298 | break; | ||
1299 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | ||
1300 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
1301 | (is_multicast_ether_addr(dst) && | ||
1302 | !compare_ether_addr(src, dev->dev_addr))) | ||
1303 | return -1; | ||
1304 | break; | ||
1305 | case cpu_to_le16(0): | ||
1306 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1307 | return -1; | ||
1308 | break; | ||
1309 | } | ||
1310 | |||
1311 | if (unlikely(skb->len - hdrlen < 8)) | ||
1312 | return -1; | ||
1313 | |||
1314 | payload = skb->data + hdrlen; | ||
1315 | ethertype = (payload[6] << 8) | payload[7]; | ||
1316 | |||
1317 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | ||
1318 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
1319 | compare_ether_addr(payload, bridge_tunnel_header) == 0)) { | ||
1320 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
1321 | * replace EtherType */ | ||
1322 | skb_pull(skb, hdrlen + 6); | ||
1323 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
1324 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
1325 | } else { | ||
1326 | struct ethhdr *ehdr; | ||
1327 | __be16 len; | ||
1328 | |||
1329 | skb_pull(skb, hdrlen); | ||
1330 | len = htons(skb->len); | ||
1331 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | ||
1332 | memcpy(ehdr->h_dest, dst, ETH_ALEN); | ||
1333 | memcpy(ehdr->h_source, src, ETH_ALEN); | ||
1334 | ehdr->h_proto = len; | ||
1335 | } | ||
1336 | return 0; | ||
1337 | } | 1256 | } |
1338 | 1257 | ||
1339 | /* | 1258 | /* |
@@ -1472,7 +1391,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) | |||
1472 | if (!(rx->flags & IEEE80211_RX_AMSDU)) | 1391 | if (!(rx->flags & IEEE80211_RX_AMSDU)) |
1473 | return RX_CONTINUE; | 1392 | return RX_CONTINUE; |
1474 | 1393 | ||
1475 | err = ieee80211_data_to_8023(rx); | 1394 | err = __ieee80211_data_to_8023(rx); |
1476 | if (unlikely(err)) | 1395 | if (unlikely(err)) |
1477 | return RX_DROP_UNUSABLE; | 1396 | return RX_DROP_UNUSABLE; |
1478 | 1397 | ||
@@ -1658,7 +1577,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1658 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 1577 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
1659 | return RX_DROP_MONITOR; | 1578 | return RX_DROP_MONITOR; |
1660 | 1579 | ||
1661 | err = ieee80211_data_to_8023(rx); | 1580 | err = __ieee80211_data_to_8023(rx); |
1662 | if (unlikely(err)) | 1581 | if (unlikely(err)) |
1663 | return RX_DROP_UNUSABLE; | 1582 | return RX_DROP_UNUSABLE; |
1664 | 1583 | ||
@@ -1846,6 +1765,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1846 | sizeof(mgmt->u.action.u.chan_switch))) | 1765 | sizeof(mgmt->u.action.u.chan_switch))) |
1847 | return RX_DROP_MONITOR; | 1766 | return RX_DROP_MONITOR; |
1848 | 1767 | ||
1768 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1769 | return RX_DROP_MONITOR; | ||
1770 | |||
1849 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) | 1771 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
1850 | return RX_DROP_MONITOR; | 1772 | return RX_DROP_MONITOR; |
1851 | 1773 | ||
@@ -1856,7 +1778,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1856 | if (!bss) | 1778 | if (!bss) |
1857 | return RX_DROP_MONITOR; | 1779 | return RX_DROP_MONITOR; |
1858 | 1780 | ||
1859 | ieee80211_process_chanswitch(sdata, | 1781 | ieee80211_sta_process_chanswitch(sdata, |
1860 | &mgmt->u.action.u.chan_switch.sw_elem, bss); | 1782 | &mgmt->u.action.u.chan_switch.sw_elem, bss); |
1861 | ieee80211_rx_bss_put(local, bss); | 1783 | ieee80211_rx_bss_put(local, bss); |
1862 | break; | 1784 | break; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index e65d74ba404b..2a8d09ad17ff 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -631,3 +631,21 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
631 | mutex_unlock(&local->scan_mtx); | 631 | mutex_unlock(&local->scan_mtx); |
632 | return ret; | 632 | return ret; |
633 | } | 633 | } |
634 | |||
635 | void ieee80211_scan_cancel(struct ieee80211_local *local) | ||
636 | { | ||
637 | bool swscan; | ||
638 | |||
639 | cancel_delayed_work_sync(&local->scan_work); | ||
640 | |||
641 | /* | ||
642 | * Only call this function when a scan can't be | ||
643 | * queued -- mostly at suspend under RTNL. | ||
644 | */ | ||
645 | mutex_lock(&local->scan_mtx); | ||
646 | swscan = local->sw_scanning; | ||
647 | mutex_unlock(&local->scan_mtx); | ||
648 | |||
649 | if (swscan) | ||
650 | ieee80211_scan_completed(&local->hw, true); | ||
651 | } | ||
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 48bf78e7fa7a..68953033403d 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -84,104 +84,3 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
84 | mgmt->sa, mgmt->bssid, | 84 | mgmt->sa, mgmt->bssid, |
85 | mgmt->u.action.u.measurement.dialog_token); | 85 | mgmt->u.action.u.measurement.dialog_token); |
86 | } | 86 | } |
87 | |||
88 | void ieee80211_chswitch_work(struct work_struct *work) | ||
89 | { | ||
90 | struct ieee80211_sub_if_data *sdata = | ||
91 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); | ||
92 | struct ieee80211_bss *bss; | ||
93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
94 | |||
95 | if (!netif_running(sdata->dev)) | ||
96 | return; | ||
97 | |||
98 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, | ||
99 | sdata->local->hw.conf.channel->center_freq, | ||
100 | ifmgd->ssid, ifmgd->ssid_len); | ||
101 | if (!bss) | ||
102 | goto exit; | ||
103 | |||
104 | sdata->local->oper_channel = sdata->local->csa_channel; | ||
105 | /* XXX: shouldn't really modify cfg80211-owned data! */ | ||
106 | if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
107 | bss->cbss.channel = sdata->local->oper_channel; | ||
108 | |||
109 | ieee80211_rx_bss_put(sdata->local, bss); | ||
110 | exit: | ||
111 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
113 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
114 | } | ||
115 | |||
116 | void ieee80211_chswitch_timer(unsigned long data) | ||
117 | { | ||
118 | struct ieee80211_sub_if_data *sdata = | ||
119 | (struct ieee80211_sub_if_data *) data; | ||
120 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
121 | |||
122 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
123 | } | ||
124 | |||
125 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | ||
126 | struct ieee80211_channel_sw_ie *sw_elem, | ||
127 | struct ieee80211_bss *bss) | ||
128 | { | ||
129 | struct ieee80211_channel *new_ch; | ||
130 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
131 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | ||
132 | |||
133 | /* FIXME: Handle ADHOC later */ | ||
134 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
135 | return; | ||
136 | |||
137 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) | ||
138 | return; | ||
139 | |||
140 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | ||
141 | return; | ||
142 | |||
143 | /* Disregard subsequent beacons if we are already running a timer | ||
144 | processing a CSA */ | ||
145 | |||
146 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) | ||
147 | return; | ||
148 | |||
149 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | ||
150 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | ||
151 | return; | ||
152 | |||
153 | sdata->local->csa_channel = new_ch; | ||
154 | |||
155 | if (sw_elem->count <= 1) { | ||
156 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); | ||
157 | } else { | ||
158 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
159 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
160 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
161 | mod_timer(&ifmgd->chswitch_timer, | ||
162 | jiffies + | ||
163 | msecs_to_jiffies(sw_elem->count * | ||
164 | bss->cbss.beacon_interval)); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | ||
169 | u16 capab_info, u8 *pwr_constr_elem, | ||
170 | u8 pwr_constr_elem_len) | ||
171 | { | ||
172 | struct ieee80211_conf *conf = &sdata->local->hw.conf; | ||
173 | |||
174 | if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT)) | ||
175 | return; | ||
176 | |||
177 | /* Power constraint IE length should be 1 octet */ | ||
178 | if (pwr_constr_elem_len != 1) | ||
179 | return; | ||
180 | |||
181 | if ((*pwr_constr_elem <= conf->channel->max_power) && | ||
182 | (*pwr_constr_elem != sdata->local->power_constr_level)) { | ||
183 | sdata->local->power_constr_level = *pwr_constr_elem; | ||
184 | ieee80211_hw_config(sdata->local, 0); | ||
185 | } | ||
186 | } | ||
187 | |||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a98ea273a155..d5611d8fd0d6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -293,6 +293,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
293 | skb_queue_head_init(&sta->ps_tx_buf); | 293 | skb_queue_head_init(&sta->ps_tx_buf); |
294 | skb_queue_head_init(&sta->tx_filtered); | 294 | skb_queue_head_init(&sta->tx_filtered); |
295 | 295 | ||
296 | for (i = 0; i < NUM_RX_DATA_QUEUES; i++) | ||
297 | sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX); | ||
298 | |||
296 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 299 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
297 | printk(KERN_DEBUG "%s: Allocated STA %pM\n", | 300 | printk(KERN_DEBUG "%s: Allocated STA %pM\n", |
298 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 301 | wiphy_name(local->hw.wiphy), sta->sta.addr); |
@@ -608,6 +611,9 @@ static void sta_info_cleanup(unsigned long data) | |||
608 | sta_info_cleanup_expire_buffered(local, sta); | 611 | sta_info_cleanup_expire_buffered(local, sta); |
609 | rcu_read_unlock(); | 612 | rcu_read_unlock(); |
610 | 613 | ||
614 | if (local->quiescing) | ||
615 | return; | ||
616 | |||
611 | local->sta_cleanup.expires = | 617 | local->sta_cleanup.expires = |
612 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 618 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
613 | add_timer(&local->sta_cleanup); | 619 | add_timer(&local->sta_cleanup); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 164b16cbe0a5..49a1a1f76511 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -216,6 +216,7 @@ struct sta_ampdu_mlme { | |||
216 | * @plink_state: peer link state | 216 | * @plink_state: peer link state |
217 | * @plink_timeout: timeout of peer link | 217 | * @plink_timeout: timeout of peer link |
218 | * @plink_timer: peer link watch timer | 218 | * @plink_timer: peer link watch timer |
219 | * @plink_timer_was_running: used by suspend/resume to restore timers | ||
219 | * @debugfs: debug filesystem info | 220 | * @debugfs: debug filesystem info |
220 | * @sta: station information we share with the driver | 221 | * @sta: station information we share with the driver |
221 | */ | 222 | */ |
@@ -293,6 +294,7 @@ struct sta_info { | |||
293 | __le16 reason; | 294 | __le16 reason; |
294 | u8 plink_retries; | 295 | u8 plink_retries; |
295 | bool ignore_plink_timer; | 296 | bool ignore_plink_timer; |
297 | bool plink_timer_was_running; | ||
296 | enum plink_state plink_state; | 298 | enum plink_state plink_state; |
297 | u32 plink_timeout; | 299 | u32 plink_timeout; |
298 | struct timer_list plink_timer; | 300 | struct timer_list plink_timer; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8f68bf9746d0..a910148b8228 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -872,6 +872,8 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | |||
872 | 872 | ||
873 | do { | 873 | do { |
874 | hdr = (void *) skb->data; | 874 | hdr = (void *) skb->data; |
875 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) | ||
876 | break; /* must not overwrite AID */ | ||
875 | next_len = skb->next ? skb->next->len : 0; | 877 | next_len = skb->next ? skb->next->len : 0; |
876 | group_addr = is_multicast_ether_addr(hdr->addr1); | 878 | group_addr = is_multicast_ether_addr(hdr->addr1); |
877 | 879 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0689a8fbd1e6..949d857debd8 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -35,15 +35,6 @@ | |||
35 | /* privid for wiphys to determine whether they belong to us or not */ | 35 | /* privid for wiphys to determine whether they belong to us or not */ |
36 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 36 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
37 | 37 | ||
38 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
39 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
40 | const unsigned char rfc1042_header[] __aligned(2) = | ||
41 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
42 | |||
43 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
44 | const unsigned char bridge_tunnel_header[] __aligned(2) = | ||
45 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
46 | |||
47 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) | 38 | struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) |
48 | { | 39 | { |
49 | struct ieee80211_local *local; | 40 | struct ieee80211_local *local; |
@@ -103,70 +94,6 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | |||
103 | return NULL; | 94 | return NULL; |
104 | } | 95 | } |
105 | 96 | ||
106 | unsigned int ieee80211_hdrlen(__le16 fc) | ||
107 | { | ||
108 | unsigned int hdrlen = 24; | ||
109 | |||
110 | if (ieee80211_is_data(fc)) { | ||
111 | if (ieee80211_has_a4(fc)) | ||
112 | hdrlen = 30; | ||
113 | if (ieee80211_is_data_qos(fc)) | ||
114 | hdrlen += IEEE80211_QOS_CTL_LEN; | ||
115 | goto out; | ||
116 | } | ||
117 | |||
118 | if (ieee80211_is_ctl(fc)) { | ||
119 | /* | ||
120 | * ACK and CTS are 10 bytes, all others 16. To see how | ||
121 | * to get this condition consider | ||
122 | * subtype mask: 0b0000000011110000 (0x00F0) | ||
123 | * ACK subtype: 0b0000000011010000 (0x00D0) | ||
124 | * CTS subtype: 0b0000000011000000 (0x00C0) | ||
125 | * bits that matter: ^^^ (0x00E0) | ||
126 | * value of those: 0b0000000011000000 (0x00C0) | ||
127 | */ | ||
128 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | ||
129 | hdrlen = 10; | ||
130 | else | ||
131 | hdrlen = 16; | ||
132 | } | ||
133 | out: | ||
134 | return hdrlen; | ||
135 | } | ||
136 | EXPORT_SYMBOL(ieee80211_hdrlen); | ||
137 | |||
138 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | ||
139 | { | ||
140 | const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)skb->data; | ||
141 | unsigned int hdrlen; | ||
142 | |||
143 | if (unlikely(skb->len < 10)) | ||
144 | return 0; | ||
145 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
146 | if (unlikely(hdrlen > skb->len)) | ||
147 | return 0; | ||
148 | return hdrlen; | ||
149 | } | ||
150 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | ||
151 | |||
152 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||
153 | { | ||
154 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; | ||
155 | /* 7.1.3.5a.2 */ | ||
156 | switch (ae) { | ||
157 | case 0: | ||
158 | return 6; | ||
159 | case 1: | ||
160 | return 12; | ||
161 | case 2: | ||
162 | return 18; | ||
163 | case 3: | ||
164 | return 24; | ||
165 | default: | ||
166 | return 6; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 97 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
171 | { | 98 | { |
172 | struct sk_buff *skb = tx->skb; | 99 | struct sk_buff *skb = tx->skb; |
@@ -1034,6 +961,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1034 | struct sta_info *sta; | 961 | struct sta_info *sta; |
1035 | unsigned long flags; | 962 | unsigned long flags; |
1036 | int res; | 963 | int res; |
964 | bool from_suspend = local->suspended; | ||
965 | |||
966 | /* | ||
967 | * We're going to start the hardware, at that point | ||
968 | * we are no longer suspended and can RX frames. | ||
969 | */ | ||
970 | local->suspended = false; | ||
1037 | 971 | ||
1038 | /* restart hardware */ | 972 | /* restart hardware */ |
1039 | if (local->open_count) { | 973 | if (local->open_count) { |
@@ -1058,6 +992,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1058 | if (local->ops->sta_notify) { | 992 | if (local->ops->sta_notify) { |
1059 | spin_lock_irqsave(&local->sta_lock, flags); | 993 | spin_lock_irqsave(&local->sta_lock, flags); |
1060 | list_for_each_entry(sta, &local->sta_list, list) { | 994 | list_for_each_entry(sta, &local->sta_list, list) { |
995 | sdata = sta->sdata; | ||
1061 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 996 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1062 | sdata = container_of(sdata->bss, | 997 | sdata = container_of(sdata->bss, |
1063 | struct ieee80211_sub_if_data, | 998 | struct ieee80211_sub_if_data, |
@@ -1128,5 +1063,40 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1128 | ieee80211_wake_queues_by_reason(hw, | 1063 | ieee80211_wake_queues_by_reason(hw, |
1129 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1064 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1130 | 1065 | ||
1066 | /* | ||
1067 | * If this is for hw restart things are still running. | ||
1068 | * We may want to change that later, however. | ||
1069 | */ | ||
1070 | if (!from_suspend) | ||
1071 | return 0; | ||
1072 | |||
1073 | #ifdef CONFIG_PM | ||
1074 | local->suspended = false; | ||
1075 | |||
1076 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1077 | switch(sdata->vif.type) { | ||
1078 | case NL80211_IFTYPE_STATION: | ||
1079 | ieee80211_sta_restart(sdata); | ||
1080 | break; | ||
1081 | case NL80211_IFTYPE_ADHOC: | ||
1082 | ieee80211_ibss_restart(sdata); | ||
1083 | break; | ||
1084 | case NL80211_IFTYPE_MESH_POINT: | ||
1085 | ieee80211_mesh_restart(sdata); | ||
1086 | break; | ||
1087 | default: | ||
1088 | break; | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | add_timer(&local->sta_cleanup); | ||
1093 | |||
1094 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1095 | list_for_each_entry(sta, &local->sta_list, list) | ||
1096 | mesh_plink_restart(sta); | ||
1097 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1098 | #else | ||
1099 | WARN_ON(1); | ||
1100 | #endif | ||
1131 | return 0; | 1101 | return 0; |
1132 | } | 1102 | } |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index c14394744a9c..a01154e127f0 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -37,12 +37,13 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
37 | 37 | ||
38 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 38 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
39 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 39 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); |
40 | if (ret) | 40 | if (ret && ret != -EALREADY) |
41 | return ret; | 41 | return ret; |
42 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 42 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
43 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | 43 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; |
44 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | 44 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; |
45 | ieee80211_sta_req_auth(sdata); | 45 | if (ret != -EALREADY) |
46 | ieee80211_sta_req_auth(sdata); | ||
46 | return 0; | 47 | return 0; |
47 | } | 48 | } |
48 | 49 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 45b74f38b867..694343b9102b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -23,34 +23,6 @@ | |||
23 | */ | 23 | */ |
24 | const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; | 24 | const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; |
25 | 25 | ||
26 | static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0}; | ||
27 | |||
28 | /* Given a data frame determine the 802.1p/1d tag to use. */ | ||
29 | static unsigned int classify_1d(struct sk_buff *skb) | ||
30 | { | ||
31 | unsigned int dscp; | ||
32 | |||
33 | /* skb->priority values from 256->263 are magic values to | ||
34 | * directly indicate a specific 802.1d priority. This is used | ||
35 | * to allow 802.1d priority to be passed directly in from VLAN | ||
36 | * tags, etc. | ||
37 | */ | ||
38 | if (skb->priority >= 256 && skb->priority <= 263) | ||
39 | return skb->priority - 256; | ||
40 | |||
41 | switch (skb->protocol) { | ||
42 | case htons(ETH_P_IP): | ||
43 | dscp = ip_hdr(skb)->tos & 0xfc; | ||
44 | break; | ||
45 | |||
46 | default: | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | return dscp >> 5; | ||
51 | } | ||
52 | |||
53 | |||
54 | static int wme_downgrade_ac(struct sk_buff *skb) | 26 | static int wme_downgrade_ac(struct sk_buff *skb) |
55 | { | 27 | { |
56 | switch (skb->priority) { | 28 | switch (skb->priority) { |
@@ -94,7 +66,7 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | |||
94 | 66 | ||
95 | /* use the data classifier to determine what 802.1d tag the | 67 | /* use the data classifier to determine what 802.1d tag the |
96 | * data frame has */ | 68 | * data frame has */ |
97 | skb->priority = classify_1d(skb); | 69 | skb->priority = cfg80211_classify8021d(skb); |
98 | 70 | ||
99 | /* in case we are a client verify acm is not set for this ac */ | 71 | /* in case we are a client verify acm is not set for this ac */ |
100 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { | 72 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 3c3bc9e579ed..45005497c634 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -10,6 +10,14 @@ config CFG80211_REG_DEBUG | |||
10 | 10 | ||
11 | If unsure, say N. | 11 | If unsure, say N. |
12 | 12 | ||
13 | config CFG80211_DEBUGFS | ||
14 | bool "cfg80211 DebugFS entries" | ||
15 | depends on CFG80211 && DEBUG_FS | ||
16 | ---help--- | ||
17 | You can enable this if you want to debugfs entries for cfg80211. | ||
18 | |||
19 | If unsure, say N. | ||
20 | |||
13 | config WIRELESS_OLD_REGULATORY | 21 | config WIRELESS_OLD_REGULATORY |
14 | bool "Old wireless static regulatory definitions" | 22 | bool "Old wireless static regulatory definitions" |
15 | default n | 23 | default n |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 14ea01c4a103..f78c4832a9ca 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | |||
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o |
9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | ||
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | 11 | ||
11 | ccflags-y += -D__CHECK_ENDIAN__ | 12 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 47c20eb0c04d..a5dbea1da476 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "nl80211.h" | 17 | #include "nl80211.h" |
18 | #include "core.h" | 18 | #include "core.h" |
19 | #include "sysfs.h" | 19 | #include "sysfs.h" |
20 | #include "debugfs.h" | ||
20 | 21 | ||
21 | /* name for sysfs, %d is appended */ | 22 | /* name for sysfs, %d is appended */ |
22 | #define PHY_NAME "phy" | 23 | #define PHY_NAME "phy" |
@@ -228,7 +229,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
228 | 229 | ||
229 | /* exported functions */ | 230 | /* exported functions */ |
230 | 231 | ||
231 | struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | 232 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
232 | { | 233 | { |
233 | static int wiphy_counter; | 234 | static int wiphy_counter; |
234 | 235 | ||
@@ -375,6 +376,8 @@ int wiphy_register(struct wiphy *wiphy) | |||
375 | nl80211_send_reg_change_event(&request); | 376 | nl80211_send_reg_change_event(&request); |
376 | } | 377 | } |
377 | 378 | ||
379 | cfg80211_debugfs_drv_add(drv); | ||
380 | |||
378 | res = 0; | 381 | res = 0; |
379 | out_unlock: | 382 | out_unlock: |
380 | mutex_unlock(&cfg80211_mutex); | 383 | mutex_unlock(&cfg80211_mutex); |
@@ -405,6 +408,8 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
405 | /* unlock again before freeing */ | 408 | /* unlock again before freeing */ |
406 | mutex_unlock(&drv->mtx); | 409 | mutex_unlock(&drv->mtx); |
407 | 410 | ||
411 | cfg80211_debugfs_drv_del(drv); | ||
412 | |||
408 | /* If this device got a regulatory hint tell core its | 413 | /* If this device got a regulatory hint tell core its |
409 | * free to listen now to a new shiny device regulatory hint */ | 414 | * free to listen now to a new shiny device regulatory hint */ |
410 | reg_device_remove(wiphy); | 415 | reg_device_remove(wiphy); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index f14b6c5f4221..ab512bcd8153 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -10,12 +10,13 @@ | |||
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | 11 | #include <linux/kref.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/debugfs.h> | ||
13 | #include <net/genetlink.h> | 14 | #include <net/genetlink.h> |
14 | #include <net/cfg80211.h> | 15 | #include <net/cfg80211.h> |
15 | #include "reg.h" | 16 | #include "reg.h" |
16 | 17 | ||
17 | struct cfg80211_registered_device { | 18 | struct cfg80211_registered_device { |
18 | struct cfg80211_ops *ops; | 19 | const struct cfg80211_ops *ops; |
19 | struct list_head list; | 20 | struct list_head list; |
20 | /* we hold this mutex during any call so that | 21 | /* we hold this mutex during any call so that |
21 | * we cannot do multiple calls at once, and also | 22 | * we cannot do multiple calls at once, and also |
@@ -50,6 +51,17 @@ struct cfg80211_registered_device { | |||
50 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 51 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
51 | unsigned long suspend_at; | 52 | unsigned long suspend_at; |
52 | 53 | ||
54 | #ifdef CONFIG_CFG80211_DEBUGFS | ||
55 | /* Debugfs entries */ | ||
56 | struct wiphy_debugfsdentries { | ||
57 | struct dentry *rts_threshold; | ||
58 | struct dentry *fragmentation_threshold; | ||
59 | struct dentry *short_retry_limit; | ||
60 | struct dentry *long_retry_limit; | ||
61 | struct dentry *ht40allow_map; | ||
62 | } debugfs; | ||
63 | #endif | ||
64 | |||
53 | /* must be last because of the way we do wiphy_priv(), | 65 | /* must be last because of the way we do wiphy_priv(), |
54 | * and it should at least be aligned to NETDEV_ALIGN */ | 66 | * and it should at least be aligned to NETDEV_ALIGN */ |
55 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); | 67 | struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN))); |
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c new file mode 100644 index 000000000000..679ddfcec1ee --- /dev/null +++ b/net/wireless/debugfs.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * cfg80211 debugfs | ||
3 | * | ||
4 | * Copyright 2009 Luis R. Rodriguez <lrodriguez@atheros.com> | ||
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include "core.h" | ||
13 | #include "debugfs.h" | ||
14 | |||
15 | static int cfg80211_open_file_generic(struct inode *inode, struct file *file) | ||
16 | { | ||
17 | file->private_data = inode->i_private; | ||
18 | return 0; | ||
19 | } | ||
20 | |||
21 | #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ | ||
22 | static ssize_t name## _read(struct file *file, char __user *userbuf, \ | ||
23 | size_t count, loff_t *ppos) \ | ||
24 | { \ | ||
25 | struct wiphy *wiphy= file->private_data; \ | ||
26 | char buf[buflen]; \ | ||
27 | int res; \ | ||
28 | \ | ||
29 | res = scnprintf(buf, buflen, fmt "\n", ##value); \ | ||
30 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ | ||
31 | } \ | ||
32 | \ | ||
33 | static const struct file_operations name## _ops = { \ | ||
34 | .read = name## _read, \ | ||
35 | .open = cfg80211_open_file_generic, \ | ||
36 | }; | ||
37 | |||
38 | DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", | ||
39 | wiphy->rts_threshold) | ||
40 | DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", | ||
41 | wiphy->frag_threshold); | ||
42 | DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", | ||
43 | wiphy->retry_short) | ||
44 | DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", | ||
45 | wiphy->retry_long); | ||
46 | |||
47 | static int ht_print_chan(struct ieee80211_channel *chan, | ||
48 | char *buf, int buf_size, int offset) | ||
49 | { | ||
50 | if (WARN_ON(offset > buf_size)) | ||
51 | return 0; | ||
52 | |||
53 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
54 | return snprintf(buf + offset, | ||
55 | buf_size - offset, | ||
56 | "%d Disabled\n", | ||
57 | chan->center_freq); | ||
58 | |||
59 | return snprintf(buf + offset, | ||
60 | buf_size - offset, | ||
61 | "%d HT40 %c%c\n", | ||
62 | chan->center_freq, | ||
63 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', | ||
64 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); | ||
65 | } | ||
66 | |||
67 | static ssize_t ht40allow_map_read(struct file *file, | ||
68 | char __user *user_buf, | ||
69 | size_t count, loff_t *ppos) | ||
70 | { | ||
71 | struct wiphy *wiphy = file->private_data; | ||
72 | char *buf; | ||
73 | unsigned int offset = 0, buf_size = PAGE_SIZE, i, r; | ||
74 | enum ieee80211_band band; | ||
75 | struct ieee80211_supported_band *sband; | ||
76 | |||
77 | buf = kzalloc(buf_size, GFP_KERNEL); | ||
78 | if (!buf) | ||
79 | return -ENOMEM; | ||
80 | |||
81 | mutex_lock(&cfg80211_mutex); | ||
82 | |||
83 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
84 | sband = wiphy->bands[band]; | ||
85 | if (!sband) | ||
86 | continue; | ||
87 | for (i = 0; i < sband->n_channels; i++) | ||
88 | offset += ht_print_chan(&sband->channels[i], | ||
89 | buf, buf_size, offset); | ||
90 | } | ||
91 | |||
92 | mutex_unlock(&cfg80211_mutex); | ||
93 | |||
94 | r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); | ||
95 | |||
96 | kfree(buf); | ||
97 | |||
98 | return r; | ||
99 | } | ||
100 | |||
101 | static const struct file_operations ht40allow_map_ops = { | ||
102 | .read = ht40allow_map_read, | ||
103 | .open = cfg80211_open_file_generic, | ||
104 | }; | ||
105 | |||
106 | #define DEBUGFS_ADD(name) \ | ||
107 | drv->debugfs.name = debugfs_create_file(#name, S_IRUGO, phyd, \ | ||
108 | &drv->wiphy, &name## _ops); | ||
109 | #define DEBUGFS_DEL(name) \ | ||
110 | debugfs_remove(drv->debugfs.name); \ | ||
111 | drv->debugfs.name = NULL; | ||
112 | |||
113 | void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) | ||
114 | { | ||
115 | struct dentry *phyd = drv->wiphy.debugfsdir; | ||
116 | |||
117 | DEBUGFS_ADD(rts_threshold); | ||
118 | DEBUGFS_ADD(fragmentation_threshold); | ||
119 | DEBUGFS_ADD(short_retry_limit); | ||
120 | DEBUGFS_ADD(long_retry_limit); | ||
121 | DEBUGFS_ADD(ht40allow_map); | ||
122 | } | ||
123 | |||
124 | void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) | ||
125 | { | ||
126 | DEBUGFS_DEL(rts_threshold); | ||
127 | DEBUGFS_DEL(fragmentation_threshold); | ||
128 | DEBUGFS_DEL(short_retry_limit); | ||
129 | DEBUGFS_DEL(long_retry_limit); | ||
130 | DEBUGFS_DEL(ht40allow_map); | ||
131 | } | ||
diff --git a/net/wireless/debugfs.h b/net/wireless/debugfs.h new file mode 100644 index 000000000000..c226983ae66b --- /dev/null +++ b/net/wireless/debugfs.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef __CFG80211_DEBUGFS_H | ||
2 | #define __CFG80211_DEBUGFS_H | ||
3 | |||
4 | #ifdef CONFIG_CFG80211_DEBUGFS | ||
5 | void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv); | ||
6 | void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv); | ||
7 | #else | ||
8 | static inline | ||
9 | void cfg80211_debugfs_drv_add(struct cfg80211_registered_device *drv) {} | ||
10 | static inline | ||
11 | void cfg80211_debugfs_drv_del(struct cfg80211_registered_device *drv) {} | ||
12 | #endif | ||
13 | |||
14 | #endif /* __CFG80211_DEBUGFS_H */ | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a3a152f55dd0..56d729c43b31 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
77 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 77 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
78 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 78 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
79 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 79 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
80 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | ||
80 | 81 | ||
81 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 82 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
82 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 83 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -492,7 +493,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
492 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 493 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
493 | struct ieee80211_channel *chan; | 494 | struct ieee80211_channel *chan; |
494 | struct ieee80211_sta_ht_cap *ht_cap; | 495 | struct ieee80211_sta_ht_cap *ht_cap; |
495 | u32 freq, sec_freq; | 496 | u32 freq; |
496 | 497 | ||
497 | if (!rdev->ops->set_channel) { | 498 | if (!rdev->ops->set_channel) { |
498 | result = -EOPNOTSUPP; | 499 | result = -EOPNOTSUPP; |
@@ -518,33 +519,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
518 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 519 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
519 | goto bad_res; | 520 | goto bad_res; |
520 | 521 | ||
521 | if (channel_type == NL80211_CHAN_HT40MINUS) | 522 | if (channel_type == NL80211_CHAN_HT40MINUS && |
522 | sec_freq = freq - 20; | 523 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) |
523 | else if (channel_type == NL80211_CHAN_HT40PLUS) | 524 | goto bad_res; |
524 | sec_freq = freq + 20; | 525 | else if (channel_type == NL80211_CHAN_HT40PLUS && |
525 | else | 526 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) |
526 | sec_freq = 0; | ||
527 | |||
528 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
529 | |||
530 | /* no HT capabilities */ | ||
531 | if (channel_type != NL80211_CHAN_NO_HT && | ||
532 | !ht_cap->ht_supported) | ||
533 | goto bad_res; | 527 | goto bad_res; |
534 | 528 | ||
535 | if (sec_freq) { | 529 | /* |
536 | struct ieee80211_channel *schan; | 530 | * At this point we know if that if HT40 was requested |
531 | * we are allowed to use it and the extension channel | ||
532 | * exists. | ||
533 | */ | ||
534 | |||
535 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
537 | 536 | ||
538 | /* no 40 MHz capabilities */ | 537 | /* no HT capabilities or intolerant */ |
538 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
539 | if (!ht_cap->ht_supported) | ||
540 | goto bad_res; | ||
539 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 541 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || |
540 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | 542 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) |
541 | goto bad_res; | 543 | goto bad_res; |
542 | |||
543 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | ||
544 | |||
545 | /* Secondary channel not allowed */ | ||
546 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) | ||
547 | goto bad_res; | ||
548 | } | 544 | } |
549 | 545 | ||
550 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 546 | result = rdev->ops->set_channel(&rdev->wiphy, chan, |
@@ -2571,18 +2567,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2571 | rem_reg_rules) { | 2567 | rem_reg_rules) { |
2572 | num_rules++; | 2568 | num_rules++; |
2573 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 2569 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
2574 | goto bad_reg; | 2570 | return -EINVAL; |
2575 | } | 2571 | } |
2576 | 2572 | ||
2577 | if (!reg_is_valid_request(alpha2)) | 2573 | mutex_lock(&cfg80211_mutex); |
2578 | return -EINVAL; | 2574 | |
2575 | if (!reg_is_valid_request(alpha2)) { | ||
2576 | r = -EINVAL; | ||
2577 | goto bad_reg; | ||
2578 | } | ||
2579 | 2579 | ||
2580 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 2580 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
2581 | (num_rules * sizeof(struct ieee80211_reg_rule)); | 2581 | (num_rules * sizeof(struct ieee80211_reg_rule)); |
2582 | 2582 | ||
2583 | rd = kzalloc(size_of_regd, GFP_KERNEL); | 2583 | rd = kzalloc(size_of_regd, GFP_KERNEL); |
2584 | if (!rd) | 2584 | if (!rd) { |
2585 | return -ENOMEM; | 2585 | r = -ENOMEM; |
2586 | goto bad_reg; | ||
2587 | } | ||
2586 | 2588 | ||
2587 | rd->n_reg_rules = num_rules; | 2589 | rd->n_reg_rules = num_rules; |
2588 | rd->alpha2[0] = alpha2[0]; | 2590 | rd->alpha2[0] = alpha2[0]; |
@@ -2599,20 +2601,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2599 | 2601 | ||
2600 | rule_idx++; | 2602 | rule_idx++; |
2601 | 2603 | ||
2602 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) | 2604 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { |
2605 | r = -EINVAL; | ||
2603 | goto bad_reg; | 2606 | goto bad_reg; |
2607 | } | ||
2604 | } | 2608 | } |
2605 | 2609 | ||
2606 | BUG_ON(rule_idx != num_rules); | 2610 | BUG_ON(rule_idx != num_rules); |
2607 | 2611 | ||
2608 | mutex_lock(&cfg80211_mutex); | ||
2609 | r = set_regdom(rd); | 2612 | r = set_regdom(rd); |
2613 | |||
2610 | mutex_unlock(&cfg80211_mutex); | 2614 | mutex_unlock(&cfg80211_mutex); |
2615 | |||
2611 | return r; | 2616 | return r; |
2612 | 2617 | ||
2613 | bad_reg: | 2618 | bad_reg: |
2619 | mutex_unlock(&cfg80211_mutex); | ||
2614 | kfree(rd); | 2620 | kfree(rd); |
2615 | return -EINVAL; | 2621 | return r; |
2616 | } | 2622 | } |
2617 | 2623 | ||
2618 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2624 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 537af62ec42b..df0ced9405d3 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -48,12 +48,6 @@ static struct regulatory_request *last_request; | |||
48 | /* To trigger userspace events */ | 48 | /* To trigger userspace events */ |
49 | static struct platform_device *reg_pdev; | 49 | static struct platform_device *reg_pdev; |
50 | 50 | ||
51 | /* Keep the ordering from large to small */ | ||
52 | static u32 supported_bandwidths[] = { | ||
53 | MHZ_TO_KHZ(40), | ||
54 | MHZ_TO_KHZ(20), | ||
55 | }; | ||
56 | |||
57 | /* | 51 | /* |
58 | * Central wireless core regulatory domains, we only need two, | 52 | * Central wireless core regulatory domains, we only need two, |
59 | * the current one and a world regulatory domain in case we have no | 53 | * the current one and a world regulatory domain in case we have no |
@@ -388,6 +382,8 @@ static int call_crda(const char *alpha2) | |||
388 | /* Used by nl80211 before kmalloc'ing our regulatory domain */ | 382 | /* Used by nl80211 before kmalloc'ing our regulatory domain */ |
389 | bool reg_is_valid_request(const char *alpha2) | 383 | bool reg_is_valid_request(const char *alpha2) |
390 | { | 384 | { |
385 | assert_cfg80211_lock(); | ||
386 | |||
391 | if (!last_request) | 387 | if (!last_request) |
392 | return false; | 388 | return false; |
393 | 389 | ||
@@ -435,19 +431,20 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) | |||
435 | return true; | 431 | return true; |
436 | } | 432 | } |
437 | 433 | ||
438 | /* Returns value in KHz */ | 434 | static bool reg_does_bw_fit(const struct ieee80211_freq_range *freq_range, |
439 | static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, | 435 | u32 center_freq_khz, |
440 | u32 freq) | 436 | u32 bw_khz) |
441 | { | 437 | { |
442 | unsigned int i; | 438 | u32 start_freq_khz, end_freq_khz; |
443 | for (i = 0; i < ARRAY_SIZE(supported_bandwidths); i++) { | 439 | |
444 | u32 start_freq_khz = freq - supported_bandwidths[i]/2; | 440 | start_freq_khz = center_freq_khz - (bw_khz/2); |
445 | u32 end_freq_khz = freq + supported_bandwidths[i]/2; | 441 | end_freq_khz = center_freq_khz + (bw_khz/2); |
446 | if (start_freq_khz >= freq_range->start_freq_khz && | 442 | |
447 | end_freq_khz <= freq_range->end_freq_khz) | 443 | if (start_freq_khz >= freq_range->start_freq_khz && |
448 | return supported_bandwidths[i]; | 444 | end_freq_khz <= freq_range->end_freq_khz) |
449 | } | 445 | return true; |
450 | return 0; | 446 | |
447 | return false; | ||
451 | } | 448 | } |
452 | 449 | ||
453 | /** | 450 | /** |
@@ -847,14 +844,17 @@ static u32 map_regdom_flags(u32 rd_flags) | |||
847 | 844 | ||
848 | static int freq_reg_info_regd(struct wiphy *wiphy, | 845 | static int freq_reg_info_regd(struct wiphy *wiphy, |
849 | u32 center_freq, | 846 | u32 center_freq, |
850 | u32 *bandwidth, | 847 | u32 desired_bw_khz, |
851 | const struct ieee80211_reg_rule **reg_rule, | 848 | const struct ieee80211_reg_rule **reg_rule, |
852 | const struct ieee80211_regdomain *custom_regd) | 849 | const struct ieee80211_regdomain *custom_regd) |
853 | { | 850 | { |
854 | int i; | 851 | int i; |
855 | bool band_rule_found = false; | 852 | bool band_rule_found = false; |
856 | const struct ieee80211_regdomain *regd; | 853 | const struct ieee80211_regdomain *regd; |
857 | u32 max_bandwidth = 0; | 854 | bool bw_fits = false; |
855 | |||
856 | if (!desired_bw_khz) | ||
857 | desired_bw_khz = MHZ_TO_KHZ(20); | ||
858 | 858 | ||
859 | regd = custom_regd ? custom_regd : cfg80211_regdomain; | 859 | regd = custom_regd ? custom_regd : cfg80211_regdomain; |
860 | 860 | ||
@@ -887,38 +887,54 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
887 | if (!band_rule_found) | 887 | if (!band_rule_found) |
888 | band_rule_found = freq_in_rule_band(fr, center_freq); | 888 | band_rule_found = freq_in_rule_band(fr, center_freq); |
889 | 889 | ||
890 | max_bandwidth = freq_max_bandwidth(fr, center_freq); | 890 | bw_fits = reg_does_bw_fit(fr, |
891 | center_freq, | ||
892 | desired_bw_khz); | ||
891 | 893 | ||
892 | if (max_bandwidth && *bandwidth <= max_bandwidth) { | 894 | if (band_rule_found && bw_fits) { |
893 | *reg_rule = rr; | 895 | *reg_rule = rr; |
894 | *bandwidth = max_bandwidth; | 896 | return 0; |
895 | break; | ||
896 | } | 897 | } |
897 | } | 898 | } |
898 | 899 | ||
899 | if (!band_rule_found) | 900 | if (!band_rule_found) |
900 | return -ERANGE; | 901 | return -ERANGE; |
901 | 902 | ||
902 | return !max_bandwidth; | 903 | return -EINVAL; |
903 | } | 904 | } |
904 | EXPORT_SYMBOL(freq_reg_info); | 905 | EXPORT_SYMBOL(freq_reg_info); |
905 | 906 | ||
906 | int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, | 907 | int freq_reg_info(struct wiphy *wiphy, |
907 | const struct ieee80211_reg_rule **reg_rule) | 908 | u32 center_freq, |
909 | u32 desired_bw_khz, | ||
910 | const struct ieee80211_reg_rule **reg_rule) | ||
908 | { | 911 | { |
909 | assert_cfg80211_lock(); | 912 | assert_cfg80211_lock(); |
910 | return freq_reg_info_regd(wiphy, center_freq, | 913 | return freq_reg_info_regd(wiphy, |
911 | bandwidth, reg_rule, NULL); | 914 | center_freq, |
915 | desired_bw_khz, | ||
916 | reg_rule, | ||
917 | NULL); | ||
912 | } | 918 | } |
913 | 919 | ||
920 | /* | ||
921 | * Note that right now we assume the desired channel bandwidth | ||
922 | * is always 20 MHz for each individual channel (HT40 uses 20 MHz | ||
923 | * per channel, the primary and the extension channel). To support | ||
924 | * smaller custom bandwidths such as 5 MHz or 10 MHz we'll need a | ||
925 | * new ieee80211_channel.target_bw and re run the regulatory check | ||
926 | * on the wiphy with the target_bw specified. Then we can simply use | ||
927 | * that below for the desired_bw_khz below. | ||
928 | */ | ||
914 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | 929 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, |
915 | unsigned int chan_idx) | 930 | unsigned int chan_idx) |
916 | { | 931 | { |
917 | int r; | 932 | int r; |
918 | u32 flags; | 933 | u32 flags, bw_flags = 0; |
919 | u32 max_bandwidth = 0; | 934 | u32 desired_bw_khz = MHZ_TO_KHZ(20); |
920 | const struct ieee80211_reg_rule *reg_rule = NULL; | 935 | const struct ieee80211_reg_rule *reg_rule = NULL; |
921 | const struct ieee80211_power_rule *power_rule = NULL; | 936 | const struct ieee80211_power_rule *power_rule = NULL; |
937 | const struct ieee80211_freq_range *freq_range = NULL; | ||
922 | struct ieee80211_supported_band *sband; | 938 | struct ieee80211_supported_band *sband; |
923 | struct ieee80211_channel *chan; | 939 | struct ieee80211_channel *chan; |
924 | struct wiphy *request_wiphy = NULL; | 940 | struct wiphy *request_wiphy = NULL; |
@@ -933,8 +949,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
933 | 949 | ||
934 | flags = chan->orig_flags; | 950 | flags = chan->orig_flags; |
935 | 951 | ||
936 | r = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq), | 952 | r = freq_reg_info(wiphy, |
937 | &max_bandwidth, ®_rule); | 953 | MHZ_TO_KHZ(chan->center_freq), |
954 | desired_bw_khz, | ||
955 | ®_rule); | ||
938 | 956 | ||
939 | if (r) { | 957 | if (r) { |
940 | /* | 958 | /* |
@@ -977,6 +995,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
977 | } | 995 | } |
978 | 996 | ||
979 | power_rule = ®_rule->power_rule; | 997 | power_rule = ®_rule->power_rule; |
998 | freq_range = ®_rule->freq_range; | ||
999 | |||
1000 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) | ||
1001 | bw_flags = IEEE80211_CHAN_NO_HT40; | ||
980 | 1002 | ||
981 | if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && | 1003 | if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && |
982 | request_wiphy && request_wiphy == wiphy && | 1004 | request_wiphy && request_wiphy == wiphy && |
@@ -987,19 +1009,19 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
987 | * settings | 1009 | * settings |
988 | */ | 1010 | */ |
989 | chan->flags = chan->orig_flags = | 1011 | chan->flags = chan->orig_flags = |
990 | map_regdom_flags(reg_rule->flags); | 1012 | map_regdom_flags(reg_rule->flags) | bw_flags; |
991 | chan->max_antenna_gain = chan->orig_mag = | 1013 | chan->max_antenna_gain = chan->orig_mag = |
992 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1014 | (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
993 | chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); | 1015 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); |
994 | chan->max_power = chan->orig_mpwr = | 1016 | chan->max_power = chan->orig_mpwr = |
995 | (int) MBM_TO_DBM(power_rule->max_eirp); | 1017 | (int) MBM_TO_DBM(power_rule->max_eirp); |
996 | return; | 1018 | return; |
997 | } | 1019 | } |
998 | 1020 | ||
999 | chan->flags = flags | map_regdom_flags(reg_rule->flags); | 1021 | chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); |
1000 | chan->max_antenna_gain = min(chan->orig_mag, | 1022 | chan->max_antenna_gain = min(chan->orig_mag, |
1001 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); | 1023 | (int) MBI_TO_DBI(power_rule->max_antenna_gain)); |
1002 | chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); | 1024 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); |
1003 | if (chan->orig_mpwr) | 1025 | if (chan->orig_mpwr) |
1004 | chan->max_power = min(chan->orig_mpwr, | 1026 | chan->max_power = min(chan->orig_mpwr, |
1005 | (int) MBM_TO_DBM(power_rule->max_eirp)); | 1027 | (int) MBM_TO_DBM(power_rule->max_eirp)); |
@@ -1156,6 +1178,93 @@ static void reg_process_beacons(struct wiphy *wiphy) | |||
1156 | wiphy_update_beacon_reg(wiphy); | 1178 | wiphy_update_beacon_reg(wiphy); |
1157 | } | 1179 | } |
1158 | 1180 | ||
1181 | static bool is_ht40_not_allowed(struct ieee80211_channel *chan) | ||
1182 | { | ||
1183 | if (!chan) | ||
1184 | return true; | ||
1185 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
1186 | return true; | ||
1187 | /* This would happen when regulatory rules disallow HT40 completely */ | ||
1188 | if (IEEE80211_CHAN_NO_HT40 == (chan->flags & (IEEE80211_CHAN_NO_HT40))) | ||
1189 | return true; | ||
1190 | return false; | ||
1191 | } | ||
1192 | |||
1193 | static void reg_process_ht_flags_channel(struct wiphy *wiphy, | ||
1194 | enum ieee80211_band band, | ||
1195 | unsigned int chan_idx) | ||
1196 | { | ||
1197 | struct ieee80211_supported_band *sband; | ||
1198 | struct ieee80211_channel *channel; | ||
1199 | struct ieee80211_channel *channel_before = NULL, *channel_after = NULL; | ||
1200 | unsigned int i; | ||
1201 | |||
1202 | assert_cfg80211_lock(); | ||
1203 | |||
1204 | sband = wiphy->bands[band]; | ||
1205 | BUG_ON(chan_idx >= sband->n_channels); | ||
1206 | channel = &sband->channels[chan_idx]; | ||
1207 | |||
1208 | if (is_ht40_not_allowed(channel)) { | ||
1209 | channel->flags |= IEEE80211_CHAN_NO_HT40; | ||
1210 | return; | ||
1211 | } | ||
1212 | |||
1213 | /* | ||
1214 | * We need to ensure the extension channels exist to | ||
1215 | * be able to use HT40- or HT40+, this finds them (or not) | ||
1216 | */ | ||
1217 | for (i = 0; i < sband->n_channels; i++) { | ||
1218 | struct ieee80211_channel *c = &sband->channels[i]; | ||
1219 | if (c->center_freq == (channel->center_freq - 20)) | ||
1220 | channel_before = c; | ||
1221 | if (c->center_freq == (channel->center_freq + 20)) | ||
1222 | channel_after = c; | ||
1223 | } | ||
1224 | |||
1225 | /* | ||
1226 | * Please note that this assumes target bandwidth is 20 MHz, | ||
1227 | * if that ever changes we also need to change the below logic | ||
1228 | * to include that as well. | ||
1229 | */ | ||
1230 | if (is_ht40_not_allowed(channel_before)) | ||
1231 | channel->flags |= IEEE80211_CHAN_NO_HT40MINUS; | ||
1232 | else | ||
1233 | channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | ||
1234 | |||
1235 | if (is_ht40_not_allowed(channel_after)) | ||
1236 | channel->flags |= IEEE80211_CHAN_NO_HT40PLUS; | ||
1237 | else | ||
1238 | channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | ||
1239 | } | ||
1240 | |||
1241 | static void reg_process_ht_flags_band(struct wiphy *wiphy, | ||
1242 | enum ieee80211_band band) | ||
1243 | { | ||
1244 | unsigned int i; | ||
1245 | struct ieee80211_supported_band *sband; | ||
1246 | |||
1247 | BUG_ON(!wiphy->bands[band]); | ||
1248 | sband = wiphy->bands[band]; | ||
1249 | |||
1250 | for (i = 0; i < sband->n_channels; i++) | ||
1251 | reg_process_ht_flags_channel(wiphy, band, i); | ||
1252 | } | ||
1253 | |||
1254 | static void reg_process_ht_flags(struct wiphy *wiphy) | ||
1255 | { | ||
1256 | enum ieee80211_band band; | ||
1257 | |||
1258 | if (!wiphy) | ||
1259 | return; | ||
1260 | |||
1261 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1262 | if (wiphy->bands[band]) | ||
1263 | reg_process_ht_flags_band(wiphy, band); | ||
1264 | } | ||
1265 | |||
1266 | } | ||
1267 | |||
1159 | void wiphy_update_regulatory(struct wiphy *wiphy, | 1268 | void wiphy_update_regulatory(struct wiphy *wiphy, |
1160 | enum nl80211_reg_initiator initiator) | 1269 | enum nl80211_reg_initiator initiator) |
1161 | { | 1270 | { |
@@ -1169,6 +1278,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1169 | } | 1278 | } |
1170 | out: | 1279 | out: |
1171 | reg_process_beacons(wiphy); | 1280 | reg_process_beacons(wiphy); |
1281 | reg_process_ht_flags(wiphy); | ||
1172 | if (wiphy->reg_notifier) | 1282 | if (wiphy->reg_notifier) |
1173 | wiphy->reg_notifier(wiphy, last_request); | 1283 | wiphy->reg_notifier(wiphy, last_request); |
1174 | } | 1284 | } |
@@ -1179,9 +1289,11 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1179 | const struct ieee80211_regdomain *regd) | 1289 | const struct ieee80211_regdomain *regd) |
1180 | { | 1290 | { |
1181 | int r; | 1291 | int r; |
1182 | u32 max_bandwidth = 0; | 1292 | u32 desired_bw_khz = MHZ_TO_KHZ(20); |
1293 | u32 bw_flags = 0; | ||
1183 | const struct ieee80211_reg_rule *reg_rule = NULL; | 1294 | const struct ieee80211_reg_rule *reg_rule = NULL; |
1184 | const struct ieee80211_power_rule *power_rule = NULL; | 1295 | const struct ieee80211_power_rule *power_rule = NULL; |
1296 | const struct ieee80211_freq_range *freq_range = NULL; | ||
1185 | struct ieee80211_supported_band *sband; | 1297 | struct ieee80211_supported_band *sband; |
1186 | struct ieee80211_channel *chan; | 1298 | struct ieee80211_channel *chan; |
1187 | 1299 | ||
@@ -1191,8 +1303,11 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1191 | BUG_ON(chan_idx >= sband->n_channels); | 1303 | BUG_ON(chan_idx >= sband->n_channels); |
1192 | chan = &sband->channels[chan_idx]; | 1304 | chan = &sband->channels[chan_idx]; |
1193 | 1305 | ||
1194 | r = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq), | 1306 | r = freq_reg_info_regd(wiphy, |
1195 | &max_bandwidth, ®_rule, regd); | 1307 | MHZ_TO_KHZ(chan->center_freq), |
1308 | desired_bw_khz, | ||
1309 | ®_rule, | ||
1310 | regd); | ||
1196 | 1311 | ||
1197 | if (r) { | 1312 | if (r) { |
1198 | chan->flags = IEEE80211_CHAN_DISABLED; | 1313 | chan->flags = IEEE80211_CHAN_DISABLED; |
@@ -1200,10 +1315,14 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1200 | } | 1315 | } |
1201 | 1316 | ||
1202 | power_rule = ®_rule->power_rule; | 1317 | power_rule = ®_rule->power_rule; |
1318 | freq_range = ®_rule->freq_range; | ||
1203 | 1319 | ||
1204 | chan->flags |= map_regdom_flags(reg_rule->flags); | 1320 | if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) |
1321 | bw_flags = IEEE80211_CHAN_NO_HT40; | ||
1322 | |||
1323 | chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags; | ||
1205 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); | 1324 | chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain); |
1206 | chan->max_bandwidth = KHZ_TO_MHZ(max_bandwidth); | 1325 | chan->max_bandwidth = KHZ_TO_MHZ(desired_bw_khz); |
1207 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 1326 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
1208 | } | 1327 | } |
1209 | 1328 | ||
@@ -1225,13 +1344,22 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1225 | const struct ieee80211_regdomain *regd) | 1344 | const struct ieee80211_regdomain *regd) |
1226 | { | 1345 | { |
1227 | enum ieee80211_band band; | 1346 | enum ieee80211_band band; |
1347 | unsigned int bands_set = 0; | ||
1228 | 1348 | ||
1229 | mutex_lock(&cfg80211_mutex); | 1349 | mutex_lock(&cfg80211_mutex); |
1230 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1350 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1231 | if (wiphy->bands[band]) | 1351 | if (!wiphy->bands[band]) |
1232 | handle_band_custom(wiphy, band, regd); | 1352 | continue; |
1353 | handle_band_custom(wiphy, band, regd); | ||
1354 | bands_set++; | ||
1233 | } | 1355 | } |
1234 | mutex_unlock(&cfg80211_mutex); | 1356 | mutex_unlock(&cfg80211_mutex); |
1357 | |||
1358 | /* | ||
1359 | * no point in calling this if it won't have any effect | ||
1360 | * on your device's supportd bands. | ||
1361 | */ | ||
1362 | WARN_ON(!bands_set); | ||
1235 | } | 1363 | } |
1236 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1364 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
1237 | 1365 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index beb226e78cd7..d072bff463aa 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -4,7 +4,9 @@ | |||
4 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #include <linux/bitops.h> | 6 | #include <linux/bitops.h> |
7 | #include <linux/etherdevice.h> | ||
7 | #include <net/cfg80211.h> | 8 | #include <net/cfg80211.h> |
9 | #include <net/ip.h> | ||
8 | #include "core.h" | 10 | #include "core.h" |
9 | 11 | ||
10 | struct ieee80211_rate * | 12 | struct ieee80211_rate * |
@@ -181,5 +183,323 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | |||
181 | return -EINVAL; | 183 | return -EINVAL; |
182 | } | 184 | } |
183 | 185 | ||
186 | if (params->seq) { | ||
187 | switch (params->cipher) { | ||
188 | case WLAN_CIPHER_SUITE_WEP40: | ||
189 | case WLAN_CIPHER_SUITE_WEP104: | ||
190 | /* These ciphers do not use key sequence */ | ||
191 | return -EINVAL; | ||
192 | case WLAN_CIPHER_SUITE_TKIP: | ||
193 | case WLAN_CIPHER_SUITE_CCMP: | ||
194 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
195 | if (params->seq_len != 6) | ||
196 | return -EINVAL; | ||
197 | break; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
205 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
206 | const unsigned char rfc1042_header[] __aligned(2) = | ||
207 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
208 | EXPORT_SYMBOL(rfc1042_header); | ||
209 | |||
210 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
211 | const unsigned char bridge_tunnel_header[] __aligned(2) = | ||
212 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
213 | EXPORT_SYMBOL(bridge_tunnel_header); | ||
214 | |||
215 | unsigned int ieee80211_hdrlen(__le16 fc) | ||
216 | { | ||
217 | unsigned int hdrlen = 24; | ||
218 | |||
219 | if (ieee80211_is_data(fc)) { | ||
220 | if (ieee80211_has_a4(fc)) | ||
221 | hdrlen = 30; | ||
222 | if (ieee80211_is_data_qos(fc)) | ||
223 | hdrlen += IEEE80211_QOS_CTL_LEN; | ||
224 | goto out; | ||
225 | } | ||
226 | |||
227 | if (ieee80211_is_ctl(fc)) { | ||
228 | /* | ||
229 | * ACK and CTS are 10 bytes, all others 16. To see how | ||
230 | * to get this condition consider | ||
231 | * subtype mask: 0b0000000011110000 (0x00F0) | ||
232 | * ACK subtype: 0b0000000011010000 (0x00D0) | ||
233 | * CTS subtype: 0b0000000011000000 (0x00C0) | ||
234 | * bits that matter: ^^^ (0x00E0) | ||
235 | * value of those: 0b0000000011000000 (0x00C0) | ||
236 | */ | ||
237 | if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) | ||
238 | hdrlen = 10; | ||
239 | else | ||
240 | hdrlen = 16; | ||
241 | } | ||
242 | out: | ||
243 | return hdrlen; | ||
244 | } | ||
245 | EXPORT_SYMBOL(ieee80211_hdrlen); | ||
246 | |||
247 | unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | ||
248 | { | ||
249 | const struct ieee80211_hdr *hdr = | ||
250 | (const struct ieee80211_hdr *)skb->data; | ||
251 | unsigned int hdrlen; | ||
252 | |||
253 | if (unlikely(skb->len < 10)) | ||
254 | return 0; | ||
255 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
256 | if (unlikely(hdrlen > skb->len)) | ||
257 | return 0; | ||
258 | return hdrlen; | ||
259 | } | ||
260 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | ||
261 | |||
262 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||
263 | { | ||
264 | int ae = meshhdr->flags & MESH_FLAGS_AE; | ||
265 | /* 7.1.3.5a.2 */ | ||
266 | switch (ae) { | ||
267 | case 0: | ||
268 | return 6; | ||
269 | case 1: | ||
270 | return 12; | ||
271 | case 2: | ||
272 | return 18; | ||
273 | case 3: | ||
274 | return 24; | ||
275 | default: | ||
276 | return 6; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | ||
281 | enum nl80211_iftype iftype) | ||
282 | { | ||
283 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
284 | u16 hdrlen, ethertype; | ||
285 | u8 *payload; | ||
286 | u8 dst[ETH_ALEN]; | ||
287 | u8 src[ETH_ALEN] __aligned(2); | ||
288 | |||
289 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | ||
290 | return -1; | ||
291 | |||
292 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||
293 | |||
294 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | ||
295 | * header | ||
296 | * IEEE 802.11 address fields: | ||
297 | * ToDS FromDS Addr1 Addr2 Addr3 Addr4 | ||
298 | * 0 0 DA SA BSSID n/a | ||
299 | * 0 1 DA BSSID SA n/a | ||
300 | * 1 0 BSSID SA DA n/a | ||
301 | * 1 1 RA TA DA SA | ||
302 | */ | ||
303 | memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); | ||
304 | memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); | ||
305 | |||
306 | switch (hdr->frame_control & | ||
307 | cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | ||
308 | case cpu_to_le16(IEEE80211_FCTL_TODS): | ||
309 | if (unlikely(iftype != NL80211_IFTYPE_AP && | ||
310 | iftype != NL80211_IFTYPE_AP_VLAN)) | ||
311 | return -1; | ||
312 | break; | ||
313 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | ||
314 | if (unlikely(iftype != NL80211_IFTYPE_WDS && | ||
315 | iftype != NL80211_IFTYPE_MESH_POINT)) | ||
316 | return -1; | ||
317 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||
318 | struct ieee80211s_hdr *meshdr = | ||
319 | (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
320 | hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||
321 | if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { | ||
322 | memcpy(dst, meshdr->eaddr1, ETH_ALEN); | ||
323 | memcpy(src, meshdr->eaddr2, ETH_ALEN); | ||
324 | } | ||
325 | } | ||
326 | break; | ||
327 | case cpu_to_le16(IEEE80211_FCTL_FROMDS): | ||
328 | if (iftype != NL80211_IFTYPE_STATION || | ||
329 | (is_multicast_ether_addr(dst) && | ||
330 | !compare_ether_addr(src, addr))) | ||
331 | return -1; | ||
332 | break; | ||
333 | case cpu_to_le16(0): | ||
334 | if (iftype != NL80211_IFTYPE_ADHOC) | ||
335 | return -1; | ||
336 | break; | ||
337 | } | ||
338 | |||
339 | if (unlikely(skb->len - hdrlen < 8)) | ||
340 | return -1; | ||
341 | |||
342 | payload = skb->data + hdrlen; | ||
343 | ethertype = (payload[6] << 8) | payload[7]; | ||
344 | |||
345 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | ||
346 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
347 | compare_ether_addr(payload, bridge_tunnel_header) == 0)) { | ||
348 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
349 | * replace EtherType */ | ||
350 | skb_pull(skb, hdrlen + 6); | ||
351 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
352 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
353 | } else { | ||
354 | struct ethhdr *ehdr; | ||
355 | __be16 len; | ||
356 | |||
357 | skb_pull(skb, hdrlen); | ||
358 | len = htons(skb->len); | ||
359 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | ||
360 | memcpy(ehdr->h_dest, dst, ETH_ALEN); | ||
361 | memcpy(ehdr->h_source, src, ETH_ALEN); | ||
362 | ehdr->h_proto = len; | ||
363 | } | ||
364 | return 0; | ||
365 | } | ||
366 | EXPORT_SYMBOL(ieee80211_data_to_8023); | ||
367 | |||
368 | int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr, | ||
369 | enum nl80211_iftype iftype, u8 *bssid, bool qos) | ||
370 | { | ||
371 | struct ieee80211_hdr hdr; | ||
372 | u16 hdrlen, ethertype; | ||
373 | __le16 fc; | ||
374 | const u8 *encaps_data; | ||
375 | int encaps_len, skip_header_bytes; | ||
376 | int nh_pos, h_pos; | ||
377 | int head_need; | ||
378 | |||
379 | if (unlikely(skb->len < ETH_HLEN)) | ||
380 | return -EINVAL; | ||
381 | |||
382 | nh_pos = skb_network_header(skb) - skb->data; | ||
383 | h_pos = skb_transport_header(skb) - skb->data; | ||
384 | |||
385 | /* convert Ethernet header to proper 802.11 header (based on | ||
386 | * operation mode) */ | ||
387 | ethertype = (skb->data[12] << 8) | skb->data[13]; | ||
388 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | ||
389 | |||
390 | switch (iftype) { | ||
391 | case NL80211_IFTYPE_AP: | ||
392 | case NL80211_IFTYPE_AP_VLAN: | ||
393 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | ||
394 | /* DA BSSID SA */ | ||
395 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
396 | memcpy(hdr.addr2, addr, ETH_ALEN); | ||
397 | memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); | ||
398 | hdrlen = 24; | ||
399 | break; | ||
400 | case NL80211_IFTYPE_STATION: | ||
401 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
402 | /* BSSID SA DA */ | ||
403 | memcpy(hdr.addr1, bssid, ETH_ALEN); | ||
404 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
405 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
406 | hdrlen = 24; | ||
407 | break; | ||
408 | case NL80211_IFTYPE_ADHOC: | ||
409 | /* DA SA BSSID */ | ||
410 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
411 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
412 | memcpy(hdr.addr3, bssid, ETH_ALEN); | ||
413 | hdrlen = 24; | ||
414 | break; | ||
415 | default: | ||
416 | return -EOPNOTSUPP; | ||
417 | } | ||
418 | |||
419 | if (qos) { | ||
420 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | ||
421 | hdrlen += 2; | ||
422 | } | ||
423 | |||
424 | hdr.frame_control = fc; | ||
425 | hdr.duration_id = 0; | ||
426 | hdr.seq_ctrl = 0; | ||
427 | |||
428 | skip_header_bytes = ETH_HLEN; | ||
429 | if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { | ||
430 | encaps_data = bridge_tunnel_header; | ||
431 | encaps_len = sizeof(bridge_tunnel_header); | ||
432 | skip_header_bytes -= 2; | ||
433 | } else if (ethertype > 0x600) { | ||
434 | encaps_data = rfc1042_header; | ||
435 | encaps_len = sizeof(rfc1042_header); | ||
436 | skip_header_bytes -= 2; | ||
437 | } else { | ||
438 | encaps_data = NULL; | ||
439 | encaps_len = 0; | ||
440 | } | ||
441 | |||
442 | skb_pull(skb, skip_header_bytes); | ||
443 | nh_pos -= skip_header_bytes; | ||
444 | h_pos -= skip_header_bytes; | ||
445 | |||
446 | head_need = hdrlen + encaps_len - skb_headroom(skb); | ||
447 | |||
448 | if (head_need > 0 || skb_cloned(skb)) { | ||
449 | head_need = max(head_need, 0); | ||
450 | if (head_need) | ||
451 | skb_orphan(skb); | ||
452 | |||
453 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { | ||
454 | printk(KERN_ERR "failed to reallocate Tx buffer\n"); | ||
455 | return -ENOMEM; | ||
456 | } | ||
457 | skb->truesize += head_need; | ||
458 | } | ||
459 | |||
460 | if (encaps_data) { | ||
461 | memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); | ||
462 | nh_pos += encaps_len; | ||
463 | h_pos += encaps_len; | ||
464 | } | ||
465 | |||
466 | memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); | ||
467 | |||
468 | nh_pos += hdrlen; | ||
469 | h_pos += hdrlen; | ||
470 | |||
471 | /* Update skb pointers to various headers since this modified frame | ||
472 | * is going to go through Linux networking code that may potentially | ||
473 | * need things like pointer to IP header. */ | ||
474 | skb_set_mac_header(skb, 0); | ||
475 | skb_set_network_header(skb, nh_pos); | ||
476 | skb_set_transport_header(skb, h_pos); | ||
477 | |||
184 | return 0; | 478 | return 0; |
185 | } | 479 | } |
480 | EXPORT_SYMBOL(ieee80211_data_from_8023); | ||
481 | |||
482 | /* Given a data frame determine the 802.1p/1d tag to use. */ | ||
483 | unsigned int cfg80211_classify8021d(struct sk_buff *skb) | ||
484 | { | ||
485 | unsigned int dscp; | ||
486 | |||
487 | /* skb->priority values from 256->263 are magic values to | ||
488 | * directly indicate a specific 802.1d priority. This is used | ||
489 | * to allow 802.1d priority to be passed directly in from VLAN | ||
490 | * tags, etc. | ||
491 | */ | ||
492 | if (skb->priority >= 256 && skb->priority <= 263) | ||
493 | return skb->priority - 256; | ||
494 | |||
495 | switch (skb->protocol) { | ||
496 | case htons(ETH_P_IP): | ||
497 | dscp = ip_hdr(skb)->tos & 0xfc; | ||
498 | break; | ||
499 | default: | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | return dscp >> 5; | ||
504 | } | ||
505 | EXPORT_SYMBOL(cfg80211_classify8021d); | ||
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index f98090b90fbf..711e00a0c9b5 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -504,6 +504,13 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
504 | else if (idx == wdev->wext.default_mgmt_key) | 504 | else if (idx == wdev->wext.default_mgmt_key) |
505 | wdev->wext.default_mgmt_key = -1; | 505 | wdev->wext.default_mgmt_key = -1; |
506 | } | 506 | } |
507 | /* | ||
508 | * Applications using wireless extensions expect to be | ||
509 | * able to delete keys that don't exist, so allow that. | ||
510 | */ | ||
511 | if (err == -ENOENT) | ||
512 | return 0; | ||
513 | |||
507 | return err; | 514 | return err; |
508 | } else { | 515 | } else { |
509 | if (addr) | 516 | if (addr) |
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index d3bbef70cc7c..22378daceb94 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -636,8 +636,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq, | |||
636 | /* | 636 | /* |
637 | * Print info for /proc/net/wireless (print all entries) | 637 | * Print info for /proc/net/wireless (print all entries) |
638 | */ | 638 | */ |
639 | static int wireless_seq_show(struct seq_file *seq, void *v) | 639 | static int wireless_dev_seq_show(struct seq_file *seq, void *v) |
640 | { | 640 | { |
641 | might_sleep(); | ||
642 | |||
641 | if (v == SEQ_START_TOKEN) | 643 | if (v == SEQ_START_TOKEN) |
642 | seq_printf(seq, "Inter-| sta-| Quality | Discarded " | 644 | seq_printf(seq, "Inter-| sta-| Quality | Discarded " |
643 | "packets | Missed | WE\n" | 645 | "packets | Missed | WE\n" |
@@ -651,21 +653,41 @@ static int wireless_seq_show(struct seq_file *seq, void *v) | |||
651 | 653 | ||
652 | static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) | 654 | static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) |
653 | { | 655 | { |
656 | struct net *net = seq_file_net(seq); | ||
657 | loff_t off; | ||
658 | struct net_device *dev; | ||
659 | |||
654 | rtnl_lock(); | 660 | rtnl_lock(); |
655 | return dev_seq_start(seq, pos); | 661 | if (!*pos) |
662 | return SEQ_START_TOKEN; | ||
663 | |||
664 | off = 1; | ||
665 | for_each_netdev(net, dev) | ||
666 | if (off++ == *pos) | ||
667 | return dev; | ||
668 | return NULL; | ||
669 | } | ||
670 | |||
671 | static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
672 | { | ||
673 | struct net *net = seq_file_net(seq); | ||
674 | |||
675 | ++*pos; | ||
676 | |||
677 | return v == SEQ_START_TOKEN ? | ||
678 | first_net_device(net) : next_net_device(v); | ||
656 | } | 679 | } |
657 | 680 | ||
658 | static void wireless_dev_seq_stop(struct seq_file *seq, void *v) | 681 | static void wireless_dev_seq_stop(struct seq_file *seq, void *v) |
659 | { | 682 | { |
660 | dev_seq_stop(seq, v); | ||
661 | rtnl_unlock(); | 683 | rtnl_unlock(); |
662 | } | 684 | } |
663 | 685 | ||
664 | static const struct seq_operations wireless_seq_ops = { | 686 | static const struct seq_operations wireless_seq_ops = { |
665 | .start = wireless_dev_seq_start, | 687 | .start = wireless_dev_seq_start, |
666 | .next = dev_seq_next, | 688 | .next = wireless_dev_seq_next, |
667 | .stop = wireless_dev_seq_stop, | 689 | .stop = wireless_dev_seq_stop, |
668 | .show = wireless_seq_show, | 690 | .show = wireless_dev_seq_show, |
669 | }; | 691 | }; |
670 | 692 | ||
671 | static int seq_open_wireless(struct inode *inode, struct file *file) | 693 | static int seq_open_wireless(struct inode *inode, struct file *file) |