d6bc232b72c8e44db49f134980d03f4bd2cfc5f8
[openwrt.git] / package / mac80211 / patches / 340-ath9k_ap_rc.patch
1 Hostapd now passes the HT parameters through the config()
2 callback, use these to set the appropriate channel in AP mode.
3
4 Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
5 ---
6 Note: This patch depends on [PATCHv2] nl80211: Add frequency configuration (including HT40)
7 posted by Jouni.
8
9  drivers/net/wireless/ath9k/main.c |   60 ++++++++++++++++++++++++++----------
10  drivers/net/wireless/ath9k/rc.c   |   55 +++++++++++++++++++++++++++++----
11  2 files changed, 91 insertions(+), 24 deletions(-)
12
13 diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
14 index 6e103d5..d1ddb07 100644
15 --- a/drivers/net/wireless/ath9k/main.c
16 +++ b/drivers/net/wireless/ath9k/main.c
17 @@ -622,35 +622,35 @@ static int ath_get_channel(struct ath_softc *sc,
18         return -1;
19  }
20  
21 +/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
22 +
23  static u32 ath_get_extchanmode(struct ath_softc *sc,
24                                struct ieee80211_channel *chan,
25 -                              struct ieee80211_bss_conf *bss_conf)
26 +                              int ext_chan_offset,
27 +                              enum ath9k_ht_macmode tx_chan_width)
28  {
29         u32 chanmode = 0;
30 -       u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset;
31 -       enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ?
32 -               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
33  
34         switch (chan->band) {
35         case IEEE80211_BAND_2GHZ:
36 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
37 +               if ((ext_chan_offset == 0) &&
38                     (tx_chan_width == ATH9K_HT_MACMODE_20))
39                         chanmode = CHANNEL_G_HT20;
40 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
41 +               if ((ext_chan_offset == 1) &&
42                     (tx_chan_width == ATH9K_HT_MACMODE_2040))
43                         chanmode = CHANNEL_G_HT40PLUS;
44 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
45 +               if ((ext_chan_offset == -1) &&
46                     (tx_chan_width == ATH9K_HT_MACMODE_2040))
47                         chanmode = CHANNEL_G_HT40MINUS;
48                 break;
49         case IEEE80211_BAND_5GHZ:
50 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
51 +               if ((ext_chan_offset == 0) &&
52                     (tx_chan_width == ATH9K_HT_MACMODE_20))
53                         chanmode = CHANNEL_A_HT20;
54 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
55 +               if ((ext_chan_offset == 1) &&
56                     (tx_chan_width == ATH9K_HT_MACMODE_2040))
57                         chanmode = CHANNEL_A_HT40PLUS;
58 -               if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
59 +               if ((ext_chan_offset == -1) &&
60                     (tx_chan_width == ATH9K_HT_MACMODE_2040))
61                         chanmode = CHANNEL_A_HT40MINUS;
62                 break;
63 @@ -841,6 +841,18 @@ static void ath9k_ht_conf(struct ath_softc *sc,
64         }
65  }
66  
67 +static inline int ath_sec_offset(u8 ext_offset)
68 +{
69 +       if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
70 +               return 0;
71 +       else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
72 +               return 1;
73 +       else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
74 +               return -1;
75 +
76 +       return 0;
77 +}
78 +
79  static void ath9k_bss_assoc_info(struct ath_softc *sc,
80                                  struct ieee80211_vif *vif,
81                                  struct ieee80211_bss_conf *bss_conf)
82 @@ -893,13 +905,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
83                 }
84  
85                 if (hw->conf.ht.enabled) {
86 -                       sc->sc_ah->ah_channels[pos].chanmode =
87 -                               ath_get_extchanmode(sc, curchan, bss_conf);
88 +                       int offset =
89 +                               ath_sec_offset(bss_conf->ht.secondary_channel_offset);
90 +                       sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
91 +                               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
92  
93 -                       if (bss_conf->ht.width_40_ok)
94 -                               sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
95 -                       else
96 -                               sc->tx_chan_width = ATH9K_HT_MACMODE_20;
97 +                       sc->sc_ah->ah_channels[pos].chanmode =
98 +                               ath_get_extchanmode(sc, curchan,
99 +                                                   offset, sc->tx_chan_width);
100                 } else {
101                         sc->sc_ah->ah_channels[pos].chanmode =
102                                 (curchan->band == IEEE80211_BAND_2GHZ) ?
103 @@ -2172,9 +2185,22 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
104                         (curchan->band == IEEE80211_BAND_2GHZ) ?
105                         CHANNEL_G : CHANNEL_A;
106  
107 -               if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
108 +               if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) &&
109 +                   (conf->ht.enabled)) {
110 +                       sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
111 +                               ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
112 +
113 +                       sc->sc_ah->ah_channels[pos].chanmode =
114 +                               ath_get_extchanmode(sc, curchan,
115 +                                                   conf->ht.sec_chan_offset,
116 +                                                   sc->tx_chan_width);
117 +               }
118 +
119 +               if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
120                         DPRINTF(sc, ATH_DBG_FATAL,
121                                 "%s: Unable to set channel\n", __func__);
122 +                       return -EINVAL;
123 +               }
124         }
125  
126         if (changed & IEEE80211_CONF_CHANGE_HT)
127 diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
128 index 93dfea8..7c08583 100644
129 --- a/drivers/net/wireless/ath9k/rc.c
130 +++ b/drivers/net/wireless/ath9k/rc.c
131 @@ -1304,6 +1304,38 @@ static void ath_rc_tx_status(struct ath_softc *sc,
132                          xretries, long_retry);
133  }
134  
135 +static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
136 +                                                   enum ieee80211_band band,
137 +                                                   bool is_ht, bool is_cw_40)
138 +{
139 +       int mode = 0;
140 +
141 +       switch(band) {
142 +       case IEEE80211_BAND_2GHZ:
143 +               mode = ATH9K_MODE_11G;
144 +               if (is_ht)
145 +                       mode = ATH9K_MODE_11NG_HT20;
146 +               if (is_cw_40)
147 +                       mode = ATH9K_MODE_11NG_HT40PLUS;
148 +               break;
149 +       case IEEE80211_BAND_5GHZ:
150 +               mode = ATH9K_MODE_11A;
151 +               if (is_ht)
152 +                       mode = ATH9K_MODE_11NA_HT20;
153 +               if (is_cw_40)
154 +                       mode = ATH9K_MODE_11NA_HT40PLUS;
155 +               break;
156 +       default:
157 +               DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n");
158 +               return NULL;
159 +       }
160 +
161 +       BUG_ON(mode >= ATH9K_MODE_MAX);
162 +
163 +       DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode);
164 +       return sc->hw_rate_table[mode];
165 +}
166 +
167  static void ath_rc_init(struct ath_softc *sc,
168                         struct ath_rate_priv *ath_rc_priv,
169                         struct ieee80211_supported_band *sband,
170 @@ -1314,16 +1346,25 @@ static void ath_rc_init(struct ath_softc *sc,
171         u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
172         u8 i, j, k, hi = 0, hthi = 0;
173  
174 -       rate_table = sc->hw_rate_table[sc->sc_curmode];
175 +       /* FIXME: Adhoc */
176 +       if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
177 +           (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) {
178 +               bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
179 +               rate_table = ath_choose_rate_table(sc, sband->band,
180 +                                                  sta->ht_cap.ht_supported,
181 +                                                  is_cw_40);
182 +       } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
183 +               /* sc_curmode would be set on init through config() */
184 +               rate_table = sc->hw_rate_table[sc->sc_curmode];
185 +       }
186  
187 -       if (sta->ht_cap.ht_supported) {
188 -               if (sband->band == IEEE80211_BAND_2GHZ)
189 -                       rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
190 -               else
191 -                       rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
192 +       if (!rate_table) {
193 +               DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
194 +               return;
195 +       }
196  
197 +       if (sta->ht_cap.ht_supported) {
198                 ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
199 -
200                 if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
201                         ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
202         }
203 -- 
204 1.6.0.3
205
206 --
207 To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
208 the body of a message to majordomo@vger.kernel.org
209 More majordomo info at  http://vger.kernel.org/majordomo-info.html
210