diff options
author | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
commit | 6373464288cab09bc641be301d8d30fc9f64ba71 (patch) | |
tree | c1bc92dc630aa15da2e12bc0d09c92169817a702 | |
parent | 6d955180b2f9ccff444df06265160868cabb289a (diff) | |
parent | 730dd70549e0ec755dd55615ba5cfc38a482a947 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts:
drivers/net/wireless/iwlwifi/iwl-core.h
92 files changed, 7260 insertions, 2757 deletions
diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl index f3f37f141dbd..971d1c0c83e5 100644 --- a/Documentation/DocBook/mac80211.tmpl +++ b/Documentation/DocBook/mac80211.tmpl | |||
@@ -144,7 +144,7 @@ usage should require reading the full document. | |||
144 | this though and the recommendation to allow only a single | 144 | this though and the recommendation to allow only a single |
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_vif |
148 | </chapter> | 148 | </chapter> |
149 | 149 | ||
150 | <chapter id="rx-tx"> | 150 | <chapter id="rx-tx"> |
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 6a2a96761111..66bcb506a112 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h | |||
@@ -1063,6 +1063,7 @@ struct ath5k_hw { | |||
1063 | u32 ah_cw_min; | 1063 | u32 ah_cw_min; |
1064 | u32 ah_cw_max; | 1064 | u32 ah_cw_max; |
1065 | u32 ah_limit_tx_retries; | 1065 | u32 ah_limit_tx_retries; |
1066 | u8 ah_coverage_class; | ||
1066 | 1067 | ||
1067 | /* Antenna Control */ | 1068 | /* Antenna Control */ |
1068 | u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; | 1069 | u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; |
@@ -1200,6 +1201,7 @@ extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); | |||
1200 | 1201 | ||
1201 | /* Protocol Control Unit Functions */ | 1202 | /* Protocol Control Unit Functions */ |
1202 | extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); | 1203 | extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); |
1204 | extern void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class); | ||
1203 | /* BSSID Functions */ | 1205 | /* BSSID Functions */ |
1204 | extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); | 1206 | extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); |
1205 | extern void ath5k_hw_set_associd(struct ath5k_hw *ah); | 1207 | extern void ath5k_hw_set_associd(struct ath5k_hw *ah); |
@@ -1231,6 +1233,10 @@ extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); | |||
1231 | extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); | 1233 | extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); |
1232 | extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); | 1234 | extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); |
1233 | extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); | 1235 | extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); |
1236 | /* Clock rate related functions */ | ||
1237 | unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec); | ||
1238 | unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock); | ||
1239 | unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah); | ||
1234 | /* Key table (WEP) functions */ | 1240 | /* Key table (WEP) functions */ |
1235 | extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); | 1241 | extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); |
1236 | extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); | 1242 | extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); |
@@ -1310,24 +1316,6 @@ extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower); | |||
1310 | * Functions used internaly | 1316 | * Functions used internaly |
1311 | */ | 1317 | */ |
1312 | 1318 | ||
1313 | /* | ||
1314 | * Translate usec to hw clock units | ||
1315 | * TODO: Half/quarter rate | ||
1316 | */ | ||
1317 | static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) | ||
1318 | { | ||
1319 | return turbo ? (usec * 80) : (usec * 40); | ||
1320 | } | ||
1321 | |||
1322 | /* | ||
1323 | * Translate hw clock units to usec | ||
1324 | * TODO: Half/quarter rate | ||
1325 | */ | ||
1326 | static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) | ||
1327 | { | ||
1328 | return turbo ? (clock / 80) : (clock / 40); | ||
1329 | } | ||
1330 | |||
1331 | static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) | 1319 | static inline struct ath_common *ath5k_hw_common(struct ath5k_hw *ah) |
1332 | { | 1320 | { |
1333 | return &ah->common; | 1321 | return &ah->common; |
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 72e5ed51c0af..5577bcc80eac 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -254,6 +254,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw, | |||
254 | u32 changes); | 254 | u32 changes); |
255 | static void ath5k_sw_scan_start(struct ieee80211_hw *hw); | 255 | static void ath5k_sw_scan_start(struct ieee80211_hw *hw); |
256 | static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); | 256 | static void ath5k_sw_scan_complete(struct ieee80211_hw *hw); |
257 | static void ath5k_set_coverage_class(struct ieee80211_hw *hw, | ||
258 | u8 coverage_class); | ||
257 | 259 | ||
258 | static const struct ieee80211_ops ath5k_hw_ops = { | 260 | static const struct ieee80211_ops ath5k_hw_ops = { |
259 | .tx = ath5k_tx, | 261 | .tx = ath5k_tx, |
@@ -274,6 +276,7 @@ static const struct ieee80211_ops ath5k_hw_ops = { | |||
274 | .bss_info_changed = ath5k_bss_info_changed, | 276 | .bss_info_changed = ath5k_bss_info_changed, |
275 | .sw_scan_start = ath5k_sw_scan_start, | 277 | .sw_scan_start = ath5k_sw_scan_start, |
276 | .sw_scan_complete = ath5k_sw_scan_complete, | 278 | .sw_scan_complete = ath5k_sw_scan_complete, |
279 | .set_coverage_class = ath5k_set_coverage_class, | ||
277 | }; | 280 | }; |
278 | 281 | ||
279 | /* | 282 | /* |
@@ -3262,3 +3265,22 @@ static void ath5k_sw_scan_complete(struct ieee80211_hw *hw) | |||
3262 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? | 3265 | ath5k_hw_set_ledstate(sc->ah, sc->assoc ? |
3263 | AR5K_LED_ASSOC : AR5K_LED_INIT); | 3266 | AR5K_LED_ASSOC : AR5K_LED_INIT); |
3264 | } | 3267 | } |
3268 | |||
3269 | /** | ||
3270 | * ath5k_set_coverage_class - Set IEEE 802.11 coverage class | ||
3271 | * | ||
3272 | * @hw: struct ieee80211_hw pointer | ||
3273 | * @coverage_class: IEEE 802.11 coverage class number | ||
3274 | * | ||
3275 | * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given | ||
3276 | * coverage class. The values are persistent, they are restored after device | ||
3277 | * reset. | ||
3278 | */ | ||
3279 | static void ath5k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | ||
3280 | { | ||
3281 | struct ath5k_softc *sc = hw->priv; | ||
3282 | |||
3283 | mutex_lock(&sc->lock); | ||
3284 | ath5k_hw_set_coverage_class(sc->ah, coverage_class); | ||
3285 | mutex_unlock(&sc->lock); | ||
3286 | } | ||
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 5d1c8677f180..6a3f4da7fb48 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c | |||
@@ -97,7 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
97 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 97 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
98 | int ret; | 98 | int ret; |
99 | u16 val; | 99 | u16 val; |
100 | u32 cksum, offset; | 100 | u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; |
101 | 101 | ||
102 | /* | 102 | /* |
103 | * Read values from EEPROM and store them in the capability structure | 103 | * Read values from EEPROM and store them in the capability structure |
@@ -116,12 +116,38 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
116 | * Validate the checksum of the EEPROM date. There are some | 116 | * Validate the checksum of the EEPROM date. There are some |
117 | * devices with invalid EEPROMs. | 117 | * devices with invalid EEPROMs. |
118 | */ | 118 | */ |
119 | for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { | 119 | AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); |
120 | if (val) { | ||
121 | eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << | ||
122 | AR5K_EEPROM_SIZE_ENDLOC_SHIFT; | ||
123 | AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); | ||
124 | eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; | ||
125 | |||
126 | /* | ||
127 | * Fail safe check to prevent stupid loops due | ||
128 | * to busted EEPROMs. XXX: This value is likely too | ||
129 | * big still, waiting on a better value. | ||
130 | */ | ||
131 | if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { | ||
132 | ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: " | ||
133 | "%d (0x%04x) max expected: %d (0x%04x)\n", | ||
134 | eep_max, eep_max, | ||
135 | 3 * AR5K_EEPROM_INFO_MAX, | ||
136 | 3 * AR5K_EEPROM_INFO_MAX); | ||
137 | return -EIO; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | for (cksum = 0, offset = 0; offset < eep_max; offset++) { | ||
120 | AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); | 142 | AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); |
121 | cksum ^= val; | 143 | cksum ^= val; |
122 | } | 144 | } |
123 | if (cksum != AR5K_EEPROM_INFO_CKSUM) { | 145 | if (cksum != AR5K_EEPROM_INFO_CKSUM) { |
124 | ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); | 146 | ATH5K_ERR(ah->ah_sc, "Invalid EEPROM " |
147 | "checksum: 0x%04x eep_max: 0x%04x (%s)\n", | ||
148 | cksum, eep_max, | ||
149 | eep_max == AR5K_EEPROM_INFO_MAX ? | ||
150 | "default size" : "custom size"); | ||
125 | return -EIO; | 151 | return -EIO; |
126 | } | 152 | } |
127 | 153 | ||
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index 0123f3521a0b..473a483bb9c3 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h | |||
@@ -37,6 +37,14 @@ | |||
37 | #define AR5K_EEPROM_RFKILL_POLARITY_S 1 | 37 | #define AR5K_EEPROM_RFKILL_POLARITY_S 1 |
38 | 38 | ||
39 | #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ | 39 | #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ |
40 | |||
41 | /* FLASH(EEPROM) Defines for AR531X chips */ | ||
42 | #define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */ | ||
43 | #define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */ | ||
44 | #define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0 | ||
45 | #define AR5K_EEPROM_SIZE_UPPER_SHIFT 4 | ||
46 | #define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12 | ||
47 | |||
40 | #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ | 48 | #define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ |
41 | #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ | 49 | #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ |
42 | #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) | 50 | #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) |
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 64fc1eb9b6d9..aefe84f9c04b 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c | |||
@@ -187,8 +187,8 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) | |||
187 | { | 187 | { |
188 | ATH5K_TRACE(ah->ah_sc); | 188 | ATH5K_TRACE(ah->ah_sc); |
189 | 189 | ||
190 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, | 190 | return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, |
191 | AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); | 191 | AR5K_TIME_OUT), AR5K_TIME_OUT_ACK)); |
192 | } | 192 | } |
193 | 193 | ||
194 | /** | 194 | /** |
@@ -200,12 +200,12 @@ unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) | |||
200 | int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) | 200 | int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) |
201 | { | 201 | { |
202 | ATH5K_TRACE(ah->ah_sc); | 202 | ATH5K_TRACE(ah->ah_sc); |
203 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), | 203 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK)) |
204 | ah->ah_turbo) <= timeout) | 204 | <= timeout) |
205 | return -EINVAL; | 205 | return -EINVAL; |
206 | 206 | ||
207 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, | 207 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, |
208 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); | 208 | ath5k_hw_htoclock(ah, timeout)); |
209 | 209 | ||
210 | return 0; | 210 | return 0; |
211 | } | 211 | } |
@@ -218,8 +218,8 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) | |||
218 | unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) | 218 | unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) |
219 | { | 219 | { |
220 | ATH5K_TRACE(ah->ah_sc); | 220 | ATH5K_TRACE(ah->ah_sc); |
221 | return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, | 221 | return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah, |
222 | AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); | 222 | AR5K_TIME_OUT), AR5K_TIME_OUT_CTS)); |
223 | } | 223 | } |
224 | 224 | ||
225 | /** | 225 | /** |
@@ -231,17 +231,97 @@ unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) | |||
231 | int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) | 231 | int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) |
232 | { | 232 | { |
233 | ATH5K_TRACE(ah->ah_sc); | 233 | ATH5K_TRACE(ah->ah_sc); |
234 | if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), | 234 | if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS)) |
235 | ah->ah_turbo) <= timeout) | 235 | <= timeout) |
236 | return -EINVAL; | 236 | return -EINVAL; |
237 | 237 | ||
238 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, | 238 | AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, |
239 | ath5k_hw_htoclock(timeout, ah->ah_turbo)); | 239 | ath5k_hw_htoclock(ah, timeout)); |
240 | 240 | ||
241 | return 0; | 241 | return 0; |
242 | } | 242 | } |
243 | 243 | ||
244 | /** | 244 | /** |
245 | * ath5k_hw_htoclock - Translate usec to hw clock units | ||
246 | * | ||
247 | * @ah: The &struct ath5k_hw | ||
248 | * @usec: value in microseconds | ||
249 | */ | ||
250 | unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec) | ||
251 | { | ||
252 | return usec * ath5k_hw_get_clockrate(ah); | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * ath5k_hw_clocktoh - Translate hw clock units to usec | ||
257 | * @clock: value in hw clock units | ||
258 | */ | ||
259 | unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock) | ||
260 | { | ||
261 | return clock / ath5k_hw_get_clockrate(ah); | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * ath5k_hw_get_clockrate - Get the clock rate for current mode | ||
266 | * | ||
267 | * @ah: The &struct ath5k_hw | ||
268 | */ | ||
269 | unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah) | ||
270 | { | ||
271 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
272 | int clock; | ||
273 | |||
274 | if (channel->hw_value & CHANNEL_5GHZ) | ||
275 | clock = 40; /* 802.11a */ | ||
276 | else if (channel->hw_value & CHANNEL_CCK) | ||
277 | clock = 22; /* 802.11b */ | ||
278 | else | ||
279 | clock = 44; /* 802.11g */ | ||
280 | |||
281 | /* Clock rate in turbo modes is twice the normal rate */ | ||
282 | if (channel->hw_value & CHANNEL_TURBO) | ||
283 | clock *= 2; | ||
284 | |||
285 | return clock; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * ath5k_hw_get_default_slottime - Get the default slot time for current mode | ||
290 | * | ||
291 | * @ah: The &struct ath5k_hw | ||
292 | */ | ||
293 | unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) | ||
294 | { | ||
295 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
296 | |||
297 | if (channel->hw_value & CHANNEL_TURBO) | ||
298 | return 6; /* both turbo modes */ | ||
299 | |||
300 | if (channel->hw_value & CHANNEL_CCK) | ||
301 | return 20; /* 802.11b */ | ||
302 | |||
303 | return 9; /* 802.11 a/g */ | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * ath5k_hw_get_default_sifs - Get the default SIFS for current mode | ||
308 | * | ||
309 | * @ah: The &struct ath5k_hw | ||
310 | */ | ||
311 | unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) | ||
312 | { | ||
313 | struct ieee80211_channel *channel = ah->ah_current_channel; | ||
314 | |||
315 | if (channel->hw_value & CHANNEL_TURBO) | ||
316 | return 8; /* both turbo modes */ | ||
317 | |||
318 | if (channel->hw_value & CHANNEL_5GHZ) | ||
319 | return 16; /* 802.11a */ | ||
320 | |||
321 | return 10; /* 802.11 b/g */ | ||
322 | } | ||
323 | |||
324 | /** | ||
245 | * ath5k_hw_set_lladdr - Set station id | 325 | * ath5k_hw_set_lladdr - Set station id |
246 | * | 326 | * |
247 | * @ah: The &struct ath5k_hw | 327 | * @ah: The &struct ath5k_hw |
@@ -1050,3 +1130,24 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) | |||
1050 | return 0; | 1130 | return 0; |
1051 | } | 1131 | } |
1052 | 1132 | ||
1133 | /** | ||
1134 | * ath5k_hw_set_coverage_class - Set IEEE 802.11 coverage class | ||
1135 | * | ||
1136 | * @ah: The &struct ath5k_hw | ||
1137 | * @coverage_class: IEEE 802.11 coverage class number | ||
1138 | * | ||
1139 | * Sets slot time, ACK timeout and CTS timeout for given coverage class. | ||
1140 | */ | ||
1141 | void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class) | ||
1142 | { | ||
1143 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | ||
1144 | int slot_time = ath5k_hw_get_default_slottime(ah) + 3 * coverage_class; | ||
1145 | int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time; | ||
1146 | int cts_timeout = ack_timeout; | ||
1147 | |||
1148 | ath5k_hw_set_slot_time(ah, slot_time); | ||
1149 | ath5k_hw_set_ack_timeout(ah, ack_timeout); | ||
1150 | ath5k_hw_set_cts_timeout(ah, cts_timeout); | ||
1151 | |||
1152 | ah->ah_coverage_class = coverage_class; | ||
1153 | } | ||
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index eeebb9aef206..abe36c0d139c 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c | |||
@@ -520,12 +520,16 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) | |||
520 | */ | 520 | */ |
521 | unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) | 521 | unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) |
522 | { | 522 | { |
523 | unsigned int slot_time_clock; | ||
524 | |||
523 | ATH5K_TRACE(ah->ah_sc); | 525 | ATH5K_TRACE(ah->ah_sc); |
526 | |||
524 | if (ah->ah_version == AR5K_AR5210) | 527 | if (ah->ah_version == AR5K_AR5210) |
525 | return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, | 528 | slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME); |
526 | AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); | ||
527 | else | 529 | else |
528 | return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; | 530 | slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT); |
531 | |||
532 | return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff); | ||
529 | } | 533 | } |
530 | 534 | ||
531 | /* | 535 | /* |
@@ -533,15 +537,17 @@ unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) | |||
533 | */ | 537 | */ |
534 | int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) | 538 | int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) |
535 | { | 539 | { |
540 | u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time); | ||
541 | |||
536 | ATH5K_TRACE(ah->ah_sc); | 542 | ATH5K_TRACE(ah->ah_sc); |
537 | if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) | 543 | |
544 | if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX) | ||
538 | return -EINVAL; | 545 | return -EINVAL; |
539 | 546 | ||
540 | if (ah->ah_version == AR5K_AR5210) | 547 | if (ah->ah_version == AR5K_AR5210) |
541 | ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, | 548 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME); |
542 | ah->ah_turbo), AR5K_SLOT_TIME); | ||
543 | else | 549 | else |
544 | ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); | 550 | ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT); |
545 | 551 | ||
546 | return 0; | 552 | return 0; |
547 | } | 553 | } |
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 62954fc77869..6690923fd78c 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c | |||
@@ -60,12 +60,11 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, | |||
60 | !(channel->hw_value & CHANNEL_OFDM)); | 60 | !(channel->hw_value & CHANNEL_OFDM)); |
61 | 61 | ||
62 | /* Get coefficient | 62 | /* Get coefficient |
63 | * ALGO: coef = (5 * clock * carrier_freq) / 2) | 63 | * ALGO: coef = (5 * clock / carrier_freq) / 2 |
64 | * we scale coef by shifting clock value by 24 for | 64 | * we scale coef by shifting clock value by 24 for |
65 | * better precision since we use integers */ | 65 | * better precision since we use integers */ |
66 | /* TODO: Half/quarter rate */ | 66 | /* TODO: Half/quarter rate */ |
67 | clock = ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO); | 67 | clock = (channel->hw_value & CHANNEL_TURBO) ? 80 : 40; |
68 | |||
69 | coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; | 68 | coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq; |
70 | 69 | ||
71 | /* Get exponent | 70 | /* Get exponent |
@@ -1317,6 +1316,10 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
1317 | /* Restore antenna mode */ | 1316 | /* Restore antenna mode */ |
1318 | ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); | 1317 | ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); |
1319 | 1318 | ||
1319 | /* Restore slot time and ACK timeouts */ | ||
1320 | if (ah->ah_coverage_class > 0) | ||
1321 | ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class); | ||
1322 | |||
1320 | /* | 1323 | /* |
1321 | * Configure QCUs/DCUs | 1324 | * Configure QCUs/DCUs |
1322 | */ | 1325 | */ |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 03a1106ad725..5774cea23a3b 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -25,7 +25,7 @@ config ATH9K | |||
25 | 25 | ||
26 | config ATH9K_DEBUGFS | 26 | config ATH9K_DEBUGFS |
27 | bool "Atheros ath9k debugging" | 27 | bool "Atheros ath9k debugging" |
28 | depends on ATH9K | 28 | depends on ATH9K && DEBUG_FS |
29 | ---help--- | 29 | ---help--- |
30 | Say Y, if you need access to ath9k's statistics for | 30 | Say Y, if you need access to ath9k's statistics for |
31 | interrupts, rate control, etc. | 31 | interrupts, rate control, etc. |
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 4985b2b1b0a9..6b50d5eb9ec3 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | ath9k-y += beacon.o \ | 1 | ath9k-y += beacon.o \ |
2 | gpio.o \ | ||
3 | init.o \ | ||
2 | main.o \ | 4 | main.o \ |
3 | recv.o \ | 5 | recv.o \ |
4 | xmit.o \ | 6 | xmit.o \ |
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 329e6bc137ab..9e62a569e816 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c | |||
@@ -121,16 +121,19 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
121 | sc->mem = mem; | 121 | sc->mem = mem; |
122 | sc->irq = irq; | 122 | sc->irq = irq; |
123 | 123 | ||
124 | ret = ath_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); | 124 | /* Will be cleared in ath9k_start() */ |
125 | sc->sc_flags |= SC_OP_INVALID; | ||
126 | |||
127 | ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); | ||
125 | if (ret) { | 128 | if (ret) { |
126 | dev_err(&pdev->dev, "failed to initialize device\n"); | 129 | dev_err(&pdev->dev, "request_irq failed\n"); |
127 | goto err_free_hw; | 130 | goto err_free_hw; |
128 | } | 131 | } |
129 | 132 | ||
130 | ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc); | 133 | ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops); |
131 | if (ret) { | 134 | if (ret) { |
132 | dev_err(&pdev->dev, "request_irq failed\n"); | 135 | dev_err(&pdev->dev, "failed to initialize device\n"); |
133 | goto err_detach; | 136 | goto err_irq; |
134 | } | 137 | } |
135 | 138 | ||
136 | ah = sc->sc_ah; | 139 | ah = sc->sc_ah; |
@@ -143,8 +146,8 @@ static int ath_ahb_probe(struct platform_device *pdev) | |||
143 | 146 | ||
144 | return 0; | 147 | return 0; |
145 | 148 | ||
146 | err_detach: | 149 | err_irq: |
147 | ath_detach(sc); | 150 | free_irq(irq, sc); |
148 | err_free_hw: | 151 | err_free_hw: |
149 | ieee80211_free_hw(hw); | 152 | ieee80211_free_hw(hw); |
150 | platform_set_drvdata(pdev, NULL); | 153 | platform_set_drvdata(pdev, NULL); |
@@ -161,8 +164,12 @@ static int ath_ahb_remove(struct platform_device *pdev) | |||
161 | if (hw) { | 164 | if (hw) { |
162 | struct ath_wiphy *aphy = hw->priv; | 165 | struct ath_wiphy *aphy = hw->priv; |
163 | struct ath_softc *sc = aphy->sc; | 166 | struct ath_softc *sc = aphy->sc; |
167 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
164 | 168 | ||
165 | ath_cleanup(sc); | 169 | ath9k_deinit_device(sc); |
170 | free_irq(sc->irq, sc); | ||
171 | ieee80211_free_hw(sc->hw); | ||
172 | ath_bus_cleanup(common); | ||
166 | platform_set_drvdata(pdev, NULL); | 173 | platform_set_drvdata(pdev, NULL); |
167 | } | 174 | } |
168 | 175 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9f1f523e02eb..bf3d4c4bfa52 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -33,11 +33,11 @@ struct ath_node; | |||
33 | 33 | ||
34 | /* Macro to expand scalars to 64-bit objects */ | 34 | /* Macro to expand scalars to 64-bit objects */ |
35 | 35 | ||
36 | #define ito64(x) (sizeof(x) == 8) ? \ | 36 | #define ito64(x) (sizeof(x) == 1) ? \ |
37 | (((unsigned long long int)(x)) & (0xff)) : \ | 37 | (((unsigned long long int)(x)) & (0xff)) : \ |
38 | (sizeof(x) == 16) ? \ | 38 | (sizeof(x) == 2) ? \ |
39 | (((unsigned long long int)(x)) & 0xffff) : \ | 39 | (((unsigned long long int)(x)) & 0xffff) : \ |
40 | ((sizeof(x) == 32) ? \ | 40 | ((sizeof(x) == 4) ? \ |
41 | (((unsigned long long int)(x)) & 0xffffffff) : \ | 41 | (((unsigned long long int)(x)) & 0xffffffff) : \ |
42 | (unsigned long long int)(x)) | 42 | (unsigned long long int)(x)) |
43 | 43 | ||
@@ -341,6 +341,12 @@ int ath_beaconq_config(struct ath_softc *sc); | |||
341 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ | 341 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ |
342 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ | 342 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ |
343 | 343 | ||
344 | void ath_ani_calibrate(unsigned long data); | ||
345 | |||
346 | /**********/ | ||
347 | /* BTCOEX */ | ||
348 | /**********/ | ||
349 | |||
344 | /* Defines the BT AR_BT_COEX_WGHT used */ | 350 | /* Defines the BT AR_BT_COEX_WGHT used */ |
345 | enum ath_stomp_type { | 351 | enum ath_stomp_type { |
346 | ATH_BTCOEX_NO_STOMP, | 352 | ATH_BTCOEX_NO_STOMP, |
@@ -361,6 +367,10 @@ struct ath_btcoex { | |||
361 | struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ | 367 | struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ |
362 | }; | 368 | }; |
363 | 369 | ||
370 | int ath_init_btcoex_timer(struct ath_softc *sc); | ||
371 | void ath9k_btcoex_timer_resume(struct ath_softc *sc); | ||
372 | void ath9k_btcoex_timer_pause(struct ath_softc *sc); | ||
373 | |||
364 | /********************/ | 374 | /********************/ |
365 | /* LED Control */ | 375 | /* LED Control */ |
366 | /********************/ | 376 | /********************/ |
@@ -385,6 +395,9 @@ struct ath_led { | |||
385 | bool registered; | 395 | bool registered; |
386 | }; | 396 | }; |
387 | 397 | ||
398 | void ath_init_leds(struct ath_softc *sc); | ||
399 | void ath_deinit_leds(struct ath_softc *sc); | ||
400 | |||
388 | /********************/ | 401 | /********************/ |
389 | /* Main driver core */ | 402 | /* Main driver core */ |
390 | /********************/ | 403 | /********************/ |
@@ -403,26 +416,28 @@ struct ath_led { | |||
403 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ | 416 | #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ |
404 | #define ATH_RATE_DUMMY_MARKER 0 | 417 | #define ATH_RATE_DUMMY_MARKER 0 |
405 | 418 | ||
406 | #define SC_OP_INVALID BIT(0) | 419 | #define SC_OP_INVALID BIT(0) |
407 | #define SC_OP_BEACONS BIT(1) | 420 | #define SC_OP_BEACONS BIT(1) |
408 | #define SC_OP_RXAGGR BIT(2) | 421 | #define SC_OP_RXAGGR BIT(2) |
409 | #define SC_OP_TXAGGR BIT(3) | 422 | #define SC_OP_TXAGGR BIT(3) |
410 | #define SC_OP_FULL_RESET BIT(4) | 423 | #define SC_OP_FULL_RESET BIT(4) |
411 | #define SC_OP_PREAMBLE_SHORT BIT(5) | 424 | #define SC_OP_PREAMBLE_SHORT BIT(5) |
412 | #define SC_OP_PROTECT_ENABLE BIT(6) | 425 | #define SC_OP_PROTECT_ENABLE BIT(6) |
413 | #define SC_OP_RXFLUSH BIT(7) | 426 | #define SC_OP_RXFLUSH BIT(7) |
414 | #define SC_OP_LED_ASSOCIATED BIT(8) | 427 | #define SC_OP_LED_ASSOCIATED BIT(8) |
415 | #define SC_OP_WAIT_FOR_BEACON BIT(12) | 428 | #define SC_OP_LED_ON BIT(9) |
416 | #define SC_OP_LED_ON BIT(13) | 429 | #define SC_OP_SCANNING BIT(10) |
417 | #define SC_OP_SCANNING BIT(14) | 430 | #define SC_OP_TSF_RESET BIT(11) |
418 | #define SC_OP_TSF_RESET BIT(15) | 431 | #define SC_OP_BT_PRIORITY_DETECTED BIT(12) |
419 | #define SC_OP_WAIT_FOR_CAB BIT(16) | 432 | |
420 | #define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17) | 433 | /* Powersave flags */ |
421 | #define SC_OP_WAIT_FOR_TX_ACK BIT(18) | 434 | #define PS_WAIT_FOR_BEACON BIT(0) |
422 | #define SC_OP_BEACON_SYNC BIT(19) | 435 | #define PS_WAIT_FOR_CAB BIT(1) |
423 | #define SC_OP_BT_PRIORITY_DETECTED BIT(21) | 436 | #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) |
424 | #define SC_OP_NULLFUNC_COMPLETED BIT(22) | 437 | #define PS_WAIT_FOR_TX_ACK BIT(3) |
425 | #define SC_OP_PS_ENABLED BIT(23) | 438 | #define PS_BEACON_SYNC BIT(4) |
439 | #define PS_NULLFUNC_COMPLETED BIT(5) | ||
440 | #define PS_ENABLED BIT(6) | ||
426 | 441 | ||
427 | struct ath_wiphy; | 442 | struct ath_wiphy; |
428 | struct ath_rate_table; | 443 | struct ath_rate_table; |
@@ -458,6 +473,7 @@ struct ath_softc { | |||
458 | 473 | ||
459 | u32 intrstatus; | 474 | u32 intrstatus; |
460 | u32 sc_flags; /* SC_OP_* */ | 475 | u32 sc_flags; /* SC_OP_* */ |
476 | u16 ps_flags; /* PS_* */ | ||
461 | u16 curtxpow; | 477 | u16 curtxpow; |
462 | u8 nbcnvifs; | 478 | u8 nbcnvifs; |
463 | u16 nvifs; | 479 | u16 nvifs; |
@@ -508,6 +524,7 @@ struct ath_wiphy { | |||
508 | int chan_is_ht; | 524 | int chan_is_ht; |
509 | }; | 525 | }; |
510 | 526 | ||
527 | void ath9k_tasklet(unsigned long data); | ||
511 | int ath_reset(struct ath_softc *sc, bool retry_tx); | 528 | int ath_reset(struct ath_softc *sc, bool retry_tx); |
512 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); | 529 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); |
513 | int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); | 530 | int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); |
@@ -524,15 +541,15 @@ static inline void ath_bus_cleanup(struct ath_common *common) | |||
524 | } | 541 | } |
525 | 542 | ||
526 | extern struct ieee80211_ops ath9k_ops; | 543 | extern struct ieee80211_ops ath9k_ops; |
544 | extern int modparam_nohwcrypt; | ||
527 | 545 | ||
528 | irqreturn_t ath_isr(int irq, void *dev); | 546 | irqreturn_t ath_isr(int irq, void *dev); |
529 | void ath_cleanup(struct ath_softc *sc); | 547 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, |
530 | int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | ||
531 | const struct ath_bus_ops *bus_ops); | 548 | const struct ath_bus_ops *bus_ops); |
532 | void ath_detach(struct ath_softc *sc); | 549 | void ath9k_deinit_device(struct ath_softc *sc); |
533 | const char *ath_mac_bb_name(u32 mac_bb_version); | 550 | const char *ath_mac_bb_name(u32 mac_bb_version); |
534 | const char *ath_rf_name(u16 rf_version); | 551 | const char *ath_rf_name(u16 rf_version); |
535 | void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); | 552 | void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); |
536 | void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, | 553 | void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, |
537 | struct ath9k_channel *ichan); | 554 | struct ath9k_channel *ichan); |
538 | void ath_update_chainmask(struct ath_softc *sc, int is_ht); | 555 | void ath_update_chainmask(struct ath_softc *sc, int is_ht); |
@@ -541,6 +558,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
541 | 558 | ||
542 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); | 559 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw); |
543 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); | 560 | void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); |
561 | bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode); | ||
544 | 562 | ||
545 | #ifdef CONFIG_PCI | 563 | #ifdef CONFIG_PCI |
546 | int ath_pci_init(void); | 564 | int ath_pci_init(void); |
@@ -582,4 +600,8 @@ void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue); | |||
582 | void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); | 600 | void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue); |
583 | 601 | ||
584 | int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); | 602 | int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); |
603 | |||
604 | void ath_start_rfkill_poll(struct ath_softc *sc); | ||
605 | extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw); | ||
606 | |||
585 | #endif /* ATH9K_H */ | 607 | #endif /* ATH9K_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 1660ef17aaf5..422454fe4ff0 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long data) | |||
480 | sc->beacon.updateslot = COMMIT; /* commit next beacon */ | 480 | sc->beacon.updateslot = COMMIT; /* commit next beacon */ |
481 | sc->beacon.slotupdate = slot; | 481 | sc->beacon.slotupdate = slot; |
482 | } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { | 482 | } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { |
483 | ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); | 483 | ah->slottime = sc->beacon.slottime; |
484 | ath9k_hw_init_global_settings(ah); | ||
484 | sc->beacon.updateslot = OK; | 485 | sc->beacon.updateslot = OK; |
485 | } | 486 | } |
486 | if (bfaddr != 0) { | 487 | if (bfaddr != 0) { |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 592f1b70f55a..9489b6b25b5f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -580,6 +580,116 @@ static const struct file_operations fops_xmit = { | |||
580 | .owner = THIS_MODULE | 580 | .owner = THIS_MODULE |
581 | }; | 581 | }; |
582 | 582 | ||
583 | static ssize_t read_file_recv(struct file *file, char __user *user_buf, | ||
584 | size_t count, loff_t *ppos) | ||
585 | { | ||
586 | #define PHY_ERR(s, p) \ | ||
587 | len += snprintf(buf + len, size - len, "%18s : %10u\n", s, \ | ||
588 | sc->debug.stats.rxstats.phy_err_stats[p]); | ||
589 | |||
590 | struct ath_softc *sc = file->private_data; | ||
591 | char *buf; | ||
592 | unsigned int len = 0, size = 1152; | ||
593 | ssize_t retval = 0; | ||
594 | |||
595 | buf = kzalloc(size, GFP_KERNEL); | ||
596 | if (buf == NULL) | ||
597 | return 0; | ||
598 | |||
599 | len += snprintf(buf + len, size - len, | ||
600 | "%18s : %10u\n", "CRC ERR", | ||
601 | sc->debug.stats.rxstats.crc_err); | ||
602 | len += snprintf(buf + len, size - len, | ||
603 | "%18s : %10u\n", "DECRYPT CRC ERR", | ||
604 | sc->debug.stats.rxstats.decrypt_crc_err); | ||
605 | len += snprintf(buf + len, size - len, | ||
606 | "%18s : %10u\n", "PHY ERR", | ||
607 | sc->debug.stats.rxstats.phy_err); | ||
608 | len += snprintf(buf + len, size - len, | ||
609 | "%18s : %10u\n", "MIC ERR", | ||
610 | sc->debug.stats.rxstats.mic_err); | ||
611 | len += snprintf(buf + len, size - len, | ||
612 | "%18s : %10u\n", "PRE-DELIM CRC ERR", | ||
613 | sc->debug.stats.rxstats.pre_delim_crc_err); | ||
614 | len += snprintf(buf + len, size - len, | ||
615 | "%18s : %10u\n", "POST-DELIM CRC ERR", | ||
616 | sc->debug.stats.rxstats.post_delim_crc_err); | ||
617 | len += snprintf(buf + len, size - len, | ||
618 | "%18s : %10u\n", "DECRYPT BUSY ERR", | ||
619 | sc->debug.stats.rxstats.decrypt_busy_err); | ||
620 | |||
621 | PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN); | ||
622 | PHY_ERR("TIMING", ATH9K_PHYERR_TIMING); | ||
623 | PHY_ERR("PARITY", ATH9K_PHYERR_PARITY); | ||
624 | PHY_ERR("RATE", ATH9K_PHYERR_RATE); | ||
625 | PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH); | ||
626 | PHY_ERR("RADAR", ATH9K_PHYERR_RADAR); | ||
627 | PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE); | ||
628 | PHY_ERR("TOR", ATH9K_PHYERR_TOR); | ||
629 | PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING); | ||
630 | PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY); | ||
631 | PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL); | ||
632 | PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL); | ||
633 | PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP); | ||
634 | PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE); | ||
635 | PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART); | ||
636 | PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT); | ||
637 | PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING); | ||
638 | PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC); | ||
639 | PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL); | ||
640 | PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE); | ||
641 | PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART); | ||
642 | PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL); | ||
643 | PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP); | ||
644 | PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR); | ||
645 | PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL); | ||
646 | PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL); | ||
647 | |||
648 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
649 | kfree(buf); | ||
650 | |||
651 | return retval; | ||
652 | |||
653 | #undef PHY_ERR | ||
654 | } | ||
655 | |||
656 | void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf) | ||
657 | { | ||
658 | #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ | ||
659 | #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ | ||
660 | |||
661 | struct ath_desc *ds = bf->bf_desc; | ||
662 | u32 phyerr; | ||
663 | |||
664 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) | ||
665 | RX_STAT_INC(crc_err); | ||
666 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) | ||
667 | RX_STAT_INC(decrypt_crc_err); | ||
668 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) | ||
669 | RX_STAT_INC(mic_err); | ||
670 | if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE) | ||
671 | RX_STAT_INC(pre_delim_crc_err); | ||
672 | if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_POST) | ||
673 | RX_STAT_INC(post_delim_crc_err); | ||
674 | if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY) | ||
675 | RX_STAT_INC(decrypt_busy_err); | ||
676 | |||
677 | if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { | ||
678 | RX_STAT_INC(phy_err); | ||
679 | phyerr = ds->ds_rxstat.rs_phyerr & 0x24; | ||
680 | RX_PHY_ERR_INC(phyerr); | ||
681 | } | ||
682 | |||
683 | #undef RX_STAT_INC | ||
684 | #undef RX_PHY_ERR_INC | ||
685 | } | ||
686 | |||
687 | static const struct file_operations fops_recv = { | ||
688 | .read = read_file_recv, | ||
689 | .open = ath9k_debugfs_open, | ||
690 | .owner = THIS_MODULE | ||
691 | }; | ||
692 | |||
583 | int ath9k_init_debug(struct ath_hw *ah) | 693 | int ath9k_init_debug(struct ath_hw *ah) |
584 | { | 694 | { |
585 | struct ath_common *common = ath9k_hw_common(ah); | 695 | struct ath_common *common = ath9k_hw_common(ah); |
@@ -632,6 +742,13 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
632 | if (!sc->debug.debugfs_xmit) | 742 | if (!sc->debug.debugfs_xmit) |
633 | goto err; | 743 | goto err; |
634 | 744 | ||
745 | sc->debug.debugfs_recv = debugfs_create_file("recv", | ||
746 | S_IRUSR, | ||
747 | sc->debug.debugfs_phy, | ||
748 | sc, &fops_recv); | ||
749 | if (!sc->debug.debugfs_recv) | ||
750 | goto err; | ||
751 | |||
635 | return 0; | 752 | return 0; |
636 | err: | 753 | err: |
637 | ath9k_exit_debug(ah); | 754 | ath9k_exit_debug(ah); |
@@ -643,6 +760,7 @@ void ath9k_exit_debug(struct ath_hw *ah) | |||
643 | struct ath_common *common = ath9k_hw_common(ah); | 760 | struct ath_common *common = ath9k_hw_common(ah); |
644 | struct ath_softc *sc = (struct ath_softc *) common->priv; | 761 | struct ath_softc *sc = (struct ath_softc *) common->priv; |
645 | 762 | ||
763 | debugfs_remove(sc->debug.debugfs_recv); | ||
646 | debugfs_remove(sc->debug.debugfs_xmit); | 764 | debugfs_remove(sc->debug.debugfs_xmit); |
647 | debugfs_remove(sc->debug.debugfs_wiphy); | 765 | debugfs_remove(sc->debug.debugfs_wiphy); |
648 | debugfs_remove(sc->debug.debugfs_rcstat); | 766 | debugfs_remove(sc->debug.debugfs_rcstat); |
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 536663e3ee11..86780e68b31e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
@@ -116,10 +116,35 @@ struct ath_tx_stats { | |||
116 | u32 delim_underrun; | 116 | u32 delim_underrun; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /** | ||
120 | * struct ath_rx_stats - RX Statistics | ||
121 | * @crc_err: No. of frames with incorrect CRC value | ||
122 | * @decrypt_crc_err: No. of frames whose CRC check failed after | ||
123 | decryption process completed | ||
124 | * @phy_err: No. of frames whose reception failed because the PHY | ||
125 | encountered an error | ||
126 | * @mic_err: No. of frames with incorrect TKIP MIC verification failure | ||
127 | * @pre_delim_crc_err: Pre-Frame delimiter CRC error detections | ||
128 | * @post_delim_crc_err: Post-Frame delimiter CRC error detections | ||
129 | * @decrypt_busy_err: Decryption interruptions counter | ||
130 | * @phy_err_stats: Individual PHY error statistics | ||
131 | */ | ||
132 | struct ath_rx_stats { | ||
133 | u32 crc_err; | ||
134 | u32 decrypt_crc_err; | ||
135 | u32 phy_err; | ||
136 | u32 mic_err; | ||
137 | u32 pre_delim_crc_err; | ||
138 | u32 post_delim_crc_err; | ||
139 | u32 decrypt_busy_err; | ||
140 | u32 phy_err_stats[ATH9K_PHYERR_MAX]; | ||
141 | }; | ||
142 | |||
119 | struct ath_stats { | 143 | struct ath_stats { |
120 | struct ath_interrupt_stats istats; | 144 | struct ath_interrupt_stats istats; |
121 | struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; | 145 | struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; |
122 | struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; | 146 | struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; |
147 | struct ath_rx_stats rxstats; | ||
123 | }; | 148 | }; |
124 | 149 | ||
125 | struct ath9k_debug { | 150 | struct ath9k_debug { |
@@ -130,6 +155,7 @@ struct ath9k_debug { | |||
130 | struct dentry *debugfs_rcstat; | 155 | struct dentry *debugfs_rcstat; |
131 | struct dentry *debugfs_wiphy; | 156 | struct dentry *debugfs_wiphy; |
132 | struct dentry *debugfs_xmit; | 157 | struct dentry *debugfs_xmit; |
158 | struct dentry *debugfs_recv; | ||
133 | struct ath_stats stats; | 159 | struct ath_stats stats; |
134 | }; | 160 | }; |
135 | 161 | ||
@@ -142,6 +168,7 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); | |||
142 | void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); | 168 | void ath_debug_stat_rc(struct ath_softc *sc, int final_rate); |
143 | void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, | 169 | void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, |
144 | struct ath_buf *bf); | 170 | struct ath_buf *bf); |
171 | void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf); | ||
145 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 172 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
146 | int xretries, int retries, u8 per); | 173 | int xretries, int retries, u8 per); |
147 | 174 | ||
@@ -181,6 +208,11 @@ static inline void ath_debug_stat_tx(struct ath_softc *sc, | |||
181 | { | 208 | { |
182 | } | 209 | } |
183 | 210 | ||
211 | static inline void ath_debug_stat_rx(struct ath_softc *sc, | ||
212 | struct ath_buf *bf) | ||
213 | { | ||
214 | } | ||
215 | |||
184 | static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 216 | static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
185 | int xretries, int retries, u8 per) | 217 | int xretries, int retries, u8 per) |
186 | { | 218 | { |
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c new file mode 100644 index 000000000000..e204bd25ff65 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/gpio.c | |||
@@ -0,0 +1,428 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | /********************************/ | ||
20 | /* LED functions */ | ||
21 | /********************************/ | ||
22 | |||
23 | static void ath_led_blink_work(struct work_struct *work) | ||
24 | { | ||
25 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
26 | ath_led_blink_work.work); | ||
27 | |||
28 | if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) | ||
29 | return; | ||
30 | |||
31 | if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
32 | (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
33 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); | ||
34 | else | ||
35 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, | ||
36 | (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); | ||
37 | |||
38 | ieee80211_queue_delayed_work(sc->hw, | ||
39 | &sc->ath_led_blink_work, | ||
40 | (sc->sc_flags & SC_OP_LED_ON) ? | ||
41 | msecs_to_jiffies(sc->led_off_duration) : | ||
42 | msecs_to_jiffies(sc->led_on_duration)); | ||
43 | |||
44 | sc->led_on_duration = sc->led_on_cnt ? | ||
45 | max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : | ||
46 | ATH_LED_ON_DURATION_IDLE; | ||
47 | sc->led_off_duration = sc->led_off_cnt ? | ||
48 | max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : | ||
49 | ATH_LED_OFF_DURATION_IDLE; | ||
50 | sc->led_on_cnt = sc->led_off_cnt = 0; | ||
51 | if (sc->sc_flags & SC_OP_LED_ON) | ||
52 | sc->sc_flags &= ~SC_OP_LED_ON; | ||
53 | else | ||
54 | sc->sc_flags |= SC_OP_LED_ON; | ||
55 | } | ||
56 | |||
57 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
58 | enum led_brightness brightness) | ||
59 | { | ||
60 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
61 | struct ath_softc *sc = led->sc; | ||
62 | |||
63 | switch (brightness) { | ||
64 | case LED_OFF: | ||
65 | if (led->led_type == ATH_LED_ASSOC || | ||
66 | led->led_type == ATH_LED_RADIO) { | ||
67 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, | ||
68 | (led->led_type == ATH_LED_RADIO)); | ||
69 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
70 | if (led->led_type == ATH_LED_RADIO) | ||
71 | sc->sc_flags &= ~SC_OP_LED_ON; | ||
72 | } else { | ||
73 | sc->led_off_cnt++; | ||
74 | } | ||
75 | break; | ||
76 | case LED_FULL: | ||
77 | if (led->led_type == ATH_LED_ASSOC) { | ||
78 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
79 | ieee80211_queue_delayed_work(sc->hw, | ||
80 | &sc->ath_led_blink_work, 0); | ||
81 | } else if (led->led_type == ATH_LED_RADIO) { | ||
82 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); | ||
83 | sc->sc_flags |= SC_OP_LED_ON; | ||
84 | } else { | ||
85 | sc->led_on_cnt++; | ||
86 | } | ||
87 | break; | ||
88 | default: | ||
89 | break; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
94 | char *trigger) | ||
95 | { | ||
96 | int ret; | ||
97 | |||
98 | led->sc = sc; | ||
99 | led->led_cdev.name = led->name; | ||
100 | led->led_cdev.default_trigger = trigger; | ||
101 | led->led_cdev.brightness_set = ath_led_brightness; | ||
102 | |||
103 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
104 | if (ret) | ||
105 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, | ||
106 | "Failed to register led:%s", led->name); | ||
107 | else | ||
108 | led->registered = 1; | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static void ath_unregister_led(struct ath_led *led) | ||
113 | { | ||
114 | if (led->registered) { | ||
115 | led_classdev_unregister(&led->led_cdev); | ||
116 | led->registered = 0; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void ath_deinit_leds(struct ath_softc *sc) | ||
121 | { | ||
122 | ath_unregister_led(&sc->assoc_led); | ||
123 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
124 | ath_unregister_led(&sc->tx_led); | ||
125 | ath_unregister_led(&sc->rx_led); | ||
126 | ath_unregister_led(&sc->radio_led); | ||
127 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | ||
128 | } | ||
129 | |||
130 | void ath_init_leds(struct ath_softc *sc) | ||
131 | { | ||
132 | char *trigger; | ||
133 | int ret; | ||
134 | |||
135 | if (AR_SREV_9287(sc->sc_ah)) | ||
136 | sc->sc_ah->led_pin = ATH_LED_PIN_9287; | ||
137 | else | ||
138 | sc->sc_ah->led_pin = ATH_LED_PIN_DEF; | ||
139 | |||
140 | /* Configure gpio 1 for output */ | ||
141 | ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, | ||
142 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
143 | /* LED off, active low */ | ||
144 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | ||
145 | |||
146 | INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); | ||
147 | |||
148 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
149 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
150 | "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); | ||
151 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
152 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
153 | if (ret) | ||
154 | goto fail; | ||
155 | |||
156 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
157 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
158 | "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); | ||
159 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
160 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
161 | if (ret) | ||
162 | goto fail; | ||
163 | |||
164 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
165 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
166 | "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); | ||
167 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
168 | sc->tx_led.led_type = ATH_LED_TX; | ||
169 | if (ret) | ||
170 | goto fail; | ||
171 | |||
172 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
173 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
174 | "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); | ||
175 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
176 | sc->rx_led.led_type = ATH_LED_RX; | ||
177 | if (ret) | ||
178 | goto fail; | ||
179 | |||
180 | return; | ||
181 | |||
182 | fail: | ||
183 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | ||
184 | ath_deinit_leds(sc); | ||
185 | } | ||
186 | |||
187 | /*******************/ | ||
188 | /* Rfkill */ | ||
189 | /*******************/ | ||
190 | |||
191 | static bool ath_is_rfkill_set(struct ath_softc *sc) | ||
192 | { | ||
193 | struct ath_hw *ah = sc->sc_ah; | ||
194 | |||
195 | return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == | ||
196 | ah->rfkill_polarity; | ||
197 | } | ||
198 | |||
199 | void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) | ||
200 | { | ||
201 | struct ath_wiphy *aphy = hw->priv; | ||
202 | struct ath_softc *sc = aphy->sc; | ||
203 | bool blocked = !!ath_is_rfkill_set(sc); | ||
204 | |||
205 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
206 | } | ||
207 | |||
208 | void ath_start_rfkill_poll(struct ath_softc *sc) | ||
209 | { | ||
210 | struct ath_hw *ah = sc->sc_ah; | ||
211 | |||
212 | if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
213 | wiphy_rfkill_start_polling(sc->hw->wiphy); | ||
214 | } | ||
215 | |||
216 | /******************/ | ||
217 | /* BTCOEX */ | ||
218 | /******************/ | ||
219 | |||
220 | /* | ||
221 | * Detects if there is any priority bt traffic | ||
222 | */ | ||
223 | static void ath_detect_bt_priority(struct ath_softc *sc) | ||
224 | { | ||
225 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
226 | struct ath_hw *ah = sc->sc_ah; | ||
227 | |||
228 | if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) | ||
229 | btcoex->bt_priority_cnt++; | ||
230 | |||
231 | if (time_after(jiffies, btcoex->bt_priority_time + | ||
232 | msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { | ||
233 | if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { | ||
234 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, | ||
235 | "BT priority traffic detected"); | ||
236 | sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; | ||
237 | } else { | ||
238 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
239 | } | ||
240 | |||
241 | btcoex->bt_priority_cnt = 0; | ||
242 | btcoex->bt_priority_time = jiffies; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Configures appropriate weight based on stomp type. | ||
248 | */ | ||
249 | static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, | ||
250 | enum ath_stomp_type stomp_type) | ||
251 | { | ||
252 | struct ath_hw *ah = sc->sc_ah; | ||
253 | |||
254 | switch (stomp_type) { | ||
255 | case ATH_BTCOEX_STOMP_ALL: | ||
256 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
257 | AR_STOMP_ALL_WLAN_WGHT); | ||
258 | break; | ||
259 | case ATH_BTCOEX_STOMP_LOW: | ||
260 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
261 | AR_STOMP_LOW_WLAN_WGHT); | ||
262 | break; | ||
263 | case ATH_BTCOEX_STOMP_NONE: | ||
264 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
265 | AR_STOMP_NONE_WLAN_WGHT); | ||
266 | break; | ||
267 | default: | ||
268 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
269 | "Invalid Stomptype\n"); | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | ath9k_hw_btcoex_enable(ah); | ||
274 | } | ||
275 | |||
276 | static void ath9k_gen_timer_start(struct ath_hw *ah, | ||
277 | struct ath_gen_timer *timer, | ||
278 | u32 timer_next, | ||
279 | u32 timer_period) | ||
280 | { | ||
281 | struct ath_common *common = ath9k_hw_common(ah); | ||
282 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
283 | |||
284 | ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); | ||
285 | |||
286 | if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { | ||
287 | ath9k_hw_set_interrupts(ah, 0); | ||
288 | sc->imask |= ATH9K_INT_GENTIMER; | ||
289 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | ||
294 | { | ||
295 | struct ath_common *common = ath9k_hw_common(ah); | ||
296 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
297 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | ||
298 | |||
299 | ath9k_hw_gen_timer_stop(ah, timer); | ||
300 | |||
301 | /* if no timer is enabled, turn off interrupt mask */ | ||
302 | if (timer_table->timer_mask.val == 0) { | ||
303 | ath9k_hw_set_interrupts(ah, 0); | ||
304 | sc->imask &= ~ATH9K_INT_GENTIMER; | ||
305 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * This is the master bt coex timer which runs for every | ||
311 | * 45ms, bt traffic will be given priority during 55% of this | ||
312 | * period while wlan gets remaining 45% | ||
313 | */ | ||
314 | static void ath_btcoex_period_timer(unsigned long data) | ||
315 | { | ||
316 | struct ath_softc *sc = (struct ath_softc *) data; | ||
317 | struct ath_hw *ah = sc->sc_ah; | ||
318 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
319 | |||
320 | ath_detect_bt_priority(sc); | ||
321 | |||
322 | spin_lock_bh(&btcoex->btcoex_lock); | ||
323 | |||
324 | ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); | ||
325 | |||
326 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
327 | |||
328 | if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { | ||
329 | if (btcoex->hw_timer_enabled) | ||
330 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
331 | |||
332 | ath9k_gen_timer_start(ah, | ||
333 | btcoex->no_stomp_timer, | ||
334 | (ath9k_hw_gettsf32(ah) + | ||
335 | btcoex->btcoex_no_stomp), | ||
336 | btcoex->btcoex_no_stomp * 10); | ||
337 | btcoex->hw_timer_enabled = true; | ||
338 | } | ||
339 | |||
340 | mod_timer(&btcoex->period_timer, jiffies + | ||
341 | msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * Generic tsf based hw timer which configures weight | ||
346 | * registers to time slice between wlan and bt traffic | ||
347 | */ | ||
348 | static void ath_btcoex_no_stomp_timer(void *arg) | ||
349 | { | ||
350 | struct ath_softc *sc = (struct ath_softc *)arg; | ||
351 | struct ath_hw *ah = sc->sc_ah; | ||
352 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
353 | |||
354 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
355 | "no stomp timer running \n"); | ||
356 | |||
357 | spin_lock_bh(&btcoex->btcoex_lock); | ||
358 | |||
359 | if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) | ||
360 | ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); | ||
361 | else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) | ||
362 | ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); | ||
363 | |||
364 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
365 | } | ||
366 | |||
367 | int ath_init_btcoex_timer(struct ath_softc *sc) | ||
368 | { | ||
369 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
370 | |||
371 | btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; | ||
372 | btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * | ||
373 | btcoex->btcoex_period / 100; | ||
374 | |||
375 | setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, | ||
376 | (unsigned long) sc); | ||
377 | |||
378 | spin_lock_init(&btcoex->btcoex_lock); | ||
379 | |||
380 | btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, | ||
381 | ath_btcoex_no_stomp_timer, | ||
382 | ath_btcoex_no_stomp_timer, | ||
383 | (void *) sc, AR_FIRST_NDP_TIMER); | ||
384 | |||
385 | if (!btcoex->no_stomp_timer) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * (Re)start btcoex timers | ||
393 | */ | ||
394 | void ath9k_btcoex_timer_resume(struct ath_softc *sc) | ||
395 | { | ||
396 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
397 | struct ath_hw *ah = sc->sc_ah; | ||
398 | |||
399 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
400 | "Starting btcoex timers"); | ||
401 | |||
402 | /* make sure duty cycle timer is also stopped when resuming */ | ||
403 | if (btcoex->hw_timer_enabled) | ||
404 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | ||
405 | |||
406 | btcoex->bt_priority_cnt = 0; | ||
407 | btcoex->bt_priority_time = jiffies; | ||
408 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
409 | |||
410 | mod_timer(&btcoex->period_timer, jiffies); | ||
411 | } | ||
412 | |||
413 | |||
414 | /* | ||
415 | * Pause btcoex timer and bt duty cycle timer | ||
416 | */ | ||
417 | void ath9k_btcoex_timer_pause(struct ath_softc *sc) | ||
418 | { | ||
419 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
420 | struct ath_hw *ah = sc->sc_ah; | ||
421 | |||
422 | del_timer_sync(&btcoex->period_timer); | ||
423 | |||
424 | if (btcoex->hw_timer_enabled) | ||
425 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
426 | |||
427 | btcoex->hw_timer_enabled = false; | ||
428 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 9474f9f6d400..0b1dd10f1d84 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -52,28 +52,6 @@ module_exit(ath9k_exit); | |||
52 | /* Helper Functions */ | 52 | /* Helper Functions */ |
53 | /********************/ | 53 | /********************/ |
54 | 54 | ||
55 | static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) | ||
56 | { | ||
57 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | ||
58 | |||
59 | if (!ah->curchan) /* should really check for CCK instead */ | ||
60 | return clks / ATH9K_CLOCK_RATE_CCK; | ||
61 | if (conf->channel->band == IEEE80211_BAND_2GHZ) | ||
62 | return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; | ||
63 | |||
64 | return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; | ||
65 | } | ||
66 | |||
67 | static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) | ||
68 | { | ||
69 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | ||
70 | |||
71 | if (conf_is_ht40(conf)) | ||
72 | return ath9k_hw_mac_usec(ah, clks) / 2; | ||
73 | else | ||
74 | return ath9k_hw_mac_usec(ah, clks); | ||
75 | } | ||
76 | |||
77 | static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) | 55 | static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) |
78 | { | 56 | { |
79 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | 57 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; |
@@ -413,8 +391,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) | |||
413 | ah->beacon_interval = 100; | 391 | ah->beacon_interval = 100; |
414 | ah->enable_32kHz_clock = DONT_USE_32KHZ; | 392 | ah->enable_32kHz_clock = DONT_USE_32KHZ; |
415 | ah->slottime = (u32) -1; | 393 | ah->slottime = (u32) -1; |
416 | ah->acktimeout = (u32) -1; | ||
417 | ah->ctstimeout = (u32) -1; | ||
418 | ah->globaltxtimeout = (u32) -1; | 394 | ah->globaltxtimeout = (u32) -1; |
419 | ah->power_mode = ATH9K_PM_UNDEFINED; | 395 | ah->power_mode = ATH9K_PM_UNDEFINED; |
420 | } | 396 | } |
@@ -1180,34 +1156,25 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, | |||
1180 | } | 1156 | } |
1181 | } | 1157 | } |
1182 | 1158 | ||
1183 | static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) | 1159 | static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) |
1184 | { | 1160 | { |
1185 | if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { | 1161 | u32 val = ath9k_hw_mac_to_clks(ah, us); |
1186 | ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, | 1162 | val = min(val, (u32) 0xFFFF); |
1187 | "bad ack timeout %u\n", us); | 1163 | REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); |
1188 | ah->acktimeout = (u32) -1; | ||
1189 | return false; | ||
1190 | } else { | ||
1191 | REG_RMW_FIELD(ah, AR_TIME_OUT, | ||
1192 | AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); | ||
1193 | ah->acktimeout = us; | ||
1194 | return true; | ||
1195 | } | ||
1196 | } | 1164 | } |
1197 | 1165 | ||
1198 | static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) | 1166 | static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) |
1199 | { | 1167 | { |
1200 | if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { | 1168 | u32 val = ath9k_hw_mac_to_clks(ah, us); |
1201 | ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, | 1169 | val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); |
1202 | "bad cts timeout %u\n", us); | 1170 | REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); |
1203 | ah->ctstimeout = (u32) -1; | 1171 | } |
1204 | return false; | 1172 | |
1205 | } else { | 1173 | static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) |
1206 | REG_RMW_FIELD(ah, AR_TIME_OUT, | 1174 | { |
1207 | AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); | 1175 | u32 val = ath9k_hw_mac_to_clks(ah, us); |
1208 | ah->ctstimeout = us; | 1176 | val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); |
1209 | return true; | 1177 | REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val); |
1210 | } | ||
1211 | } | 1178 | } |
1212 | 1179 | ||
1213 | static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) | 1180 | static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) |
@@ -1224,25 +1191,37 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) | |||
1224 | } | 1191 | } |
1225 | } | 1192 | } |
1226 | 1193 | ||
1227 | static void ath9k_hw_init_user_settings(struct ath_hw *ah) | 1194 | void ath9k_hw_init_global_settings(struct ath_hw *ah) |
1228 | { | 1195 | { |
1196 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | ||
1197 | int acktimeout; | ||
1198 | int slottime; | ||
1199 | int sifstime; | ||
1200 | |||
1229 | ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", | 1201 | ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", |
1230 | ah->misc_mode); | 1202 | ah->misc_mode); |
1231 | 1203 | ||
1232 | if (ah->misc_mode != 0) | 1204 | if (ah->misc_mode != 0) |
1233 | REG_WRITE(ah, AR_PCU_MISC, | 1205 | REG_WRITE(ah, AR_PCU_MISC, |
1234 | REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); | 1206 | REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); |
1235 | if (ah->slottime != (u32) -1) | 1207 | |
1236 | ath9k_hw_setslottime(ah, ah->slottime); | 1208 | if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) |
1237 | if (ah->acktimeout != (u32) -1) | 1209 | sifstime = 16; |
1238 | ath9k_hw_set_ack_timeout(ah, ah->acktimeout); | 1210 | else |
1239 | if (ah->ctstimeout != (u32) -1) | 1211 | sifstime = 10; |
1240 | ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); | 1212 | |
1213 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ | ||
1214 | slottime = ah->slottime + 3 * ah->coverage_class; | ||
1215 | acktimeout = slottime + sifstime; | ||
1216 | ath9k_hw_setslottime(ah, slottime); | ||
1217 | ath9k_hw_set_ack_timeout(ah, acktimeout); | ||
1218 | ath9k_hw_set_cts_timeout(ah, acktimeout); | ||
1241 | if (ah->globaltxtimeout != (u32) -1) | 1219 | if (ah->globaltxtimeout != (u32) -1) |
1242 | ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); | 1220 | ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); |
1243 | } | 1221 | } |
1222 | EXPORT_SYMBOL(ath9k_hw_init_global_settings); | ||
1244 | 1223 | ||
1245 | void ath9k_hw_detach(struct ath_hw *ah) | 1224 | void ath9k_hw_deinit(struct ath_hw *ah) |
1246 | { | 1225 | { |
1247 | struct ath_common *common = ath9k_hw_common(ah); | 1226 | struct ath_common *common = ath9k_hw_common(ah); |
1248 | 1227 | ||
@@ -1260,7 +1239,7 @@ free_hw: | |||
1260 | kfree(ah); | 1239 | kfree(ah); |
1261 | ah = NULL; | 1240 | ah = NULL; |
1262 | } | 1241 | } |
1263 | EXPORT_SYMBOL(ath9k_hw_detach); | 1242 | EXPORT_SYMBOL(ath9k_hw_deinit); |
1264 | 1243 | ||
1265 | /*******/ | 1244 | /*******/ |
1266 | /* INI */ | 1245 | /* INI */ |
@@ -2061,7 +2040,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
2061 | if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | 2040 | if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) |
2062 | ath9k_enable_rfkill(ah); | 2041 | ath9k_enable_rfkill(ah); |
2063 | 2042 | ||
2064 | ath9k_hw_init_user_settings(ah); | 2043 | ath9k_hw_init_global_settings(ah); |
2065 | 2044 | ||
2066 | if (AR_SREV_9287_12_OR_LATER(ah)) { | 2045 | if (AR_SREV_9287_12_OR_LATER(ah)) { |
2067 | REG_WRITE(ah, AR_D_GBL_IFS_SIFS, | 2046 | REG_WRITE(ah, AR_D_GBL_IFS_SIFS, |
@@ -3658,21 +3637,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp) | |||
3658 | } | 3637 | } |
3659 | EXPORT_SYMBOL(ath9k_hw_extend_tsf); | 3638 | EXPORT_SYMBOL(ath9k_hw_extend_tsf); |
3660 | 3639 | ||
3661 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) | ||
3662 | { | ||
3663 | if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { | ||
3664 | ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, | ||
3665 | "bad slot time %u\n", us); | ||
3666 | ah->slottime = (u32) -1; | ||
3667 | return false; | ||
3668 | } else { | ||
3669 | REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); | ||
3670 | ah->slottime = us; | ||
3671 | return true; | ||
3672 | } | ||
3673 | } | ||
3674 | EXPORT_SYMBOL(ath9k_hw_setslottime); | ||
3675 | |||
3676 | void ath9k_hw_set11nmac2040(struct ath_hw *ah) | 3640 | void ath9k_hw_set11nmac2040(struct ath_hw *ah) |
3677 | { | 3641 | { |
3678 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; | 3642 | struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 8849450dc591..ab1f1981d857 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -551,10 +551,9 @@ struct ath_hw { | |||
551 | u32 *bank6Temp; | 551 | u32 *bank6Temp; |
552 | 552 | ||
553 | int16_t txpower_indexoffset; | 553 | int16_t txpower_indexoffset; |
554 | int coverage_class; | ||
554 | u32 beacon_interval; | 555 | u32 beacon_interval; |
555 | u32 slottime; | 556 | u32 slottime; |
556 | u32 acktimeout; | ||
557 | u32 ctstimeout; | ||
558 | u32 globaltxtimeout; | 557 | u32 globaltxtimeout; |
559 | 558 | ||
560 | /* ANI */ | 559 | /* ANI */ |
@@ -616,7 +615,7 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah) | |||
616 | 615 | ||
617 | /* Initialization, Detach, Reset */ | 616 | /* Initialization, Detach, Reset */ |
618 | const char *ath9k_hw_probe(u16 vendorid, u16 devid); | 617 | const char *ath9k_hw_probe(u16 vendorid, u16 devid); |
619 | void ath9k_hw_detach(struct ath_hw *ah); | 618 | void ath9k_hw_deinit(struct ath_hw *ah); |
620 | int ath9k_hw_init(struct ath_hw *ah); | 619 | int ath9k_hw_init(struct ath_hw *ah); |
621 | int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | 620 | int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, |
622 | bool bChannelChange); | 621 | bool bChannelChange); |
@@ -668,7 +667,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); | |||
668 | void ath9k_hw_reset_tsf(struct ath_hw *ah); | 667 | void ath9k_hw_reset_tsf(struct ath_hw *ah); |
669 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); | 668 | void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); |
670 | u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); | 669 | u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); |
671 | bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); | 670 | void ath9k_hw_init_global_settings(struct ath_hw *ah); |
672 | void ath9k_hw_set11nmac2040(struct ath_hw *ah); | 671 | void ath9k_hw_set11nmac2040(struct ath_hw *ah); |
673 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); | 672 | void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); |
674 | void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, | 673 | void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c new file mode 100644 index 000000000000..5f78d7a5ff22 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -0,0 +1,861 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "ath9k.h" | ||
18 | |||
19 | static char *dev_info = "ath9k"; | ||
20 | |||
21 | MODULE_AUTHOR("Atheros Communications"); | ||
22 | MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); | ||
23 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); | ||
24 | MODULE_LICENSE("Dual BSD/GPL"); | ||
25 | |||
26 | static unsigned int ath9k_debug = ATH_DBG_DEFAULT; | ||
27 | module_param_named(debug, ath9k_debug, uint, 0); | ||
28 | MODULE_PARM_DESC(debug, "Debugging mask"); | ||
29 | |||
30 | int modparam_nohwcrypt; | ||
31 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | ||
32 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | ||
33 | |||
34 | /* We use the hw_value as an index into our private channel structure */ | ||
35 | |||
36 | #define CHAN2G(_freq, _idx) { \ | ||
37 | .center_freq = (_freq), \ | ||
38 | .hw_value = (_idx), \ | ||
39 | .max_power = 20, \ | ||
40 | } | ||
41 | |||
42 | #define CHAN5G(_freq, _idx) { \ | ||
43 | .band = IEEE80211_BAND_5GHZ, \ | ||
44 | .center_freq = (_freq), \ | ||
45 | .hw_value = (_idx), \ | ||
46 | .max_power = 20, \ | ||
47 | } | ||
48 | |||
49 | /* Some 2 GHz radios are actually tunable on 2312-2732 | ||
50 | * on 5 MHz steps, we support the channels which we know | ||
51 | * we have calibration data for all cards though to make | ||
52 | * this static */ | ||
53 | static struct ieee80211_channel ath9k_2ghz_chantable[] = { | ||
54 | CHAN2G(2412, 0), /* Channel 1 */ | ||
55 | CHAN2G(2417, 1), /* Channel 2 */ | ||
56 | CHAN2G(2422, 2), /* Channel 3 */ | ||
57 | CHAN2G(2427, 3), /* Channel 4 */ | ||
58 | CHAN2G(2432, 4), /* Channel 5 */ | ||
59 | CHAN2G(2437, 5), /* Channel 6 */ | ||
60 | CHAN2G(2442, 6), /* Channel 7 */ | ||
61 | CHAN2G(2447, 7), /* Channel 8 */ | ||
62 | CHAN2G(2452, 8), /* Channel 9 */ | ||
63 | CHAN2G(2457, 9), /* Channel 10 */ | ||
64 | CHAN2G(2462, 10), /* Channel 11 */ | ||
65 | CHAN2G(2467, 11), /* Channel 12 */ | ||
66 | CHAN2G(2472, 12), /* Channel 13 */ | ||
67 | CHAN2G(2484, 13), /* Channel 14 */ | ||
68 | }; | ||
69 | |||
70 | /* Some 5 GHz radios are actually tunable on XXXX-YYYY | ||
71 | * on 5 MHz steps, we support the channels which we know | ||
72 | * we have calibration data for all cards though to make | ||
73 | * this static */ | ||
74 | static struct ieee80211_channel ath9k_5ghz_chantable[] = { | ||
75 | /* _We_ call this UNII 1 */ | ||
76 | CHAN5G(5180, 14), /* Channel 36 */ | ||
77 | CHAN5G(5200, 15), /* Channel 40 */ | ||
78 | CHAN5G(5220, 16), /* Channel 44 */ | ||
79 | CHAN5G(5240, 17), /* Channel 48 */ | ||
80 | /* _We_ call this UNII 2 */ | ||
81 | CHAN5G(5260, 18), /* Channel 52 */ | ||
82 | CHAN5G(5280, 19), /* Channel 56 */ | ||
83 | CHAN5G(5300, 20), /* Channel 60 */ | ||
84 | CHAN5G(5320, 21), /* Channel 64 */ | ||
85 | /* _We_ call this "Middle band" */ | ||
86 | CHAN5G(5500, 22), /* Channel 100 */ | ||
87 | CHAN5G(5520, 23), /* Channel 104 */ | ||
88 | CHAN5G(5540, 24), /* Channel 108 */ | ||
89 | CHAN5G(5560, 25), /* Channel 112 */ | ||
90 | CHAN5G(5580, 26), /* Channel 116 */ | ||
91 | CHAN5G(5600, 27), /* Channel 120 */ | ||
92 | CHAN5G(5620, 28), /* Channel 124 */ | ||
93 | CHAN5G(5640, 29), /* Channel 128 */ | ||
94 | CHAN5G(5660, 30), /* Channel 132 */ | ||
95 | CHAN5G(5680, 31), /* Channel 136 */ | ||
96 | CHAN5G(5700, 32), /* Channel 140 */ | ||
97 | /* _We_ call this UNII 3 */ | ||
98 | CHAN5G(5745, 33), /* Channel 149 */ | ||
99 | CHAN5G(5765, 34), /* Channel 153 */ | ||
100 | CHAN5G(5785, 35), /* Channel 157 */ | ||
101 | CHAN5G(5805, 36), /* Channel 161 */ | ||
102 | CHAN5G(5825, 37), /* Channel 165 */ | ||
103 | }; | ||
104 | |||
105 | /* Atheros hardware rate code addition for short premble */ | ||
106 | #define SHPCHECK(__hw_rate, __flags) \ | ||
107 | ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) | ||
108 | |||
109 | #define RATE(_bitrate, _hw_rate, _flags) { \ | ||
110 | .bitrate = (_bitrate), \ | ||
111 | .flags = (_flags), \ | ||
112 | .hw_value = (_hw_rate), \ | ||
113 | .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ | ||
114 | } | ||
115 | |||
116 | static struct ieee80211_rate ath9k_legacy_rates[] = { | ||
117 | RATE(10, 0x1b, 0), | ||
118 | RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), | ||
119 | RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), | ||
120 | RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), | ||
121 | RATE(60, 0x0b, 0), | ||
122 | RATE(90, 0x0f, 0), | ||
123 | RATE(120, 0x0a, 0), | ||
124 | RATE(180, 0x0e, 0), | ||
125 | RATE(240, 0x09, 0), | ||
126 | RATE(360, 0x0d, 0), | ||
127 | RATE(480, 0x08, 0), | ||
128 | RATE(540, 0x0c, 0), | ||
129 | }; | ||
130 | |||
131 | static void ath9k_deinit_softc(struct ath_softc *sc); | ||
132 | |||
133 | /* | ||
134 | * Read and write, they both share the same lock. We do this to serialize | ||
135 | * reads and writes on Atheros 802.11n PCI devices only. This is required | ||
136 | * as the FIFO on these devices can only accept sanely 2 requests. | ||
137 | */ | ||
138 | |||
139 | static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) | ||
140 | { | ||
141 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
142 | struct ath_common *common = ath9k_hw_common(ah); | ||
143 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
144 | |||
145 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
146 | unsigned long flags; | ||
147 | spin_lock_irqsave(&sc->sc_serial_rw, flags); | ||
148 | iowrite32(val, sc->mem + reg_offset); | ||
149 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | ||
150 | } else | ||
151 | iowrite32(val, sc->mem + reg_offset); | ||
152 | } | ||
153 | |||
154 | static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) | ||
155 | { | ||
156 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
157 | struct ath_common *common = ath9k_hw_common(ah); | ||
158 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
159 | u32 val; | ||
160 | |||
161 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
162 | unsigned long flags; | ||
163 | spin_lock_irqsave(&sc->sc_serial_rw, flags); | ||
164 | val = ioread32(sc->mem + reg_offset); | ||
165 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | ||
166 | } else | ||
167 | val = ioread32(sc->mem + reg_offset); | ||
168 | return val; | ||
169 | } | ||
170 | |||
171 | static const struct ath_ops ath9k_common_ops = { | ||
172 | .read = ath9k_ioread32, | ||
173 | .write = ath9k_iowrite32, | ||
174 | }; | ||
175 | |||
176 | /**************************/ | ||
177 | /* Initialization */ | ||
178 | /**************************/ | ||
179 | |||
180 | static void setup_ht_cap(struct ath_softc *sc, | ||
181 | struct ieee80211_sta_ht_cap *ht_info) | ||
182 | { | ||
183 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
184 | u8 tx_streams, rx_streams; | ||
185 | |||
186 | ht_info->ht_supported = true; | ||
187 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
188 | IEEE80211_HT_CAP_SM_PS | | ||
189 | IEEE80211_HT_CAP_SGI_40 | | ||
190 | IEEE80211_HT_CAP_DSSSCCK40; | ||
191 | |||
192 | ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | ||
193 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; | ||
194 | |||
195 | /* set up supported mcs set */ | ||
196 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||
197 | tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? | ||
198 | 1 : 2; | ||
199 | rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? | ||
200 | 1 : 2; | ||
201 | |||
202 | if (tx_streams != rx_streams) { | ||
203 | ath_print(common, ATH_DBG_CONFIG, | ||
204 | "TX streams %d, RX streams: %d\n", | ||
205 | tx_streams, rx_streams); | ||
206 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | ||
207 | ht_info->mcs.tx_params |= ((tx_streams - 1) << | ||
208 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||
209 | } | ||
210 | |||
211 | ht_info->mcs.rx_mask[0] = 0xff; | ||
212 | if (rx_streams >= 2) | ||
213 | ht_info->mcs.rx_mask[1] = 0xff; | ||
214 | |||
215 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; | ||
216 | } | ||
217 | |||
218 | static int ath9k_reg_notifier(struct wiphy *wiphy, | ||
219 | struct regulatory_request *request) | ||
220 | { | ||
221 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
222 | struct ath_wiphy *aphy = hw->priv; | ||
223 | struct ath_softc *sc = aphy->sc; | ||
224 | struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); | ||
225 | |||
226 | return ath_reg_notifier_apply(wiphy, request, reg); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * This function will allocate both the DMA descriptor structure, and the | ||
231 | * buffers it contains. These are used to contain the descriptors used | ||
232 | * by the system. | ||
233 | */ | ||
234 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, | ||
235 | struct list_head *head, const char *name, | ||
236 | int nbuf, int ndesc) | ||
237 | { | ||
238 | #define DS2PHYS(_dd, _ds) \ | ||
239 | ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) | ||
240 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) | ||
241 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) | ||
242 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
243 | struct ath_desc *ds; | ||
244 | struct ath_buf *bf; | ||
245 | int i, bsize, error; | ||
246 | |||
247 | ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", | ||
248 | name, nbuf, ndesc); | ||
249 | |||
250 | INIT_LIST_HEAD(head); | ||
251 | /* ath_desc must be a multiple of DWORDs */ | ||
252 | if ((sizeof(struct ath_desc) % 4) != 0) { | ||
253 | ath_print(common, ATH_DBG_FATAL, | ||
254 | "ath_desc not DWORD aligned\n"); | ||
255 | BUG_ON((sizeof(struct ath_desc) % 4) != 0); | ||
256 | error = -ENOMEM; | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; | ||
261 | |||
262 | /* | ||
263 | * Need additional DMA memory because we can't use | ||
264 | * descriptors that cross the 4K page boundary. Assume | ||
265 | * one skipped descriptor per 4K page. | ||
266 | */ | ||
267 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { | ||
268 | u32 ndesc_skipped = | ||
269 | ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); | ||
270 | u32 dma_len; | ||
271 | |||
272 | while (ndesc_skipped) { | ||
273 | dma_len = ndesc_skipped * sizeof(struct ath_desc); | ||
274 | dd->dd_desc_len += dma_len; | ||
275 | |||
276 | ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); | ||
277 | }; | ||
278 | } | ||
279 | |||
280 | /* allocate descriptors */ | ||
281 | dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | ||
282 | &dd->dd_desc_paddr, GFP_KERNEL); | ||
283 | if (dd->dd_desc == NULL) { | ||
284 | error = -ENOMEM; | ||
285 | goto fail; | ||
286 | } | ||
287 | ds = dd->dd_desc; | ||
288 | ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", | ||
289 | name, ds, (u32) dd->dd_desc_len, | ||
290 | ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); | ||
291 | |||
292 | /* allocate buffers */ | ||
293 | bsize = sizeof(struct ath_buf) * nbuf; | ||
294 | bf = kzalloc(bsize, GFP_KERNEL); | ||
295 | if (bf == NULL) { | ||
296 | error = -ENOMEM; | ||
297 | goto fail2; | ||
298 | } | ||
299 | dd->dd_bufptr = bf; | ||
300 | |||
301 | for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { | ||
302 | bf->bf_desc = ds; | ||
303 | bf->bf_daddr = DS2PHYS(dd, ds); | ||
304 | |||
305 | if (!(sc->sc_ah->caps.hw_caps & | ||
306 | ATH9K_HW_CAP_4KB_SPLITTRANS)) { | ||
307 | /* | ||
308 | * Skip descriptor addresses which can cause 4KB | ||
309 | * boundary crossing (addr + length) with a 32 dword | ||
310 | * descriptor fetch. | ||
311 | */ | ||
312 | while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { | ||
313 | BUG_ON((caddr_t) bf->bf_desc >= | ||
314 | ((caddr_t) dd->dd_desc + | ||
315 | dd->dd_desc_len)); | ||
316 | |||
317 | ds += ndesc; | ||
318 | bf->bf_desc = ds; | ||
319 | bf->bf_daddr = DS2PHYS(dd, ds); | ||
320 | } | ||
321 | } | ||
322 | list_add_tail(&bf->list, head); | ||
323 | } | ||
324 | return 0; | ||
325 | fail2: | ||
326 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | ||
327 | dd->dd_desc_paddr); | ||
328 | fail: | ||
329 | memset(dd, 0, sizeof(*dd)); | ||
330 | return error; | ||
331 | #undef ATH_DESC_4KB_BOUND_CHECK | ||
332 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED | ||
333 | #undef DS2PHYS | ||
334 | } | ||
335 | |||
336 | static void ath9k_init_crypto(struct ath_softc *sc) | ||
337 | { | ||
338 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
339 | int i = 0; | ||
340 | |||
341 | /* Get the hardware key cache size. */ | ||
342 | common->keymax = sc->sc_ah->caps.keycache_size; | ||
343 | if (common->keymax > ATH_KEYMAX) { | ||
344 | ath_print(common, ATH_DBG_ANY, | ||
345 | "Warning, using only %u entries in %u key cache\n", | ||
346 | ATH_KEYMAX, common->keymax); | ||
347 | common->keymax = ATH_KEYMAX; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Reset the key cache since some parts do not | ||
352 | * reset the contents on initial power up. | ||
353 | */ | ||
354 | for (i = 0; i < common->keymax; i++) | ||
355 | ath9k_hw_keyreset(sc->sc_ah, (u16) i); | ||
356 | |||
357 | if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, | ||
358 | ATH9K_CIPHER_TKIP, NULL)) { | ||
359 | /* | ||
360 | * Whether we should enable h/w TKIP MIC. | ||
361 | * XXX: if we don't support WME TKIP MIC, then we wouldn't | ||
362 | * report WMM capable, so it's always safe to turn on | ||
363 | * TKIP MIC in this case. | ||
364 | */ | ||
365 | ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Check whether the separate key cache entries | ||
370 | * are required to handle both tx+rx MIC keys. | ||
371 | * With split mic keys the number of stations is limited | ||
372 | * to 27 otherwise 59. | ||
373 | */ | ||
374 | if (ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, | ||
375 | ATH9K_CIPHER_TKIP, NULL) | ||
376 | && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_CIPHER, | ||
377 | ATH9K_CIPHER_MIC, NULL) | ||
378 | && ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_TKIP_SPLIT, | ||
379 | 0, NULL)) | ||
380 | common->splitmic = 1; | ||
381 | |||
382 | /* turn on mcast key search if possible */ | ||
383 | if (!ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) | ||
384 | (void)ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_MCAST_KEYSRCH, | ||
385 | 1, 1, NULL); | ||
386 | |||
387 | } | ||
388 | |||
389 | static int ath9k_init_btcoex(struct ath_softc *sc) | ||
390 | { | ||
391 | int r, qnum; | ||
392 | |||
393 | switch (sc->sc_ah->btcoex_hw.scheme) { | ||
394 | case ATH_BTCOEX_CFG_NONE: | ||
395 | break; | ||
396 | case ATH_BTCOEX_CFG_2WIRE: | ||
397 | ath9k_hw_btcoex_init_2wire(sc->sc_ah); | ||
398 | break; | ||
399 | case ATH_BTCOEX_CFG_3WIRE: | ||
400 | ath9k_hw_btcoex_init_3wire(sc->sc_ah); | ||
401 | r = ath_init_btcoex_timer(sc); | ||
402 | if (r) | ||
403 | return -1; | ||
404 | qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); | ||
405 | ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum); | ||
406 | sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | ||
407 | break; | ||
408 | default: | ||
409 | WARN_ON(1); | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int ath9k_init_queues(struct ath_softc *sc) | ||
417 | { | ||
418 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
419 | int i = 0; | ||
420 | |||
421 | for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) | ||
422 | sc->tx.hwq_map[i] = -1; | ||
423 | |||
424 | sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); | ||
425 | if (sc->beacon.beaconq == -1) { | ||
426 | ath_print(common, ATH_DBG_FATAL, | ||
427 | "Unable to setup a beacon xmit queue\n"); | ||
428 | goto err; | ||
429 | } | ||
430 | |||
431 | sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); | ||
432 | if (sc->beacon.cabq == NULL) { | ||
433 | ath_print(common, ATH_DBG_FATAL, | ||
434 | "Unable to setup CAB xmit queue\n"); | ||
435 | goto err; | ||
436 | } | ||
437 | |||
438 | sc->config.cabqReadytime = ATH_CABQ_READY_TIME; | ||
439 | ath_cabq_update(sc); | ||
440 | |||
441 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { | ||
442 | ath_print(common, ATH_DBG_FATAL, | ||
443 | "Unable to setup xmit queue for BK traffic\n"); | ||
444 | goto err; | ||
445 | } | ||
446 | |||
447 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { | ||
448 | ath_print(common, ATH_DBG_FATAL, | ||
449 | "Unable to setup xmit queue for BE traffic\n"); | ||
450 | goto err; | ||
451 | } | ||
452 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { | ||
453 | ath_print(common, ATH_DBG_FATAL, | ||
454 | "Unable to setup xmit queue for VI traffic\n"); | ||
455 | goto err; | ||
456 | } | ||
457 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { | ||
458 | ath_print(common, ATH_DBG_FATAL, | ||
459 | "Unable to setup xmit queue for VO traffic\n"); | ||
460 | goto err; | ||
461 | } | ||
462 | |||
463 | return 0; | ||
464 | |||
465 | err: | ||
466 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
467 | if (ATH_TXQ_SETUP(sc, i)) | ||
468 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
469 | |||
470 | return -EIO; | ||
471 | } | ||
472 | |||
473 | static void ath9k_init_channels_rates(struct ath_softc *sc) | ||
474 | { | ||
475 | if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { | ||
476 | sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; | ||
477 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
478 | sc->sbands[IEEE80211_BAND_2GHZ].n_channels = | ||
479 | ARRAY_SIZE(ath9k_2ghz_chantable); | ||
480 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; | ||
481 | sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = | ||
482 | ARRAY_SIZE(ath9k_legacy_rates); | ||
483 | } | ||
484 | |||
485 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { | ||
486 | sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; | ||
487 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; | ||
488 | sc->sbands[IEEE80211_BAND_5GHZ].n_channels = | ||
489 | ARRAY_SIZE(ath9k_5ghz_chantable); | ||
490 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
491 | ath9k_legacy_rates + 4; | ||
492 | sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = | ||
493 | ARRAY_SIZE(ath9k_legacy_rates) - 4; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void ath9k_init_misc(struct ath_softc *sc) | ||
498 | { | ||
499 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
500 | int i = 0; | ||
501 | |||
502 | common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; | ||
503 | setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); | ||
504 | |||
505 | sc->config.txpowlimit = ATH_TXPOWER_MAX; | ||
506 | |||
507 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
508 | sc->sc_flags |= SC_OP_TXAGGR; | ||
509 | sc->sc_flags |= SC_OP_RXAGGR; | ||
510 | } | ||
511 | |||
512 | common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; | ||
513 | common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; | ||
514 | |||
515 | ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); | ||
516 | sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); | ||
517 | |||
518 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | ||
519 | memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); | ||
520 | |||
521 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; | ||
522 | |||
523 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { | ||
524 | sc->beacon.bslot[i] = NULL; | ||
525 | sc->beacon.bslot_aphy[i] = NULL; | ||
526 | } | ||
527 | } | ||
528 | |||
529 | static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | ||
530 | const struct ath_bus_ops *bus_ops) | ||
531 | { | ||
532 | struct ath_hw *ah = NULL; | ||
533 | struct ath_common *common; | ||
534 | int ret = 0, i; | ||
535 | int csz = 0; | ||
536 | |||
537 | ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | ||
538 | if (!ah) | ||
539 | return -ENOMEM; | ||
540 | |||
541 | ah->hw_version.devid = devid; | ||
542 | ah->hw_version.subsysid = subsysid; | ||
543 | sc->sc_ah = ah; | ||
544 | |||
545 | common = ath9k_hw_common(ah); | ||
546 | common->ops = &ath9k_common_ops; | ||
547 | common->bus_ops = bus_ops; | ||
548 | common->ah = ah; | ||
549 | common->hw = sc->hw; | ||
550 | common->priv = sc; | ||
551 | common->debug_mask = ath9k_debug; | ||
552 | |||
553 | spin_lock_init(&sc->wiphy_lock); | ||
554 | spin_lock_init(&sc->sc_resetlock); | ||
555 | spin_lock_init(&sc->sc_serial_rw); | ||
556 | spin_lock_init(&sc->sc_pm_lock); | ||
557 | mutex_init(&sc->mutex); | ||
558 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | ||
559 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, | ||
560 | (unsigned long)sc); | ||
561 | |||
562 | /* | ||
563 | * Cache line size is used to size and align various | ||
564 | * structures used to communicate with the hardware. | ||
565 | */ | ||
566 | ath_read_cachesize(common, &csz); | ||
567 | common->cachelsz = csz << 2; /* convert to bytes */ | ||
568 | |||
569 | ret = ath9k_hw_init(ah); | ||
570 | if (ret) { | ||
571 | ath_print(common, ATH_DBG_FATAL, | ||
572 | "Unable to initialize hardware; " | ||
573 | "initialization status: %d\n", ret); | ||
574 | goto err_hw; | ||
575 | } | ||
576 | |||
577 | ret = ath9k_init_debug(ah); | ||
578 | if (ret) { | ||
579 | ath_print(common, ATH_DBG_FATAL, | ||
580 | "Unable to create debugfs files\n"); | ||
581 | goto err_debug; | ||
582 | } | ||
583 | |||
584 | ret = ath9k_init_queues(sc); | ||
585 | if (ret) | ||
586 | goto err_queues; | ||
587 | |||
588 | ret = ath9k_init_btcoex(sc); | ||
589 | if (ret) | ||
590 | goto err_btcoex; | ||
591 | |||
592 | ath9k_init_crypto(sc); | ||
593 | ath9k_init_channels_rates(sc); | ||
594 | ath9k_init_misc(sc); | ||
595 | |||
596 | return 0; | ||
597 | |||
598 | err_btcoex: | ||
599 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
600 | if (ATH_TXQ_SETUP(sc, i)) | ||
601 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
602 | err_queues: | ||
603 | ath9k_exit_debug(ah); | ||
604 | err_debug: | ||
605 | ath9k_hw_deinit(ah); | ||
606 | err_hw: | ||
607 | tasklet_kill(&sc->intr_tq); | ||
608 | tasklet_kill(&sc->bcon_tasklet); | ||
609 | |||
610 | kfree(ah); | ||
611 | sc->sc_ah = NULL; | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | ||
617 | { | ||
618 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
619 | |||
620 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | ||
621 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
622 | IEEE80211_HW_SIGNAL_DBM | | ||
623 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
624 | IEEE80211_HW_SUPPORTS_PS | | ||
625 | IEEE80211_HW_PS_NULLFUNC_STACK | | ||
626 | IEEE80211_HW_SPECTRUM_MGMT; | ||
627 | |||
628 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) | ||
629 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | ||
630 | |||
631 | hw->wiphy->interface_modes = | ||
632 | BIT(NL80211_IFTYPE_AP) | | ||
633 | BIT(NL80211_IFTYPE_STATION) | | ||
634 | BIT(NL80211_IFTYPE_ADHOC) | | ||
635 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
636 | |||
637 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
638 | |||
639 | hw->queues = 4; | ||
640 | hw->max_rates = 4; | ||
641 | hw->channel_change_time = 5000; | ||
642 | hw->max_listen_interval = 10; | ||
643 | /* Hardware supports 10 but we use 4 */ | ||
644 | hw->max_rate_tries = 4; | ||
645 | hw->sta_data_size = sizeof(struct ath_node); | ||
646 | hw->vif_data_size = sizeof(struct ath_vif); | ||
647 | |||
648 | hw->rate_control_algorithm = "ath9k_rate_control"; | ||
649 | |||
650 | if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) | ||
651 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
652 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
653 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | ||
654 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
655 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
656 | |||
657 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
658 | if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) | ||
659 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||
660 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | ||
661 | setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | ||
662 | } | ||
663 | |||
664 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); | ||
665 | } | ||
666 | |||
667 | int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | ||
668 | const struct ath_bus_ops *bus_ops) | ||
669 | { | ||
670 | struct ieee80211_hw *hw = sc->hw; | ||
671 | struct ath_common *common; | ||
672 | struct ath_hw *ah; | ||
673 | int error = 0; | ||
674 | struct ath_regulatory *reg; | ||
675 | |||
676 | /* Bring up device */ | ||
677 | error = ath9k_init_softc(devid, sc, subsysid, bus_ops); | ||
678 | if (error != 0) | ||
679 | goto error_init; | ||
680 | |||
681 | ah = sc->sc_ah; | ||
682 | common = ath9k_hw_common(ah); | ||
683 | ath9k_set_hw_capab(sc, hw); | ||
684 | |||
685 | /* Initialize regulatory */ | ||
686 | error = ath_regd_init(&common->regulatory, sc->hw->wiphy, | ||
687 | ath9k_reg_notifier); | ||
688 | if (error) | ||
689 | goto error_regd; | ||
690 | |||
691 | reg = &common->regulatory; | ||
692 | |||
693 | /* Setup TX DMA */ | ||
694 | error = ath_tx_init(sc, ATH_TXBUF); | ||
695 | if (error != 0) | ||
696 | goto error_tx; | ||
697 | |||
698 | /* Setup RX DMA */ | ||
699 | error = ath_rx_init(sc, ATH_RXBUF); | ||
700 | if (error != 0) | ||
701 | goto error_rx; | ||
702 | |||
703 | /* Register with mac80211 */ | ||
704 | error = ieee80211_register_hw(hw); | ||
705 | if (error) | ||
706 | goto error_register; | ||
707 | |||
708 | /* Handle world regulatory */ | ||
709 | if (!ath_is_world_regd(reg)) { | ||
710 | error = regulatory_hint(hw->wiphy, reg->alpha2); | ||
711 | if (error) | ||
712 | goto error_world; | ||
713 | } | ||
714 | |||
715 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); | ||
716 | INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); | ||
717 | sc->wiphy_scheduler_int = msecs_to_jiffies(500); | ||
718 | |||
719 | ath_init_leds(sc); | ||
720 | ath_start_rfkill_poll(sc); | ||
721 | |||
722 | return 0; | ||
723 | |||
724 | error_world: | ||
725 | ieee80211_unregister_hw(hw); | ||
726 | error_register: | ||
727 | ath_rx_cleanup(sc); | ||
728 | error_rx: | ||
729 | ath_tx_cleanup(sc); | ||
730 | error_tx: | ||
731 | /* Nothing */ | ||
732 | error_regd: | ||
733 | ath9k_deinit_softc(sc); | ||
734 | error_init: | ||
735 | return error; | ||
736 | } | ||
737 | |||
738 | /*****************************/ | ||
739 | /* De-Initialization */ | ||
740 | /*****************************/ | ||
741 | |||
742 | static void ath9k_deinit_softc(struct ath_softc *sc) | ||
743 | { | ||
744 | int i = 0; | ||
745 | |||
746 | if ((sc->btcoex.no_stomp_timer) && | ||
747 | sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | ||
748 | ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); | ||
749 | |||
750 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
751 | if (ATH_TXQ_SETUP(sc, i)) | ||
752 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
753 | |||
754 | ath9k_exit_debug(sc->sc_ah); | ||
755 | ath9k_hw_deinit(sc->sc_ah); | ||
756 | |||
757 | tasklet_kill(&sc->intr_tq); | ||
758 | tasklet_kill(&sc->bcon_tasklet); | ||
759 | } | ||
760 | |||
761 | void ath9k_deinit_device(struct ath_softc *sc) | ||
762 | { | ||
763 | struct ieee80211_hw *hw = sc->hw; | ||
764 | int i = 0; | ||
765 | |||
766 | ath9k_ps_wakeup(sc); | ||
767 | |||
768 | wiphy_rfkill_stop_polling(sc->hw->wiphy); | ||
769 | ath_deinit_leds(sc); | ||
770 | |||
771 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
772 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
773 | if (aphy == NULL) | ||
774 | continue; | ||
775 | sc->sec_wiphy[i] = NULL; | ||
776 | ieee80211_unregister_hw(aphy->hw); | ||
777 | ieee80211_free_hw(aphy->hw); | ||
778 | } | ||
779 | kfree(sc->sec_wiphy); | ||
780 | |||
781 | ieee80211_unregister_hw(hw); | ||
782 | ath_rx_cleanup(sc); | ||
783 | ath_tx_cleanup(sc); | ||
784 | ath9k_deinit_softc(sc); | ||
785 | } | ||
786 | |||
787 | void ath_descdma_cleanup(struct ath_softc *sc, | ||
788 | struct ath_descdma *dd, | ||
789 | struct list_head *head) | ||
790 | { | ||
791 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | ||
792 | dd->dd_desc_paddr); | ||
793 | |||
794 | INIT_LIST_HEAD(head); | ||
795 | kfree(dd->dd_bufptr); | ||
796 | memset(dd, 0, sizeof(*dd)); | ||
797 | } | ||
798 | |||
799 | /************************/ | ||
800 | /* Module Hooks */ | ||
801 | /************************/ | ||
802 | |||
803 | static int __init ath9k_init(void) | ||
804 | { | ||
805 | int error; | ||
806 | |||
807 | /* Register rate control algorithm */ | ||
808 | error = ath_rate_control_register(); | ||
809 | if (error != 0) { | ||
810 | printk(KERN_ERR | ||
811 | "ath9k: Unable to register rate control " | ||
812 | "algorithm: %d\n", | ||
813 | error); | ||
814 | goto err_out; | ||
815 | } | ||
816 | |||
817 | error = ath9k_debug_create_root(); | ||
818 | if (error) { | ||
819 | printk(KERN_ERR | ||
820 | "ath9k: Unable to create debugfs root: %d\n", | ||
821 | error); | ||
822 | goto err_rate_unregister; | ||
823 | } | ||
824 | |||
825 | error = ath_pci_init(); | ||
826 | if (error < 0) { | ||
827 | printk(KERN_ERR | ||
828 | "ath9k: No PCI devices found, driver not installed.\n"); | ||
829 | error = -ENODEV; | ||
830 | goto err_remove_root; | ||
831 | } | ||
832 | |||
833 | error = ath_ahb_init(); | ||
834 | if (error < 0) { | ||
835 | error = -ENODEV; | ||
836 | goto err_pci_exit; | ||
837 | } | ||
838 | |||
839 | return 0; | ||
840 | |||
841 | err_pci_exit: | ||
842 | ath_pci_exit(); | ||
843 | |||
844 | err_remove_root: | ||
845 | ath9k_debug_remove_root(); | ||
846 | err_rate_unregister: | ||
847 | ath_rate_control_unregister(); | ||
848 | err_out: | ||
849 | return error; | ||
850 | } | ||
851 | module_init(ath9k_init); | ||
852 | |||
853 | static void __exit ath9k_exit(void) | ||
854 | { | ||
855 | ath_ahb_exit(); | ||
856 | ath_pci_exit(); | ||
857 | ath9k_debug_remove_root(); | ||
858 | ath_rate_control_unregister(); | ||
859 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
860 | } | ||
861 | module_exit(ath9k_exit); | ||
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index e185479e295e..29851e6376a9 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -167,6 +167,40 @@ struct ath_rx_status { | |||
167 | #define ATH9K_RXKEYIX_INVALID ((u8)-1) | 167 | #define ATH9K_RXKEYIX_INVALID ((u8)-1) |
168 | #define ATH9K_TXKEYIX_INVALID ((u32)-1) | 168 | #define ATH9K_TXKEYIX_INVALID ((u32)-1) |
169 | 169 | ||
170 | enum ath9k_phyerr { | ||
171 | ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */ | ||
172 | ATH9K_PHYERR_TIMING = 1, /* Timing error */ | ||
173 | ATH9K_PHYERR_PARITY = 2, /* Illegal parity */ | ||
174 | ATH9K_PHYERR_RATE = 3, /* Illegal rate */ | ||
175 | ATH9K_PHYERR_LENGTH = 4, /* Illegal length */ | ||
176 | ATH9K_PHYERR_RADAR = 5, /* Radar detect */ | ||
177 | ATH9K_PHYERR_SERVICE = 6, /* Illegal service */ | ||
178 | ATH9K_PHYERR_TOR = 7, /* Transmit override receive */ | ||
179 | |||
180 | ATH9K_PHYERR_OFDM_TIMING = 17, | ||
181 | ATH9K_PHYERR_OFDM_SIGNAL_PARITY = 18, | ||
182 | ATH9K_PHYERR_OFDM_RATE_ILLEGAL = 19, | ||
183 | ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL = 20, | ||
184 | ATH9K_PHYERR_OFDM_POWER_DROP = 21, | ||
185 | ATH9K_PHYERR_OFDM_SERVICE = 22, | ||
186 | ATH9K_PHYERR_OFDM_RESTART = 23, | ||
187 | ATH9K_PHYERR_FALSE_RADAR_EXT = 24, | ||
188 | |||
189 | ATH9K_PHYERR_CCK_TIMING = 25, | ||
190 | ATH9K_PHYERR_CCK_HEADER_CRC = 26, | ||
191 | ATH9K_PHYERR_CCK_RATE_ILLEGAL = 27, | ||
192 | ATH9K_PHYERR_CCK_SERVICE = 30, | ||
193 | ATH9K_PHYERR_CCK_RESTART = 31, | ||
194 | ATH9K_PHYERR_CCK_LENGTH_ILLEGAL = 32, | ||
195 | ATH9K_PHYERR_CCK_POWER_DROP = 33, | ||
196 | |||
197 | ATH9K_PHYERR_HT_CRC_ERROR = 34, | ||
198 | ATH9K_PHYERR_HT_LENGTH_ILLEGAL = 35, | ||
199 | ATH9K_PHYERR_HT_RATE_ILLEGAL = 36, | ||
200 | |||
201 | ATH9K_PHYERR_MAX = 37, | ||
202 | }; | ||
203 | |||
170 | struct ath_desc { | 204 | struct ath_desc { |
171 | u32 ds_link; | 205 | u32 ds_link; |
172 | u32 ds_data; | 206 | u32 ds_data; |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 79fbbda15493..c0c571c2e8c4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -18,118 +18,6 @@ | |||
18 | #include "ath9k.h" | 18 | #include "ath9k.h" |
19 | #include "btcoex.h" | 19 | #include "btcoex.h" |
20 | 20 | ||
21 | static char *dev_info = "ath9k"; | ||
22 | |||
23 | MODULE_AUTHOR("Atheros Communications"); | ||
24 | MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); | ||
25 | MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); | ||
26 | MODULE_LICENSE("Dual BSD/GPL"); | ||
27 | |||
28 | static int modparam_nohwcrypt; | ||
29 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | ||
30 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | ||
31 | |||
32 | static unsigned int ath9k_debug = ATH_DBG_DEFAULT; | ||
33 | module_param_named(debug, ath9k_debug, uint, 0); | ||
34 | MODULE_PARM_DESC(debug, "Debugging mask"); | ||
35 | |||
36 | /* We use the hw_value as an index into our private channel structure */ | ||
37 | |||
38 | #define CHAN2G(_freq, _idx) { \ | ||
39 | .center_freq = (_freq), \ | ||
40 | .hw_value = (_idx), \ | ||
41 | .max_power = 20, \ | ||
42 | } | ||
43 | |||
44 | #define CHAN5G(_freq, _idx) { \ | ||
45 | .band = IEEE80211_BAND_5GHZ, \ | ||
46 | .center_freq = (_freq), \ | ||
47 | .hw_value = (_idx), \ | ||
48 | .max_power = 20, \ | ||
49 | } | ||
50 | |||
51 | /* Some 2 GHz radios are actually tunable on 2312-2732 | ||
52 | * on 5 MHz steps, we support the channels which we know | ||
53 | * we have calibration data for all cards though to make | ||
54 | * this static */ | ||
55 | static struct ieee80211_channel ath9k_2ghz_chantable[] = { | ||
56 | CHAN2G(2412, 0), /* Channel 1 */ | ||
57 | CHAN2G(2417, 1), /* Channel 2 */ | ||
58 | CHAN2G(2422, 2), /* Channel 3 */ | ||
59 | CHAN2G(2427, 3), /* Channel 4 */ | ||
60 | CHAN2G(2432, 4), /* Channel 5 */ | ||
61 | CHAN2G(2437, 5), /* Channel 6 */ | ||
62 | CHAN2G(2442, 6), /* Channel 7 */ | ||
63 | CHAN2G(2447, 7), /* Channel 8 */ | ||
64 | CHAN2G(2452, 8), /* Channel 9 */ | ||
65 | CHAN2G(2457, 9), /* Channel 10 */ | ||
66 | CHAN2G(2462, 10), /* Channel 11 */ | ||
67 | CHAN2G(2467, 11), /* Channel 12 */ | ||
68 | CHAN2G(2472, 12), /* Channel 13 */ | ||
69 | CHAN2G(2484, 13), /* Channel 14 */ | ||
70 | }; | ||
71 | |||
72 | /* Some 5 GHz radios are actually tunable on XXXX-YYYY | ||
73 | * on 5 MHz steps, we support the channels which we know | ||
74 | * we have calibration data for all cards though to make | ||
75 | * this static */ | ||
76 | static struct ieee80211_channel ath9k_5ghz_chantable[] = { | ||
77 | /* _We_ call this UNII 1 */ | ||
78 | CHAN5G(5180, 14), /* Channel 36 */ | ||
79 | CHAN5G(5200, 15), /* Channel 40 */ | ||
80 | CHAN5G(5220, 16), /* Channel 44 */ | ||
81 | CHAN5G(5240, 17), /* Channel 48 */ | ||
82 | /* _We_ call this UNII 2 */ | ||
83 | CHAN5G(5260, 18), /* Channel 52 */ | ||
84 | CHAN5G(5280, 19), /* Channel 56 */ | ||
85 | CHAN5G(5300, 20), /* Channel 60 */ | ||
86 | CHAN5G(5320, 21), /* Channel 64 */ | ||
87 | /* _We_ call this "Middle band" */ | ||
88 | CHAN5G(5500, 22), /* Channel 100 */ | ||
89 | CHAN5G(5520, 23), /* Channel 104 */ | ||
90 | CHAN5G(5540, 24), /* Channel 108 */ | ||
91 | CHAN5G(5560, 25), /* Channel 112 */ | ||
92 | CHAN5G(5580, 26), /* Channel 116 */ | ||
93 | CHAN5G(5600, 27), /* Channel 120 */ | ||
94 | CHAN5G(5620, 28), /* Channel 124 */ | ||
95 | CHAN5G(5640, 29), /* Channel 128 */ | ||
96 | CHAN5G(5660, 30), /* Channel 132 */ | ||
97 | CHAN5G(5680, 31), /* Channel 136 */ | ||
98 | CHAN5G(5700, 32), /* Channel 140 */ | ||
99 | /* _We_ call this UNII 3 */ | ||
100 | CHAN5G(5745, 33), /* Channel 149 */ | ||
101 | CHAN5G(5765, 34), /* Channel 153 */ | ||
102 | CHAN5G(5785, 35), /* Channel 157 */ | ||
103 | CHAN5G(5805, 36), /* Channel 161 */ | ||
104 | CHAN5G(5825, 37), /* Channel 165 */ | ||
105 | }; | ||
106 | |||
107 | /* Atheros hardware rate code addition for short premble */ | ||
108 | #define SHPCHECK(__hw_rate, __flags) \ | ||
109 | ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) | ||
110 | |||
111 | #define RATE(_bitrate, _hw_rate, _flags) { \ | ||
112 | .bitrate = (_bitrate), \ | ||
113 | .flags = (_flags), \ | ||
114 | .hw_value = (_hw_rate), \ | ||
115 | .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ | ||
116 | } | ||
117 | |||
118 | static struct ieee80211_rate ath9k_legacy_rates[] = { | ||
119 | RATE(10, 0x1b, 0), | ||
120 | RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), | ||
121 | RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), | ||
122 | RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), | ||
123 | RATE(60, 0x0b, 0), | ||
124 | RATE(90, 0x0f, 0), | ||
125 | RATE(120, 0x0a, 0), | ||
126 | RATE(180, 0x0e, 0), | ||
127 | RATE(240, 0x09, 0), | ||
128 | RATE(360, 0x0d, 0), | ||
129 | RATE(480, 0x08, 0), | ||
130 | RATE(540, 0x0c, 0), | ||
131 | }; | ||
132 | |||
133 | static void ath_cache_conf_rate(struct ath_softc *sc, | 21 | static void ath_cache_conf_rate(struct ath_softc *sc, |
134 | struct ieee80211_conf *conf) | 22 | struct ieee80211_conf *conf) |
135 | { | 23 | { |
@@ -221,7 +109,7 @@ static struct ath9k_channel *ath_get_curchannel(struct ath_softc *sc, | |||
221 | return channel; | 109 | return channel; |
222 | } | 110 | } |
223 | 111 | ||
224 | static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) | 112 | bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode) |
225 | { | 113 | { |
226 | unsigned long flags; | 114 | unsigned long flags; |
227 | bool ret; | 115 | bool ret; |
@@ -256,10 +144,10 @@ void ath9k_ps_restore(struct ath_softc *sc) | |||
256 | goto unlock; | 144 | goto unlock; |
257 | 145 | ||
258 | if (sc->ps_enabled && | 146 | if (sc->ps_enabled && |
259 | !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | 147 | !(sc->ps_flags & (PS_WAIT_FOR_BEACON | |
260 | SC_OP_WAIT_FOR_CAB | | 148 | PS_WAIT_FOR_CAB | |
261 | SC_OP_WAIT_FOR_PSPOLL_DATA | | 149 | PS_WAIT_FOR_PSPOLL_DATA | |
262 | SC_OP_WAIT_FOR_TX_ACK))) | 150 | PS_WAIT_FOR_TX_ACK))) |
263 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); | 151 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); |
264 | 152 | ||
265 | unlock: | 153 | unlock: |
@@ -349,7 +237,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
349 | * When the task is complete, it reschedules itself depending on the | 237 | * When the task is complete, it reschedules itself depending on the |
350 | * appropriate interval that was calculated. | 238 | * appropriate interval that was calculated. |
351 | */ | 239 | */ |
352 | static void ath_ani_calibrate(unsigned long data) | 240 | void ath_ani_calibrate(unsigned long data) |
353 | { | 241 | { |
354 | struct ath_softc *sc = (struct ath_softc *)data; | 242 | struct ath_softc *sc = (struct ath_softc *)data; |
355 | struct ath_hw *ah = sc->sc_ah; | 243 | struct ath_hw *ah = sc->sc_ah; |
@@ -504,7 +392,7 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
504 | ath_tx_node_cleanup(sc, an); | 392 | ath_tx_node_cleanup(sc, an); |
505 | } | 393 | } |
506 | 394 | ||
507 | static void ath9k_tasklet(unsigned long data) | 395 | void ath9k_tasklet(unsigned long data) |
508 | { | 396 | { |
509 | struct ath_softc *sc = (struct ath_softc *)data; | 397 | struct ath_softc *sc = (struct ath_softc *)data; |
510 | struct ath_hw *ah = sc->sc_ah; | 398 | struct ath_hw *ah = sc->sc_ah; |
@@ -536,7 +424,7 @@ static void ath9k_tasklet(unsigned long data) | |||
536 | */ | 424 | */ |
537 | ath_print(common, ATH_DBG_PS, | 425 | ath_print(common, ATH_DBG_PS, |
538 | "TSFOOR - Sync with next Beacon\n"); | 426 | "TSFOOR - Sync with next Beacon\n"); |
539 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON | SC_OP_BEACON_SYNC; | 427 | sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; |
540 | } | 428 | } |
541 | 429 | ||
542 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | 430 | if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) |
@@ -637,7 +525,7 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
637 | * receive frames */ | 525 | * receive frames */ |
638 | ath9k_setpower(sc, ATH9K_PM_AWAKE); | 526 | ath9k_setpower(sc, ATH9K_PM_AWAKE); |
639 | ath9k_hw_setrxabort(sc->sc_ah, 0); | 527 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
640 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; | 528 | sc->ps_flags |= PS_WAIT_FOR_BEACON; |
641 | } | 529 | } |
642 | 530 | ||
643 | chip_reset: | 531 | chip_reset: |
@@ -924,44 +812,6 @@ static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf | |||
924 | } | 812 | } |
925 | } | 813 | } |
926 | 814 | ||
927 | static void setup_ht_cap(struct ath_softc *sc, | ||
928 | struct ieee80211_sta_ht_cap *ht_info) | ||
929 | { | ||
930 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
931 | u8 tx_streams, rx_streams; | ||
932 | |||
933 | ht_info->ht_supported = true; | ||
934 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
935 | IEEE80211_HT_CAP_SM_PS | | ||
936 | IEEE80211_HT_CAP_SGI_40 | | ||
937 | IEEE80211_HT_CAP_DSSSCCK40; | ||
938 | |||
939 | ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | ||
940 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; | ||
941 | |||
942 | /* set up supported mcs set */ | ||
943 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||
944 | tx_streams = !(common->tx_chainmask & (common->tx_chainmask - 1)) ? | ||
945 | 1 : 2; | ||
946 | rx_streams = !(common->rx_chainmask & (common->rx_chainmask - 1)) ? | ||
947 | 1 : 2; | ||
948 | |||
949 | if (tx_streams != rx_streams) { | ||
950 | ath_print(common, ATH_DBG_CONFIG, | ||
951 | "TX streams %d, RX streams: %d\n", | ||
952 | tx_streams, rx_streams); | ||
953 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | ||
954 | ht_info->mcs.tx_params |= ((tx_streams - 1) << | ||
955 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | ||
956 | } | ||
957 | |||
958 | ht_info->mcs.rx_mask[0] = 0xff; | ||
959 | if (rx_streams >= 2) | ||
960 | ht_info->mcs.rx_mask[1] = 0xff; | ||
961 | |||
962 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; | ||
963 | } | ||
964 | |||
965 | static void ath9k_bss_assoc_info(struct ath_softc *sc, | 815 | static void ath9k_bss_assoc_info(struct ath_softc *sc, |
966 | struct ieee80211_vif *vif, | 816 | struct ieee80211_vif *vif, |
967 | struct ieee80211_bss_conf *bss_conf) | 817 | struct ieee80211_bss_conf *bss_conf) |
@@ -983,7 +833,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
983 | * on the receipt of the first Beacon frame (i.e., | 833 | * on the receipt of the first Beacon frame (i.e., |
984 | * after time sync with the AP). | 834 | * after time sync with the AP). |
985 | */ | 835 | */ |
986 | sc->sc_flags |= SC_OP_BEACON_SYNC; | 836 | sc->ps_flags |= PS_BEACON_SYNC; |
987 | 837 | ||
988 | /* Configure the beacon */ | 838 | /* Configure the beacon */ |
989 | ath_beacon_config(sc, vif); | 839 | ath_beacon_config(sc, vif); |
@@ -1000,174 +850,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
1000 | } | 850 | } |
1001 | } | 851 | } |
1002 | 852 | ||
1003 | /********************************/ | ||
1004 | /* LED functions */ | ||
1005 | /********************************/ | ||
1006 | |||
1007 | static void ath_led_blink_work(struct work_struct *work) | ||
1008 | { | ||
1009 | struct ath_softc *sc = container_of(work, struct ath_softc, | ||
1010 | ath_led_blink_work.work); | ||
1011 | |||
1012 | if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) | ||
1013 | return; | ||
1014 | |||
1015 | if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
1016 | (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
1017 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); | ||
1018 | else | ||
1019 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, | ||
1020 | (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); | ||
1021 | |||
1022 | ieee80211_queue_delayed_work(sc->hw, | ||
1023 | &sc->ath_led_blink_work, | ||
1024 | (sc->sc_flags & SC_OP_LED_ON) ? | ||
1025 | msecs_to_jiffies(sc->led_off_duration) : | ||
1026 | msecs_to_jiffies(sc->led_on_duration)); | ||
1027 | |||
1028 | sc->led_on_duration = sc->led_on_cnt ? | ||
1029 | max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : | ||
1030 | ATH_LED_ON_DURATION_IDLE; | ||
1031 | sc->led_off_duration = sc->led_off_cnt ? | ||
1032 | max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : | ||
1033 | ATH_LED_OFF_DURATION_IDLE; | ||
1034 | sc->led_on_cnt = sc->led_off_cnt = 0; | ||
1035 | if (sc->sc_flags & SC_OP_LED_ON) | ||
1036 | sc->sc_flags &= ~SC_OP_LED_ON; | ||
1037 | else | ||
1038 | sc->sc_flags |= SC_OP_LED_ON; | ||
1039 | } | ||
1040 | |||
1041 | static void ath_led_brightness(struct led_classdev *led_cdev, | ||
1042 | enum led_brightness brightness) | ||
1043 | { | ||
1044 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
1045 | struct ath_softc *sc = led->sc; | ||
1046 | |||
1047 | switch (brightness) { | ||
1048 | case LED_OFF: | ||
1049 | if (led->led_type == ATH_LED_ASSOC || | ||
1050 | led->led_type == ATH_LED_RADIO) { | ||
1051 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, | ||
1052 | (led->led_type == ATH_LED_RADIO)); | ||
1053 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1054 | if (led->led_type == ATH_LED_RADIO) | ||
1055 | sc->sc_flags &= ~SC_OP_LED_ON; | ||
1056 | } else { | ||
1057 | sc->led_off_cnt++; | ||
1058 | } | ||
1059 | break; | ||
1060 | case LED_FULL: | ||
1061 | if (led->led_type == ATH_LED_ASSOC) { | ||
1062 | sc->sc_flags |= SC_OP_LED_ASSOCIATED; | ||
1063 | ieee80211_queue_delayed_work(sc->hw, | ||
1064 | &sc->ath_led_blink_work, 0); | ||
1065 | } else if (led->led_type == ATH_LED_RADIO) { | ||
1066 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); | ||
1067 | sc->sc_flags |= SC_OP_LED_ON; | ||
1068 | } else { | ||
1069 | sc->led_on_cnt++; | ||
1070 | } | ||
1071 | break; | ||
1072 | default: | ||
1073 | break; | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | static int ath_register_led(struct ath_softc *sc, struct ath_led *led, | ||
1078 | char *trigger) | ||
1079 | { | ||
1080 | int ret; | ||
1081 | |||
1082 | led->sc = sc; | ||
1083 | led->led_cdev.name = led->name; | ||
1084 | led->led_cdev.default_trigger = trigger; | ||
1085 | led->led_cdev.brightness_set = ath_led_brightness; | ||
1086 | |||
1087 | ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); | ||
1088 | if (ret) | ||
1089 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, | ||
1090 | "Failed to register led:%s", led->name); | ||
1091 | else | ||
1092 | led->registered = 1; | ||
1093 | return ret; | ||
1094 | } | ||
1095 | |||
1096 | static void ath_unregister_led(struct ath_led *led) | ||
1097 | { | ||
1098 | if (led->registered) { | ||
1099 | led_classdev_unregister(&led->led_cdev); | ||
1100 | led->registered = 0; | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | static void ath_deinit_leds(struct ath_softc *sc) | ||
1105 | { | ||
1106 | ath_unregister_led(&sc->assoc_led); | ||
1107 | sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; | ||
1108 | ath_unregister_led(&sc->tx_led); | ||
1109 | ath_unregister_led(&sc->rx_led); | ||
1110 | ath_unregister_led(&sc->radio_led); | ||
1111 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | ||
1112 | } | ||
1113 | |||
1114 | static void ath_init_leds(struct ath_softc *sc) | ||
1115 | { | ||
1116 | char *trigger; | ||
1117 | int ret; | ||
1118 | |||
1119 | if (AR_SREV_9287(sc->sc_ah)) | ||
1120 | sc->sc_ah->led_pin = ATH_LED_PIN_9287; | ||
1121 | else | ||
1122 | sc->sc_ah->led_pin = ATH_LED_PIN_DEF; | ||
1123 | |||
1124 | /* Configure gpio 1 for output */ | ||
1125 | ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, | ||
1126 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
1127 | /* LED off, active low */ | ||
1128 | ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); | ||
1129 | |||
1130 | INIT_DELAYED_WORK(&sc->ath_led_blink_work, ath_led_blink_work); | ||
1131 | |||
1132 | trigger = ieee80211_get_radio_led_name(sc->hw); | ||
1133 | snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), | ||
1134 | "ath9k-%s::radio", wiphy_name(sc->hw->wiphy)); | ||
1135 | ret = ath_register_led(sc, &sc->radio_led, trigger); | ||
1136 | sc->radio_led.led_type = ATH_LED_RADIO; | ||
1137 | if (ret) | ||
1138 | goto fail; | ||
1139 | |||
1140 | trigger = ieee80211_get_assoc_led_name(sc->hw); | ||
1141 | snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), | ||
1142 | "ath9k-%s::assoc", wiphy_name(sc->hw->wiphy)); | ||
1143 | ret = ath_register_led(sc, &sc->assoc_led, trigger); | ||
1144 | sc->assoc_led.led_type = ATH_LED_ASSOC; | ||
1145 | if (ret) | ||
1146 | goto fail; | ||
1147 | |||
1148 | trigger = ieee80211_get_tx_led_name(sc->hw); | ||
1149 | snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), | ||
1150 | "ath9k-%s::tx", wiphy_name(sc->hw->wiphy)); | ||
1151 | ret = ath_register_led(sc, &sc->tx_led, trigger); | ||
1152 | sc->tx_led.led_type = ATH_LED_TX; | ||
1153 | if (ret) | ||
1154 | goto fail; | ||
1155 | |||
1156 | trigger = ieee80211_get_rx_led_name(sc->hw); | ||
1157 | snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), | ||
1158 | "ath9k-%s::rx", wiphy_name(sc->hw->wiphy)); | ||
1159 | ret = ath_register_led(sc, &sc->rx_led, trigger); | ||
1160 | sc->rx_led.led_type = ATH_LED_RX; | ||
1161 | if (ret) | ||
1162 | goto fail; | ||
1163 | |||
1164 | return; | ||
1165 | |||
1166 | fail: | ||
1167 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | ||
1168 | ath_deinit_leds(sc); | ||
1169 | } | ||
1170 | |||
1171 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) | 853 | void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) |
1172 | { | 854 | { |
1173 | struct ath_hw *ah = sc->sc_ah; | 855 | struct ath_hw *ah = sc->sc_ah; |
@@ -1252,710 +934,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
1252 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); | 934 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); |
1253 | } | 935 | } |
1254 | 936 | ||
1255 | /*******************/ | ||
1256 | /* Rfkill */ | ||
1257 | /*******************/ | ||
1258 | |||
1259 | static bool ath_is_rfkill_set(struct ath_softc *sc) | ||
1260 | { | ||
1261 | struct ath_hw *ah = sc->sc_ah; | ||
1262 | |||
1263 | return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == | ||
1264 | ah->rfkill_polarity; | ||
1265 | } | ||
1266 | |||
1267 | static void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) | ||
1268 | { | ||
1269 | struct ath_wiphy *aphy = hw->priv; | ||
1270 | struct ath_softc *sc = aphy->sc; | ||
1271 | bool blocked = !!ath_is_rfkill_set(sc); | ||
1272 | |||
1273 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
1274 | } | ||
1275 | |||
1276 | static void ath_start_rfkill_poll(struct ath_softc *sc) | ||
1277 | { | ||
1278 | struct ath_hw *ah = sc->sc_ah; | ||
1279 | |||
1280 | if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
1281 | wiphy_rfkill_start_polling(sc->hw->wiphy); | ||
1282 | } | ||
1283 | |||
1284 | static void ath9k_uninit_hw(struct ath_softc *sc) | ||
1285 | { | ||
1286 | struct ath_hw *ah = sc->sc_ah; | ||
1287 | |||
1288 | BUG_ON(!ah); | ||
1289 | |||
1290 | ath9k_exit_debug(ah); | ||
1291 | ath9k_hw_detach(ah); | ||
1292 | sc->sc_ah = NULL; | ||
1293 | } | ||
1294 | |||
1295 | static void ath_clean_core(struct ath_softc *sc) | ||
1296 | { | ||
1297 | struct ieee80211_hw *hw = sc->hw; | ||
1298 | struct ath_hw *ah = sc->sc_ah; | ||
1299 | int i = 0; | ||
1300 | |||
1301 | ath9k_ps_wakeup(sc); | ||
1302 | |||
1303 | dev_dbg(sc->dev, "Detach ATH hw\n"); | ||
1304 | |||
1305 | ath_deinit_leds(sc); | ||
1306 | wiphy_rfkill_stop_polling(sc->hw->wiphy); | ||
1307 | |||
1308 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
1309 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
1310 | if (aphy == NULL) | ||
1311 | continue; | ||
1312 | sc->sec_wiphy[i] = NULL; | ||
1313 | ieee80211_unregister_hw(aphy->hw); | ||
1314 | ieee80211_free_hw(aphy->hw); | ||
1315 | } | ||
1316 | ieee80211_unregister_hw(hw); | ||
1317 | ath_rx_cleanup(sc); | ||
1318 | ath_tx_cleanup(sc); | ||
1319 | |||
1320 | tasklet_kill(&sc->intr_tq); | ||
1321 | tasklet_kill(&sc->bcon_tasklet); | ||
1322 | |||
1323 | if (!(sc->sc_flags & SC_OP_INVALID)) | ||
1324 | ath9k_setpower(sc, ATH9K_PM_AWAKE); | ||
1325 | |||
1326 | /* cleanup tx queues */ | ||
1327 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
1328 | if (ATH_TXQ_SETUP(sc, i)) | ||
1329 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
1330 | |||
1331 | if ((sc->btcoex.no_stomp_timer) && | ||
1332 | ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | ||
1333 | ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); | ||
1334 | } | ||
1335 | |||
1336 | void ath_detach(struct ath_softc *sc) | ||
1337 | { | ||
1338 | ath_clean_core(sc); | ||
1339 | ath9k_uninit_hw(sc); | ||
1340 | } | ||
1341 | |||
1342 | void ath_cleanup(struct ath_softc *sc) | ||
1343 | { | ||
1344 | struct ath_hw *ah = sc->sc_ah; | ||
1345 | struct ath_common *common = ath9k_hw_common(ah); | ||
1346 | |||
1347 | ath_clean_core(sc); | ||
1348 | free_irq(sc->irq, sc); | ||
1349 | ath_bus_cleanup(common); | ||
1350 | kfree(sc->sec_wiphy); | ||
1351 | ieee80211_free_hw(sc->hw); | ||
1352 | |||
1353 | ath9k_uninit_hw(sc); | ||
1354 | } | ||
1355 | |||
1356 | static int ath9k_reg_notifier(struct wiphy *wiphy, | ||
1357 | struct regulatory_request *request) | ||
1358 | { | ||
1359 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
1360 | struct ath_wiphy *aphy = hw->priv; | ||
1361 | struct ath_softc *sc = aphy->sc; | ||
1362 | struct ath_regulatory *reg = ath9k_hw_regulatory(sc->sc_ah); | ||
1363 | |||
1364 | return ath_reg_notifier_apply(wiphy, request, reg); | ||
1365 | } | ||
1366 | |||
1367 | /* | ||
1368 | * Detects if there is any priority bt traffic | ||
1369 | */ | ||
1370 | static void ath_detect_bt_priority(struct ath_softc *sc) | ||
1371 | { | ||
1372 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1373 | struct ath_hw *ah = sc->sc_ah; | ||
1374 | |||
1375 | if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) | ||
1376 | btcoex->bt_priority_cnt++; | ||
1377 | |||
1378 | if (time_after(jiffies, btcoex->bt_priority_time + | ||
1379 | msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { | ||
1380 | if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { | ||
1381 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_BTCOEX, | ||
1382 | "BT priority traffic detected"); | ||
1383 | sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; | ||
1384 | } else { | ||
1385 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
1386 | } | ||
1387 | |||
1388 | btcoex->bt_priority_cnt = 0; | ||
1389 | btcoex->bt_priority_time = jiffies; | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | /* | ||
1394 | * Configures appropriate weight based on stomp type. | ||
1395 | */ | ||
1396 | static void ath9k_btcoex_bt_stomp(struct ath_softc *sc, | ||
1397 | enum ath_stomp_type stomp_type) | ||
1398 | { | ||
1399 | struct ath_hw *ah = sc->sc_ah; | ||
1400 | |||
1401 | switch (stomp_type) { | ||
1402 | case ATH_BTCOEX_STOMP_ALL: | ||
1403 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
1404 | AR_STOMP_ALL_WLAN_WGHT); | ||
1405 | break; | ||
1406 | case ATH_BTCOEX_STOMP_LOW: | ||
1407 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
1408 | AR_STOMP_LOW_WLAN_WGHT); | ||
1409 | break; | ||
1410 | case ATH_BTCOEX_STOMP_NONE: | ||
1411 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
1412 | AR_STOMP_NONE_WLAN_WGHT); | ||
1413 | break; | ||
1414 | default: | ||
1415 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
1416 | "Invalid Stomptype\n"); | ||
1417 | break; | ||
1418 | } | ||
1419 | |||
1420 | ath9k_hw_btcoex_enable(ah); | ||
1421 | } | ||
1422 | |||
1423 | static void ath9k_gen_timer_start(struct ath_hw *ah, | ||
1424 | struct ath_gen_timer *timer, | ||
1425 | u32 timer_next, | ||
1426 | u32 timer_period) | ||
1427 | { | ||
1428 | struct ath_common *common = ath9k_hw_common(ah); | ||
1429 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
1430 | |||
1431 | ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); | ||
1432 | |||
1433 | if ((sc->imask & ATH9K_INT_GENTIMER) == 0) { | ||
1434 | ath9k_hw_set_interrupts(ah, 0); | ||
1435 | sc->imask |= ATH9K_INT_GENTIMER; | ||
1436 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
1437 | } | ||
1438 | } | ||
1439 | |||
1440 | static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) | ||
1441 | { | ||
1442 | struct ath_common *common = ath9k_hw_common(ah); | ||
1443 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
1444 | struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; | ||
1445 | |||
1446 | ath9k_hw_gen_timer_stop(ah, timer); | ||
1447 | |||
1448 | /* if no timer is enabled, turn off interrupt mask */ | ||
1449 | if (timer_table->timer_mask.val == 0) { | ||
1450 | ath9k_hw_set_interrupts(ah, 0); | ||
1451 | sc->imask &= ~ATH9K_INT_GENTIMER; | ||
1452 | ath9k_hw_set_interrupts(ah, sc->imask); | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | /* | ||
1457 | * This is the master bt coex timer which runs for every | ||
1458 | * 45ms, bt traffic will be given priority during 55% of this | ||
1459 | * period while wlan gets remaining 45% | ||
1460 | */ | ||
1461 | static void ath_btcoex_period_timer(unsigned long data) | ||
1462 | { | ||
1463 | struct ath_softc *sc = (struct ath_softc *) data; | ||
1464 | struct ath_hw *ah = sc->sc_ah; | ||
1465 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1466 | |||
1467 | ath_detect_bt_priority(sc); | ||
1468 | |||
1469 | spin_lock_bh(&btcoex->btcoex_lock); | ||
1470 | |||
1471 | ath9k_btcoex_bt_stomp(sc, btcoex->bt_stomp_type); | ||
1472 | |||
1473 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
1474 | |||
1475 | if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { | ||
1476 | if (btcoex->hw_timer_enabled) | ||
1477 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
1478 | |||
1479 | ath9k_gen_timer_start(ah, | ||
1480 | btcoex->no_stomp_timer, | ||
1481 | (ath9k_hw_gettsf32(ah) + | ||
1482 | btcoex->btcoex_no_stomp), | ||
1483 | btcoex->btcoex_no_stomp * 10); | ||
1484 | btcoex->hw_timer_enabled = true; | ||
1485 | } | ||
1486 | |||
1487 | mod_timer(&btcoex->period_timer, jiffies + | ||
1488 | msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); | ||
1489 | } | ||
1490 | |||
1491 | /* | ||
1492 | * Generic tsf based hw timer which configures weight | ||
1493 | * registers to time slice between wlan and bt traffic | ||
1494 | */ | ||
1495 | static void ath_btcoex_no_stomp_timer(void *arg) | ||
1496 | { | ||
1497 | struct ath_softc *sc = (struct ath_softc *)arg; | ||
1498 | struct ath_hw *ah = sc->sc_ah; | ||
1499 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1500 | |||
1501 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
1502 | "no stomp timer running \n"); | ||
1503 | |||
1504 | spin_lock_bh(&btcoex->btcoex_lock); | ||
1505 | |||
1506 | if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) | ||
1507 | ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_NONE); | ||
1508 | else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) | ||
1509 | ath9k_btcoex_bt_stomp(sc, ATH_BTCOEX_STOMP_LOW); | ||
1510 | |||
1511 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
1512 | } | ||
1513 | |||
1514 | static int ath_init_btcoex_timer(struct ath_softc *sc) | ||
1515 | { | ||
1516 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1517 | |||
1518 | btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; | ||
1519 | btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * | ||
1520 | btcoex->btcoex_period / 100; | ||
1521 | |||
1522 | setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, | ||
1523 | (unsigned long) sc); | ||
1524 | |||
1525 | spin_lock_init(&btcoex->btcoex_lock); | ||
1526 | |||
1527 | btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, | ||
1528 | ath_btcoex_no_stomp_timer, | ||
1529 | ath_btcoex_no_stomp_timer, | ||
1530 | (void *) sc, AR_FIRST_NDP_TIMER); | ||
1531 | |||
1532 | if (!btcoex->no_stomp_timer) | ||
1533 | return -ENOMEM; | ||
1534 | |||
1535 | return 0; | ||
1536 | } | ||
1537 | |||
1538 | /* | ||
1539 | * Read and write, they both share the same lock. We do this to serialize | ||
1540 | * reads and writes on Atheros 802.11n PCI devices only. This is required | ||
1541 | * as the FIFO on these devices can only accept sanely 2 requests. After | ||
1542 | * that the device goes bananas. Serializing the reads/writes prevents this | ||
1543 | * from happening. | ||
1544 | */ | ||
1545 | |||
1546 | static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) | ||
1547 | { | ||
1548 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
1549 | struct ath_common *common = ath9k_hw_common(ah); | ||
1550 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
1551 | |||
1552 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
1553 | unsigned long flags; | ||
1554 | spin_lock_irqsave(&sc->sc_serial_rw, flags); | ||
1555 | iowrite32(val, sc->mem + reg_offset); | ||
1556 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | ||
1557 | } else | ||
1558 | iowrite32(val, sc->mem + reg_offset); | ||
1559 | } | ||
1560 | |||
1561 | static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) | ||
1562 | { | ||
1563 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
1564 | struct ath_common *common = ath9k_hw_common(ah); | ||
1565 | struct ath_softc *sc = (struct ath_softc *) common->priv; | ||
1566 | u32 val; | ||
1567 | |||
1568 | if (ah->config.serialize_regmode == SER_REG_MODE_ON) { | ||
1569 | unsigned long flags; | ||
1570 | spin_lock_irqsave(&sc->sc_serial_rw, flags); | ||
1571 | val = ioread32(sc->mem + reg_offset); | ||
1572 | spin_unlock_irqrestore(&sc->sc_serial_rw, flags); | ||
1573 | } else | ||
1574 | val = ioread32(sc->mem + reg_offset); | ||
1575 | return val; | ||
1576 | } | ||
1577 | |||
1578 | static const struct ath_ops ath9k_common_ops = { | ||
1579 | .read = ath9k_ioread32, | ||
1580 | .write = ath9k_iowrite32, | ||
1581 | }; | ||
1582 | |||
1583 | /* | ||
1584 | * Initialize and fill ath_softc, ath_sofct is the | ||
1585 | * "Software Carrier" struct. Historically it has existed | ||
1586 | * to allow the separation between hardware specific | ||
1587 | * variables (now in ath_hw) and driver specific variables. | ||
1588 | */ | ||
1589 | static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, | ||
1590 | const struct ath_bus_ops *bus_ops) | ||
1591 | { | ||
1592 | struct ath_hw *ah = NULL; | ||
1593 | struct ath_common *common; | ||
1594 | int r = 0, i; | ||
1595 | int csz = 0; | ||
1596 | int qnum; | ||
1597 | |||
1598 | /* XXX: hardware will not be ready until ath_open() being called */ | ||
1599 | sc->sc_flags |= SC_OP_INVALID; | ||
1600 | |||
1601 | spin_lock_init(&sc->wiphy_lock); | ||
1602 | spin_lock_init(&sc->sc_resetlock); | ||
1603 | spin_lock_init(&sc->sc_serial_rw); | ||
1604 | spin_lock_init(&sc->sc_pm_lock); | ||
1605 | mutex_init(&sc->mutex); | ||
1606 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | ||
1607 | tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, | ||
1608 | (unsigned long)sc); | ||
1609 | |||
1610 | ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | ||
1611 | if (!ah) | ||
1612 | return -ENOMEM; | ||
1613 | |||
1614 | ah->hw_version.devid = devid; | ||
1615 | ah->hw_version.subsysid = subsysid; | ||
1616 | sc->sc_ah = ah; | ||
1617 | |||
1618 | common = ath9k_hw_common(ah); | ||
1619 | common->ops = &ath9k_common_ops; | ||
1620 | common->bus_ops = bus_ops; | ||
1621 | common->ah = ah; | ||
1622 | common->hw = sc->hw; | ||
1623 | common->priv = sc; | ||
1624 | common->debug_mask = ath9k_debug; | ||
1625 | |||
1626 | /* | ||
1627 | * Cache line size is used to size and align various | ||
1628 | * structures used to communicate with the hardware. | ||
1629 | */ | ||
1630 | ath_read_cachesize(common, &csz); | ||
1631 | /* XXX assert csz is non-zero */ | ||
1632 | common->cachelsz = csz << 2; /* convert to bytes */ | ||
1633 | |||
1634 | r = ath9k_hw_init(ah); | ||
1635 | if (r) { | ||
1636 | ath_print(common, ATH_DBG_FATAL, | ||
1637 | "Unable to initialize hardware; " | ||
1638 | "initialization status: %d\n", r); | ||
1639 | goto bad_free_hw; | ||
1640 | } | ||
1641 | |||
1642 | if (ath9k_init_debug(ah) < 0) { | ||
1643 | ath_print(common, ATH_DBG_FATAL, | ||
1644 | "Unable to create debugfs files\n"); | ||
1645 | goto bad_free_hw; | ||
1646 | } | ||
1647 | |||
1648 | /* Get the hardware key cache size. */ | ||
1649 | common->keymax = ah->caps.keycache_size; | ||
1650 | if (common->keymax > ATH_KEYMAX) { | ||
1651 | ath_print(common, ATH_DBG_ANY, | ||
1652 | "Warning, using only %u entries in %u key cache\n", | ||
1653 | ATH_KEYMAX, common->keymax); | ||
1654 | common->keymax = ATH_KEYMAX; | ||
1655 | } | ||
1656 | |||
1657 | /* | ||
1658 | * Reset the key cache since some parts do not | ||
1659 | * reset the contents on initial power up. | ||
1660 | */ | ||
1661 | for (i = 0; i < common->keymax; i++) | ||
1662 | ath9k_hw_keyreset(ah, (u16) i); | ||
1663 | |||
1664 | /* default to MONITOR mode */ | ||
1665 | sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; | ||
1666 | |||
1667 | /* | ||
1668 | * Allocate hardware transmit queues: one queue for | ||
1669 | * beacon frames and one data queue for each QoS | ||
1670 | * priority. Note that the hal handles reseting | ||
1671 | * these queues at the needed time. | ||
1672 | */ | ||
1673 | sc->beacon.beaconq = ath9k_hw_beaconq_setup(ah); | ||
1674 | if (sc->beacon.beaconq == -1) { | ||
1675 | ath_print(common, ATH_DBG_FATAL, | ||
1676 | "Unable to setup a beacon xmit queue\n"); | ||
1677 | r = -EIO; | ||
1678 | goto bad2; | ||
1679 | } | ||
1680 | sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); | ||
1681 | if (sc->beacon.cabq == NULL) { | ||
1682 | ath_print(common, ATH_DBG_FATAL, | ||
1683 | "Unable to setup CAB xmit queue\n"); | ||
1684 | r = -EIO; | ||
1685 | goto bad2; | ||
1686 | } | ||
1687 | |||
1688 | sc->config.cabqReadytime = ATH_CABQ_READY_TIME; | ||
1689 | ath_cabq_update(sc); | ||
1690 | |||
1691 | for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) | ||
1692 | sc->tx.hwq_map[i] = -1; | ||
1693 | |||
1694 | /* Setup data queues */ | ||
1695 | /* NB: ensure BK queue is the lowest priority h/w queue */ | ||
1696 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { | ||
1697 | ath_print(common, ATH_DBG_FATAL, | ||
1698 | "Unable to setup xmit queue for BK traffic\n"); | ||
1699 | r = -EIO; | ||
1700 | goto bad2; | ||
1701 | } | ||
1702 | |||
1703 | if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { | ||
1704 | ath_print(common, ATH_DBG_FATAL, | ||
1705 | "Unable to setup xmit queue for BE traffic\n"); | ||
1706 | r = -EIO; | ||
1707 | goto bad2; | ||
1708 | } | ||
1709 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { | ||
1710 | ath_print(common, ATH_DBG_FATAL, | ||
1711 | "Unable to setup xmit queue for VI traffic\n"); | ||
1712 | r = -EIO; | ||
1713 | goto bad2; | ||
1714 | } | ||
1715 | if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { | ||
1716 | ath_print(common, ATH_DBG_FATAL, | ||
1717 | "Unable to setup xmit queue for VO traffic\n"); | ||
1718 | r = -EIO; | ||
1719 | goto bad2; | ||
1720 | } | ||
1721 | |||
1722 | /* Initializes the noise floor to a reasonable default value. | ||
1723 | * Later on this will be updated during ANI processing. */ | ||
1724 | |||
1725 | common->ani.noise_floor = ATH_DEFAULT_NOISE_FLOOR; | ||
1726 | setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); | ||
1727 | |||
1728 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | ||
1729 | ATH9K_CIPHER_TKIP, NULL)) { | ||
1730 | /* | ||
1731 | * Whether we should enable h/w TKIP MIC. | ||
1732 | * XXX: if we don't support WME TKIP MIC, then we wouldn't | ||
1733 | * report WMM capable, so it's always safe to turn on | ||
1734 | * TKIP MIC in this case. | ||
1735 | */ | ||
1736 | ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, | ||
1737 | 0, 1, NULL); | ||
1738 | } | ||
1739 | |||
1740 | /* | ||
1741 | * Check whether the separate key cache entries | ||
1742 | * are required to handle both tx+rx MIC keys. | ||
1743 | * With split mic keys the number of stations is limited | ||
1744 | * to 27 otherwise 59. | ||
1745 | */ | ||
1746 | if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | ||
1747 | ATH9K_CIPHER_TKIP, NULL) | ||
1748 | && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, | ||
1749 | ATH9K_CIPHER_MIC, NULL) | ||
1750 | && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, | ||
1751 | 0, NULL)) | ||
1752 | common->splitmic = 1; | ||
1753 | |||
1754 | /* turn on mcast key search if possible */ | ||
1755 | if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) | ||
1756 | (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, | ||
1757 | 1, NULL); | ||
1758 | |||
1759 | sc->config.txpowlimit = ATH_TXPOWER_MAX; | ||
1760 | |||
1761 | /* 11n Capabilities */ | ||
1762 | if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
1763 | sc->sc_flags |= SC_OP_TXAGGR; | ||
1764 | sc->sc_flags |= SC_OP_RXAGGR; | ||
1765 | } | ||
1766 | |||
1767 | common->tx_chainmask = ah->caps.tx_chainmask; | ||
1768 | common->rx_chainmask = ah->caps.rx_chainmask; | ||
1769 | |||
1770 | ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); | ||
1771 | sc->rx.defant = ath9k_hw_getdefantenna(ah); | ||
1772 | |||
1773 | if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | ||
1774 | memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); | ||
1775 | |||
1776 | sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ | ||
1777 | |||
1778 | /* initialize beacon slots */ | ||
1779 | for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { | ||
1780 | sc->beacon.bslot[i] = NULL; | ||
1781 | sc->beacon.bslot_aphy[i] = NULL; | ||
1782 | } | ||
1783 | |||
1784 | /* setup channels and rates */ | ||
1785 | |||
1786 | if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { | ||
1787 | sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; | ||
1788 | sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
1789 | sc->sbands[IEEE80211_BAND_2GHZ].n_channels = | ||
1790 | ARRAY_SIZE(ath9k_2ghz_chantable); | ||
1791 | sc->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; | ||
1792 | sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates = | ||
1793 | ARRAY_SIZE(ath9k_legacy_rates); | ||
1794 | } | ||
1795 | |||
1796 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { | ||
1797 | sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; | ||
1798 | sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; | ||
1799 | sc->sbands[IEEE80211_BAND_5GHZ].n_channels = | ||
1800 | ARRAY_SIZE(ath9k_5ghz_chantable); | ||
1801 | sc->sbands[IEEE80211_BAND_5GHZ].bitrates = | ||
1802 | ath9k_legacy_rates + 4; | ||
1803 | sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = | ||
1804 | ARRAY_SIZE(ath9k_legacy_rates) - 4; | ||
1805 | } | ||
1806 | |||
1807 | switch (ah->btcoex_hw.scheme) { | ||
1808 | case ATH_BTCOEX_CFG_NONE: | ||
1809 | break; | ||
1810 | case ATH_BTCOEX_CFG_2WIRE: | ||
1811 | ath9k_hw_btcoex_init_2wire(ah); | ||
1812 | break; | ||
1813 | case ATH_BTCOEX_CFG_3WIRE: | ||
1814 | ath9k_hw_btcoex_init_3wire(ah); | ||
1815 | r = ath_init_btcoex_timer(sc); | ||
1816 | if (r) | ||
1817 | goto bad2; | ||
1818 | qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); | ||
1819 | ath9k_hw_init_btcoex_hw(ah, qnum); | ||
1820 | sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | ||
1821 | break; | ||
1822 | default: | ||
1823 | WARN_ON(1); | ||
1824 | break; | ||
1825 | } | ||
1826 | |||
1827 | return 0; | ||
1828 | bad2: | ||
1829 | /* cleanup tx queues */ | ||
1830 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
1831 | if (ATH_TXQ_SETUP(sc, i)) | ||
1832 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
1833 | |||
1834 | bad_free_hw: | ||
1835 | ath9k_uninit_hw(sc); | ||
1836 | return r; | ||
1837 | } | ||
1838 | |||
1839 | void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | ||
1840 | { | ||
1841 | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | ||
1842 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
1843 | IEEE80211_HW_SIGNAL_DBM | | ||
1844 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
1845 | IEEE80211_HW_SUPPORTS_PS | | ||
1846 | IEEE80211_HW_PS_NULLFUNC_STACK | | ||
1847 | IEEE80211_HW_SPECTRUM_MGMT; | ||
1848 | |||
1849 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt) | ||
1850 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | ||
1851 | |||
1852 | hw->wiphy->interface_modes = | ||
1853 | BIT(NL80211_IFTYPE_AP) | | ||
1854 | BIT(NL80211_IFTYPE_STATION) | | ||
1855 | BIT(NL80211_IFTYPE_ADHOC) | | ||
1856 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
1857 | |||
1858 | hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; | ||
1859 | |||
1860 | hw->queues = 4; | ||
1861 | hw->max_rates = 4; | ||
1862 | hw->channel_change_time = 5000; | ||
1863 | hw->max_listen_interval = 10; | ||
1864 | /* Hardware supports 10 but we use 4 */ | ||
1865 | hw->max_rate_tries = 4; | ||
1866 | hw->sta_data_size = sizeof(struct ath_node); | ||
1867 | hw->vif_data_size = sizeof(struct ath_vif); | ||
1868 | |||
1869 | hw->rate_control_algorithm = "ath9k_rate_control"; | ||
1870 | |||
1871 | if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) | ||
1872 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
1873 | &sc->sbands[IEEE80211_BAND_2GHZ]; | ||
1874 | if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) | ||
1875 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = | ||
1876 | &sc->sbands[IEEE80211_BAND_5GHZ]; | ||
1877 | } | ||
1878 | |||
1879 | /* Device driver core initialization */ | ||
1880 | int ath_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, | ||
1881 | const struct ath_bus_ops *bus_ops) | ||
1882 | { | ||
1883 | struct ieee80211_hw *hw = sc->hw; | ||
1884 | struct ath_common *common; | ||
1885 | struct ath_hw *ah; | ||
1886 | int error = 0, i; | ||
1887 | struct ath_regulatory *reg; | ||
1888 | |||
1889 | dev_dbg(sc->dev, "Attach ATH hw\n"); | ||
1890 | |||
1891 | error = ath_init_softc(devid, sc, subsysid, bus_ops); | ||
1892 | if (error != 0) | ||
1893 | return error; | ||
1894 | |||
1895 | ah = sc->sc_ah; | ||
1896 | common = ath9k_hw_common(ah); | ||
1897 | |||
1898 | /* get mac address from hardware and set in mac80211 */ | ||
1899 | |||
1900 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); | ||
1901 | |||
1902 | ath_set_hw_capab(sc, hw); | ||
1903 | |||
1904 | error = ath_regd_init(&common->regulatory, sc->hw->wiphy, | ||
1905 | ath9k_reg_notifier); | ||
1906 | if (error) | ||
1907 | return error; | ||
1908 | |||
1909 | reg = &common->regulatory; | ||
1910 | |||
1911 | if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
1912 | if (test_bit(ATH9K_MODE_11G, ah->caps.wireless_modes)) | ||
1913 | setup_ht_cap(sc, | ||
1914 | &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||
1915 | if (test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) | ||
1916 | setup_ht_cap(sc, | ||
1917 | &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); | ||
1918 | } | ||
1919 | |||
1920 | /* initialize tx/rx engine */ | ||
1921 | error = ath_tx_init(sc, ATH_TXBUF); | ||
1922 | if (error != 0) | ||
1923 | goto error_attach; | ||
1924 | |||
1925 | error = ath_rx_init(sc, ATH_RXBUF); | ||
1926 | if (error != 0) | ||
1927 | goto error_attach; | ||
1928 | |||
1929 | INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); | ||
1930 | INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); | ||
1931 | sc->wiphy_scheduler_int = msecs_to_jiffies(500); | ||
1932 | |||
1933 | error = ieee80211_register_hw(hw); | ||
1934 | |||
1935 | if (!ath_is_world_regd(reg)) { | ||
1936 | error = regulatory_hint(hw->wiphy, reg->alpha2); | ||
1937 | if (error) | ||
1938 | goto error_attach; | ||
1939 | } | ||
1940 | |||
1941 | /* Initialize LED control */ | ||
1942 | ath_init_leds(sc); | ||
1943 | |||
1944 | ath_start_rfkill_poll(sc); | ||
1945 | |||
1946 | return 0; | ||
1947 | |||
1948 | error_attach: | ||
1949 | /* cleanup tx queues */ | ||
1950 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) | ||
1951 | if (ATH_TXQ_SETUP(sc, i)) | ||
1952 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | ||
1953 | |||
1954 | ath9k_uninit_hw(sc); | ||
1955 | |||
1956 | return error; | ||
1957 | } | ||
1958 | |||
1959 | int ath_reset(struct ath_softc *sc, bool retry_tx) | 937 | int ath_reset(struct ath_softc *sc, bool retry_tx) |
1960 | { | 938 | { |
1961 | struct ath_hw *ah = sc->sc_ah; | 939 | struct ath_hw *ah = sc->sc_ah; |
@@ -1966,6 +944,8 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
1966 | /* Stop ANI */ | 944 | /* Stop ANI */ |
1967 | del_timer_sync(&common->ani.timer); | 945 | del_timer_sync(&common->ani.timer); |
1968 | 946 | ||
947 | ieee80211_stop_queues(hw); | ||
948 | |||
1969 | ath9k_hw_set_interrupts(ah, 0); | 949 | ath9k_hw_set_interrupts(ah, 0); |
1970 | ath_drain_all_txq(sc, retry_tx); | 950 | ath_drain_all_txq(sc, retry_tx); |
1971 | ath_stoprecv(sc); | 951 | ath_stoprecv(sc); |
@@ -2007,131 +987,14 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
2007 | } | 987 | } |
2008 | } | 988 | } |
2009 | 989 | ||
990 | ieee80211_wake_queues(hw); | ||
991 | |||
2010 | /* Start ANI */ | 992 | /* Start ANI */ |
2011 | ath_start_ani(common); | 993 | ath_start_ani(common); |
2012 | 994 | ||
2013 | return r; | 995 | return r; |
2014 | } | 996 | } |
2015 | 997 | ||
2016 | /* | ||
2017 | * This function will allocate both the DMA descriptor structure, and the | ||
2018 | * buffers it contains. These are used to contain the descriptors used | ||
2019 | * by the system. | ||
2020 | */ | ||
2021 | int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, | ||
2022 | struct list_head *head, const char *name, | ||
2023 | int nbuf, int ndesc) | ||
2024 | { | ||
2025 | #define DS2PHYS(_dd, _ds) \ | ||
2026 | ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) | ||
2027 | #define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) | ||
2028 | #define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) | ||
2029 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
2030 | struct ath_desc *ds; | ||
2031 | struct ath_buf *bf; | ||
2032 | int i, bsize, error; | ||
2033 | |||
2034 | ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", | ||
2035 | name, nbuf, ndesc); | ||
2036 | |||
2037 | INIT_LIST_HEAD(head); | ||
2038 | /* ath_desc must be a multiple of DWORDs */ | ||
2039 | if ((sizeof(struct ath_desc) % 4) != 0) { | ||
2040 | ath_print(common, ATH_DBG_FATAL, | ||
2041 | "ath_desc not DWORD aligned\n"); | ||
2042 | BUG_ON((sizeof(struct ath_desc) % 4) != 0); | ||
2043 | error = -ENOMEM; | ||
2044 | goto fail; | ||
2045 | } | ||
2046 | |||
2047 | dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; | ||
2048 | |||
2049 | /* | ||
2050 | * Need additional DMA memory because we can't use | ||
2051 | * descriptors that cross the 4K page boundary. Assume | ||
2052 | * one skipped descriptor per 4K page. | ||
2053 | */ | ||
2054 | if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { | ||
2055 | u32 ndesc_skipped = | ||
2056 | ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); | ||
2057 | u32 dma_len; | ||
2058 | |||
2059 | while (ndesc_skipped) { | ||
2060 | dma_len = ndesc_skipped * sizeof(struct ath_desc); | ||
2061 | dd->dd_desc_len += dma_len; | ||
2062 | |||
2063 | ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); | ||
2064 | }; | ||
2065 | } | ||
2066 | |||
2067 | /* allocate descriptors */ | ||
2068 | dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len, | ||
2069 | &dd->dd_desc_paddr, GFP_KERNEL); | ||
2070 | if (dd->dd_desc == NULL) { | ||
2071 | error = -ENOMEM; | ||
2072 | goto fail; | ||
2073 | } | ||
2074 | ds = dd->dd_desc; | ||
2075 | ath_print(common, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", | ||
2076 | name, ds, (u32) dd->dd_desc_len, | ||
2077 | ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); | ||
2078 | |||
2079 | /* allocate buffers */ | ||
2080 | bsize = sizeof(struct ath_buf) * nbuf; | ||
2081 | bf = kzalloc(bsize, GFP_KERNEL); | ||
2082 | if (bf == NULL) { | ||
2083 | error = -ENOMEM; | ||
2084 | goto fail2; | ||
2085 | } | ||
2086 | dd->dd_bufptr = bf; | ||
2087 | |||
2088 | for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { | ||
2089 | bf->bf_desc = ds; | ||
2090 | bf->bf_daddr = DS2PHYS(dd, ds); | ||
2091 | |||
2092 | if (!(sc->sc_ah->caps.hw_caps & | ||
2093 | ATH9K_HW_CAP_4KB_SPLITTRANS)) { | ||
2094 | /* | ||
2095 | * Skip descriptor addresses which can cause 4KB | ||
2096 | * boundary crossing (addr + length) with a 32 dword | ||
2097 | * descriptor fetch. | ||
2098 | */ | ||
2099 | while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { | ||
2100 | BUG_ON((caddr_t) bf->bf_desc >= | ||
2101 | ((caddr_t) dd->dd_desc + | ||
2102 | dd->dd_desc_len)); | ||
2103 | |||
2104 | ds += ndesc; | ||
2105 | bf->bf_desc = ds; | ||
2106 | bf->bf_daddr = DS2PHYS(dd, ds); | ||
2107 | } | ||
2108 | } | ||
2109 | list_add_tail(&bf->list, head); | ||
2110 | } | ||
2111 | return 0; | ||
2112 | fail2: | ||
2113 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | ||
2114 | dd->dd_desc_paddr); | ||
2115 | fail: | ||
2116 | memset(dd, 0, sizeof(*dd)); | ||
2117 | return error; | ||
2118 | #undef ATH_DESC_4KB_BOUND_CHECK | ||
2119 | #undef ATH_DESC_4KB_BOUND_NUM_SKIPPED | ||
2120 | #undef DS2PHYS | ||
2121 | } | ||
2122 | |||
2123 | void ath_descdma_cleanup(struct ath_softc *sc, | ||
2124 | struct ath_descdma *dd, | ||
2125 | struct list_head *head) | ||
2126 | { | ||
2127 | dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc, | ||
2128 | dd->dd_desc_paddr); | ||
2129 | |||
2130 | INIT_LIST_HEAD(head); | ||
2131 | kfree(dd->dd_bufptr); | ||
2132 | memset(dd, 0, sizeof(*dd)); | ||
2133 | } | ||
2134 | |||
2135 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) | 998 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) |
2136 | { | 999 | { |
2137 | int qnum; | 1000 | int qnum; |
@@ -2210,28 +1073,6 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
2210 | /* mac80211 callbacks */ | 1073 | /* mac80211 callbacks */ |
2211 | /**********************/ | 1074 | /**********************/ |
2212 | 1075 | ||
2213 | /* | ||
2214 | * (Re)start btcoex timers | ||
2215 | */ | ||
2216 | static void ath9k_btcoex_timer_resume(struct ath_softc *sc) | ||
2217 | { | ||
2218 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
2219 | struct ath_hw *ah = sc->sc_ah; | ||
2220 | |||
2221 | ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
2222 | "Starting btcoex timers"); | ||
2223 | |||
2224 | /* make sure duty cycle timer is also stopped when resuming */ | ||
2225 | if (btcoex->hw_timer_enabled) | ||
2226 | ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | ||
2227 | |||
2228 | btcoex->bt_priority_cnt = 0; | ||
2229 | btcoex->bt_priority_time = jiffies; | ||
2230 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
2231 | |||
2232 | mod_timer(&btcoex->period_timer, jiffies); | ||
2233 | } | ||
2234 | |||
2235 | static int ath9k_start(struct ieee80211_hw *hw) | 1076 | static int ath9k_start(struct ieee80211_hw *hw) |
2236 | { | 1077 | { |
2237 | struct ath_wiphy *aphy = hw->priv; | 1078 | struct ath_wiphy *aphy = hw->priv; |
@@ -2401,11 +1242,11 @@ static int ath9k_tx(struct ieee80211_hw *hw, | |||
2401 | if (ieee80211_is_pspoll(hdr->frame_control)) { | 1242 | if (ieee80211_is_pspoll(hdr->frame_control)) { |
2402 | ath_print(common, ATH_DBG_PS, | 1243 | ath_print(common, ATH_DBG_PS, |
2403 | "Sending PS-Poll to pick a buffered frame\n"); | 1244 | "Sending PS-Poll to pick a buffered frame\n"); |
2404 | sc->sc_flags |= SC_OP_WAIT_FOR_PSPOLL_DATA; | 1245 | sc->ps_flags |= PS_WAIT_FOR_PSPOLL_DATA; |
2405 | } else { | 1246 | } else { |
2406 | ath_print(common, ATH_DBG_PS, | 1247 | ath_print(common, ATH_DBG_PS, |
2407 | "Wake up to complete TX\n"); | 1248 | "Wake up to complete TX\n"); |
2408 | sc->sc_flags |= SC_OP_WAIT_FOR_TX_ACK; | 1249 | sc->ps_flags |= PS_WAIT_FOR_TX_ACK; |
2409 | } | 1250 | } |
2410 | /* | 1251 | /* |
2411 | * The actual restore operation will happen only after | 1252 | * The actual restore operation will happen only after |
@@ -2458,22 +1299,6 @@ exit: | |||
2458 | return 0; | 1299 | return 0; |
2459 | } | 1300 | } |
2460 | 1301 | ||
2461 | /* | ||
2462 | * Pause btcoex timer and bt duty cycle timer | ||
2463 | */ | ||
2464 | static void ath9k_btcoex_timer_pause(struct ath_softc *sc) | ||
2465 | { | ||
2466 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
2467 | struct ath_hw *ah = sc->sc_ah; | ||
2468 | |||
2469 | del_timer_sync(&btcoex->period_timer); | ||
2470 | |||
2471 | if (btcoex->hw_timer_enabled) | ||
2472 | ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
2473 | |||
2474 | btcoex->hw_timer_enabled = false; | ||
2475 | } | ||
2476 | |||
2477 | static void ath9k_stop(struct ieee80211_hw *hw) | 1302 | static void ath9k_stop(struct ieee80211_hw *hw) |
2478 | { | 1303 | { |
2479 | struct ath_wiphy *aphy = hw->priv; | 1304 | struct ath_wiphy *aphy = hw->priv; |
@@ -2717,7 +1542,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2717 | */ | 1542 | */ |
2718 | if (changed & IEEE80211_CONF_CHANGE_PS) { | 1543 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
2719 | if (conf->flags & IEEE80211_CONF_PS) { | 1544 | if (conf->flags & IEEE80211_CONF_PS) { |
2720 | sc->sc_flags |= SC_OP_PS_ENABLED; | 1545 | sc->ps_flags |= PS_ENABLED; |
2721 | if (!(ah->caps.hw_caps & | 1546 | if (!(ah->caps.hw_caps & |
2722 | ATH9K_HW_CAP_AUTOSLEEP)) { | 1547 | ATH9K_HW_CAP_AUTOSLEEP)) { |
2723 | if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { | 1548 | if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) { |
@@ -2730,23 +1555,23 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2730 | * At this point we know hardware has received an ACK | 1555 | * At this point we know hardware has received an ACK |
2731 | * of a previously sent null data frame. | 1556 | * of a previously sent null data frame. |
2732 | */ | 1557 | */ |
2733 | if ((sc->sc_flags & SC_OP_NULLFUNC_COMPLETED)) { | 1558 | if ((sc->ps_flags & PS_NULLFUNC_COMPLETED)) { |
2734 | sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; | 1559 | sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; |
2735 | sc->ps_enabled = true; | 1560 | sc->ps_enabled = true; |
2736 | ath9k_hw_setrxabort(sc->sc_ah, 1); | 1561 | ath9k_hw_setrxabort(sc->sc_ah, 1); |
2737 | } | 1562 | } |
2738 | } else { | 1563 | } else { |
2739 | sc->ps_enabled = false; | 1564 | sc->ps_enabled = false; |
2740 | sc->sc_flags &= ~(SC_OP_PS_ENABLED | | 1565 | sc->ps_flags &= ~(PS_ENABLED | |
2741 | SC_OP_NULLFUNC_COMPLETED); | 1566 | PS_NULLFUNC_COMPLETED); |
2742 | ath9k_setpower(sc, ATH9K_PM_AWAKE); | 1567 | ath9k_setpower(sc, ATH9K_PM_AWAKE); |
2743 | if (!(ah->caps.hw_caps & | 1568 | if (!(ah->caps.hw_caps & |
2744 | ATH9K_HW_CAP_AUTOSLEEP)) { | 1569 | ATH9K_HW_CAP_AUTOSLEEP)) { |
2745 | ath9k_hw_setrxabort(sc->sc_ah, 0); | 1570 | ath9k_hw_setrxabort(sc->sc_ah, 0); |
2746 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | | 1571 | sc->ps_flags &= ~(PS_WAIT_FOR_BEACON | |
2747 | SC_OP_WAIT_FOR_CAB | | 1572 | PS_WAIT_FOR_CAB | |
2748 | SC_OP_WAIT_FOR_PSPOLL_DATA | | 1573 | PS_WAIT_FOR_PSPOLL_DATA | |
2749 | SC_OP_WAIT_FOR_TX_ACK); | 1574 | PS_WAIT_FOR_TX_ACK); |
2750 | if (sc->imask & ATH9K_INT_TIM_TIMER) { | 1575 | if (sc->imask & ATH9K_INT_TIM_TIMER) { |
2751 | sc->imask &= ~ATH9K_INT_TIM_TIMER; | 1576 | sc->imask &= ~ATH9K_INT_TIM_TIMER; |
2752 | ath9k_hw_set_interrupts(sc->sc_ah, | 1577 | ath9k_hw_set_interrupts(sc->sc_ah, |
@@ -2756,6 +1581,14 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
2756 | } | 1581 | } |
2757 | } | 1582 | } |
2758 | 1583 | ||
1584 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | ||
1585 | if (conf->flags & IEEE80211_CONF_MONITOR) { | ||
1586 | ath_print(common, ATH_DBG_CONFIG, | ||
1587 | "HW opmode set to Monitor mode\n"); | ||
1588 | sc->sc_ah->opmode = NL80211_IFTYPE_MONITOR; | ||
1589 | } | ||
1590 | } | ||
1591 | |||
2759 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | 1592 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
2760 | struct ieee80211_channel *curchan = hw->conf.channel; | 1593 | struct ieee80211_channel *curchan = hw->conf.channel; |
2761 | int pos = curchan->hw_value; | 1594 | int pos = curchan->hw_value; |
@@ -2956,6 +1789,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
2956 | struct ath_hw *ah = sc->sc_ah; | 1789 | struct ath_hw *ah = sc->sc_ah; |
2957 | struct ath_common *common = ath9k_hw_common(ah); | 1790 | struct ath_common *common = ath9k_hw_common(ah); |
2958 | struct ath_vif *avp = (void *)vif->drv_priv; | 1791 | struct ath_vif *avp = (void *)vif->drv_priv; |
1792 | int slottime; | ||
2959 | int error; | 1793 | int error; |
2960 | 1794 | ||
2961 | mutex_lock(&sc->mutex); | 1795 | mutex_lock(&sc->mutex); |
@@ -2991,6 +1825,25 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
2991 | ath_beacon_config(sc, vif); | 1825 | ath_beacon_config(sc, vif); |
2992 | } | 1826 | } |
2993 | 1827 | ||
1828 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1829 | if (bss_conf->use_short_slot) | ||
1830 | slottime = 9; | ||
1831 | else | ||
1832 | slottime = 20; | ||
1833 | if (vif->type == NL80211_IFTYPE_AP) { | ||
1834 | /* | ||
1835 | * Defer update, so that connected stations can adjust | ||
1836 | * their settings at the same time. | ||
1837 | * See beacon.c for more details | ||
1838 | */ | ||
1839 | sc->beacon.slottime = slottime; | ||
1840 | sc->beacon.updateslot = UPDATE; | ||
1841 | } else { | ||
1842 | ah->slottime = slottime; | ||
1843 | ath9k_hw_init_global_settings(ah); | ||
1844 | } | ||
1845 | } | ||
1846 | |||
2994 | /* Disable transmission of beacons */ | 1847 | /* Disable transmission of beacons */ |
2995 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) | 1848 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) |
2996 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 1849 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
@@ -3161,6 +2014,18 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | |||
3161 | mutex_unlock(&sc->mutex); | 2014 | mutex_unlock(&sc->mutex); |
3162 | } | 2015 | } |
3163 | 2016 | ||
2017 | static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) | ||
2018 | { | ||
2019 | struct ath_wiphy *aphy = hw->priv; | ||
2020 | struct ath_softc *sc = aphy->sc; | ||
2021 | struct ath_hw *ah = sc->sc_ah; | ||
2022 | |||
2023 | mutex_lock(&sc->mutex); | ||
2024 | ah->coverage_class = coverage_class; | ||
2025 | ath9k_hw_init_global_settings(ah); | ||
2026 | mutex_unlock(&sc->mutex); | ||
2027 | } | ||
2028 | |||
3164 | struct ieee80211_ops ath9k_ops = { | 2029 | struct ieee80211_ops ath9k_ops = { |
3165 | .tx = ath9k_tx, | 2030 | .tx = ath9k_tx, |
3166 | .start = ath9k_start, | 2031 | .start = ath9k_start, |
@@ -3180,64 +2045,5 @@ struct ieee80211_ops ath9k_ops = { | |||
3180 | .sw_scan_start = ath9k_sw_scan_start, | 2045 | .sw_scan_start = ath9k_sw_scan_start, |
3181 | .sw_scan_complete = ath9k_sw_scan_complete, | 2046 | .sw_scan_complete = ath9k_sw_scan_complete, |
3182 | .rfkill_poll = ath9k_rfkill_poll_state, | 2047 | .rfkill_poll = ath9k_rfkill_poll_state, |
2048 | .set_coverage_class = ath9k_set_coverage_class, | ||
3183 | }; | 2049 | }; |
3184 | |||
3185 | static int __init ath9k_init(void) | ||
3186 | { | ||
3187 | int error; | ||
3188 | |||
3189 | /* Register rate control algorithm */ | ||
3190 | error = ath_rate_control_register(); | ||
3191 | if (error != 0) { | ||
3192 | printk(KERN_ERR | ||
3193 | "ath9k: Unable to register rate control " | ||
3194 | "algorithm: %d\n", | ||
3195 | error); | ||
3196 | goto err_out; | ||
3197 | } | ||
3198 | |||
3199 | error = ath9k_debug_create_root(); | ||
3200 | if (error) { | ||
3201 | printk(KERN_ERR | ||
3202 | "ath9k: Unable to create debugfs root: %d\n", | ||
3203 | error); | ||
3204 | goto err_rate_unregister; | ||
3205 | } | ||
3206 | |||
3207 | error = ath_pci_init(); | ||
3208 | if (error < 0) { | ||
3209 | printk(KERN_ERR | ||
3210 | "ath9k: No PCI devices found, driver not installed.\n"); | ||
3211 | error = -ENODEV; | ||
3212 | goto err_remove_root; | ||
3213 | } | ||
3214 | |||
3215 | error = ath_ahb_init(); | ||
3216 | if (error < 0) { | ||
3217 | error = -ENODEV; | ||
3218 | goto err_pci_exit; | ||
3219 | } | ||
3220 | |||
3221 | return 0; | ||
3222 | |||
3223 | err_pci_exit: | ||
3224 | ath_pci_exit(); | ||
3225 | |||
3226 | err_remove_root: | ||
3227 | ath9k_debug_remove_root(); | ||
3228 | err_rate_unregister: | ||
3229 | ath_rate_control_unregister(); | ||
3230 | err_out: | ||
3231 | return error; | ||
3232 | } | ||
3233 | module_init(ath9k_init); | ||
3234 | |||
3235 | static void __exit ath9k_exit(void) | ||
3236 | { | ||
3237 | ath_ahb_exit(); | ||
3238 | ath_pci_exit(); | ||
3239 | ath9k_debug_remove_root(); | ||
3240 | ath_rate_control_unregister(); | ||
3241 | printk(KERN_INFO "%s: Driver unloaded\n", dev_info); | ||
3242 | } | ||
3243 | module_exit(ath9k_exit); | ||
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index ee617205cb4a..fe2c3a644a6e 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c | |||
@@ -113,25 +113,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
113 | u16 subsysid; | 113 | u16 subsysid; |
114 | u32 val; | 114 | u32 val; |
115 | int ret = 0; | 115 | int ret = 0; |
116 | struct ath_hw *ah; | ||
117 | char hw_name[64]; | 116 | char hw_name[64]; |
118 | 117 | ||
119 | if (pci_enable_device(pdev)) | 118 | if (pci_enable_device(pdev)) |
120 | return -EIO; | 119 | return -EIO; |
121 | 120 | ||
122 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | 121 | ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
123 | |||
124 | if (ret) { | 122 | if (ret) { |
125 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); | 123 | printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); |
126 | goto bad; | 124 | goto err_dma; |
127 | } | 125 | } |
128 | 126 | ||
129 | ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | 127 | ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); |
130 | |||
131 | if (ret) { | 128 | if (ret) { |
132 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " | 129 | printk(KERN_ERR "ath9k: 32-bit DMA consistent " |
133 | "DMA enable failed\n"); | 130 | "DMA enable failed\n"); |
134 | goto bad; | 131 | goto err_dma; |
135 | } | 132 | } |
136 | 133 | ||
137 | /* | 134 | /* |
@@ -171,22 +168,22 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
171 | if (ret) { | 168 | if (ret) { |
172 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | 169 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); |
173 | ret = -ENODEV; | 170 | ret = -ENODEV; |
174 | goto bad; | 171 | goto err_region; |
175 | } | 172 | } |
176 | 173 | ||
177 | mem = pci_iomap(pdev, 0, 0); | 174 | mem = pci_iomap(pdev, 0, 0); |
178 | if (!mem) { | 175 | if (!mem) { |
179 | printk(KERN_ERR "PCI memory map error\n") ; | 176 | printk(KERN_ERR "PCI memory map error\n") ; |
180 | ret = -EIO; | 177 | ret = -EIO; |
181 | goto bad1; | 178 | goto err_iomap; |
182 | } | 179 | } |
183 | 180 | ||
184 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + | 181 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) + |
185 | sizeof(struct ath_softc), &ath9k_ops); | 182 | sizeof(struct ath_softc), &ath9k_ops); |
186 | if (!hw) { | 183 | if (!hw) { |
187 | dev_err(&pdev->dev, "no memory for ieee80211_hw\n"); | 184 | dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); |
188 | ret = -ENOMEM; | 185 | ret = -ENOMEM; |
189 | goto bad2; | 186 | goto err_alloc_hw; |
190 | } | 187 | } |
191 | 188 | ||
192 | SET_IEEE80211_DEV(hw, &pdev->dev); | 189 | SET_IEEE80211_DEV(hw, &pdev->dev); |
@@ -201,25 +198,25 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
201 | sc->dev = &pdev->dev; | 198 | sc->dev = &pdev->dev; |
202 | sc->mem = mem; | 199 | sc->mem = mem; |
203 | 200 | ||
204 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); | 201 | /* Will be cleared in ath9k_start() */ |
205 | ret = ath_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); | 202 | sc->sc_flags |= SC_OP_INVALID; |
206 | if (ret) { | ||
207 | dev_err(&pdev->dev, "failed to initialize device\n"); | ||
208 | goto bad3; | ||
209 | } | ||
210 | |||
211 | /* setup interrupt service routine */ | ||
212 | 203 | ||
213 | ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); | 204 | ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); |
214 | if (ret) { | 205 | if (ret) { |
215 | dev_err(&pdev->dev, "request_irq failed\n"); | 206 | dev_err(&pdev->dev, "request_irq failed\n"); |
216 | goto bad4; | 207 | goto err_irq; |
217 | } | 208 | } |
218 | 209 | ||
219 | sc->irq = pdev->irq; | 210 | sc->irq = pdev->irq; |
220 | 211 | ||
221 | ah = sc->sc_ah; | 212 | pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); |
222 | ath9k_hw_name(ah, hw_name, sizeof(hw_name)); | 213 | ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); |
214 | if (ret) { | ||
215 | dev_err(&pdev->dev, "Failed to initialize device\n"); | ||
216 | goto err_init; | ||
217 | } | ||
218 | |||
219 | ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); | ||
223 | printk(KERN_INFO | 220 | printk(KERN_INFO |
224 | "%s: %s mem=0x%lx, irq=%d\n", | 221 | "%s: %s mem=0x%lx, irq=%d\n", |
225 | wiphy_name(hw->wiphy), | 222 | wiphy_name(hw->wiphy), |
@@ -227,15 +224,18 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
227 | (unsigned long)mem, pdev->irq); | 224 | (unsigned long)mem, pdev->irq); |
228 | 225 | ||
229 | return 0; | 226 | return 0; |
230 | bad4: | 227 | |
231 | ath_detach(sc); | 228 | err_init: |
232 | bad3: | 229 | free_irq(sc->irq, sc); |
230 | err_irq: | ||
233 | ieee80211_free_hw(hw); | 231 | ieee80211_free_hw(hw); |
234 | bad2: | 232 | err_alloc_hw: |
235 | pci_iounmap(pdev, mem); | 233 | pci_iounmap(pdev, mem); |
236 | bad1: | 234 | err_iomap: |
237 | pci_release_region(pdev, 0); | 235 | pci_release_region(pdev, 0); |
238 | bad: | 236 | err_region: |
237 | /* Nothing */ | ||
238 | err_dma: | ||
239 | pci_disable_device(pdev); | 239 | pci_disable_device(pdev); |
240 | return ret; | 240 | return ret; |
241 | } | 241 | } |
@@ -245,8 +245,12 @@ static void ath_pci_remove(struct pci_dev *pdev) | |||
245 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 245 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
246 | struct ath_wiphy *aphy = hw->priv; | 246 | struct ath_wiphy *aphy = hw->priv; |
247 | struct ath_softc *sc = aphy->sc; | 247 | struct ath_softc *sc = aphy->sc; |
248 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
248 | 249 | ||
249 | ath_cleanup(sc); | 250 | ath9k_deinit_device(sc); |
251 | free_irq(sc->irq, sc); | ||
252 | ieee80211_free_hw(sc->hw); | ||
253 | ath_bus_cleanup(common); | ||
250 | } | 254 | } |
251 | 255 | ||
252 | #ifdef CONFIG_PM | 256 | #ifdef CONFIG_PM |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 477365e5ae69..40b5d05edcce 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -364,10 +364,10 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
364 | if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) | 364 | if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) |
365 | return; /* not from our current AP */ | 365 | return; /* not from our current AP */ |
366 | 366 | ||
367 | sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; | 367 | sc->ps_flags &= ~PS_WAIT_FOR_BEACON; |
368 | 368 | ||
369 | if (sc->sc_flags & SC_OP_BEACON_SYNC) { | 369 | if (sc->ps_flags & PS_BEACON_SYNC) { |
370 | sc->sc_flags &= ~SC_OP_BEACON_SYNC; | 370 | sc->ps_flags &= ~PS_BEACON_SYNC; |
371 | ath_print(common, ATH_DBG_PS, | 371 | ath_print(common, ATH_DBG_PS, |
372 | "Reconfigure Beacon timers based on " | 372 | "Reconfigure Beacon timers based on " |
373 | "timestamp from the AP\n"); | 373 | "timestamp from the AP\n"); |
@@ -384,17 +384,17 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | |||
384 | */ | 384 | */ |
385 | ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating " | 385 | ath_print(common, ATH_DBG_PS, "Received DTIM beacon indicating " |
386 | "buffered broadcast/multicast frame(s)\n"); | 386 | "buffered broadcast/multicast frame(s)\n"); |
387 | sc->sc_flags |= SC_OP_WAIT_FOR_CAB | SC_OP_WAIT_FOR_BEACON; | 387 | sc->ps_flags |= PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON; |
388 | return; | 388 | return; |
389 | } | 389 | } |
390 | 390 | ||
391 | if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { | 391 | if (sc->ps_flags & PS_WAIT_FOR_CAB) { |
392 | /* | 392 | /* |
393 | * This can happen if a broadcast frame is dropped or the AP | 393 | * This can happen if a broadcast frame is dropped or the AP |
394 | * fails to send a frame indicating that all CAB frames have | 394 | * fails to send a frame indicating that all CAB frames have |
395 | * been delivered. | 395 | * been delivered. |
396 | */ | 396 | */ |
397 | sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; | 397 | sc->ps_flags &= ~PS_WAIT_FOR_CAB; |
398 | ath_print(common, ATH_DBG_PS, | 398 | ath_print(common, ATH_DBG_PS, |
399 | "PS wait for CAB frames timed out\n"); | 399 | "PS wait for CAB frames timed out\n"); |
400 | } | 400 | } |
@@ -408,10 +408,10 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | |||
408 | hdr = (struct ieee80211_hdr *)skb->data; | 408 | hdr = (struct ieee80211_hdr *)skb->data; |
409 | 409 | ||
410 | /* Process Beacon and CAB receive in PS state */ | 410 | /* Process Beacon and CAB receive in PS state */ |
411 | if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && | 411 | if ((sc->ps_flags & PS_WAIT_FOR_BEACON) && |
412 | ieee80211_is_beacon(hdr->frame_control)) | 412 | ieee80211_is_beacon(hdr->frame_control)) |
413 | ath_rx_ps_beacon(sc, skb); | 413 | ath_rx_ps_beacon(sc, skb); |
414 | else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && | 414 | else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && |
415 | (ieee80211_is_data(hdr->frame_control) || | 415 | (ieee80211_is_data(hdr->frame_control) || |
416 | ieee80211_is_action(hdr->frame_control)) && | 416 | ieee80211_is_action(hdr->frame_control)) && |
417 | is_multicast_ether_addr(hdr->addr1) && | 417 | is_multicast_ether_addr(hdr->addr1) && |
@@ -420,20 +420,20 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | |||
420 | * No more broadcast/multicast frames to be received at this | 420 | * No more broadcast/multicast frames to be received at this |
421 | * point. | 421 | * point. |
422 | */ | 422 | */ |
423 | sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB; | 423 | sc->ps_flags &= ~PS_WAIT_FOR_CAB; |
424 | ath_print(common, ATH_DBG_PS, | 424 | ath_print(common, ATH_DBG_PS, |
425 | "All PS CAB frames received, back to sleep\n"); | 425 | "All PS CAB frames received, back to sleep\n"); |
426 | } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && | 426 | } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && |
427 | !is_multicast_ether_addr(hdr->addr1) && | 427 | !is_multicast_ether_addr(hdr->addr1) && |
428 | !ieee80211_has_morefrags(hdr->frame_control)) { | 428 | !ieee80211_has_morefrags(hdr->frame_control)) { |
429 | sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; | 429 | sc->ps_flags &= ~PS_WAIT_FOR_PSPOLL_DATA; |
430 | ath_print(common, ATH_DBG_PS, | 430 | ath_print(common, ATH_DBG_PS, |
431 | "Going back to sleep after having received " | 431 | "Going back to sleep after having received " |
432 | "PS-Poll data (0x%x)\n", | 432 | "PS-Poll data (0x%x)\n", |
433 | sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | 433 | sc->ps_flags & (PS_WAIT_FOR_BEACON | |
434 | SC_OP_WAIT_FOR_CAB | | 434 | PS_WAIT_FOR_CAB | |
435 | SC_OP_WAIT_FOR_PSPOLL_DATA | | 435 | PS_WAIT_FOR_PSPOLL_DATA | |
436 | SC_OP_WAIT_FOR_TX_ACK)); | 436 | PS_WAIT_FOR_TX_ACK)); |
437 | } | 437 | } |
438 | } | 438 | } |
439 | 439 | ||
@@ -571,6 +571,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
571 | hw = ath_get_virt_hw(sc, hdr); | 571 | hw = ath_get_virt_hw(sc, hdr); |
572 | rx_stats = &ds->ds_rxstat; | 572 | rx_stats = &ds->ds_rxstat; |
573 | 573 | ||
574 | ath_debug_stat_rx(sc, bf); | ||
575 | |||
574 | /* | 576 | /* |
575 | * If we're asked to flush receive queue, directly | 577 | * If we're asked to flush receive queue, directly |
576 | * chain it back at the queue without processing it. | 578 | * chain it back at the queue without processing it. |
@@ -631,9 +633,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
631 | sc->rx.rxotherant = 0; | 633 | sc->rx.rxotherant = 0; |
632 | } | 634 | } |
633 | 635 | ||
634 | if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | 636 | if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON | |
635 | SC_OP_WAIT_FOR_CAB | | 637 | PS_WAIT_FOR_CAB | |
636 | SC_OP_WAIT_FOR_PSPOLL_DATA))) | 638 | PS_WAIT_FOR_PSPOLL_DATA))) |
637 | ath_rx_ps(sc, skb); | 639 | ath_rx_ps(sc, skb); |
638 | 640 | ||
639 | ath_rx_send_to_mac80211(hw, sc, skb, rxs); | 641 | ath_rx_send_to_mac80211(hw, sc, skb, rxs); |
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index cd26caaf44e7..a43fbf84dab9 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c | |||
@@ -152,7 +152,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) | |||
152 | 152 | ||
153 | SET_IEEE80211_PERM_ADDR(hw, addr); | 153 | SET_IEEE80211_PERM_ADDR(hw, addr); |
154 | 154 | ||
155 | ath_set_hw_capab(sc, hw); | 155 | ath9k_set_hw_capab(sc, hw); |
156 | 156 | ||
157 | error = ieee80211_register_hw(hw); | 157 | error = ieee80211_register_hw(hw); |
158 | 158 | ||
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index fa12b9060b0b..a821bb687b3b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c | |||
@@ -1648,7 +1648,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1648 | /* tag if this is a nullfunc frame to enable PS when AP acks it */ | 1648 | /* tag if this is a nullfunc frame to enable PS when AP acks it */ |
1649 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { | 1649 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) { |
1650 | bf->bf_isnullfunc = true; | 1650 | bf->bf_isnullfunc = true; |
1651 | sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED; | 1651 | sc->ps_flags &= ~PS_NULLFUNC_COMPLETED; |
1652 | } else | 1652 | } else |
1653 | bf->bf_isnullfunc = false; | 1653 | bf->bf_isnullfunc = false; |
1654 | 1654 | ||
@@ -1858,15 +1858,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
1858 | skb_pull(skb, padsize); | 1858 | skb_pull(skb, padsize); |
1859 | } | 1859 | } |
1860 | 1860 | ||
1861 | if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) { | 1861 | if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) { |
1862 | sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK; | 1862 | sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK; |
1863 | ath_print(common, ATH_DBG_PS, | 1863 | ath_print(common, ATH_DBG_PS, |
1864 | "Going back to sleep after having " | 1864 | "Going back to sleep after having " |
1865 | "received TX status (0x%x)\n", | 1865 | "received TX status (0x%x)\n", |
1866 | sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | 1866 | sc->ps_flags & (PS_WAIT_FOR_BEACON | |
1867 | SC_OP_WAIT_FOR_CAB | | 1867 | PS_WAIT_FOR_CAB | |
1868 | SC_OP_WAIT_FOR_PSPOLL_DATA | | 1868 | PS_WAIT_FOR_PSPOLL_DATA | |
1869 | SC_OP_WAIT_FOR_TX_ACK)); | 1869 | PS_WAIT_FOR_TX_ACK)); |
1870 | } | 1870 | } |
1871 | 1871 | ||
1872 | if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) | 1872 | if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL)) |
@@ -2053,11 +2053,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
2053 | */ | 2053 | */ |
2054 | if (bf->bf_isnullfunc && | 2054 | if (bf->bf_isnullfunc && |
2055 | (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { | 2055 | (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) { |
2056 | if ((sc->sc_flags & SC_OP_PS_ENABLED)) { | 2056 | if ((sc->ps_flags & PS_ENABLED)) { |
2057 | sc->ps_enabled = true; | 2057 | sc->ps_enabled = true; |
2058 | ath9k_hw_setrxabort(sc->sc_ah, 1); | 2058 | ath9k_hw_setrxabort(sc->sc_ah, 1); |
2059 | } else | 2059 | } else |
2060 | sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED; | 2060 | sc->ps_flags |= PS_NULLFUNC_COMPLETED; |
2061 | } | 2061 | } |
2062 | 2062 | ||
2063 | /* | 2063 | /* |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 2f12a750bc98..54d6085a887b 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -253,6 +253,14 @@ enum { | |||
253 | #define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ | 253 | #define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */ |
254 | #define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ | 254 | #define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */ |
255 | #define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ | 255 | #define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */ |
256 | /* SHM_SHARED tx iq workarounds */ | ||
257 | #define B43_SHM_SH_NPHY_TXIQW0 0x0700 | ||
258 | #define B43_SHM_SH_NPHY_TXIQW1 0x0702 | ||
259 | #define B43_SHM_SH_NPHY_TXIQW2 0x0704 | ||
260 | #define B43_SHM_SH_NPHY_TXIQW3 0x0706 | ||
261 | /* SHM_SHARED tx pwr ctrl */ | ||
262 | #define B43_SHM_SH_NPHY_TXPWR_INDX0 0x0708 | ||
263 | #define B43_SHM_SH_NPHY_TXPWR_INDX1 0x070E | ||
256 | 264 | ||
257 | /* SHM_SCRATCH offsets */ | 265 | /* SHM_SCRATCH offsets */ |
258 | #define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ | 266 | #define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 60290c06e950..9c5c7c9ad530 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -67,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik"); | |||
67 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
68 | 68 | ||
69 | MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); | 69 | MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); |
70 | 70 | MODULE_FIRMWARE("b43/ucode11.fw"); | |
71 | MODULE_FIRMWARE("b43/ucode13.fw"); | ||
72 | MODULE_FIRMWARE("b43/ucode14.fw"); | ||
73 | MODULE_FIRMWARE("b43/ucode15.fw"); | ||
74 | MODULE_FIRMWARE("b43/ucode5.fw"); | ||
75 | MODULE_FIRMWARE("b43/ucode9.fw"); | ||
71 | 76 | ||
72 | static int modparam_bad_frames_preempt; | 77 | static int modparam_bad_frames_preempt; |
73 | module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); | 78 | module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); |
@@ -113,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = { | |||
113 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), | 118 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), |
114 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), | 119 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), |
115 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), | 120 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), |
121 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12), | ||
116 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), | 122 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), |
117 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), | 123 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), |
118 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16), | 124 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16), |
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c index 3e046ec1ff86..b58d6cf26580 100644 --- a/drivers/net/wireless/b43/phy_lp.c +++ b/drivers/net/wireless/b43/phy_lp.c | |||
@@ -80,6 +80,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) | |||
80 | dev->phy.lp = NULL; | 80 | dev->phy.lp = NULL; |
81 | } | 81 | } |
82 | 82 | ||
83 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ | ||
83 | static void lpphy_read_band_sprom(struct b43_wldev *dev) | 84 | static void lpphy_read_band_sprom(struct b43_wldev *dev) |
84 | { | 85 | { |
85 | struct b43_phy_lp *lpphy = dev->phy.lp; | 86 | struct b43_phy_lp *lpphy = dev->phy.lp; |
@@ -101,6 +102,12 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev) | |||
101 | maxpwr = bus->sprom.maxpwr_bg; | 102 | maxpwr = bus->sprom.maxpwr_bg; |
102 | lpphy->max_tx_pwr_med_band = maxpwr; | 103 | lpphy->max_tx_pwr_med_band = maxpwr; |
103 | cckpo = bus->sprom.cck2gpo; | 104 | cckpo = bus->sprom.cck2gpo; |
105 | /* | ||
106 | * We don't read SPROM's opo as specs say. On rev8 SPROMs | ||
107 | * opo == ofdm2gpo and we don't know any SSB with LP-PHY | ||
108 | * and SPROM rev below 8. | ||
109 | */ | ||
110 | B43_WARN_ON(bus->sprom.revision < 8); | ||
104 | ofdmpo = bus->sprom.ofdm2gpo; | 111 | ofdmpo = bus->sprom.ofdm2gpo; |
105 | if (cckpo) { | 112 | if (cckpo) { |
106 | for (i = 0; i < 4; i++) { | 113 | for (i = 0; i < 4; i++) { |
@@ -1703,19 +1710,6 @@ static const struct lpphy_rx_iq_comp lpphy_rev2plus_iq_comp = { | |||
1703 | .c0 = 0, | 1710 | .c0 = 0, |
1704 | }; | 1711 | }; |
1705 | 1712 | ||
1706 | static u8 lpphy_nbits(s32 val) | ||
1707 | { | ||
1708 | u32 tmp = abs(val); | ||
1709 | u8 nbits = 0; | ||
1710 | |||
1711 | while (tmp != 0) { | ||
1712 | nbits++; | ||
1713 | tmp >>= 1; | ||
1714 | } | ||
1715 | |||
1716 | return nbits; | ||
1717 | } | ||
1718 | |||
1719 | static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) | 1713 | static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) |
1720 | { | 1714 | { |
1721 | struct lpphy_iq_est iq_est; | 1715 | struct lpphy_iq_est iq_est; |
@@ -1742,8 +1736,8 @@ static int lpphy_calc_rx_iq_comp(struct b43_wldev *dev, u16 samples) | |||
1742 | goto out; | 1736 | goto out; |
1743 | } | 1737 | } |
1744 | 1738 | ||
1745 | prod_msb = lpphy_nbits(prod); | 1739 | prod_msb = fls(abs(prod)); |
1746 | q_msb = lpphy_nbits(qpwr); | 1740 | q_msb = fls(abs(qpwr)); |
1747 | tmp1 = prod_msb - 20; | 1741 | tmp1 = prod_msb - 20; |
1748 | 1742 | ||
1749 | if (tmp1 >= 0) { | 1743 | if (tmp1 >= 0) { |
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 992318a78077..4a817e3da163 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c | |||
@@ -28,7 +28,32 @@ | |||
28 | #include "b43.h" | 28 | #include "b43.h" |
29 | #include "phy_n.h" | 29 | #include "phy_n.h" |
30 | #include "tables_nphy.h" | 30 | #include "tables_nphy.h" |
31 | #include "main.h" | ||
31 | 32 | ||
33 | struct nphy_txgains { | ||
34 | u16 txgm[2]; | ||
35 | u16 pga[2]; | ||
36 | u16 pad[2]; | ||
37 | u16 ipa[2]; | ||
38 | }; | ||
39 | |||
40 | struct nphy_iqcal_params { | ||
41 | u16 txgm; | ||
42 | u16 pga; | ||
43 | u16 pad; | ||
44 | u16 ipa; | ||
45 | u16 cal_gain; | ||
46 | u16 ncorr[5]; | ||
47 | }; | ||
48 | |||
49 | struct nphy_iq_est { | ||
50 | s32 iq0_prod; | ||
51 | u32 i0_pwr; | ||
52 | u32 q0_pwr; | ||
53 | s32 iq1_prod; | ||
54 | u32 i1_pwr; | ||
55 | u32 q1_pwr; | ||
56 | }; | ||
32 | 57 | ||
33 | void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) | 58 | void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) |
34 | {//TODO | 59 | {//TODO |
@@ -197,44 +222,16 @@ void b43_nphy_radio_turn_off(struct b43_wldev *dev) | |||
197 | ~B43_NPHY_RFCTL_CMD_EN); | 222 | ~B43_NPHY_RFCTL_CMD_EN); |
198 | } | 223 | } |
199 | 224 | ||
200 | #define ntab_upload(dev, offset, data) do { \ | 225 | /* |
201 | unsigned int i; \ | 226 | * Upload the N-PHY tables. |
202 | for (i = 0; i < (offset##_SIZE); i++) \ | 227 | * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables |
203 | b43_ntab_write(dev, (offset) + i, (data)[i]); \ | 228 | */ |
204 | } while (0) | ||
205 | |||
206 | /* Upload the N-PHY tables. */ | ||
207 | static void b43_nphy_tables_init(struct b43_wldev *dev) | 229 | static void b43_nphy_tables_init(struct b43_wldev *dev) |
208 | { | 230 | { |
209 | /* Static tables */ | 231 | if (dev->phy.rev < 3) |
210 | ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); | 232 | b43_nphy_rev0_1_2_tables_init(dev); |
211 | ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); | 233 | else |
212 | ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); | 234 | b43_nphy_rev3plus_tables_init(dev); |
213 | ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); | ||
214 | ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); | ||
215 | ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); | ||
216 | ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); | ||
217 | ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); | ||
218 | ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); | ||
219 | ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); | ||
220 | ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); | ||
221 | ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); | ||
222 | ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); | ||
223 | ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); | ||
224 | |||
225 | /* Volatile tables */ | ||
226 | ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); | ||
227 | ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); | ||
228 | ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); | ||
229 | ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); | ||
230 | ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); | ||
231 | ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); | ||
232 | ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); | ||
233 | ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); | ||
234 | ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); | ||
235 | ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); | ||
236 | ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); | ||
237 | ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); | ||
238 | } | 235 | } |
239 | 236 | ||
240 | static void b43_nphy_workarounds(struct b43_wldev *dev) | 237 | static void b43_nphy_workarounds(struct b43_wldev *dev) |
@@ -341,18 +338,386 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) | |||
341 | b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); | 338 | b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); |
342 | } | 339 | } |
343 | 340 | ||
341 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ | ||
342 | static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) | ||
343 | { | ||
344 | struct b43_phy_n *nphy = dev->phy.n; | ||
345 | enum ieee80211_band band; | ||
346 | u16 tmp; | ||
347 | |||
348 | if (!enable) { | ||
349 | nphy->rfctrl_intc1_save = b43_phy_read(dev, | ||
350 | B43_NPHY_RFCTL_INTC1); | ||
351 | nphy->rfctrl_intc2_save = b43_phy_read(dev, | ||
352 | B43_NPHY_RFCTL_INTC2); | ||
353 | band = b43_current_band(dev->wl); | ||
354 | if (dev->phy.rev >= 3) { | ||
355 | if (band == IEEE80211_BAND_5GHZ) | ||
356 | tmp = 0x600; | ||
357 | else | ||
358 | tmp = 0x480; | ||
359 | } else { | ||
360 | if (band == IEEE80211_BAND_5GHZ) | ||
361 | tmp = 0x180; | ||
362 | else | ||
363 | tmp = 0x120; | ||
364 | } | ||
365 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp); | ||
366 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp); | ||
367 | } else { | ||
368 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, | ||
369 | nphy->rfctrl_intc1_save); | ||
370 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, | ||
371 | nphy->rfctrl_intc2_save); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ | ||
376 | static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) | ||
377 | { | ||
378 | struct b43_phy_n *nphy = dev->phy.n; | ||
379 | u16 tmp; | ||
380 | enum ieee80211_band band = b43_current_band(dev->wl); | ||
381 | bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) || | ||
382 | (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ); | ||
383 | |||
384 | if (dev->phy.rev >= 3) { | ||
385 | if (ipa) { | ||
386 | tmp = 4; | ||
387 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, | ||
388 | (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); | ||
389 | } | ||
390 | |||
391 | tmp = 1; | ||
392 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2, | ||
393 | (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ | ||
398 | static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) | ||
399 | { | ||
400 | u32 tmslow; | ||
401 | |||
402 | if (dev->phy.type != B43_PHYTYPE_N) | ||
403 | return; | ||
404 | |||
405 | tmslow = ssb_read32(dev->dev, SSB_TMSLOW); | ||
406 | if (force) | ||
407 | tmslow |= SSB_TMSLOW_FGC; | ||
408 | else | ||
409 | tmslow &= ~SSB_TMSLOW_FGC; | ||
410 | ssb_write32(dev->dev, SSB_TMSLOW, tmslow); | ||
411 | } | ||
412 | |||
413 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ | ||
344 | static void b43_nphy_reset_cca(struct b43_wldev *dev) | 414 | static void b43_nphy_reset_cca(struct b43_wldev *dev) |
345 | { | 415 | { |
346 | u16 bbcfg; | 416 | u16 bbcfg; |
347 | 417 | ||
348 | ssb_write32(dev->dev, SSB_TMSLOW, | 418 | b43_nphy_bmac_clock_fgc(dev, 1); |
349 | ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); | ||
350 | bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); | 419 | bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); |
351 | b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); | 420 | b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA); |
352 | b43_phy_write(dev, B43_NPHY_BBCFG, | 421 | udelay(1); |
353 | bbcfg & ~B43_NPHY_BBCFG_RSTCCA); | 422 | b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA); |
354 | ssb_write32(dev->dev, SSB_TMSLOW, | 423 | b43_nphy_bmac_clock_fgc(dev, 0); |
355 | ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); | 424 | /* TODO: N PHY Force RF Seq with argument 2 */ |
425 | } | ||
426 | |||
427 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ | ||
428 | static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, | ||
429 | u16 samps, u8 time, bool wait) | ||
430 | { | ||
431 | int i; | ||
432 | u16 tmp; | ||
433 | |||
434 | b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps); | ||
435 | b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time); | ||
436 | if (wait) | ||
437 | b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE); | ||
438 | else | ||
439 | b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE); | ||
440 | |||
441 | b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START); | ||
442 | |||
443 | for (i = 1000; i; i--) { | ||
444 | tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD); | ||
445 | if (!(tmp & B43_NPHY_IQEST_CMD_START)) { | ||
446 | est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) | | ||
447 | b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0); | ||
448 | est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) | | ||
449 | b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0); | ||
450 | est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) | | ||
451 | b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0); | ||
452 | |||
453 | est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) | | ||
454 | b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1); | ||
455 | est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) | | ||
456 | b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1); | ||
457 | est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) | | ||
458 | b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1); | ||
459 | return; | ||
460 | } | ||
461 | udelay(10); | ||
462 | } | ||
463 | memset(est, 0, sizeof(*est)); | ||
464 | } | ||
465 | |||
466 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ | ||
467 | static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, | ||
468 | struct b43_phy_n_iq_comp *pcomp) | ||
469 | { | ||
470 | if (write) { | ||
471 | b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0); | ||
472 | b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0); | ||
473 | b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1); | ||
474 | b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1); | ||
475 | } else { | ||
476 | pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0); | ||
477 | pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0); | ||
478 | pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1); | ||
479 | pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ | ||
484 | static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) | ||
485 | { | ||
486 | int i; | ||
487 | s32 iq; | ||
488 | u32 ii; | ||
489 | u32 qq; | ||
490 | int iq_nbits, qq_nbits; | ||
491 | int arsh, brsh; | ||
492 | u16 tmp, a, b; | ||
493 | |||
494 | struct nphy_iq_est est; | ||
495 | struct b43_phy_n_iq_comp old; | ||
496 | struct b43_phy_n_iq_comp new = { }; | ||
497 | bool error = false; | ||
498 | |||
499 | if (mask == 0) | ||
500 | return; | ||
501 | |||
502 | b43_nphy_rx_iq_coeffs(dev, false, &old); | ||
503 | b43_nphy_rx_iq_coeffs(dev, true, &new); | ||
504 | b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false); | ||
505 | new = old; | ||
506 | |||
507 | for (i = 0; i < 2; i++) { | ||
508 | if (i == 0 && (mask & 1)) { | ||
509 | iq = est.iq0_prod; | ||
510 | ii = est.i0_pwr; | ||
511 | qq = est.q0_pwr; | ||
512 | } else if (i == 1 && (mask & 2)) { | ||
513 | iq = est.iq1_prod; | ||
514 | ii = est.i1_pwr; | ||
515 | qq = est.q1_pwr; | ||
516 | } else { | ||
517 | B43_WARN_ON(1); | ||
518 | continue; | ||
519 | } | ||
520 | |||
521 | if (ii + qq < 2) { | ||
522 | error = true; | ||
523 | break; | ||
524 | } | ||
525 | |||
526 | iq_nbits = fls(abs(iq)); | ||
527 | qq_nbits = fls(qq); | ||
528 | |||
529 | arsh = iq_nbits - 20; | ||
530 | if (arsh >= 0) { | ||
531 | a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); | ||
532 | tmp = ii >> arsh; | ||
533 | } else { | ||
534 | a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); | ||
535 | tmp = ii << -arsh; | ||
536 | } | ||
537 | if (tmp == 0) { | ||
538 | error = true; | ||
539 | break; | ||
540 | } | ||
541 | a /= tmp; | ||
542 | |||
543 | brsh = qq_nbits - 11; | ||
544 | if (brsh >= 0) { | ||
545 | b = (qq << (31 - qq_nbits)); | ||
546 | tmp = ii >> brsh; | ||
547 | } else { | ||
548 | b = (qq << (31 - qq_nbits)); | ||
549 | tmp = ii << -brsh; | ||
550 | } | ||
551 | if (tmp == 0) { | ||
552 | error = true; | ||
553 | break; | ||
554 | } | ||
555 | b = int_sqrt(b / tmp - a * a) - (1 << 10); | ||
556 | |||
557 | if (i == 0 && (mask & 0x1)) { | ||
558 | if (dev->phy.rev >= 3) { | ||
559 | new.a0 = a & 0x3FF; | ||
560 | new.b0 = b & 0x3FF; | ||
561 | } else { | ||
562 | new.a0 = b & 0x3FF; | ||
563 | new.b0 = a & 0x3FF; | ||
564 | } | ||
565 | } else if (i == 1 && (mask & 0x2)) { | ||
566 | if (dev->phy.rev >= 3) { | ||
567 | new.a1 = a & 0x3FF; | ||
568 | new.b1 = b & 0x3FF; | ||
569 | } else { | ||
570 | new.a1 = b & 0x3FF; | ||
571 | new.b1 = a & 0x3FF; | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | |||
576 | if (error) | ||
577 | new = old; | ||
578 | |||
579 | b43_nphy_rx_iq_coeffs(dev, true, &new); | ||
580 | } | ||
581 | |||
582 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ | ||
583 | static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) | ||
584 | { | ||
585 | u16 array[4]; | ||
586 | int i; | ||
587 | |||
588 | b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50); | ||
589 | for (i = 0; i < 4; i++) | ||
590 | array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); | ||
591 | |||
592 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]); | ||
593 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]); | ||
594 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]); | ||
595 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]); | ||
596 | } | ||
597 | |||
598 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ | ||
599 | static void b43_nphy_write_clip_detection(struct b43_wldev *dev, u16 *clip_st) | ||
600 | { | ||
601 | b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]); | ||
602 | b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); | ||
603 | } | ||
604 | |||
605 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ | ||
606 | static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) | ||
607 | { | ||
608 | clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES); | ||
609 | clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES); | ||
610 | } | ||
611 | |||
612 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ | ||
613 | static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) | ||
614 | { | ||
615 | u16 tmp; | ||
616 | |||
617 | if (dev->dev->id.revision == 16) | ||
618 | b43_mac_suspend(dev); | ||
619 | |||
620 | tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL); | ||
621 | tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN | | ||
622 | B43_NPHY_CLASSCTL_WAITEDEN); | ||
623 | tmp &= ~mask; | ||
624 | tmp |= (val & mask); | ||
625 | b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp); | ||
626 | |||
627 | if (dev->dev->id.revision == 16) | ||
628 | b43_mac_enable(dev); | ||
629 | |||
630 | return tmp; | ||
631 | } | ||
632 | |||
633 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ | ||
634 | static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) | ||
635 | { | ||
636 | struct b43_phy *phy = &dev->phy; | ||
637 | struct b43_phy_n *nphy = phy->n; | ||
638 | |||
639 | if (enable) { | ||
640 | u16 clip[] = { 0xFFFF, 0xFFFF }; | ||
641 | if (nphy->deaf_count++ == 0) { | ||
642 | nphy->classifier_state = b43_nphy_classifier(dev, 0, 0); | ||
643 | b43_nphy_classifier(dev, 0x7, 0); | ||
644 | b43_nphy_read_clip_detection(dev, nphy->clip_state); | ||
645 | b43_nphy_write_clip_detection(dev, clip); | ||
646 | } | ||
647 | b43_nphy_reset_cca(dev); | ||
648 | } else { | ||
649 | if (--nphy->deaf_count == 0) { | ||
650 | b43_nphy_classifier(dev, 0x7, nphy->classifier_state); | ||
651 | b43_nphy_write_clip_detection(dev, nphy->clip_state); | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | |||
656 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ | ||
657 | static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) | ||
658 | { | ||
659 | struct b43_phy_n *nphy = dev->phy.n; | ||
660 | int i, j; | ||
661 | u32 tmp; | ||
662 | u32 cur_real, cur_imag, real_part, imag_part; | ||
663 | |||
664 | u16 buffer[7]; | ||
665 | |||
666 | if (nphy->hang_avoid) | ||
667 | b43_nphy_stay_in_carrier_search(dev, true); | ||
668 | |||
669 | /* TODO: Read an N PHY Table with ID 15, length 7, offset 80, | ||
670 | width 16, and data pointer buffer */ | ||
671 | |||
672 | for (i = 0; i < 2; i++) { | ||
673 | tmp = ((buffer[i * 2] & 0x3FF) << 10) | | ||
674 | (buffer[i * 2 + 1] & 0x3FF); | ||
675 | b43_phy_write(dev, B43_NPHY_TABLE_ADDR, | ||
676 | (((i + 26) << 10) | 320)); | ||
677 | for (j = 0; j < 128; j++) { | ||
678 | b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, | ||
679 | ((tmp >> 16) & 0xFFFF)); | ||
680 | b43_phy_write(dev, B43_NPHY_TABLE_DATALO, | ||
681 | (tmp & 0xFFFF)); | ||
682 | } | ||
683 | } | ||
684 | |||
685 | for (i = 0; i < 2; i++) { | ||
686 | tmp = buffer[5 + i]; | ||
687 | real_part = (tmp >> 8) & 0xFF; | ||
688 | imag_part = (tmp & 0xFF); | ||
689 | b43_phy_write(dev, B43_NPHY_TABLE_ADDR, | ||
690 | (((i + 26) << 10) | 448)); | ||
691 | |||
692 | if (dev->phy.rev >= 3) { | ||
693 | cur_real = real_part; | ||
694 | cur_imag = imag_part; | ||
695 | tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF); | ||
696 | } | ||
697 | |||
698 | for (j = 0; j < 128; j++) { | ||
699 | if (dev->phy.rev < 3) { | ||
700 | cur_real = (real_part * loscale[j] + 128) >> 8; | ||
701 | cur_imag = (imag_part * loscale[j] + 128) >> 8; | ||
702 | tmp = ((cur_real & 0xFF) << 8) | | ||
703 | (cur_imag & 0xFF); | ||
704 | } | ||
705 | b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, | ||
706 | ((tmp >> 16) & 0xFFFF)); | ||
707 | b43_phy_write(dev, B43_NPHY_TABLE_DATALO, | ||
708 | (tmp & 0xFFFF)); | ||
709 | } | ||
710 | } | ||
711 | |||
712 | if (dev->phy.rev >= 3) { | ||
713 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
714 | B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF); | ||
715 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
716 | B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF); | ||
717 | } | ||
718 | |||
719 | if (nphy->hang_avoid) | ||
720 | b43_nphy_stay_in_carrier_search(dev, false); | ||
356 | } | 721 | } |
357 | 722 | ||
358 | enum b43_nphy_rf_sequence { | 723 | enum b43_nphy_rf_sequence { |
@@ -411,81 +776,1339 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) | |||
411 | b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); | 776 | b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); |
412 | } | 777 | } |
413 | 778 | ||
414 | /* RSSI Calibration */ | 779 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ |
415 | static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) | 780 | static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, |
781 | s8 offset, u8 core, u8 rail, u8 type) | ||
416 | { | 782 | { |
417 | //TODO | 783 | u16 tmp; |
784 | bool core1or5 = (core == 1) || (core == 5); | ||
785 | bool core2or5 = (core == 2) || (core == 5); | ||
786 | |||
787 | offset = clamp_val(offset, -32, 31); | ||
788 | tmp = ((scale & 0x3F) << 8) | (offset & 0x3F); | ||
789 | |||
790 | if (core1or5 && (rail == 0) && (type == 2)) | ||
791 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp); | ||
792 | if (core1or5 && (rail == 1) && (type == 2)) | ||
793 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp); | ||
794 | if (core2or5 && (rail == 0) && (type == 2)) | ||
795 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp); | ||
796 | if (core2or5 && (rail == 1) && (type == 2)) | ||
797 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp); | ||
798 | if (core1or5 && (rail == 0) && (type == 0)) | ||
799 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp); | ||
800 | if (core1or5 && (rail == 1) && (type == 0)) | ||
801 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp); | ||
802 | if (core2or5 && (rail == 0) && (type == 0)) | ||
803 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp); | ||
804 | if (core2or5 && (rail == 1) && (type == 0)) | ||
805 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp); | ||
806 | if (core1or5 && (rail == 0) && (type == 1)) | ||
807 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp); | ||
808 | if (core1or5 && (rail == 1) && (type == 1)) | ||
809 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp); | ||
810 | if (core2or5 && (rail == 0) && (type == 1)) | ||
811 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp); | ||
812 | if (core2or5 && (rail == 1) && (type == 1)) | ||
813 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp); | ||
814 | if (core1or5 && (rail == 0) && (type == 6)) | ||
815 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp); | ||
816 | if (core1or5 && (rail == 1) && (type == 6)) | ||
817 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp); | ||
818 | if (core2or5 && (rail == 0) && (type == 6)) | ||
819 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp); | ||
820 | if (core2or5 && (rail == 1) && (type == 6)) | ||
821 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp); | ||
822 | if (core1or5 && (rail == 0) && (type == 3)) | ||
823 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp); | ||
824 | if (core1or5 && (rail == 1) && (type == 3)) | ||
825 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp); | ||
826 | if (core2or5 && (rail == 0) && (type == 3)) | ||
827 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp); | ||
828 | if (core2or5 && (rail == 1) && (type == 3)) | ||
829 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp); | ||
830 | if (core1or5 && (type == 4)) | ||
831 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp); | ||
832 | if (core2or5 && (type == 4)) | ||
833 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp); | ||
834 | if (core1or5 && (type == 5)) | ||
835 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp); | ||
836 | if (core2or5 && (type == 5)) | ||
837 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp); | ||
838 | } | ||
839 | |||
840 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ | ||
841 | static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type) | ||
842 | { | ||
843 | u16 val; | ||
844 | |||
845 | if (dev->phy.rev >= 3) { | ||
846 | /* TODO */ | ||
847 | } else { | ||
848 | if (type < 3) | ||
849 | val = 0; | ||
850 | else if (type == 6) | ||
851 | val = 1; | ||
852 | else if (type == 3) | ||
853 | val = 2; | ||
854 | else | ||
855 | val = 3; | ||
856 | |||
857 | val = (val << 12) | (val << 14); | ||
858 | b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val); | ||
859 | b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val); | ||
860 | |||
861 | if (type < 3) { | ||
862 | b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF, | ||
863 | (type + 1) << 4); | ||
864 | b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF, | ||
865 | (type + 1) << 4); | ||
866 | } | ||
867 | |||
868 | /* TODO use some definitions */ | ||
869 | if (code == 0) { | ||
870 | b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0); | ||
871 | if (type < 3) { | ||
872 | b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, | ||
873 | 0xFEC7, 0); | ||
874 | b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, | ||
875 | 0xEFDC, 0); | ||
876 | b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, | ||
877 | 0xFFFE, 0); | ||
878 | udelay(20); | ||
879 | b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, | ||
880 | 0xFFFE, 0); | ||
881 | } | ||
882 | } else { | ||
883 | b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, | ||
884 | 0x3000); | ||
885 | if (type < 3) { | ||
886 | b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, | ||
887 | 0xFEC7, 0x0180); | ||
888 | b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, | ||
889 | 0xEFDC, (code << 1 | 0x1021)); | ||
890 | b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, | ||
891 | 0xFFFE, 0x0001); | ||
892 | udelay(20); | ||
893 | b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, | ||
894 | 0xFFFE, 0); | ||
895 | } | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ | ||
901 | static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf) | ||
902 | { | ||
903 | int i; | ||
904 | for (i = 0; i < 2; i++) { | ||
905 | if (type == 2) { | ||
906 | if (i == 0) { | ||
907 | b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM, | ||
908 | 0xFC, buf[0]); | ||
909 | b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, | ||
910 | 0xFC, buf[1]); | ||
911 | } else { | ||
912 | b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM, | ||
913 | 0xFC, buf[2 * i]); | ||
914 | b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, | ||
915 | 0xFC, buf[2 * i + 1]); | ||
916 | } | ||
917 | } else { | ||
918 | if (i == 0) | ||
919 | b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5, | ||
920 | 0xF3, buf[0] << 2); | ||
921 | else | ||
922 | b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5, | ||
923 | 0xF3, buf[2 * i + 1] << 2); | ||
924 | } | ||
925 | } | ||
926 | } | ||
927 | |||
928 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ | ||
929 | static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, | ||
930 | u8 nsamp) | ||
931 | { | ||
932 | int i; | ||
933 | int out; | ||
934 | u16 save_regs_phy[9]; | ||
935 | u16 s[2]; | ||
936 | |||
937 | if (dev->phy.rev >= 3) { | ||
938 | save_regs_phy[0] = b43_phy_read(dev, | ||
939 | B43_NPHY_RFCTL_LUT_TRSW_UP1); | ||
940 | save_regs_phy[1] = b43_phy_read(dev, | ||
941 | B43_NPHY_RFCTL_LUT_TRSW_UP2); | ||
942 | save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); | ||
943 | save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); | ||
944 | save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1); | ||
945 | save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); | ||
946 | save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); | ||
947 | save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); | ||
948 | } | ||
949 | |||
950 | b43_nphy_rssi_select(dev, 5, type); | ||
951 | |||
952 | if (dev->phy.rev < 2) { | ||
953 | save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL); | ||
954 | b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5); | ||
955 | } | ||
956 | |||
957 | for (i = 0; i < 4; i++) | ||
958 | buf[i] = 0; | ||
959 | |||
960 | for (i = 0; i < nsamp; i++) { | ||
961 | if (dev->phy.rev < 2) { | ||
962 | s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT); | ||
963 | s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT); | ||
964 | } else { | ||
965 | s[0] = b43_phy_read(dev, B43_NPHY_RSSI1); | ||
966 | s[1] = b43_phy_read(dev, B43_NPHY_RSSI2); | ||
967 | } | ||
968 | |||
969 | buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2; | ||
970 | buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2; | ||
971 | buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2; | ||
972 | buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2; | ||
973 | } | ||
974 | out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 | | ||
975 | (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF); | ||
976 | |||
977 | if (dev->phy.rev < 2) | ||
978 | b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]); | ||
979 | |||
980 | if (dev->phy.rev >= 3) { | ||
981 | b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, | ||
982 | save_regs_phy[0]); | ||
983 | b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, | ||
984 | save_regs_phy[1]); | ||
985 | b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]); | ||
986 | b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]); | ||
987 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]); | ||
988 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]); | ||
989 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]); | ||
990 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]); | ||
991 | } | ||
992 | |||
993 | return out; | ||
994 | } | ||
995 | |||
996 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ | ||
997 | static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type) | ||
998 | { | ||
999 | int i, j; | ||
1000 | u8 state[4]; | ||
1001 | u8 code, val; | ||
1002 | u16 class, override; | ||
1003 | u8 regs_save_radio[2]; | ||
1004 | u16 regs_save_phy[2]; | ||
1005 | s8 offset[4]; | ||
1006 | |||
1007 | u16 clip_state[2]; | ||
1008 | u16 clip_off[2] = { 0xFFFF, 0xFFFF }; | ||
1009 | s32 results_min[4] = { }; | ||
1010 | u8 vcm_final[4] = { }; | ||
1011 | s32 results[4][4] = { }; | ||
1012 | s32 miniq[4][2] = { }; | ||
1013 | |||
1014 | if (type == 2) { | ||
1015 | code = 0; | ||
1016 | val = 6; | ||
1017 | } else if (type < 2) { | ||
1018 | code = 25; | ||
1019 | val = 4; | ||
1020 | } else { | ||
1021 | B43_WARN_ON(1); | ||
1022 | return; | ||
1023 | } | ||
1024 | |||
1025 | class = b43_nphy_classifier(dev, 0, 0); | ||
1026 | b43_nphy_classifier(dev, 7, 4); | ||
1027 | b43_nphy_read_clip_detection(dev, clip_state); | ||
1028 | b43_nphy_write_clip_detection(dev, clip_off); | ||
1029 | |||
1030 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) | ||
1031 | override = 0x140; | ||
1032 | else | ||
1033 | override = 0x110; | ||
1034 | |||
1035 | regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1); | ||
1036 | regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX); | ||
1037 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override); | ||
1038 | b43_radio_write16(dev, B2055_C1_PD_RXTX, val); | ||
1039 | |||
1040 | regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2); | ||
1041 | regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX); | ||
1042 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override); | ||
1043 | b43_radio_write16(dev, B2055_C2_PD_RXTX, val); | ||
1044 | |||
1045 | state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07; | ||
1046 | state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07; | ||
1047 | b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8); | ||
1048 | b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8); | ||
1049 | state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07; | ||
1050 | state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07; | ||
1051 | |||
1052 | b43_nphy_rssi_select(dev, 5, type); | ||
1053 | b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type); | ||
1054 | b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type); | ||
1055 | |||
1056 | for (i = 0; i < 4; i++) { | ||
1057 | u8 tmp[4]; | ||
1058 | for (j = 0; j < 4; j++) | ||
1059 | tmp[j] = i; | ||
1060 | if (type != 1) | ||
1061 | b43_nphy_set_rssi_2055_vcm(dev, type, tmp); | ||
1062 | b43_nphy_poll_rssi(dev, type, results[i], 8); | ||
1063 | if (type < 2) | ||
1064 | for (j = 0; j < 2; j++) | ||
1065 | miniq[i][j] = min(results[i][2 * j], | ||
1066 | results[i][2 * j + 1]); | ||
1067 | } | ||
1068 | |||
1069 | for (i = 0; i < 4; i++) { | ||
1070 | s32 mind = 40; | ||
1071 | u8 minvcm = 0; | ||
1072 | s32 minpoll = 249; | ||
1073 | s32 curr; | ||
1074 | for (j = 0; j < 4; j++) { | ||
1075 | if (type == 2) | ||
1076 | curr = abs(results[j][i]); | ||
1077 | else | ||
1078 | curr = abs(miniq[j][i / 2] - code * 8); | ||
1079 | |||
1080 | if (curr < mind) { | ||
1081 | mind = curr; | ||
1082 | minvcm = j; | ||
1083 | } | ||
1084 | |||
1085 | if (results[j][i] < minpoll) | ||
1086 | minpoll = results[j][i]; | ||
1087 | } | ||
1088 | results_min[i] = minpoll; | ||
1089 | vcm_final[i] = minvcm; | ||
1090 | } | ||
1091 | |||
1092 | if (type != 1) | ||
1093 | b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final); | ||
1094 | |||
1095 | for (i = 0; i < 4; i++) { | ||
1096 | offset[i] = (code * 8) - results[vcm_final[i]][i]; | ||
1097 | |||
1098 | if (offset[i] < 0) | ||
1099 | offset[i] = -((abs(offset[i]) + 4) / 8); | ||
1100 | else | ||
1101 | offset[i] = (offset[i] + 4) / 8; | ||
1102 | |||
1103 | if (results_min[i] == 248) | ||
1104 | offset[i] = code - 32; | ||
1105 | |||
1106 | if (i % 2 == 0) | ||
1107 | b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0, | ||
1108 | type); | ||
1109 | else | ||
1110 | b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1, | ||
1111 | type); | ||
1112 | } | ||
1113 | |||
1114 | b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]); | ||
1115 | b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[1]); | ||
1116 | |||
1117 | switch (state[2]) { | ||
1118 | case 1: | ||
1119 | b43_nphy_rssi_select(dev, 1, 2); | ||
1120 | break; | ||
1121 | case 4: | ||
1122 | b43_nphy_rssi_select(dev, 1, 0); | ||
1123 | break; | ||
1124 | case 2: | ||
1125 | b43_nphy_rssi_select(dev, 1, 1); | ||
1126 | break; | ||
1127 | default: | ||
1128 | b43_nphy_rssi_select(dev, 1, 1); | ||
1129 | break; | ||
1130 | } | ||
1131 | |||
1132 | switch (state[3]) { | ||
1133 | case 1: | ||
1134 | b43_nphy_rssi_select(dev, 2, 2); | ||
1135 | break; | ||
1136 | case 4: | ||
1137 | b43_nphy_rssi_select(dev, 2, 0); | ||
1138 | break; | ||
1139 | default: | ||
1140 | b43_nphy_rssi_select(dev, 2, 1); | ||
1141 | break; | ||
1142 | } | ||
1143 | |||
1144 | b43_nphy_rssi_select(dev, 0, type); | ||
1145 | |||
1146 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]); | ||
1147 | b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]); | ||
1148 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]); | ||
1149 | b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]); | ||
1150 | |||
1151 | b43_nphy_classifier(dev, 7, class); | ||
1152 | b43_nphy_write_clip_detection(dev, clip_state); | ||
1153 | } | ||
1154 | |||
1155 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ | ||
1156 | static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) | ||
1157 | { | ||
1158 | /* TODO */ | ||
1159 | } | ||
1160 | |||
1161 | /* | ||
1162 | * RSSI Calibration | ||
1163 | * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal | ||
1164 | */ | ||
1165 | static void b43_nphy_rssi_cal(struct b43_wldev *dev) | ||
1166 | { | ||
1167 | if (dev->phy.rev >= 3) { | ||
1168 | b43_nphy_rev3_rssi_cal(dev); | ||
1169 | } else { | ||
1170 | b43_nphy_rev2_rssi_cal(dev, 2); | ||
1171 | b43_nphy_rev2_rssi_cal(dev, 0); | ||
1172 | b43_nphy_rev2_rssi_cal(dev, 1); | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | /* | ||
1177 | * Restore RSSI Calibration | ||
1178 | * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal | ||
1179 | */ | ||
1180 | static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) | ||
1181 | { | ||
1182 | struct b43_phy_n *nphy = dev->phy.n; | ||
1183 | |||
1184 | u16 *rssical_radio_regs = NULL; | ||
1185 | u16 *rssical_phy_regs = NULL; | ||
1186 | |||
1187 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
1188 | if (!nphy->rssical_chanspec_2G) | ||
1189 | return; | ||
1190 | rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_2G; | ||
1191 | rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_2G; | ||
1192 | } else { | ||
1193 | if (!nphy->rssical_chanspec_5G) | ||
1194 | return; | ||
1195 | rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G; | ||
1196 | rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G; | ||
1197 | } | ||
1198 | |||
1199 | /* TODO use some definitions */ | ||
1200 | b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]); | ||
1201 | b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]); | ||
1202 | |||
1203 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]); | ||
1204 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]); | ||
1205 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, rssical_phy_regs[2]); | ||
1206 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, rssical_phy_regs[3]); | ||
1207 | |||
1208 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, rssical_phy_regs[4]); | ||
1209 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, rssical_phy_regs[5]); | ||
1210 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, rssical_phy_regs[6]); | ||
1211 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, rssical_phy_regs[7]); | ||
1212 | |||
1213 | b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, rssical_phy_regs[8]); | ||
1214 | b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, rssical_phy_regs[9]); | ||
1215 | b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, rssical_phy_regs[10]); | ||
1216 | b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]); | ||
1217 | } | ||
1218 | |||
1219 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ | ||
1220 | static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) | ||
1221 | { | ||
1222 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
1223 | if (dev->phy.rev >= 6) { | ||
1224 | /* TODO If the chip is 47162 | ||
1225 | return txpwrctrl_tx_gain_ipa_rev5 */ | ||
1226 | return txpwrctrl_tx_gain_ipa_rev6; | ||
1227 | } else if (dev->phy.rev >= 5) { | ||
1228 | return txpwrctrl_tx_gain_ipa_rev5; | ||
1229 | } else { | ||
1230 | return txpwrctrl_tx_gain_ipa; | ||
1231 | } | ||
1232 | } else { | ||
1233 | return txpwrctrl_tx_gain_ipa_5g; | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ | ||
1238 | static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) | ||
1239 | { | ||
1240 | struct b43_phy_n *nphy = dev->phy.n; | ||
1241 | u16 *save = nphy->tx_rx_cal_radio_saveregs; | ||
1242 | |||
1243 | if (dev->phy.rev >= 3) { | ||
1244 | /* TODO */ | ||
1245 | } else { | ||
1246 | save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1); | ||
1247 | b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29); | ||
1248 | |||
1249 | save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2); | ||
1250 | b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54); | ||
1251 | |||
1252 | save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1); | ||
1253 | b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29); | ||
1254 | |||
1255 | save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2); | ||
1256 | b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54); | ||
1257 | |||
1258 | save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX); | ||
1259 | save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX); | ||
1260 | |||
1261 | if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) & | ||
1262 | B43_NPHY_BANDCTL_5GHZ)) { | ||
1263 | b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04); | ||
1264 | b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04); | ||
1265 | } else { | ||
1266 | b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20); | ||
1267 | b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20); | ||
1268 | } | ||
1269 | |||
1270 | if (dev->phy.rev < 2) { | ||
1271 | b43_radio_set(dev, B2055_C1_TX_BB_MXGM, 0x20); | ||
1272 | b43_radio_set(dev, B2055_C2_TX_BB_MXGM, 0x20); | ||
1273 | } else { | ||
1274 | b43_radio_mask(dev, B2055_C1_TX_BB_MXGM, ~0x20); | ||
1275 | b43_radio_mask(dev, B2055_C2_TX_BB_MXGM, ~0x20); | ||
1276 | } | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ | ||
1281 | static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, | ||
1282 | struct nphy_txgains target, | ||
1283 | struct nphy_iqcal_params *params) | ||
1284 | { | ||
1285 | int i, j, indx; | ||
1286 | u16 gain; | ||
1287 | |||
1288 | if (dev->phy.rev >= 3) { | ||
1289 | params->txgm = target.txgm[core]; | ||
1290 | params->pga = target.pga[core]; | ||
1291 | params->pad = target.pad[core]; | ||
1292 | params->ipa = target.ipa[core]; | ||
1293 | params->cal_gain = (params->txgm << 12) | (params->pga << 8) | | ||
1294 | (params->pad << 4) | (params->ipa); | ||
1295 | for (j = 0; j < 5; j++) | ||
1296 | params->ncorr[j] = 0x79; | ||
1297 | } else { | ||
1298 | gain = (target.pad[core]) | (target.pga[core] << 4) | | ||
1299 | (target.txgm[core] << 8); | ||
1300 | |||
1301 | indx = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? | ||
1302 | 1 : 0; | ||
1303 | for (i = 0; i < 9; i++) | ||
1304 | if (tbl_iqcal_gainparams[indx][i][0] == gain) | ||
1305 | break; | ||
1306 | i = min(i, 8); | ||
1307 | |||
1308 | params->txgm = tbl_iqcal_gainparams[indx][i][1]; | ||
1309 | params->pga = tbl_iqcal_gainparams[indx][i][2]; | ||
1310 | params->pad = tbl_iqcal_gainparams[indx][i][3]; | ||
1311 | params->cal_gain = (params->txgm << 7) | (params->pga << 4) | | ||
1312 | (params->pad << 2); | ||
1313 | for (j = 0; j < 4; j++) | ||
1314 | params->ncorr[j] = tbl_iqcal_gainparams[indx][i][4 + j]; | ||
1315 | } | ||
1316 | } | ||
1317 | |||
1318 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ | ||
1319 | static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) | ||
1320 | { | ||
1321 | struct b43_phy_n *nphy = dev->phy.n; | ||
1322 | int i; | ||
1323 | u16 scale, entry; | ||
1324 | |||
1325 | u16 tmp = nphy->txcal_bbmult; | ||
1326 | if (core == 0) | ||
1327 | tmp >>= 8; | ||
1328 | tmp &= 0xff; | ||
1329 | |||
1330 | for (i = 0; i < 18; i++) { | ||
1331 | scale = (ladder_lo[i].percent * tmp) / 100; | ||
1332 | entry = ((scale & 0xFF) << 8) | ladder_lo[i].g_env; | ||
1333 | /* TODO: Write an N PHY Table with ID 15, length 1, | ||
1334 | offset i, width 16, and data entry */ | ||
1335 | |||
1336 | scale = (ladder_iq[i].percent * tmp) / 100; | ||
1337 | entry = ((scale & 0xFF) << 8) | ladder_iq[i].g_env; | ||
1338 | /* TODO: Write an N PHY Table with ID 15, length 1, | ||
1339 | offset i + 32, width 16, and data entry */ | ||
1340 | } | ||
1341 | } | ||
1342 | |||
1343 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ | ||
1344 | static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) | ||
1345 | { | ||
1346 | struct b43_phy_n *nphy = dev->phy.n; | ||
1347 | |||
1348 | u16 curr_gain[2]; | ||
1349 | struct nphy_txgains target; | ||
1350 | const u32 *table = NULL; | ||
1351 | |||
1352 | if (nphy->txpwrctrl == 0) { | ||
1353 | int i; | ||
1354 | |||
1355 | if (nphy->hang_avoid) | ||
1356 | b43_nphy_stay_in_carrier_search(dev, true); | ||
1357 | /* TODO: Read an N PHY Table with ID 7, length 2, | ||
1358 | offset 0x110, width 16, and curr_gain */ | ||
1359 | if (nphy->hang_avoid) | ||
1360 | b43_nphy_stay_in_carrier_search(dev, false); | ||
1361 | |||
1362 | for (i = 0; i < 2; ++i) { | ||
1363 | if (dev->phy.rev >= 3) { | ||
1364 | target.ipa[i] = curr_gain[i] & 0x000F; | ||
1365 | target.pad[i] = (curr_gain[i] & 0x00F0) >> 4; | ||
1366 | target.pga[i] = (curr_gain[i] & 0x0F00) >> 8; | ||
1367 | target.txgm[i] = (curr_gain[i] & 0x7000) >> 12; | ||
1368 | } else { | ||
1369 | target.ipa[i] = curr_gain[i] & 0x0003; | ||
1370 | target.pad[i] = (curr_gain[i] & 0x000C) >> 2; | ||
1371 | target.pga[i] = (curr_gain[i] & 0x0070) >> 4; | ||
1372 | target.txgm[i] = (curr_gain[i] & 0x0380) >> 7; | ||
1373 | } | ||
1374 | } | ||
1375 | } else { | ||
1376 | int i; | ||
1377 | u16 index[2]; | ||
1378 | index[0] = (b43_phy_read(dev, B43_NPHY_C1_TXPCTL_STAT) & | ||
1379 | B43_NPHY_TXPCTL_STAT_BIDX) >> | ||
1380 | B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; | ||
1381 | index[1] = (b43_phy_read(dev, B43_NPHY_C2_TXPCTL_STAT) & | ||
1382 | B43_NPHY_TXPCTL_STAT_BIDX) >> | ||
1383 | B43_NPHY_TXPCTL_STAT_BIDX_SHIFT; | ||
1384 | |||
1385 | for (i = 0; i < 2; ++i) { | ||
1386 | if (dev->phy.rev >= 3) { | ||
1387 | enum ieee80211_band band = | ||
1388 | b43_current_band(dev->wl); | ||
1389 | |||
1390 | if ((nphy->ipa2g_on && | ||
1391 | band == IEEE80211_BAND_2GHZ) || | ||
1392 | (nphy->ipa5g_on && | ||
1393 | band == IEEE80211_BAND_5GHZ)) { | ||
1394 | table = b43_nphy_get_ipa_gain_table(dev); | ||
1395 | } else { | ||
1396 | if (band == IEEE80211_BAND_5GHZ) { | ||
1397 | if (dev->phy.rev == 3) | ||
1398 | table = b43_ntab_tx_gain_rev3_5ghz; | ||
1399 | else if (dev->phy.rev == 4) | ||
1400 | table = b43_ntab_tx_gain_rev4_5ghz; | ||
1401 | else | ||
1402 | table = b43_ntab_tx_gain_rev5plus_5ghz; | ||
1403 | } else { | ||
1404 | table = b43_ntab_tx_gain_rev3plus_2ghz; | ||
1405 | } | ||
1406 | } | ||
1407 | |||
1408 | target.ipa[i] = (table[index[i]] >> 16) & 0xF; | ||
1409 | target.pad[i] = (table[index[i]] >> 20) & 0xF; | ||
1410 | target.pga[i] = (table[index[i]] >> 24) & 0xF; | ||
1411 | target.txgm[i] = (table[index[i]] >> 28) & 0xF; | ||
1412 | } else { | ||
1413 | table = b43_ntab_tx_gain_rev0_1_2; | ||
1414 | |||
1415 | target.ipa[i] = (table[index[i]] >> 16) & 0x3; | ||
1416 | target.pad[i] = (table[index[i]] >> 18) & 0x3; | ||
1417 | target.pga[i] = (table[index[i]] >> 20) & 0x7; | ||
1418 | target.txgm[i] = (table[index[i]] >> 23) & 0x7; | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | return target; | ||
1424 | } | ||
1425 | |||
1426 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ | ||
1427 | static void b43_nphy_restore_cal(struct b43_wldev *dev) | ||
1428 | { | ||
1429 | struct b43_phy_n *nphy = dev->phy.n; | ||
1430 | |||
1431 | u16 coef[4]; | ||
1432 | u16 *loft = NULL; | ||
1433 | u16 *table = NULL; | ||
1434 | |||
1435 | int i; | ||
1436 | u16 *txcal_radio_regs = NULL; | ||
1437 | struct b43_phy_n_iq_comp *rxcal_coeffs = NULL; | ||
1438 | |||
1439 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
1440 | if (nphy->iqcal_chanspec_2G == 0) | ||
1441 | return; | ||
1442 | table = nphy->cal_cache.txcal_coeffs_2G; | ||
1443 | loft = &nphy->cal_cache.txcal_coeffs_2G[5]; | ||
1444 | } else { | ||
1445 | if (nphy->iqcal_chanspec_5G == 0) | ||
1446 | return; | ||
1447 | table = nphy->cal_cache.txcal_coeffs_5G; | ||
1448 | loft = &nphy->cal_cache.txcal_coeffs_5G[5]; | ||
1449 | } | ||
1450 | |||
1451 | /* TODO: Write an N PHY table with ID 15, length 4, offset 80, | ||
1452 | width 16, and data from table */ | ||
1453 | |||
1454 | for (i = 0; i < 4; i++) { | ||
1455 | if (dev->phy.rev >= 3) | ||
1456 | table[i] = coef[i]; | ||
1457 | else | ||
1458 | coef[i] = 0; | ||
1459 | } | ||
1460 | |||
1461 | /* TODO: Write an N PHY table with ID 15, length 4, offset 88, | ||
1462 | width 16, and data from coef */ | ||
1463 | /* TODO: Write an N PHY table with ID 15, length 2, offset 85, | ||
1464 | width 16 and data from loft */ | ||
1465 | /* TODO: Write an N PHY table with ID 15, length 2, offset 93, | ||
1466 | width 16 and data from loft */ | ||
1467 | |||
1468 | if (dev->phy.rev < 2) | ||
1469 | b43_nphy_tx_iq_workaround(dev); | ||
1470 | |||
1471 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { | ||
1472 | txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_2G; | ||
1473 | rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_2G; | ||
1474 | } else { | ||
1475 | txcal_radio_regs = nphy->cal_cache.txcal_radio_regs_5G; | ||
1476 | rxcal_coeffs = &nphy->cal_cache.rxcal_coeffs_5G; | ||
1477 | } | ||
1478 | |||
1479 | /* TODO use some definitions */ | ||
1480 | if (dev->phy.rev >= 3) { | ||
1481 | b43_radio_write(dev, 0x2021, txcal_radio_regs[0]); | ||
1482 | b43_radio_write(dev, 0x2022, txcal_radio_regs[1]); | ||
1483 | b43_radio_write(dev, 0x3021, txcal_radio_regs[2]); | ||
1484 | b43_radio_write(dev, 0x3022, txcal_radio_regs[3]); | ||
1485 | b43_radio_write(dev, 0x2023, txcal_radio_regs[4]); | ||
1486 | b43_radio_write(dev, 0x2024, txcal_radio_regs[5]); | ||
1487 | b43_radio_write(dev, 0x3023, txcal_radio_regs[6]); | ||
1488 | b43_radio_write(dev, 0x3024, txcal_radio_regs[7]); | ||
1489 | } else { | ||
1490 | b43_radio_write(dev, 0x8B, txcal_radio_regs[0]); | ||
1491 | b43_radio_write(dev, 0xBA, txcal_radio_regs[1]); | ||
1492 | b43_radio_write(dev, 0x8D, txcal_radio_regs[2]); | ||
1493 | b43_radio_write(dev, 0xBC, txcal_radio_regs[3]); | ||
1494 | } | ||
1495 | b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); | ||
1496 | } | ||
1497 | |||
1498 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ | ||
1499 | static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, | ||
1500 | struct nphy_txgains target, | ||
1501 | bool full, bool mphase) | ||
1502 | { | ||
1503 | struct b43_phy_n *nphy = dev->phy.n; | ||
1504 | int i; | ||
1505 | int error = 0; | ||
1506 | int freq; | ||
1507 | bool avoid = false; | ||
1508 | u8 length; | ||
1509 | u16 tmp, core, type, count, max, numb, last, cmd; | ||
1510 | const u16 *table; | ||
1511 | bool phy6or5x; | ||
1512 | |||
1513 | u16 buffer[11]; | ||
1514 | u16 diq_start = 0; | ||
1515 | u16 save[2]; | ||
1516 | u16 gain[2]; | ||
1517 | struct nphy_iqcal_params params[2]; | ||
1518 | bool updated[2] = { }; | ||
1519 | |||
1520 | b43_nphy_stay_in_carrier_search(dev, true); | ||
1521 | |||
1522 | if (dev->phy.rev >= 4) { | ||
1523 | avoid = nphy->hang_avoid; | ||
1524 | nphy->hang_avoid = 0; | ||
1525 | } | ||
1526 | |||
1527 | /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, | ||
1528 | width 16, and data pointer save */ | ||
1529 | |||
1530 | for (i = 0; i < 2; i++) { | ||
1531 | b43_nphy_iq_cal_gain_params(dev, i, target, ¶ms[i]); | ||
1532 | gain[i] = params[i].cal_gain; | ||
1533 | } | ||
1534 | /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, | ||
1535 | width 16, and data pointer gain */ | ||
1536 | |||
1537 | b43_nphy_tx_cal_radio_setup(dev); | ||
1538 | /* TODO: Call N PHY TX Cal PHY Setup */ | ||
1539 | |||
1540 | phy6or5x = dev->phy.rev >= 6 || | ||
1541 | (dev->phy.rev == 5 && nphy->ipa2g_on && | ||
1542 | b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ); | ||
1543 | if (phy6or5x) { | ||
1544 | /* TODO */ | ||
1545 | } | ||
1546 | |||
1547 | b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8AA9); | ||
1548 | |||
1549 | if (1 /* FIXME: the band width is 20 MHz */) | ||
1550 | freq = 2500; | ||
1551 | else | ||
1552 | freq = 5000; | ||
1553 | |||
1554 | if (nphy->mphase_cal_phase_id > 2) | ||
1555 | ;/* TODO: Call N PHY Run Samples with (band width * 8), | ||
1556 | 0xFFFF, 0, 1, 0 as arguments */ | ||
1557 | else | ||
1558 | ;/* TODO: Call N PHY TX Tone with freq, 250, 1, 0 as arguments | ||
1559 | and save result as error */ | ||
1560 | |||
1561 | if (error == 0) { | ||
1562 | if (nphy->mphase_cal_phase_id > 2) { | ||
1563 | table = nphy->mphase_txcal_bestcoeffs; | ||
1564 | length = 11; | ||
1565 | if (dev->phy.rev < 3) | ||
1566 | length -= 2; | ||
1567 | } else { | ||
1568 | if (!full && nphy->txiqlocal_coeffsvalid) { | ||
1569 | table = nphy->txiqlocal_bestc; | ||
1570 | length = 11; | ||
1571 | if (dev->phy.rev < 3) | ||
1572 | length -= 2; | ||
1573 | } else { | ||
1574 | full = true; | ||
1575 | if (dev->phy.rev >= 3) { | ||
1576 | table = tbl_tx_iqlo_cal_startcoefs_nphyrev3; | ||
1577 | length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3; | ||
1578 | } else { | ||
1579 | table = tbl_tx_iqlo_cal_startcoefs; | ||
1580 | length = B43_NTAB_TX_IQLO_CAL_STARTCOEFS; | ||
1581 | } | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | /* TODO: Write an N PHY Table with ID 15, length from above, | ||
1586 | offset 64, width 16, and the data pointer from above */ | ||
1587 | |||
1588 | if (full) { | ||
1589 | if (dev->phy.rev >= 3) | ||
1590 | max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3; | ||
1591 | else | ||
1592 | max = B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL; | ||
1593 | } else { | ||
1594 | if (dev->phy.rev >= 3) | ||
1595 | max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3; | ||
1596 | else | ||
1597 | max = B43_NTAB_TX_IQLO_CAL_CMDS_RECAL; | ||
1598 | } | ||
1599 | |||
1600 | if (mphase) { | ||
1601 | count = nphy->mphase_txcal_cmdidx; | ||
1602 | numb = min(max, | ||
1603 | (u16)(count + nphy->mphase_txcal_numcmds)); | ||
1604 | } else { | ||
1605 | count = 0; | ||
1606 | numb = max; | ||
1607 | } | ||
1608 | |||
1609 | for (; count < numb; count++) { | ||
1610 | if (full) { | ||
1611 | if (dev->phy.rev >= 3) | ||
1612 | cmd = tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[count]; | ||
1613 | else | ||
1614 | cmd = tbl_tx_iqlo_cal_cmds_fullcal[count]; | ||
1615 | } else { | ||
1616 | if (dev->phy.rev >= 3) | ||
1617 | cmd = tbl_tx_iqlo_cal_cmds_recal_nphyrev3[count]; | ||
1618 | else | ||
1619 | cmd = tbl_tx_iqlo_cal_cmds_recal[count]; | ||
1620 | } | ||
1621 | |||
1622 | core = (cmd & 0x3000) >> 12; | ||
1623 | type = (cmd & 0x0F00) >> 8; | ||
1624 | |||
1625 | if (phy6or5x && updated[core] == 0) { | ||
1626 | b43_nphy_update_tx_cal_ladder(dev, core); | ||
1627 | updated[core] = 1; | ||
1628 | } | ||
1629 | |||
1630 | tmp = (params[core].ncorr[type] << 8) | 0x66; | ||
1631 | b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDNNUM, tmp); | ||
1632 | |||
1633 | if (type == 1 || type == 3 || type == 4) { | ||
1634 | /* TODO: Read an N PHY Table with ID 15, | ||
1635 | length 1, offset 69 + core, | ||
1636 | width 16, and data pointer buffer */ | ||
1637 | diq_start = buffer[0]; | ||
1638 | buffer[0] = 0; | ||
1639 | /* TODO: Write an N PHY Table with ID 15, | ||
1640 | length 1, offset 69 + core, width 16, | ||
1641 | and data of 0 */ | ||
1642 | } | ||
1643 | |||
1644 | b43_phy_write(dev, B43_NPHY_IQLOCAL_CMD, cmd); | ||
1645 | for (i = 0; i < 2000; i++) { | ||
1646 | tmp = b43_phy_read(dev, B43_NPHY_IQLOCAL_CMD); | ||
1647 | if (tmp & 0xC000) | ||
1648 | break; | ||
1649 | udelay(10); | ||
1650 | } | ||
1651 | |||
1652 | /* TODO: Read an N PHY Table with ID 15, | ||
1653 | length table_length, offset 96, width 16, | ||
1654 | and data pointer buffer */ | ||
1655 | /* TODO: Write an N PHY Table with ID 15, | ||
1656 | length table_length, offset 64, width 16, | ||
1657 | and data pointer buffer */ | ||
1658 | |||
1659 | if (type == 1 || type == 3 || type == 4) | ||
1660 | buffer[0] = diq_start; | ||
1661 | } | ||
1662 | |||
1663 | if (mphase) | ||
1664 | nphy->mphase_txcal_cmdidx = (numb >= max) ? 0 : numb; | ||
1665 | |||
1666 | last = (dev->phy.rev < 3) ? 6 : 7; | ||
1667 | |||
1668 | if (!mphase || nphy->mphase_cal_phase_id == last) { | ||
1669 | /* TODO: Write an N PHY Table with ID 15, length 4, | ||
1670 | offset 96, width 16, and data pointer buffer */ | ||
1671 | /* TODO: Read an N PHY Table with ID 15, length 4, | ||
1672 | offset 80, width 16, and data pointer buffer */ | ||
1673 | if (dev->phy.rev < 3) { | ||
1674 | buffer[0] = 0; | ||
1675 | buffer[1] = 0; | ||
1676 | buffer[2] = 0; | ||
1677 | buffer[3] = 0; | ||
1678 | } | ||
1679 | /* TODO: Write an N PHY Table with ID 15, length 4, | ||
1680 | offset 88, width 16, and data pointer buffer */ | ||
1681 | /* TODO: Read an N PHY Table with ID 15, length 2, | ||
1682 | offset 101, width 16, and data pointer buffer*/ | ||
1683 | /* TODO: Write an N PHY Table with ID 15, length 2, | ||
1684 | offset 85, width 16, and data pointer buffer */ | ||
1685 | /* TODO: Write an N PHY Table with ID 15, length 2, | ||
1686 | offset 93, width 16, and data pointer buffer */ | ||
1687 | length = 11; | ||
1688 | if (dev->phy.rev < 3) | ||
1689 | length -= 2; | ||
1690 | /* TODO: Read an N PHY Table with ID 15, length length, | ||
1691 | offset 96, width 16, and data pointer | ||
1692 | nphy->txiqlocal_bestc */ | ||
1693 | nphy->txiqlocal_coeffsvalid = true; | ||
1694 | /* TODO: Set nphy->txiqlocal_chanspec to | ||
1695 | the current channel */ | ||
1696 | } else { | ||
1697 | length = 11; | ||
1698 | if (dev->phy.rev < 3) | ||
1699 | length -= 2; | ||
1700 | /* TODO: Read an N PHY Table with ID 5, length length, | ||
1701 | offset 96, width 16, and data pointer | ||
1702 | nphy->mphase_txcal_bestcoeffs */ | ||
1703 | } | ||
1704 | |||
1705 | /* TODO: Call N PHY Stop Playback */ | ||
1706 | b43_phy_write(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0); | ||
1707 | } | ||
1708 | |||
1709 | /* TODO: Call N PHY TX Cal PHY Cleanup */ | ||
1710 | /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, | ||
1711 | width 16, and data from save */ | ||
1712 | |||
1713 | if (dev->phy.rev < 2 && (!mphase || nphy->mphase_cal_phase_id == last)) | ||
1714 | b43_nphy_tx_iq_workaround(dev); | ||
1715 | |||
1716 | if (dev->phy.rev >= 4) | ||
1717 | nphy->hang_avoid = avoid; | ||
1718 | |||
1719 | b43_nphy_stay_in_carrier_search(dev, false); | ||
1720 | |||
1721 | return error; | ||
418 | } | 1722 | } |
419 | 1723 | ||
1724 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ | ||
1725 | static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, | ||
1726 | struct nphy_txgains target, u8 type, bool debug) | ||
1727 | { | ||
1728 | struct b43_phy_n *nphy = dev->phy.n; | ||
1729 | int i, j, index; | ||
1730 | u8 rfctl[2]; | ||
1731 | u8 afectl_core; | ||
1732 | u16 tmp[6]; | ||
1733 | u16 cur_hpf1, cur_hpf2, cur_lna; | ||
1734 | u32 real, imag; | ||
1735 | enum ieee80211_band band; | ||
1736 | |||
1737 | u8 use; | ||
1738 | u16 cur_hpf; | ||
1739 | u16 lna[3] = { 3, 3, 1 }; | ||
1740 | u16 hpf1[3] = { 7, 2, 0 }; | ||
1741 | u16 hpf2[3] = { 2, 0, 0 }; | ||
1742 | u32 power[3]; | ||
1743 | u16 gain_save[2]; | ||
1744 | u16 cal_gain[2]; | ||
1745 | struct nphy_iqcal_params cal_params[2]; | ||
1746 | struct nphy_iq_est est; | ||
1747 | int ret = 0; | ||
1748 | bool playtone = true; | ||
1749 | int desired = 13; | ||
1750 | |||
1751 | b43_nphy_stay_in_carrier_search(dev, 1); | ||
1752 | |||
1753 | if (dev->phy.rev < 2) | ||
1754 | ;/* TODO: Call N PHY Reapply TX Cal Coeffs */ | ||
1755 | /* TODO: Read an N PHY Table with ID 7, length 2, offset 0x110, | ||
1756 | width 16, and data gain_save */ | ||
1757 | for (i = 0; i < 2; i++) { | ||
1758 | b43_nphy_iq_cal_gain_params(dev, i, target, &cal_params[i]); | ||
1759 | cal_gain[i] = cal_params[i].cal_gain; | ||
1760 | } | ||
1761 | /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, | ||
1762 | width 16, and data from cal_gain */ | ||
1763 | |||
1764 | for (i = 0; i < 2; i++) { | ||
1765 | if (i == 0) { | ||
1766 | rfctl[0] = B43_NPHY_RFCTL_INTC1; | ||
1767 | rfctl[1] = B43_NPHY_RFCTL_INTC2; | ||
1768 | afectl_core = B43_NPHY_AFECTL_C1; | ||
1769 | } else { | ||
1770 | rfctl[0] = B43_NPHY_RFCTL_INTC2; | ||
1771 | rfctl[1] = B43_NPHY_RFCTL_INTC1; | ||
1772 | afectl_core = B43_NPHY_AFECTL_C2; | ||
1773 | } | ||
1774 | |||
1775 | tmp[1] = b43_phy_read(dev, B43_NPHY_RFSEQCA); | ||
1776 | tmp[2] = b43_phy_read(dev, afectl_core); | ||
1777 | tmp[3] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); | ||
1778 | tmp[4] = b43_phy_read(dev, rfctl[0]); | ||
1779 | tmp[5] = b43_phy_read(dev, rfctl[1]); | ||
1780 | |||
1781 | b43_phy_maskset(dev, B43_NPHY_RFSEQCA, | ||
1782 | (u16)~B43_NPHY_RFSEQCA_RXDIS, | ||
1783 | ((1 - i) << B43_NPHY_RFSEQCA_RXDIS_SHIFT)); | ||
1784 | b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN, | ||
1785 | (1 - i)); | ||
1786 | b43_phy_set(dev, afectl_core, 0x0006); | ||
1787 | b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0006); | ||
1788 | |||
1789 | band = b43_current_band(dev->wl); | ||
1790 | |||
1791 | if (nphy->rxcalparams & 0xFF000000) { | ||
1792 | if (band == IEEE80211_BAND_5GHZ) | ||
1793 | b43_phy_write(dev, rfctl[0], 0x140); | ||
1794 | else | ||
1795 | b43_phy_write(dev, rfctl[0], 0x110); | ||
1796 | } else { | ||
1797 | if (band == IEEE80211_BAND_5GHZ) | ||
1798 | b43_phy_write(dev, rfctl[0], 0x180); | ||
1799 | else | ||
1800 | b43_phy_write(dev, rfctl[0], 0x120); | ||
1801 | } | ||
1802 | |||
1803 | if (band == IEEE80211_BAND_5GHZ) | ||
1804 | b43_phy_write(dev, rfctl[1], 0x148); | ||
1805 | else | ||
1806 | b43_phy_write(dev, rfctl[1], 0x114); | ||
1807 | |||
1808 | if (nphy->rxcalparams & 0x10000) { | ||
1809 | b43_radio_maskset(dev, B2055_C1_GENSPARE2, 0xFC, | ||
1810 | (i + 1)); | ||
1811 | b43_radio_maskset(dev, B2055_C2_GENSPARE2, 0xFC, | ||
1812 | (2 - i)); | ||
1813 | } | ||
1814 | |||
1815 | for (j = 0; i < 4; j++) { | ||
1816 | if (j < 3) { | ||
1817 | cur_lna = lna[j]; | ||
1818 | cur_hpf1 = hpf1[j]; | ||
1819 | cur_hpf2 = hpf2[j]; | ||
1820 | } else { | ||
1821 | if (power[1] > 10000) { | ||
1822 | use = 1; | ||
1823 | cur_hpf = cur_hpf1; | ||
1824 | index = 2; | ||
1825 | } else { | ||
1826 | if (power[0] > 10000) { | ||
1827 | use = 1; | ||
1828 | cur_hpf = cur_hpf1; | ||
1829 | index = 1; | ||
1830 | } else { | ||
1831 | index = 0; | ||
1832 | use = 2; | ||
1833 | cur_hpf = cur_hpf2; | ||
1834 | } | ||
1835 | } | ||
1836 | cur_lna = lna[index]; | ||
1837 | cur_hpf1 = hpf1[index]; | ||
1838 | cur_hpf2 = hpf2[index]; | ||
1839 | cur_hpf += desired - hweight32(power[index]); | ||
1840 | cur_hpf = clamp_val(cur_hpf, 0, 10); | ||
1841 | if (use == 1) | ||
1842 | cur_hpf1 = cur_hpf; | ||
1843 | else | ||
1844 | cur_hpf2 = cur_hpf; | ||
1845 | } | ||
1846 | |||
1847 | tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) | | ||
1848 | (cur_lna << 2)); | ||
1849 | /* TODO:Call N PHY RF Ctrl Override with 0x400, tmp[0], | ||
1850 | 3, 0 as arguments */ | ||
1851 | /* TODO: Call N PHY Force RF Seq with 2 as argument */ | ||
1852 | /* TODO: Call N PHT Stop Playback */ | ||
1853 | |||
1854 | if (playtone) { | ||
1855 | /* TODO: Call N PHY TX Tone with 4000, | ||
1856 | (nphy_rxcalparams & 0xffff), 0, 0 | ||
1857 | as arguments and save result as ret */ | ||
1858 | playtone = false; | ||
1859 | } else { | ||
1860 | /* TODO: Call N PHY Run Samples with 160, | ||
1861 | 0xFFFF, 0, 0, 0 as arguments */ | ||
1862 | } | ||
1863 | |||
1864 | if (ret == 0) { | ||
1865 | if (j < 3) { | ||
1866 | b43_nphy_rx_iq_est(dev, &est, 1024, 32, | ||
1867 | false); | ||
1868 | if (i == 0) { | ||
1869 | real = est.i0_pwr; | ||
1870 | imag = est.q0_pwr; | ||
1871 | } else { | ||
1872 | real = est.i1_pwr; | ||
1873 | imag = est.q1_pwr; | ||
1874 | } | ||
1875 | power[i] = ((real + imag) / 1024) + 1; | ||
1876 | } else { | ||
1877 | b43_nphy_calc_rx_iq_comp(dev, 1 << i); | ||
1878 | } | ||
1879 | /* TODO: Call N PHY Stop Playback */ | ||
1880 | } | ||
1881 | |||
1882 | if (ret != 0) | ||
1883 | break; | ||
1884 | } | ||
1885 | |||
1886 | b43_radio_mask(dev, B2055_C1_GENSPARE2, 0xFC); | ||
1887 | b43_radio_mask(dev, B2055_C2_GENSPARE2, 0xFC); | ||
1888 | b43_phy_write(dev, rfctl[1], tmp[5]); | ||
1889 | b43_phy_write(dev, rfctl[0], tmp[4]); | ||
1890 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER, tmp[3]); | ||
1891 | b43_phy_write(dev, afectl_core, tmp[2]); | ||
1892 | b43_phy_write(dev, B43_NPHY_RFSEQCA, tmp[1]); | ||
1893 | |||
1894 | if (ret != 0) | ||
1895 | break; | ||
1896 | } | ||
1897 | |||
1898 | /* TODO: Call N PHY RF Ctrl Override with 0x400, 0, 3, 1 as arguments*/ | ||
1899 | /* TODO: Call N PHY Force RF Seq with 2 as argument */ | ||
1900 | /* TODO: Write an N PHY Table with ID 7, length 2, offset 0x110, | ||
1901 | width 16, and data from gain_save */ | ||
1902 | |||
1903 | b43_nphy_stay_in_carrier_search(dev, 0); | ||
1904 | |||
1905 | return ret; | ||
1906 | } | ||
1907 | |||
1908 | static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, | ||
1909 | struct nphy_txgains target, u8 type, bool debug) | ||
1910 | { | ||
1911 | return -1; | ||
1912 | } | ||
1913 | |||
1914 | /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ | ||
1915 | static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, | ||
1916 | struct nphy_txgains target, u8 type, bool debug) | ||
1917 | { | ||
1918 | if (dev->phy.rev >= 3) | ||
1919 | return b43_nphy_rev3_cal_rx_iq(dev, target, type, debug); | ||
1920 | else | ||
1921 | return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); | ||
1922 | } | ||
1923 | |||
1924 | /* | ||
1925 | * Init N-PHY | ||
1926 | * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N | ||
1927 | */ | ||
420 | int b43_phy_initn(struct b43_wldev *dev) | 1928 | int b43_phy_initn(struct b43_wldev *dev) |
421 | { | 1929 | { |
1930 | struct ssb_bus *bus = dev->dev->bus; | ||
422 | struct b43_phy *phy = &dev->phy; | 1931 | struct b43_phy *phy = &dev->phy; |
1932 | struct b43_phy_n *nphy = phy->n; | ||
1933 | u8 tx_pwr_state; | ||
1934 | struct nphy_txgains target; | ||
423 | u16 tmp; | 1935 | u16 tmp; |
1936 | enum ieee80211_band tmp2; | ||
1937 | bool do_rssi_cal; | ||
1938 | |||
1939 | u16 clip[2]; | ||
1940 | bool do_cal = false; | ||
424 | 1941 | ||
425 | //TODO: Spectral management | 1942 | if ((dev->phy.rev >= 3) && |
1943 | (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && | ||
1944 | (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) { | ||
1945 | chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40); | ||
1946 | } | ||
1947 | nphy->deaf_count = 0; | ||
426 | b43_nphy_tables_init(dev); | 1948 | b43_nphy_tables_init(dev); |
1949 | nphy->crsminpwr_adjusted = false; | ||
1950 | nphy->noisevars_adjusted = false; | ||
427 | 1951 | ||
428 | /* Clear all overrides */ | 1952 | /* Clear all overrides */ |
429 | b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); | 1953 | if (dev->phy.rev >= 3) { |
1954 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, 0); | ||
1955 | b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); | ||
1956 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, 0); | ||
1957 | b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, 0); | ||
1958 | } else { | ||
1959 | b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); | ||
1960 | } | ||
430 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); | 1961 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); |
431 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); | 1962 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); |
432 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); | 1963 | if (dev->phy.rev < 6) { |
433 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); | 1964 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); |
1965 | b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); | ||
1966 | } | ||
434 | b43_phy_mask(dev, B43_NPHY_RFSEQMODE, | 1967 | b43_phy_mask(dev, B43_NPHY_RFSEQMODE, |
435 | ~(B43_NPHY_RFSEQMODE_CAOVER | | 1968 | ~(B43_NPHY_RFSEQMODE_CAOVER | |
436 | B43_NPHY_RFSEQMODE_TROVER)); | 1969 | B43_NPHY_RFSEQMODE_TROVER)); |
1970 | if (dev->phy.rev >= 3) | ||
1971 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, 0); | ||
437 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); | 1972 | b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); |
438 | 1973 | ||
439 | tmp = (phy->rev < 2) ? 64 : 59; | 1974 | if (dev->phy.rev <= 2) { |
440 | b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, | 1975 | tmp = (dev->phy.rev == 2) ? 0x3B : 0x40; |
441 | ~B43_NPHY_BPHY_CTL3_SCALE, | 1976 | b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, |
442 | tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); | 1977 | ~B43_NPHY_BPHY_CTL3_SCALE, |
443 | 1978 | tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); | |
1979 | } | ||
444 | b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); | 1980 | b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); |
445 | b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); | 1981 | b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); |
446 | 1982 | ||
447 | b43_phy_write(dev, B43_NPHY_TXREALFD, 184); | 1983 | if (bus->sprom.boardflags2_lo & 0x100 || |
448 | b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); | 1984 | (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && |
449 | b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); | 1985 | bus->boardinfo.type == 0x8B)) |
450 | b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); | 1986 | b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0); |
1987 | else | ||
1988 | b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8); | ||
1989 | b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 0xC8); | ||
1990 | b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x50); | ||
1991 | b43_phy_write(dev, B43_NPHY_TXRIFS_FRDEL, 0x30); | ||
451 | 1992 | ||
452 | //TODO MIMO-Config | 1993 | /* TODO MIMO-Config */ |
453 | //TODO Update TX/RX chain | 1994 | /* TODO Update TX/RX chain */ |
454 | 1995 | ||
455 | if (phy->rev < 2) { | 1996 | if (phy->rev < 2) { |
456 | b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); | 1997 | b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); |
457 | b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); | 1998 | b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); |
458 | } | 1999 | } |
2000 | |||
2001 | tmp2 = b43_current_band(dev->wl); | ||
2002 | if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) || | ||
2003 | (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) { | ||
2004 | b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1); | ||
2005 | b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F, | ||
2006 | nphy->papd_epsilon_offset[0] << 7); | ||
2007 | b43_phy_set(dev, B43_NPHY_PAPD_EN1, 0x1); | ||
2008 | b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ1, 0x007F, | ||
2009 | nphy->papd_epsilon_offset[1] << 7); | ||
2010 | /* TODO N PHY IPA Set TX Dig Filters */ | ||
2011 | } else if (phy->rev >= 5) { | ||
2012 | /* TODO N PHY Ext PA Set TX Dig Filters */ | ||
2013 | } | ||
2014 | |||
459 | b43_nphy_workarounds(dev); | 2015 | b43_nphy_workarounds(dev); |
460 | b43_nphy_reset_cca(dev); | ||
461 | 2016 | ||
462 | ssb_write32(dev->dev, SSB_TMSLOW, | 2017 | /* Reset CCA, in init code it differs a little from standard way */ |
463 | ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); | 2018 | b43_nphy_bmac_clock_fgc(dev, 1); |
2019 | tmp = b43_phy_read(dev, B43_NPHY_BBCFG); | ||
2020 | b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA); | ||
2021 | b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); | ||
2022 | b43_nphy_bmac_clock_fgc(dev, 0); | ||
2023 | |||
2024 | /* TODO N PHY MAC PHY Clock Set with argument 1 */ | ||
2025 | |||
2026 | b43_nphy_pa_override(dev, false); | ||
464 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); | 2027 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); |
465 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); | 2028 | b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); |
2029 | b43_nphy_pa_override(dev, true); | ||
2030 | |||
2031 | b43_nphy_classifier(dev, 0, 0); | ||
2032 | b43_nphy_read_clip_detection(dev, clip); | ||
2033 | tx_pwr_state = nphy->txpwrctrl; | ||
2034 | /* TODO N PHY TX power control with argument 0 | ||
2035 | (turning off power control) */ | ||
2036 | /* TODO Fix the TX Power Settings */ | ||
2037 | /* TODO N PHY TX Power Control Idle TSSI */ | ||
2038 | /* TODO N PHY TX Power Control Setup */ | ||
2039 | |||
2040 | if (phy->rev >= 3) { | ||
2041 | /* TODO */ | ||
2042 | } else { | ||
2043 | /* TODO Write an N PHY table with ID 26, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ | ||
2044 | /* TODO Write an N PHY table with ID 27, length 128, offset 192, width 32, and the data from Rev 2 TX Power Control Table */ | ||
2045 | } | ||
2046 | |||
2047 | if (nphy->phyrxchain != 3) | ||
2048 | ;/* TODO N PHY RX Core Set State with phyrxchain as argument */ | ||
2049 | if (nphy->mphase_cal_phase_id > 0) | ||
2050 | ;/* TODO PHY Periodic Calibration Multi-Phase Restart */ | ||
2051 | |||
2052 | do_rssi_cal = false; | ||
2053 | if (phy->rev >= 3) { | ||
2054 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
2055 | do_rssi_cal = (nphy->rssical_chanspec_2G == 0); | ||
2056 | else | ||
2057 | do_rssi_cal = (nphy->rssical_chanspec_5G == 0); | ||
2058 | |||
2059 | if (do_rssi_cal) | ||
2060 | b43_nphy_rssi_cal(dev); | ||
2061 | else | ||
2062 | b43_nphy_restore_rssi_cal(dev); | ||
2063 | } else { | ||
2064 | b43_nphy_rssi_cal(dev); | ||
2065 | } | ||
2066 | |||
2067 | if (!((nphy->measure_hold & 0x6) != 0)) { | ||
2068 | if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) | ||
2069 | do_cal = (nphy->iqcal_chanspec_2G == 0); | ||
2070 | else | ||
2071 | do_cal = (nphy->iqcal_chanspec_5G == 0); | ||
2072 | |||
2073 | if (nphy->mute) | ||
2074 | do_cal = false; | ||
2075 | |||
2076 | if (do_cal) { | ||
2077 | target = b43_nphy_get_tx_gains(dev); | ||
2078 | |||
2079 | if (nphy->antsel_type == 2) | ||
2080 | ;/*TODO NPHY Superswitch Init with argument 1*/ | ||
2081 | if (nphy->perical != 2) { | ||
2082 | b43_nphy_rssi_cal(dev); | ||
2083 | if (phy->rev >= 3) { | ||
2084 | nphy->cal_orig_pwr_idx[0] = | ||
2085 | nphy->txpwrindex[0].index_internal; | ||
2086 | nphy->cal_orig_pwr_idx[1] = | ||
2087 | nphy->txpwrindex[1].index_internal; | ||
2088 | /* TODO N PHY Pre Calibrate TX Gain */ | ||
2089 | target = b43_nphy_get_tx_gains(dev); | ||
2090 | } | ||
2091 | } | ||
2092 | } | ||
2093 | } | ||
2094 | |||
2095 | if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) { | ||
2096 | if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0) | ||
2097 | ;/* Call N PHY Save Cal */ | ||
2098 | else if (nphy->mphase_cal_phase_id == 0) | ||
2099 | ;/* N PHY Periodic Calibration with argument 3 */ | ||
2100 | } else { | ||
2101 | b43_nphy_restore_cal(dev); | ||
2102 | } | ||
466 | 2103 | ||
467 | b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ | 2104 | b43_nphy_tx_pwr_ctrl_coef_setup(dev); |
468 | //TODO read core1/2 clip1 thres regs | 2105 | /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */ |
469 | 2106 | b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015); | |
470 | if (1 /* FIXME Band is 2.4GHz */) | 2107 | b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320); |
471 | b43_nphy_bphy_init(dev); | 2108 | if (phy->rev >= 3 && phy->rev <= 6) |
472 | //TODO disable TX power control | 2109 | b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 0x0014); |
473 | //TODO Fix the TX power settings | 2110 | b43_nphy_tx_lp_fbw(dev); |
474 | //TODO Init periodic calibration with reason 3 | 2111 | /* TODO N PHY Spur Workaround */ |
475 | b43_nphy_rssi_cal(dev, 2); | ||
476 | b43_nphy_rssi_cal(dev, 0); | ||
477 | b43_nphy_rssi_cal(dev, 1); | ||
478 | //TODO get TX gain | ||
479 | //TODO init superswitch | ||
480 | //TODO calibrate LO | ||
481 | //TODO idle TSSI TX pctl | ||
482 | //TODO TX power control power setup | ||
483 | //TODO table writes | ||
484 | //TODO TX power control coefficients | ||
485 | //TODO enable TX power control | ||
486 | //TODO control antenna selection | ||
487 | //TODO init radar detection | ||
488 | //TODO reset channel if changed | ||
489 | 2112 | ||
490 | b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); | 2113 | b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); |
491 | return 0; | 2114 | return 0; |
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 1749aef4147d..4572866756fc 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h | |||
@@ -231,6 +231,7 @@ | |||
231 | #define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ | 231 | #define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ |
232 | #define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ | 232 | #define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ |
233 | #define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ | 233 | #define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ |
234 | #define B43_NPHY_AFECTL_OVER1 B43_PHY_N(0x08F) /* AFE control override 1 */ | ||
234 | #define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ | 235 | #define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ |
235 | #define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ | 236 | #define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ |
236 | #define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 | 237 | #define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 |
@@ -705,6 +706,10 @@ | |||
705 | #define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ | 706 | #define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ |
706 | #define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ | 707 | #define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ |
707 | #define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 | 708 | #define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 |
709 | #define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */ | ||
710 | #define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */ | ||
711 | #define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */ | ||
712 | #define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */ | ||
708 | 713 | ||
709 | 714 | ||
710 | 715 | ||
@@ -919,8 +924,88 @@ | |||
919 | 924 | ||
920 | struct b43_wldev; | 925 | struct b43_wldev; |
921 | 926 | ||
927 | struct b43_phy_n_iq_comp { | ||
928 | s16 a0; | ||
929 | s16 b0; | ||
930 | s16 a1; | ||
931 | s16 b1; | ||
932 | }; | ||
933 | |||
934 | struct b43_phy_n_rssical_cache { | ||
935 | u16 rssical_radio_regs_2G[2]; | ||
936 | u16 rssical_phy_regs_2G[12]; | ||
937 | |||
938 | u16 rssical_radio_regs_5G[2]; | ||
939 | u16 rssical_phy_regs_5G[12]; | ||
940 | }; | ||
941 | |||
942 | struct b43_phy_n_cal_cache { | ||
943 | u16 txcal_radio_regs_2G[8]; | ||
944 | u16 txcal_coeffs_2G[8]; | ||
945 | struct b43_phy_n_iq_comp rxcal_coeffs_2G; | ||
946 | |||
947 | u16 txcal_radio_regs_5G[8]; | ||
948 | u16 txcal_coeffs_5G[8]; | ||
949 | struct b43_phy_n_iq_comp rxcal_coeffs_5G; | ||
950 | }; | ||
951 | |||
952 | struct b43_phy_n_txpwrindex { | ||
953 | s8 index; | ||
954 | s8 index_internal; | ||
955 | s8 index_internal_save; | ||
956 | u16 AfectrlOverride; | ||
957 | u16 AfeCtrlDacGain; | ||
958 | u16 rad_gain; | ||
959 | u8 bbmult; | ||
960 | u16 iqcomp_a; | ||
961 | u16 iqcomp_b; | ||
962 | u16 locomp; | ||
963 | }; | ||
964 | |||
922 | struct b43_phy_n { | 965 | struct b43_phy_n { |
923 | //TODO lots of missing stuff | 966 | u8 antsel_type; |
967 | u8 cal_orig_pwr_idx[2]; | ||
968 | u8 measure_hold; | ||
969 | u8 phyrxchain; | ||
970 | u8 perical; | ||
971 | u32 deaf_count; | ||
972 | u32 rxcalparams; | ||
973 | bool hang_avoid; | ||
974 | bool mute; | ||
975 | u16 papd_epsilon_offset[2]; | ||
976 | |||
977 | u8 mphase_cal_phase_id; | ||
978 | u16 mphase_txcal_cmdidx; | ||
979 | u16 mphase_txcal_numcmds; | ||
980 | u16 mphase_txcal_bestcoeffs[11]; | ||
981 | |||
982 | u8 txpwrctrl; | ||
983 | u16 txcal_bbmult; | ||
984 | u16 txiqlocal_bestc[11]; | ||
985 | bool txiqlocal_coeffsvalid; | ||
986 | struct b43_phy_n_txpwrindex txpwrindex[2]; | ||
987 | |||
988 | u16 tx_rx_cal_phy_saveregs[11]; | ||
989 | u16 tx_rx_cal_radio_saveregs[22]; | ||
990 | |||
991 | u16 rfctrl_intc1_save; | ||
992 | u16 rfctrl_intc2_save; | ||
993 | |||
994 | u16 classifier_state; | ||
995 | u16 clip_state[2]; | ||
996 | |||
997 | bool ipa2g_on; | ||
998 | u8 iqcal_chanspec_2G; | ||
999 | u8 rssical_chanspec_2G; | ||
1000 | |||
1001 | bool ipa5g_on; | ||
1002 | u8 iqcal_chanspec_5G; | ||
1003 | u8 rssical_chanspec_5G; | ||
1004 | |||
1005 | struct b43_phy_n_rssical_cache rssical_cache; | ||
1006 | struct b43_phy_n_cal_cache cal_cache; | ||
1007 | bool crsminpwr_adjusted; | ||
1008 | bool noisevars_adjusted; | ||
924 | }; | 1009 | }; |
925 | 1010 | ||
926 | 1011 | ||
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 4e2336315545..7dff853ab962 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c | |||
@@ -1336,7 +1336,7 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel) | |||
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | 1338 | ||
1339 | const u8 b43_ntab_adjustpower0[] = { | 1339 | static const u8 b43_ntab_adjustpower0[] = { |
1340 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, | 1340 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, |
1341 | 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, | 1341 | 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, |
1342 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, | 1342 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, |
@@ -1355,7 +1355,7 @@ const u8 b43_ntab_adjustpower0[] = { | |||
1355 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, | 1355 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, |
1356 | }; | 1356 | }; |
1357 | 1357 | ||
1358 | const u8 b43_ntab_adjustpower1[] = { | 1358 | static const u8 b43_ntab_adjustpower1[] = { |
1359 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, | 1359 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, |
1360 | 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, | 1360 | 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, |
1361 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, | 1361 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, |
@@ -1374,11 +1374,11 @@ const u8 b43_ntab_adjustpower1[] = { | |||
1374 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, | 1374 | 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, |
1375 | }; | 1375 | }; |
1376 | 1376 | ||
1377 | const u16 b43_ntab_bdi[] = { | 1377 | static const u16 b43_ntab_bdi[] = { |
1378 | 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, | 1378 | 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, |
1379 | }; | 1379 | }; |
1380 | 1380 | ||
1381 | const u32 b43_ntab_channelest[] = { | 1381 | static const u32 b43_ntab_channelest[] = { |
1382 | 0x44444444, 0x44444444, 0x44444444, 0x44444444, | 1382 | 0x44444444, 0x44444444, 0x44444444, 0x44444444, |
1383 | 0x44444444, 0x44444444, 0x44444444, 0x44444444, | 1383 | 0x44444444, 0x44444444, 0x44444444, 0x44444444, |
1384 | 0x10101010, 0x10101010, 0x10101010, 0x10101010, | 1384 | 0x10101010, 0x10101010, 0x10101010, 0x10101010, |
@@ -1405,7 +1405,7 @@ const u32 b43_ntab_channelest[] = { | |||
1405 | 0x10101010, 0x10101010, 0x10101010, 0x10101010, | 1405 | 0x10101010, 0x10101010, 0x10101010, 0x10101010, |
1406 | }; | 1406 | }; |
1407 | 1407 | ||
1408 | const u8 b43_ntab_estimatepowerlt0[] = { | 1408 | static const u8 b43_ntab_estimatepowerlt0[] = { |
1409 | 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, | 1409 | 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, |
1410 | 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, | 1410 | 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, |
1411 | 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, | 1411 | 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, |
@@ -1416,7 +1416,7 @@ const u8 b43_ntab_estimatepowerlt0[] = { | |||
1416 | 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, | 1416 | 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, |
1417 | }; | 1417 | }; |
1418 | 1418 | ||
1419 | const u8 b43_ntab_estimatepowerlt1[] = { | 1419 | static const u8 b43_ntab_estimatepowerlt1[] = { |
1420 | 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, | 1420 | 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, |
1421 | 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, | 1421 | 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, |
1422 | 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, | 1422 | 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, |
@@ -1427,14 +1427,14 @@ const u8 b43_ntab_estimatepowerlt1[] = { | |||
1427 | 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, | 1427 | 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, |
1428 | }; | 1428 | }; |
1429 | 1429 | ||
1430 | const u8 b43_ntab_framelookup[] = { | 1430 | static const u8 b43_ntab_framelookup[] = { |
1431 | 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, | 1431 | 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, |
1432 | 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, | 1432 | 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, |
1433 | 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, | 1433 | 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, |
1434 | 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, | 1434 | 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, |
1435 | }; | 1435 | }; |
1436 | 1436 | ||
1437 | const u32 b43_ntab_framestruct[] = { | 1437 | static const u32 b43_ntab_framestruct[] = { |
1438 | 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, | 1438 | 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, |
1439 | 0x09804506, 0x00100030, 0x09804507, 0x00100030, | 1439 | 0x09804506, 0x00100030, 0x09804507, 0x00100030, |
1440 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 1440 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
@@ -1645,7 +1645,7 @@ const u32 b43_ntab_framestruct[] = { | |||
1645 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 1645 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
1646 | }; | 1646 | }; |
1647 | 1647 | ||
1648 | const u32 b43_ntab_gainctl0[] = { | 1648 | static const u32 b43_ntab_gainctl0[] = { |
1649 | 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, | 1649 | 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, |
1650 | 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, | 1650 | 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, |
1651 | 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, | 1651 | 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, |
@@ -1680,7 +1680,7 @@ const u32 b43_ntab_gainctl0[] = { | |||
1680 | 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, | 1680 | 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, |
1681 | }; | 1681 | }; |
1682 | 1682 | ||
1683 | const u32 b43_ntab_gainctl1[] = { | 1683 | static const u32 b43_ntab_gainctl1[] = { |
1684 | 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, | 1684 | 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, |
1685 | 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, | 1685 | 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, |
1686 | 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, | 1686 | 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, |
@@ -1715,12 +1715,12 @@ const u32 b43_ntab_gainctl1[] = { | |||
1715 | 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, | 1715 | 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, |
1716 | }; | 1716 | }; |
1717 | 1717 | ||
1718 | const u32 b43_ntab_intlevel[] = { | 1718 | static const u32 b43_ntab_intlevel[] = { |
1719 | 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, | 1719 | 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, |
1720 | 0x00C1188D, 0x080024D2, 0x00000070, | 1720 | 0x00C1188D, 0x080024D2, 0x00000070, |
1721 | }; | 1721 | }; |
1722 | 1722 | ||
1723 | const u32 b43_ntab_iqlt0[] = { | 1723 | static const u32 b43_ntab_iqlt0[] = { |
1724 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1724 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1725 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1725 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1726 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1726 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
@@ -1755,7 +1755,7 @@ const u32 b43_ntab_iqlt0[] = { | |||
1755 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1755 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1756 | }; | 1756 | }; |
1757 | 1757 | ||
1758 | const u32 b43_ntab_iqlt1[] = { | 1758 | static const u32 b43_ntab_iqlt1[] = { |
1759 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1759 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1760 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1760 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1761 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1761 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
@@ -1790,7 +1790,7 @@ const u32 b43_ntab_iqlt1[] = { | |||
1790 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, | 1790 | 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, |
1791 | }; | 1791 | }; |
1792 | 1792 | ||
1793 | const u16 b43_ntab_loftlt0[] = { | 1793 | static const u16 b43_ntab_loftlt0[] = { |
1794 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, | 1794 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, |
1795 | 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, | 1795 | 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, |
1796 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, | 1796 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, |
@@ -1815,7 +1815,7 @@ const u16 b43_ntab_loftlt0[] = { | |||
1815 | 0x0002, 0x0103, | 1815 | 0x0002, 0x0103, |
1816 | }; | 1816 | }; |
1817 | 1817 | ||
1818 | const u16 b43_ntab_loftlt1[] = { | 1818 | static const u16 b43_ntab_loftlt1[] = { |
1819 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, | 1819 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, |
1820 | 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, | 1820 | 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, |
1821 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, | 1821 | 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, |
@@ -1840,7 +1840,7 @@ const u16 b43_ntab_loftlt1[] = { | |||
1840 | 0x0002, 0x0103, | 1840 | 0x0002, 0x0103, |
1841 | }; | 1841 | }; |
1842 | 1842 | ||
1843 | const u8 b43_ntab_mcs[] = { | 1843 | static const u8 b43_ntab_mcs[] = { |
1844 | 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, | 1844 | 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, |
1845 | 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, | 1845 | 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, |
1846 | 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, | 1846 | 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, |
@@ -1859,7 +1859,7 @@ const u8 b43_ntab_mcs[] = { | |||
1859 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 1859 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1860 | }; | 1860 | }; |
1861 | 1861 | ||
1862 | const u32 b43_ntab_noisevar10[] = { | 1862 | static const u32 b43_ntab_noisevar10[] = { |
1863 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1863 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1864 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1864 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1865 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1865 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
@@ -1926,7 +1926,7 @@ const u32 b43_ntab_noisevar10[] = { | |||
1926 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1926 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1927 | }; | 1927 | }; |
1928 | 1928 | ||
1929 | const u32 b43_ntab_noisevar11[] = { | 1929 | static const u32 b43_ntab_noisevar11[] = { |
1930 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1930 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1931 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1931 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1932 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1932 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
@@ -1993,7 +1993,7 @@ const u32 b43_ntab_noisevar11[] = { | |||
1993 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, | 1993 | 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, |
1994 | }; | 1994 | }; |
1995 | 1995 | ||
1996 | const u16 b43_ntab_pilot[] = { | 1996 | static const u16 b43_ntab_pilot[] = { |
1997 | 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, | 1997 | 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, |
1998 | 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, | 1998 | 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, |
1999 | 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, | 1999 | 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, |
@@ -2011,12 +2011,12 @@ const u16 b43_ntab_pilot[] = { | |||
2011 | 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, | 2011 | 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, |
2012 | }; | 2012 | }; |
2013 | 2013 | ||
2014 | const u32 b43_ntab_pilotlt[] = { | 2014 | static const u32 b43_ntab_pilotlt[] = { |
2015 | 0x76540123, 0x62407351, 0x76543201, 0x76540213, | 2015 | 0x76540123, 0x62407351, 0x76543201, 0x76540213, |
2016 | 0x76540123, 0x76430521, | 2016 | 0x76540123, 0x76430521, |
2017 | }; | 2017 | }; |
2018 | 2018 | ||
2019 | const u32 b43_ntab_tdi20a0[] = { | 2019 | static const u32 b43_ntab_tdi20a0[] = { |
2020 | 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, | 2020 | 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, |
2021 | 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, | 2021 | 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, |
2022 | 0x00020301, 0x00030504, 0x00040708, 0x0005090B, | 2022 | 0x00020301, 0x00030504, 0x00040708, 0x0005090B, |
@@ -2033,7 +2033,7 @@ const u32 b43_ntab_tdi20a0[] = { | |||
2033 | 0x00000000, 0x00000000, 0x00000000, | 2033 | 0x00000000, 0x00000000, 0x00000000, |
2034 | }; | 2034 | }; |
2035 | 2035 | ||
2036 | const u32 b43_ntab_tdi20a1[] = { | 2036 | static const u32 b43_ntab_tdi20a1[] = { |
2037 | 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, | 2037 | 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, |
2038 | 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, | 2038 | 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, |
2039 | 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, | 2039 | 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, |
@@ -2050,7 +2050,7 @@ const u32 b43_ntab_tdi20a1[] = { | |||
2050 | 0x00000000, 0x00000000, 0x00000000, | 2050 | 0x00000000, 0x00000000, 0x00000000, |
2051 | }; | 2051 | }; |
2052 | 2052 | ||
2053 | const u32 b43_ntab_tdi40a0[] = { | 2053 | static const u32 b43_ntab_tdi40a0[] = { |
2054 | 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, | 2054 | 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, |
2055 | 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, | 2055 | 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, |
2056 | 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, | 2056 | 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, |
@@ -2081,7 +2081,7 @@ const u32 b43_ntab_tdi40a0[] = { | |||
2081 | 0x00000000, 0x00000000, | 2081 | 0x00000000, 0x00000000, |
2082 | }; | 2082 | }; |
2083 | 2083 | ||
2084 | const u32 b43_ntab_tdi40a1[] = { | 2084 | static const u32 b43_ntab_tdi40a1[] = { |
2085 | 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, | 2085 | 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, |
2086 | 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, | 2086 | 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, |
2087 | 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, | 2087 | 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, |
@@ -2112,7 +2112,7 @@ const u32 b43_ntab_tdi40a1[] = { | |||
2112 | 0x00000000, 0x00000000, | 2112 | 0x00000000, 0x00000000, |
2113 | }; | 2113 | }; |
2114 | 2114 | ||
2115 | const u32 b43_ntab_tdtrn[] = { | 2115 | static const u32 b43_ntab_tdtrn[] = { |
2116 | 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, | 2116 | 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, |
2117 | 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, | 2117 | 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, |
2118 | 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, | 2118 | 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, |
@@ -2291,7 +2291,7 @@ const u32 b43_ntab_tdtrn[] = { | |||
2291 | 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, | 2291 | 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, |
2292 | }; | 2292 | }; |
2293 | 2293 | ||
2294 | const u32 b43_ntab_tmap[] = { | 2294 | static const u32 b43_ntab_tmap[] = { |
2295 | 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, | 2295 | 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, |
2296 | 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, | 2296 | 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, |
2297 | 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, | 2297 | 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, |
@@ -2406,6 +2406,483 @@ const u32 b43_ntab_tmap[] = { | |||
2406 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, | 2406 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, |
2407 | }; | 2407 | }; |
2408 | 2408 | ||
2409 | const u32 b43_ntab_tx_gain_rev0_1_2[] = { | ||
2410 | 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, | ||
2411 | 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, | ||
2412 | 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844, | ||
2413 | 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44, | ||
2414 | 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844, | ||
2415 | 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644, | ||
2416 | 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444, | ||
2417 | 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44, | ||
2418 | 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844, | ||
2419 | 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44, | ||
2420 | 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944, | ||
2421 | 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744, | ||
2422 | 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544, | ||
2423 | 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44, | ||
2424 | 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844, | ||
2425 | 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44, | ||
2426 | 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944, | ||
2427 | 0x03902942, 0x03902844, 0x03902842, 0x03902744, | ||
2428 | 0x03902742, 0x03902644, 0x03902642, 0x03902544, | ||
2429 | 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44, | ||
2430 | 0x03802a42, 0x03802944, 0x03802942, 0x03802844, | ||
2431 | 0x03802842, 0x03802744, 0x03802742, 0x03802644, | ||
2432 | 0x03802642, 0x03802544, 0x03802542, 0x03802444, | ||
2433 | 0x03802442, 0x03802344, 0x03802342, 0x03802244, | ||
2434 | 0x03802242, 0x03802144, 0x03802142, 0x03802044, | ||
2435 | 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44, | ||
2436 | 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44, | ||
2437 | 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44, | ||
2438 | 0x03801a42, 0x03801944, 0x03801942, 0x03801844, | ||
2439 | 0x03801842, 0x03801744, 0x03801742, 0x03801644, | ||
2440 | 0x03801642, 0x03801544, 0x03801542, 0x03801444, | ||
2441 | 0x03801442, 0x03801344, 0x03801342, 0x00002b00, | ||
2442 | }; | ||
2443 | |||
2444 | const u32 b43_ntab_tx_gain_rev3plus_2ghz[] = { | ||
2445 | 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, | ||
2446 | 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, | ||
2447 | 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, | ||
2448 | 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037, | ||
2449 | 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e, | ||
2450 | 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037, | ||
2451 | 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e, | ||
2452 | 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037, | ||
2453 | 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e, | ||
2454 | 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037, | ||
2455 | 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e, | ||
2456 | 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037, | ||
2457 | 0x19410044, 0x19410042, 0x19410040, 0x1941003e, | ||
2458 | 0x1941003c, 0x1941003b, 0x19410039, 0x19410037, | ||
2459 | 0x18410044, 0x18410042, 0x18410040, 0x1841003e, | ||
2460 | 0x1841003c, 0x1841003b, 0x18410039, 0x18410037, | ||
2461 | 0x17410044, 0x17410042, 0x17410040, 0x1741003e, | ||
2462 | 0x1741003c, 0x1741003b, 0x17410039, 0x17410037, | ||
2463 | 0x16410044, 0x16410042, 0x16410040, 0x1641003e, | ||
2464 | 0x1641003c, 0x1641003b, 0x16410039, 0x16410037, | ||
2465 | 0x15410044, 0x15410042, 0x15410040, 0x1541003e, | ||
2466 | 0x1541003c, 0x1541003b, 0x15410039, 0x15410037, | ||
2467 | 0x14410044, 0x14410042, 0x14410040, 0x1441003e, | ||
2468 | 0x1441003c, 0x1441003b, 0x14410039, 0x14410037, | ||
2469 | 0x13410044, 0x13410042, 0x13410040, 0x1341003e, | ||
2470 | 0x1341003c, 0x1341003b, 0x13410039, 0x13410037, | ||
2471 | 0x12410044, 0x12410042, 0x12410040, 0x1241003e, | ||
2472 | 0x1241003c, 0x1241003b, 0x12410039, 0x12410037, | ||
2473 | 0x11410044, 0x11410042, 0x11410040, 0x1141003e, | ||
2474 | 0x1141003c, 0x1141003b, 0x11410039, 0x11410037, | ||
2475 | 0x10410044, 0x10410042, 0x10410040, 0x1041003e, | ||
2476 | 0x1041003c, 0x1041003b, 0x10410039, 0x10410037, | ||
2477 | }; | ||
2478 | |||
2479 | const u32 b43_ntab_tx_gain_rev3_5ghz[] = { | ||
2480 | 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, | ||
2481 | 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, | ||
2482 | 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, | ||
2483 | 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037, | ||
2484 | 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e, | ||
2485 | 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037, | ||
2486 | 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e, | ||
2487 | 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037, | ||
2488 | 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e, | ||
2489 | 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037, | ||
2490 | 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e, | ||
2491 | 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037, | ||
2492 | 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e, | ||
2493 | 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037, | ||
2494 | 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e, | ||
2495 | 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037, | ||
2496 | 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e, | ||
2497 | 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037, | ||
2498 | 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e, | ||
2499 | 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037, | ||
2500 | 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e, | ||
2501 | 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037, | ||
2502 | 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e, | ||
2503 | 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037, | ||
2504 | 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e, | ||
2505 | 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037, | ||
2506 | 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e, | ||
2507 | 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037, | ||
2508 | 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e, | ||
2509 | 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037, | ||
2510 | 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e, | ||
2511 | 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037, | ||
2512 | }; | ||
2513 | |||
2514 | const u32 b43_ntab_tx_gain_rev4_5ghz[] = { | ||
2515 | 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, | ||
2516 | 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, | ||
2517 | 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, | ||
2518 | 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037, | ||
2519 | 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e, | ||
2520 | 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037, | ||
2521 | 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e, | ||
2522 | 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037, | ||
2523 | 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e, | ||
2524 | 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037, | ||
2525 | 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e, | ||
2526 | 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037, | ||
2527 | 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e, | ||
2528 | 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037, | ||
2529 | 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e, | ||
2530 | 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037, | ||
2531 | 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e, | ||
2532 | 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037, | ||
2533 | 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e, | ||
2534 | 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037, | ||
2535 | 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e, | ||
2536 | 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037, | ||
2537 | 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e, | ||
2538 | 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038, | ||
2539 | 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e, | ||
2540 | 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037, | ||
2541 | 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e, | ||
2542 | 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037, | ||
2543 | 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e, | ||
2544 | 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037, | ||
2545 | 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c, | ||
2546 | 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034, | ||
2547 | }; | ||
2548 | |||
2549 | const u32 b43_ntab_tx_gain_rev5plus_5ghz[] = { | ||
2550 | 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, | ||
2551 | 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, | ||
2552 | 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, | ||
2553 | 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a, | ||
2554 | 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e, | ||
2555 | 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a, | ||
2556 | 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e, | ||
2557 | 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037, | ||
2558 | 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040, | ||
2559 | 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a, | ||
2560 | 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c, | ||
2561 | 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038, | ||
2562 | 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b, | ||
2563 | 0x09620039, 0x09620037, 0x09620035, 0x09620033, | ||
2564 | 0x08620044, 0x08620042, 0x08620040, 0x0862003e, | ||
2565 | 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039, | ||
2566 | 0x07620043, 0x07620042, 0x07620040, 0x0762003f, | ||
2567 | 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039, | ||
2568 | 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b, | ||
2569 | 0x06620039, 0x06620037, 0x06620035, 0x06620033, | ||
2570 | 0x05620046, 0x05620044, 0x05620042, 0x05620040, | ||
2571 | 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039, | ||
2572 | 0x04620044, 0x04620042, 0x04620040, 0x0462003e, | ||
2573 | 0x0462003c, 0x0462003b, 0x04620039, 0x04620038, | ||
2574 | 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039, | ||
2575 | 0x03620038, 0x03620037, 0x03620035, 0x03620033, | ||
2576 | 0x0262004c, 0x0262004a, 0x02620048, 0x02620047, | ||
2577 | 0x02620046, 0x02620044, 0x02620043, 0x02620042, | ||
2578 | 0x0162004a, 0x01620048, 0x01620046, 0x01620044, | ||
2579 | 0x01620043, 0x01620042, 0x01620041, 0x01620040, | ||
2580 | 0x00620042, 0x00620040, 0x0062003e, 0x0062003c, | ||
2581 | 0x0062003b, 0x00620039, 0x00620037, 0x00620035, | ||
2582 | }; | ||
2583 | |||
2584 | const u32 txpwrctrl_tx_gain_ipa[] = { | ||
2585 | 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, | ||
2586 | 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, | ||
2587 | 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, | ||
2588 | 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025, | ||
2589 | 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029, | ||
2590 | 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025, | ||
2591 | 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029, | ||
2592 | 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025, | ||
2593 | 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029, | ||
2594 | 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025, | ||
2595 | 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029, | ||
2596 | 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025, | ||
2597 | 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029, | ||
2598 | 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025, | ||
2599 | 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029, | ||
2600 | 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025, | ||
2601 | 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029, | ||
2602 | 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025, | ||
2603 | 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029, | ||
2604 | 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025, | ||
2605 | 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029, | ||
2606 | 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025, | ||
2607 | 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029, | ||
2608 | 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025, | ||
2609 | 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029, | ||
2610 | 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025, | ||
2611 | 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029, | ||
2612 | 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025, | ||
2613 | 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029, | ||
2614 | 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025, | ||
2615 | 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029, | ||
2616 | 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025, | ||
2617 | }; | ||
2618 | |||
2619 | const u32 txpwrctrl_tx_gain_ipa_rev5[] = { | ||
2620 | 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, | ||
2621 | 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, | ||
2622 | 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, | ||
2623 | 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025, | ||
2624 | 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029, | ||
2625 | 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025, | ||
2626 | 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029, | ||
2627 | 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025, | ||
2628 | 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029, | ||
2629 | 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025, | ||
2630 | 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029, | ||
2631 | 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025, | ||
2632 | 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029, | ||
2633 | 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025, | ||
2634 | 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029, | ||
2635 | 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025, | ||
2636 | 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029, | ||
2637 | 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025, | ||
2638 | 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029, | ||
2639 | 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025, | ||
2640 | 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029, | ||
2641 | 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025, | ||
2642 | 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029, | ||
2643 | 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025, | ||
2644 | 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029, | ||
2645 | 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025, | ||
2646 | 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029, | ||
2647 | 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025, | ||
2648 | 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029, | ||
2649 | 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025, | ||
2650 | 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029, | ||
2651 | 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025, | ||
2652 | }; | ||
2653 | |||
2654 | const u32 txpwrctrl_tx_gain_ipa_rev6[] = { | ||
2655 | 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, | ||
2656 | 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, | ||
2657 | 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, | ||
2658 | 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025, | ||
2659 | 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029, | ||
2660 | 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025, | ||
2661 | 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029, | ||
2662 | 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025, | ||
2663 | 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029, | ||
2664 | 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025, | ||
2665 | 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029, | ||
2666 | 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025, | ||
2667 | 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029, | ||
2668 | 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025, | ||
2669 | 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029, | ||
2670 | 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025, | ||
2671 | 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029, | ||
2672 | 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025, | ||
2673 | 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029, | ||
2674 | 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025, | ||
2675 | 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029, | ||
2676 | 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025, | ||
2677 | 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029, | ||
2678 | 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025, | ||
2679 | 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029, | ||
2680 | 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025, | ||
2681 | 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029, | ||
2682 | 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025, | ||
2683 | 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029, | ||
2684 | 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025, | ||
2685 | 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029, | ||
2686 | 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025, | ||
2687 | }; | ||
2688 | |||
2689 | const u32 txpwrctrl_tx_gain_ipa_5g[] = { | ||
2690 | 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, | ||
2691 | 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, | ||
2692 | 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, | ||
2693 | 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022, | ||
2694 | 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025, | ||
2695 | 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027, | ||
2696 | 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023, | ||
2697 | 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027, | ||
2698 | 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022, | ||
2699 | 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025, | ||
2700 | 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021, | ||
2701 | 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026, | ||
2702 | 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022, | ||
2703 | 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026, | ||
2704 | 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022, | ||
2705 | 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026, | ||
2706 | 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022, | ||
2707 | 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026, | ||
2708 | 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022, | ||
2709 | 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026, | ||
2710 | 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021, | ||
2711 | 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026, | ||
2712 | 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029, | ||
2713 | 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024, | ||
2714 | 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027, | ||
2715 | 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023, | ||
2716 | 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026, | ||
2717 | 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022, | ||
2718 | 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025, | ||
2719 | 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027, | ||
2720 | 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022, | ||
2721 | 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f, | ||
2722 | }; | ||
2723 | |||
2724 | const u16 tbl_iqcal_gainparams[2][9][8] = { | ||
2725 | { | ||
2726 | { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 }, | ||
2727 | { 0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69 }, | ||
2728 | { 0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68 }, | ||
2729 | { 0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67 }, | ||
2730 | { 0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66 }, | ||
2731 | { 0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65 }, | ||
2732 | { 0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65 }, | ||
2733 | { 0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65 }, | ||
2734 | { 0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65 } | ||
2735 | }, | ||
2736 | { | ||
2737 | { 0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, | ||
2738 | { 0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79 }, | ||
2739 | { 0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79 }, | ||
2740 | { 0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78 }, | ||
2741 | { 0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78 }, | ||
2742 | { 0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78 }, | ||
2743 | { 0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78 }, | ||
2744 | { 0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78 }, | ||
2745 | { 0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78 } | ||
2746 | } | ||
2747 | }; | ||
2748 | |||
2749 | const struct nphy_txiqcal_ladder ladder_lo[] = { | ||
2750 | { 3, 0 }, | ||
2751 | { 4, 0 }, | ||
2752 | { 6, 0 }, | ||
2753 | { 9, 0 }, | ||
2754 | { 13, 0 }, | ||
2755 | { 18, 0 }, | ||
2756 | { 25, 0 }, | ||
2757 | { 25, 1 }, | ||
2758 | { 25, 2 }, | ||
2759 | { 25, 3 }, | ||
2760 | { 25, 4 }, | ||
2761 | { 25, 5 }, | ||
2762 | { 25, 6 }, | ||
2763 | { 25, 7 }, | ||
2764 | { 35, 7 }, | ||
2765 | { 50, 7 }, | ||
2766 | { 71, 7 }, | ||
2767 | { 100, 7 } | ||
2768 | }; | ||
2769 | |||
2770 | const struct nphy_txiqcal_ladder ladder_iq[] = { | ||
2771 | { 3, 0 }, | ||
2772 | { 4, 0 }, | ||
2773 | { 6, 0 }, | ||
2774 | { 9, 0 }, | ||
2775 | { 13, 0 }, | ||
2776 | { 18, 0 }, | ||
2777 | { 25, 0 }, | ||
2778 | { 35, 0 }, | ||
2779 | { 50, 0 }, | ||
2780 | { 71, 0 }, | ||
2781 | { 100, 0 }, | ||
2782 | { 100, 1 }, | ||
2783 | { 100, 2 }, | ||
2784 | { 100, 3 }, | ||
2785 | { 100, 4 }, | ||
2786 | { 100, 5 }, | ||
2787 | { 100, 6 }, | ||
2788 | { 100, 7 } | ||
2789 | }; | ||
2790 | |||
2791 | const u16 loscale[] = { | ||
2792 | 256, 256, 271, 271, | ||
2793 | 287, 256, 256, 271, | ||
2794 | 271, 287, 287, 304, | ||
2795 | 304, 256, 256, 271, | ||
2796 | 271, 287, 287, 304, | ||
2797 | 304, 322, 322, 341, | ||
2798 | 341, 362, 362, 383, | ||
2799 | 383, 256, 256, 271, | ||
2800 | 271, 287, 287, 304, | ||
2801 | 304, 322, 322, 256, | ||
2802 | 256, 271, 271, 287, | ||
2803 | 287, 304, 304, 322, | ||
2804 | 322, 341, 341, 362, | ||
2805 | 362, 256, 256, 271, | ||
2806 | 271, 287, 287, 304, | ||
2807 | 304, 322, 322, 256, | ||
2808 | 256, 271, 271, 287, | ||
2809 | 287, 304, 304, 322, | ||
2810 | 322, 341, 341, 362, | ||
2811 | 362, 256, 256, 271, | ||
2812 | 271, 287, 287, 304, | ||
2813 | 304, 322, 322, 341, | ||
2814 | 341, 362, 362, 383, | ||
2815 | 383, 406, 406, 430, | ||
2816 | 430, 455, 455, 482, | ||
2817 | 482, 511, 511, 541, | ||
2818 | 541, 573, 573, 607, | ||
2819 | 607, 643, 643, 681, | ||
2820 | 681, 722, 722, 764, | ||
2821 | 764, 810, 810, 858, | ||
2822 | 858, 908, 908, 962, | ||
2823 | 962, 1019, 1019, 256 | ||
2824 | }; | ||
2825 | |||
2826 | const u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { | ||
2827 | 0x0200, 0x0300, 0x0400, 0x0700, | ||
2828 | 0x0900, 0x0c00, 0x1200, 0x1201, | ||
2829 | 0x1202, 0x1203, 0x1204, 0x1205, | ||
2830 | 0x1206, 0x1207, 0x1907, 0x2307, | ||
2831 | 0x3207, 0x4707 | ||
2832 | }; | ||
2833 | |||
2834 | const u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { | ||
2835 | 0x0300, 0x0500, 0x0700, 0x0900, | ||
2836 | 0x0d00, 0x1100, 0x1900, 0x1901, | ||
2837 | 0x1902, 0x1903, 0x1904, 0x1905, | ||
2838 | 0x1906, 0x1907, 0x2407, 0x3207, | ||
2839 | 0x4607, 0x6407 | ||
2840 | }; | ||
2841 | |||
2842 | const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { | ||
2843 | 0x0100, 0x0200, 0x0400, 0x0700, | ||
2844 | 0x0900, 0x0c00, 0x1200, 0x1900, | ||
2845 | 0x2300, 0x3200, 0x4700, 0x4701, | ||
2846 | 0x4702, 0x4703, 0x4704, 0x4705, | ||
2847 | 0x4706, 0x4707 | ||
2848 | }; | ||
2849 | |||
2850 | const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { | ||
2851 | 0x0200, 0x0300, 0x0600, 0x0900, | ||
2852 | 0x0d00, 0x1100, 0x1900, 0x2400, | ||
2853 | 0x3200, 0x4600, 0x6400, 0x6401, | ||
2854 | 0x6402, 0x6403, 0x6404, 0x6405, | ||
2855 | 0x6406, 0x6407 | ||
2856 | }; | ||
2857 | |||
2858 | const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3] = { }; | ||
2859 | |||
2860 | const u16 tbl_tx_iqlo_cal_startcoefs[B43_NTAB_TX_IQLO_CAL_STARTCOEFS] = { }; | ||
2861 | |||
2862 | const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { | ||
2863 | 0x8423, 0x8323, 0x8073, 0x8256, | ||
2864 | 0x8045, 0x8223, 0x9423, 0x9323, | ||
2865 | 0x9073, 0x9256, 0x9045, 0x9223 | ||
2866 | }; | ||
2867 | |||
2868 | const u16 tbl_tx_iqlo_cal_cmds_recal[] = { | ||
2869 | 0x8101, 0x8253, 0x8053, 0x8234, | ||
2870 | 0x8034, 0x9101, 0x9253, 0x9053, | ||
2871 | 0x9234, 0x9034 | ||
2872 | }; | ||
2873 | |||
2874 | const u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { | ||
2875 | 0x8123, 0x8264, 0x8086, 0x8245, | ||
2876 | 0x8056, 0x9123, 0x9264, 0x9086, | ||
2877 | 0x9245, 0x9056 | ||
2878 | }; | ||
2879 | |||
2880 | const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { | ||
2881 | 0x8434, 0x8334, 0x8084, 0x8267, | ||
2882 | 0x8056, 0x8234, 0x9434, 0x9334, | ||
2883 | 0x9084, 0x9267, 0x9056, 0x9234 | ||
2884 | }; | ||
2885 | |||
2409 | static inline void assert_ntab_array_sizes(void) | 2886 | static inline void assert_ntab_array_sizes(void) |
2410 | { | 2887 | { |
2411 | #undef check | 2888 | #undef check |
@@ -2474,3 +2951,51 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) | |||
2474 | /* Some compiletime assertions... */ | 2951 | /* Some compiletime assertions... */ |
2475 | assert_ntab_array_sizes(); | 2952 | assert_ntab_array_sizes(); |
2476 | } | 2953 | } |
2954 | |||
2955 | #define ntab_upload(dev, offset, data) do { \ | ||
2956 | unsigned int i; \ | ||
2957 | for (i = 0; i < (offset##_SIZE); i++) \ | ||
2958 | b43_ntab_write(dev, (offset) + i, (data)[i]); \ | ||
2959 | } while (0) | ||
2960 | |||
2961 | void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev) | ||
2962 | { | ||
2963 | /* Static tables */ | ||
2964 | ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); | ||
2965 | ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); | ||
2966 | ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); | ||
2967 | ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); | ||
2968 | ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); | ||
2969 | ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); | ||
2970 | ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); | ||
2971 | ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); | ||
2972 | ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); | ||
2973 | ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); | ||
2974 | ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); | ||
2975 | ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); | ||
2976 | ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); | ||
2977 | ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); | ||
2978 | |||
2979 | /* Volatile tables */ | ||
2980 | ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); | ||
2981 | ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); | ||
2982 | ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); | ||
2983 | ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); | ||
2984 | ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); | ||
2985 | ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); | ||
2986 | ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); | ||
2987 | ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); | ||
2988 | ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); | ||
2989 | ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); | ||
2990 | ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); | ||
2991 | ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); | ||
2992 | } | ||
2993 | |||
2994 | void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev) | ||
2995 | { | ||
2996 | /* Static tables */ | ||
2997 | /* TODO */ | ||
2998 | |||
2999 | /* Volatile tables */ | ||
3000 | /* TODO */ | ||
3001 | } | ||
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h index 4d498b053ec7..51636d02f8b1 100644 --- a/drivers/net/wireless/b43/tables_nphy.h +++ b/drivers/net/wireless/b43/tables_nphy.h | |||
@@ -46,6 +46,11 @@ struct b43_nphy_channeltab_entry { | |||
46 | 46 | ||
47 | struct b43_wldev; | 47 | struct b43_wldev; |
48 | 48 | ||
49 | struct nphy_txiqcal_ladder { | ||
50 | u8 percent; | ||
51 | u8 g_env; | ||
52 | }; | ||
53 | |||
49 | /* Upload the default register value table. | 54 | /* Upload the default register value table. |
50 | * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz | 55 | * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz |
51 | * table is uploaded. If "ignore_uploadflag" is true, we upload any value | 56 | * table is uploaded. If "ignore_uploadflag" is true, we upload any value |
@@ -126,34 +131,46 @@ b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); | |||
126 | #define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ | 131 | #define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ |
127 | #define B43_NTAB_C1_LOFEEDTH_SIZE 128 | 132 | #define B43_NTAB_C1_LOFEEDTH_SIZE 128 |
128 | 133 | ||
129 | void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); | 134 | #define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18 |
135 | #define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18 | ||
136 | #define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_40_SIZE 18 | ||
137 | #define B43_NTAB_TX_IQLO_CAL_IQIMB_LADDER_20_SIZE 18 | ||
138 | #define B43_NTAB_TX_IQLO_CAL_STARTCOEFS_REV3 11 | ||
139 | #define B43_NTAB_TX_IQLO_CAL_STARTCOEFS 9 | ||
140 | #define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL_REV3 12 | ||
141 | #define B43_NTAB_TX_IQLO_CAL_CMDS_RECAL 10 | ||
142 | #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL 10 | ||
143 | #define B43_NTAB_TX_IQLO_CAL_CMDS_FULLCAL_REV3 12 | ||
130 | 144 | ||
131 | extern const u8 b43_ntab_adjustpower0[]; | 145 | void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); |
132 | extern const u8 b43_ntab_adjustpower1[]; | ||
133 | extern const u16 b43_ntab_bdi[]; | ||
134 | extern const u32 b43_ntab_channelest[]; | ||
135 | extern const u8 b43_ntab_estimatepowerlt0[]; | ||
136 | extern const u8 b43_ntab_estimatepowerlt1[]; | ||
137 | extern const u8 b43_ntab_framelookup[]; | ||
138 | extern const u32 b43_ntab_framestruct[]; | ||
139 | extern const u32 b43_ntab_gainctl0[]; | ||
140 | extern const u32 b43_ntab_gainctl1[]; | ||
141 | extern const u32 b43_ntab_intlevel[]; | ||
142 | extern const u32 b43_ntab_iqlt0[]; | ||
143 | extern const u32 b43_ntab_iqlt1[]; | ||
144 | extern const u16 b43_ntab_loftlt0[]; | ||
145 | extern const u16 b43_ntab_loftlt1[]; | ||
146 | extern const u8 b43_ntab_mcs[]; | ||
147 | extern const u32 b43_ntab_noisevar10[]; | ||
148 | extern const u32 b43_ntab_noisevar11[]; | ||
149 | extern const u16 b43_ntab_pilot[]; | ||
150 | extern const u32 b43_ntab_pilotlt[]; | ||
151 | extern const u32 b43_ntab_tdi20a0[]; | ||
152 | extern const u32 b43_ntab_tdi20a1[]; | ||
153 | extern const u32 b43_ntab_tdi40a0[]; | ||
154 | extern const u32 b43_ntab_tdi40a1[]; | ||
155 | extern const u32 b43_ntab_tdtrn[]; | ||
156 | extern const u32 b43_ntab_tmap[]; | ||
157 | 146 | ||
147 | void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev); | ||
148 | void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev); | ||
149 | |||
150 | extern const u32 b43_ntab_tx_gain_rev0_1_2[]; | ||
151 | extern const u32 b43_ntab_tx_gain_rev3plus_2ghz[]; | ||
152 | extern const u32 b43_ntab_tx_gain_rev3_5ghz[]; | ||
153 | extern const u32 b43_ntab_tx_gain_rev4_5ghz[]; | ||
154 | extern const u32 b43_ntab_tx_gain_rev5plus_5ghz[]; | ||
155 | |||
156 | extern const u32 txpwrctrl_tx_gain_ipa[]; | ||
157 | extern const u32 txpwrctrl_tx_gain_ipa_rev5[]; | ||
158 | extern const u32 txpwrctrl_tx_gain_ipa_rev6[]; | ||
159 | extern const u32 txpwrctrl_tx_gain_ipa_5g[]; | ||
160 | extern const u16 tbl_iqcal_gainparams[2][9][8]; | ||
161 | extern const struct nphy_txiqcal_ladder ladder_lo[]; | ||
162 | extern const struct nphy_txiqcal_ladder ladder_iq[]; | ||
163 | extern const u16 loscale[]; | ||
164 | |||
165 | extern const u16 tbl_tx_iqlo_cal_loft_ladder_40[]; | ||
166 | extern const u16 tbl_tx_iqlo_cal_loft_ladder_20[]; | ||
167 | extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_40[]; | ||
168 | extern const u16 tbl_tx_iqlo_cal_iqimb_ladder_20[]; | ||
169 | extern const u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[]; | ||
170 | extern const u16 tbl_tx_iqlo_cal_startcoefs[]; | ||
171 | extern const u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[]; | ||
172 | extern const u16 tbl_tx_iqlo_cal_cmds_recal[]; | ||
173 | extern const u16 tbl_tx_iqlo_cal_cmds_fullcal[]; | ||
174 | extern const u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[]; | ||
158 | 175 | ||
159 | #endif /* B43_TABLES_NPHY_H_ */ | 176 | #endif /* B43_TABLES_NPHY_H_ */ |
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index fbae264095cc..874a64a6c610 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c | |||
@@ -61,6 +61,8 @@ MODULE_AUTHOR("Michael Buesch"); | |||
61 | MODULE_LICENSE("GPL"); | 61 | MODULE_LICENSE("GPL"); |
62 | 62 | ||
63 | MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); | 63 | MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); |
64 | MODULE_FIRMWARE("b43legacy/ucode2.fw"); | ||
65 | MODULE_FIRMWARE("b43legacy/ucode4.fw"); | ||
64 | 66 | ||
65 | #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) | 67 | #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) |
66 | static int modparam_pio; | 68 | static int modparam_pio; |
@@ -3960,7 +3962,7 @@ static struct ssb_driver b43legacy_ssb_driver = { | |||
3960 | 3962 | ||
3961 | static void b43legacy_print_driverinfo(void) | 3963 | static void b43legacy_print_driverinfo(void) |
3962 | { | 3964 | { |
3963 | const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "", | 3965 | const char *feat_pci = "", *feat_leds = "", |
3964 | *feat_pio = "", *feat_dma = ""; | 3966 | *feat_pio = "", *feat_dma = ""; |
3965 | 3967 | ||
3966 | #ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT | 3968 | #ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT |
@@ -3969,9 +3971,6 @@ static void b43legacy_print_driverinfo(void) | |||
3969 | #ifdef CONFIG_B43LEGACY_LEDS | 3971 | #ifdef CONFIG_B43LEGACY_LEDS |
3970 | feat_leds = "L"; | 3972 | feat_leds = "L"; |
3971 | #endif | 3973 | #endif |
3972 | #ifdef CONFIG_B43LEGACY_RFKILL | ||
3973 | feat_rfkill = "R"; | ||
3974 | #endif | ||
3975 | #ifdef CONFIG_B43LEGACY_PIO | 3974 | #ifdef CONFIG_B43LEGACY_PIO |
3976 | feat_pio = "I"; | 3975 | feat_pio = "I"; |
3977 | #endif | 3976 | #endif |
@@ -3979,9 +3978,9 @@ static void b43legacy_print_driverinfo(void) | |||
3979 | feat_dma = "D"; | 3978 | feat_dma = "D"; |
3980 | #endif | 3979 | #endif |
3981 | printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " | 3980 | printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " |
3982 | "[ Features: %s%s%s%s%s, Firmware-ID: " | 3981 | "[ Features: %s%s%s%s, Firmware-ID: " |
3983 | B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", | 3982 | B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", |
3984 | feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); | 3983 | feat_pci, feat_leds, feat_pio, feat_dma); |
3985 | } | 3984 | } |
3986 | 3985 | ||
3987 | static int __init b43legacy_init(void) | 3986 | static int __init b43legacy_init(void) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 78706ce8b7ae..cee368d4859f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1961,7 +1961,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, | |||
1961 | struct ieee80211_tx_info *info; | 1961 | struct ieee80211_tx_info *info; |
1962 | struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | 1962 | struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; |
1963 | u32 status = le32_to_cpu(tx_resp->u.status); | 1963 | u32 status = le32_to_cpu(tx_resp->u.status); |
1964 | int tid = MAX_TID_COUNT; | 1964 | int tid = MAX_TID_COUNT - 1; |
1965 | int sta_id; | 1965 | int sta_id; |
1966 | int freed; | 1966 | int freed; |
1967 | u8 *qc = NULL; | 1967 | u8 *qc = NULL; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ec6b27689fa8..c3f8ec0a38b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -781,7 +781,7 @@ void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, | |||
781 | 781 | ||
782 | scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; | 782 | scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; |
783 | 783 | ||
784 | if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) | 784 | if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) |
785 | scd_bc_tbl[txq_id]. | 785 | scd_bc_tbl[txq_id]. |
786 | tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; | 786 | tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; |
787 | } | 787 | } |
@@ -800,12 +800,12 @@ void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, | |||
800 | if (txq_id != IWL_CMD_QUEUE_NUM) | 800 | if (txq_id != IWL_CMD_QUEUE_NUM) |
801 | sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; | 801 | sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; |
802 | 802 | ||
803 | bc_ent = cpu_to_le16(1 | (sta_id << 12)); | 803 | bc_ent = cpu_to_le16(1 | (sta_id << 12)); |
804 | scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; | 804 | scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; |
805 | 805 | ||
806 | if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) | 806 | if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) |
807 | scd_bc_tbl[txq_id]. | 807 | scd_bc_tbl[txq_id]. |
808 | tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; | 808 | tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; |
809 | } | 809 | } |
810 | 810 | ||
811 | static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, | 811 | static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c8fec626b714..344e99de4cab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -2955,6 +2955,9 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
2955 | return 0; | 2955 | return 0; |
2956 | else | 2956 | else |
2957 | return ret; | 2957 | return ret; |
2958 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
2959 | /* do nothing */ | ||
2960 | return -EOPNOTSUPP; | ||
2958 | default: | 2961 | default: |
2959 | IWL_DEBUG_HT(priv, "unknown\n"); | 2962 | IWL_DEBUG_HT(priv, "unknown\n"); |
2960 | return -EINVAL; | 2963 | return -EINVAL; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 28f3800c560e..3320cce3d57b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -120,7 +120,6 @@ enum { | |||
120 | CALIBRATION_COMPLETE_NOTIFICATION = 0x67, | 120 | CALIBRATION_COMPLETE_NOTIFICATION = 0x67, |
121 | 121 | ||
122 | /* 802.11h related */ | 122 | /* 802.11h related */ |
123 | RADAR_NOTIFICATION = 0x70, /* not used */ | ||
124 | REPLY_QUIET_CMD = 0x71, /* not used */ | 123 | REPLY_QUIET_CMD = 0x71, /* not used */ |
125 | REPLY_CHANNEL_SWITCH = 0x72, | 124 | REPLY_CHANNEL_SWITCH = 0x72, |
126 | CHANNEL_SWITCH_NOTIFICATION = 0x73, | 125 | CHANNEL_SWITCH_NOTIFICATION = 0x73, |
@@ -2984,7 +2983,7 @@ struct statistics_rx_ht_phy { | |||
2984 | __le32 agg_crc32_good; | 2983 | __le32 agg_crc32_good; |
2985 | __le32 agg_mpdu_cnt; | 2984 | __le32 agg_mpdu_cnt; |
2986 | __le32 agg_cnt; | 2985 | __le32 agg_cnt; |
2987 | __le32 reserved2; | 2986 | __le32 unsupport_mcs; |
2988 | } __attribute__ ((packed)); | 2987 | } __attribute__ ((packed)); |
2989 | 2988 | ||
2990 | #define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1) | 2989 | #define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1) |
@@ -3087,8 +3086,8 @@ struct statistics_div { | |||
3087 | } __attribute__ ((packed)); | 3086 | } __attribute__ ((packed)); |
3088 | 3087 | ||
3089 | struct statistics_general { | 3088 | struct statistics_general { |
3090 | __le32 temperature; | 3089 | __le32 temperature; /* radio temperature */ |
3091 | __le32 temperature_m; | 3090 | __le32 temperature_m; /* for 5000 and up, this is radio voltage */ |
3092 | struct statistics_dbg dbg; | 3091 | struct statistics_dbg dbg; |
3093 | __le32 sleep_time; | 3092 | __le32 sleep_time; |
3094 | __le32 slots_out; | 3093 | __le32 slots_out; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3ef86f6c7755..8deb83bfe182 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -63,8 +63,6 @@ | |||
63 | #ifndef __iwl_core_h__ | 63 | #ifndef __iwl_core_h__ |
64 | #define __iwl_core_h__ | 64 | #define __iwl_core_h__ |
65 | 65 | ||
66 | #include <generated/utsrelease.h> | ||
67 | |||
68 | /************************ | 66 | /************************ |
69 | * forward declarations * | 67 | * forward declarations * |
70 | ************************/ | 68 | ************************/ |
@@ -72,7 +70,7 @@ struct iwl_host_cmd; | |||
72 | struct iwl_cmd; | 70 | struct iwl_cmd; |
73 | 71 | ||
74 | 72 | ||
75 | #define IWLWIFI_VERSION UTS_RELEASE "-k" | 73 | #define IWLWIFI_VERSION "in-tree:" |
76 | #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" | 74 | #define DRV_COPYRIGHT "Copyright(c) 2003-2009 Intel Corporation" |
77 | #define DRV_AUTHOR "<ilw@linux.intel.com>" | 75 | #define DRV_AUTHOR "<ilw@linux.intel.com>" |
78 | 76 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ee5aed12a4b1..4a2ac9311ba8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
@@ -125,7 +125,7 @@ static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file, | |||
125 | char __user *user_buf, | 125 | char __user *user_buf, |
126 | size_t count, loff_t *ppos) { | 126 | size_t count, loff_t *ppos) { |
127 | 127 | ||
128 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 128 | struct iwl_priv *priv = file->private_data; |
129 | char *buf; | 129 | char *buf; |
130 | int pos = 0; | 130 | int pos = 0; |
131 | 131 | ||
@@ -184,7 +184,7 @@ static ssize_t iwl_dbgfs_rx_statistics_read(struct file *file, | |||
184 | char __user *user_buf, | 184 | char __user *user_buf, |
185 | size_t count, loff_t *ppos) { | 185 | size_t count, loff_t *ppos) { |
186 | 186 | ||
187 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 187 | struct iwl_priv *priv = file->private_data; |
188 | char *buf; | 188 | char *buf; |
189 | int pos = 0; | 189 | int pos = 0; |
190 | int cnt; | 190 | int cnt; |
@@ -232,7 +232,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, | |||
232 | ssize_t ret; | 232 | ssize_t ret; |
233 | int i; | 233 | int i; |
234 | int pos = 0; | 234 | int pos = 0; |
235 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 235 | struct iwl_priv *priv = file->private_data; |
236 | size_t bufsz; | 236 | size_t bufsz; |
237 | 237 | ||
238 | /* default is to dump the entire data segment */ | 238 | /* default is to dump the entire data segment */ |
@@ -306,7 +306,7 @@ static ssize_t iwl_dbgfs_sram_write(struct file *file, | |||
306 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, | 306 | static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, |
307 | size_t count, loff_t *ppos) | 307 | size_t count, loff_t *ppos) |
308 | { | 308 | { |
309 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 309 | struct iwl_priv *priv = file->private_data; |
310 | struct iwl_station_entry *station; | 310 | struct iwl_station_entry *station; |
311 | int max_sta = priv->hw_params.max_stations; | 311 | int max_sta = priv->hw_params.max_stations; |
312 | char *buf; | 312 | char *buf; |
@@ -376,7 +376,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, | |||
376 | loff_t *ppos) | 376 | loff_t *ppos) |
377 | { | 377 | { |
378 | ssize_t ret; | 378 | ssize_t ret; |
379 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 379 | struct iwl_priv *priv = file->private_data; |
380 | int pos = 0, ofs = 0, buf_size = 0; | 380 | int pos = 0, ofs = 0, buf_size = 0; |
381 | const u8 *ptr; | 381 | const u8 *ptr; |
382 | char *buf; | 382 | char *buf; |
@@ -464,7 +464,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, | |||
464 | static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, | 464 | static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, |
465 | size_t count, loff_t *ppos) | 465 | size_t count, loff_t *ppos) |
466 | { | 466 | { |
467 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 467 | struct iwl_priv *priv = file->private_data; |
468 | struct ieee80211_channel *channels = NULL; | 468 | struct ieee80211_channel *channels = NULL; |
469 | const struct ieee80211_supported_band *supp_band = NULL; | 469 | const struct ieee80211_supported_band *supp_band = NULL; |
470 | int pos = 0, i, bufsz = PAGE_SIZE; | 470 | int pos = 0, i, bufsz = PAGE_SIZE; |
@@ -537,7 +537,7 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, | |||
537 | char __user *user_buf, | 537 | char __user *user_buf, |
538 | size_t count, loff_t *ppos) { | 538 | size_t count, loff_t *ppos) { |
539 | 539 | ||
540 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 540 | struct iwl_priv *priv = file->private_data; |
541 | char buf[512]; | 541 | char buf[512]; |
542 | int pos = 0; | 542 | int pos = 0; |
543 | const size_t bufsz = sizeof(buf); | 543 | const size_t bufsz = sizeof(buf); |
@@ -585,7 +585,7 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file, | |||
585 | char __user *user_buf, | 585 | char __user *user_buf, |
586 | size_t count, loff_t *ppos) { | 586 | size_t count, loff_t *ppos) { |
587 | 587 | ||
588 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 588 | struct iwl_priv *priv = file->private_data; |
589 | int pos = 0; | 589 | int pos = 0; |
590 | int cnt = 0; | 590 | int cnt = 0; |
591 | char *buf; | 591 | char *buf; |
@@ -672,7 +672,7 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, | |||
672 | static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, | 672 | static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, |
673 | size_t count, loff_t *ppos) | 673 | size_t count, loff_t *ppos) |
674 | { | 674 | { |
675 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 675 | struct iwl_priv *priv = file->private_data; |
676 | int pos = 0, i; | 676 | int pos = 0, i; |
677 | char buf[256]; | 677 | char buf[256]; |
678 | const size_t bufsz = sizeof(buf); | 678 | const size_t bufsz = sizeof(buf); |
@@ -695,7 +695,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf, | |||
695 | static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, | 695 | static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf, |
696 | size_t count, loff_t *ppos) | 696 | size_t count, loff_t *ppos) |
697 | { | 697 | { |
698 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 698 | struct iwl_priv *priv = file->private_data; |
699 | int pos = 0; | 699 | int pos = 0; |
700 | char buf[256]; | 700 | char buf[256]; |
701 | const size_t bufsz = sizeof(buf); | 701 | const size_t bufsz = sizeof(buf); |
@@ -721,7 +721,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file, | |||
721 | char __user *user_buf, | 721 | char __user *user_buf, |
722 | size_t count, loff_t *ppos) | 722 | size_t count, loff_t *ppos) |
723 | { | 723 | { |
724 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 724 | struct iwl_priv *priv = file->private_data; |
725 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; | 725 | struct iwl_tt_mgmt *tt = &priv->thermal_throttle; |
726 | struct iwl_tt_restriction *restriction; | 726 | struct iwl_tt_restriction *restriction; |
727 | char buf[100]; | 727 | char buf[100]; |
@@ -781,7 +781,7 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, | |||
781 | char __user *user_buf, | 781 | char __user *user_buf, |
782 | size_t count, loff_t *ppos) | 782 | size_t count, loff_t *ppos) |
783 | { | 783 | { |
784 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 784 | struct iwl_priv *priv = file->private_data; |
785 | char buf[100]; | 785 | char buf[100]; |
786 | int pos = 0; | 786 | int pos = 0; |
787 | const size_t bufsz = sizeof(buf); | 787 | const size_t bufsz = sizeof(buf); |
@@ -838,7 +838,7 @@ static ssize_t iwl_dbgfs_sleep_level_override_read(struct file *file, | |||
838 | char __user *user_buf, | 838 | char __user *user_buf, |
839 | size_t count, loff_t *ppos) | 839 | size_t count, loff_t *ppos) |
840 | { | 840 | { |
841 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 841 | struct iwl_priv *priv = file->private_data; |
842 | char buf[10]; | 842 | char buf[10]; |
843 | int pos, value; | 843 | int pos, value; |
844 | const size_t bufsz = sizeof(buf); | 844 | const size_t bufsz = sizeof(buf); |
@@ -856,7 +856,7 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, | |||
856 | char __user *user_buf, | 856 | char __user *user_buf, |
857 | size_t count, loff_t *ppos) | 857 | size_t count, loff_t *ppos) |
858 | { | 858 | { |
859 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 859 | struct iwl_priv *priv = file->private_data; |
860 | char buf[200]; | 860 | char buf[200]; |
861 | int pos = 0, i; | 861 | int pos = 0, i; |
862 | const size_t bufsz = sizeof(buf); | 862 | const size_t bufsz = sizeof(buf); |
@@ -994,7 +994,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, | |||
994 | char __user *user_buf, | 994 | char __user *user_buf, |
995 | size_t count, loff_t *ppos) { | 995 | size_t count, loff_t *ppos) { |
996 | 996 | ||
997 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 997 | struct iwl_priv *priv = file->private_data; |
998 | struct iwl_tx_queue *txq; | 998 | struct iwl_tx_queue *txq; |
999 | struct iwl_queue *q; | 999 | struct iwl_queue *q; |
1000 | char *buf; | 1000 | char *buf; |
@@ -1040,7 +1040,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, | |||
1040 | char __user *user_buf, | 1040 | char __user *user_buf, |
1041 | size_t count, loff_t *ppos) { | 1041 | size_t count, loff_t *ppos) { |
1042 | 1042 | ||
1043 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1043 | struct iwl_priv *priv = file->private_data; |
1044 | struct iwl_rx_queue *rxq = &priv->rxq; | 1044 | struct iwl_rx_queue *rxq = &priv->rxq; |
1045 | char buf[256]; | 1045 | char buf[256]; |
1046 | int pos = 0; | 1046 | int pos = 0; |
@@ -1086,7 +1086,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, | |||
1086 | char __user *user_buf, | 1086 | char __user *user_buf, |
1087 | size_t count, loff_t *ppos) | 1087 | size_t count, loff_t *ppos) |
1088 | { | 1088 | { |
1089 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1089 | struct iwl_priv *priv = file->private_data; |
1090 | int pos = 0; | 1090 | int pos = 0; |
1091 | char *buf; | 1091 | char *buf; |
1092 | int bufsz = sizeof(struct statistics_rx_phy) * 20 + | 1092 | int bufsz = sizeof(struct statistics_rx_phy) * 20 + |
@@ -1387,6 +1387,9 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, | |||
1387 | accum_ht->agg_mpdu_cnt); | 1387 | accum_ht->agg_mpdu_cnt); |
1388 | pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", | 1388 | pos += scnprintf(buf + pos, bufsz - pos, "agg_cnt:\t\t%u\t\t\t%u\n", |
1389 | le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); | 1389 | le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt); |
1390 | pos += scnprintf(buf + pos, bufsz - pos, "unsupport_mcs:\t\t%u\t\t\t%u\n", | ||
1391 | le32_to_cpu(ht->unsupport_mcs), | ||
1392 | accum_ht->unsupport_mcs); | ||
1390 | 1393 | ||
1391 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | 1394 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); |
1392 | kfree(buf); | 1395 | kfree(buf); |
@@ -1397,7 +1400,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, | |||
1397 | char __user *user_buf, | 1400 | char __user *user_buf, |
1398 | size_t count, loff_t *ppos) | 1401 | size_t count, loff_t *ppos) |
1399 | { | 1402 | { |
1400 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1403 | struct iwl_priv *priv = file->private_data; |
1401 | int pos = 0; | 1404 | int pos = 0; |
1402 | char *buf; | 1405 | char *buf; |
1403 | int bufsz = (sizeof(struct statistics_tx) * 24) + 250; | 1406 | int bufsz = (sizeof(struct statistics_tx) * 24) + 250; |
@@ -1539,7 +1542,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, | |||
1539 | char __user *user_buf, | 1542 | char __user *user_buf, |
1540 | size_t count, loff_t *ppos) | 1543 | size_t count, loff_t *ppos) |
1541 | { | 1544 | { |
1542 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1545 | struct iwl_priv *priv = file->private_data; |
1543 | int pos = 0; | 1546 | int pos = 0; |
1544 | char *buf; | 1547 | char *buf; |
1545 | int bufsz = sizeof(struct statistics_general) * 4 + 250; | 1548 | int bufsz = sizeof(struct statistics_general) * 4 + 250; |
@@ -1630,7 +1633,7 @@ static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, | |||
1630 | char __user *user_buf, | 1633 | char __user *user_buf, |
1631 | size_t count, loff_t *ppos) { | 1634 | size_t count, loff_t *ppos) { |
1632 | 1635 | ||
1633 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1636 | struct iwl_priv *priv = file->private_data; |
1634 | int pos = 0; | 1637 | int pos = 0; |
1635 | int cnt = 0; | 1638 | int cnt = 0; |
1636 | char *buf; | 1639 | char *buf; |
@@ -1711,7 +1714,7 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file, | |||
1711 | char __user *user_buf, | 1714 | char __user *user_buf, |
1712 | size_t count, loff_t *ppos) { | 1715 | size_t count, loff_t *ppos) { |
1713 | 1716 | ||
1714 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1717 | struct iwl_priv *priv = file->private_data; |
1715 | int pos = 0; | 1718 | int pos = 0; |
1716 | int cnt = 0; | 1719 | int cnt = 0; |
1717 | char *buf; | 1720 | char *buf; |
@@ -1769,7 +1772,7 @@ static ssize_t iwl_dbgfs_tx_power_read(struct file *file, | |||
1769 | char __user *user_buf, | 1772 | char __user *user_buf, |
1770 | size_t count, loff_t *ppos) { | 1773 | size_t count, loff_t *ppos) { |
1771 | 1774 | ||
1772 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1775 | struct iwl_priv *priv = file->private_data; |
1773 | char buf[128]; | 1776 | char buf[128]; |
1774 | int pos = 0; | 1777 | int pos = 0; |
1775 | ssize_t ret; | 1778 | ssize_t ret; |
@@ -1820,7 +1823,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, | |||
1820 | char __user *user_buf, | 1823 | char __user *user_buf, |
1821 | size_t count, loff_t *ppos) | 1824 | size_t count, loff_t *ppos) |
1822 | { | 1825 | { |
1823 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | 1826 | struct iwl_priv *priv = file->private_data; |
1824 | char buf[60]; | 1827 | char buf[60]; |
1825 | int pos = 0; | 1828 | int pos = 0; |
1826 | const size_t bufsz = sizeof(buf); | 1829 | const size_t bufsz = sizeof(buf); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 30e9ea6d54ec..87d684efe110 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c | |||
@@ -58,7 +58,6 @@ const char *get_cmd_string(u8 cmd) | |||
58 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); | 58 | IWL_CMD(COEX_PRIORITY_TABLE_CMD); |
59 | IWL_CMD(COEX_MEDIUM_NOTIFICATION); | 59 | IWL_CMD(COEX_MEDIUM_NOTIFICATION); |
60 | IWL_CMD(COEX_EVENT_CMD); | 60 | IWL_CMD(COEX_EVENT_CMD); |
61 | IWL_CMD(RADAR_NOTIFICATION); | ||
62 | IWL_CMD(REPLY_QUIET_CMD); | 61 | IWL_CMD(REPLY_QUIET_CMD); |
63 | IWL_CMD(REPLY_CHANNEL_SWITCH); | 62 | IWL_CMD(REPLY_CHANNEL_SWITCH); |
64 | IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); | 63 | IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); |
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 842811142bef..79ffa3b98d73 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h | |||
@@ -268,7 +268,7 @@ struct iwm_priv { | |||
268 | 268 | ||
269 | struct sk_buff_head rx_list; | 269 | struct sk_buff_head rx_list; |
270 | struct list_head rx_tickets; | 270 | struct list_head rx_tickets; |
271 | struct list_head rx_packets[IWM_RX_ID_HASH + 1]; | 271 | struct list_head rx_packets[IWM_RX_ID_HASH]; |
272 | struct workqueue_struct *rx_wq; | 272 | struct workqueue_struct *rx_wq; |
273 | struct work_struct rx_worker; | 273 | struct work_struct rx_worker; |
274 | 274 | ||
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index c1c6ecd0c5b3..68546ca0ba37 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/net/wireless/mwl8k.c | 2 | * drivers/net/wireless/mwl8k.c |
3 | * Driver for Marvell TOPDOG 802.11 Wireless cards | 3 | * Driver for Marvell TOPDOG 802.11 Wireless cards |
4 | * | 4 | * |
5 | * Copyright (C) 2008-2009 Marvell Semiconductor Inc. | 5 | * Copyright (C) 2008, 2009, 2010 Marvell Semiconductor Inc. |
6 | * | 6 | * |
7 | * This file is licensed under the terms of the GNU General Public | 7 | * This file is licensed under the terms of the GNU General Public |
8 | * License version 2. This program is licensed "as is" without any | 8 | * License version 2. This program is licensed "as is" without any |
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" | 27 | #define MWL8K_DESC "Marvell TOPDOG(R) 802.11 Wireless Network Driver" |
28 | #define MWL8K_NAME KBUILD_MODNAME | 28 | #define MWL8K_NAME KBUILD_MODNAME |
29 | #define MWL8K_VERSION "0.10" | 29 | #define MWL8K_VERSION "0.12" |
30 | 30 | ||
31 | /* Register definitions */ | 31 | /* Register definitions */ |
32 | #define MWL8K_HIU_GEN_PTR 0x00000c10 | 32 | #define MWL8K_HIU_GEN_PTR 0x00000c10 |
@@ -141,6 +141,14 @@ struct mwl8k_priv { | |||
141 | /* hardware/firmware parameters */ | 141 | /* hardware/firmware parameters */ |
142 | bool ap_fw; | 142 | bool ap_fw; |
143 | struct rxd_ops *rxd_ops; | 143 | struct rxd_ops *rxd_ops; |
144 | struct ieee80211_supported_band band_24; | ||
145 | struct ieee80211_channel channels_24[14]; | ||
146 | struct ieee80211_rate rates_24[14]; | ||
147 | struct ieee80211_supported_band band_50; | ||
148 | struct ieee80211_channel channels_50[4]; | ||
149 | struct ieee80211_rate rates_50[9]; | ||
150 | u32 ap_macids_supported; | ||
151 | u32 sta_macids_supported; | ||
144 | 152 | ||
145 | /* firmware access */ | 153 | /* firmware access */ |
146 | struct mutex fw_mutex; | 154 | struct mutex fw_mutex; |
@@ -154,9 +162,9 @@ struct mwl8k_priv { | |||
154 | /* TX quiesce completion, protected by fw_mutex and tx_lock */ | 162 | /* TX quiesce completion, protected by fw_mutex and tx_lock */ |
155 | struct completion *tx_wait; | 163 | struct completion *tx_wait; |
156 | 164 | ||
157 | struct ieee80211_vif *vif; | 165 | /* List of interfaces. */ |
158 | 166 | u32 macids_used; | |
159 | struct ieee80211_channel *current_channel; | 167 | struct list_head vif_list; |
160 | 168 | ||
161 | /* power management status cookie from firmware */ | 169 | /* power management status cookie from firmware */ |
162 | u32 *cookie; | 170 | u32 *cookie; |
@@ -175,16 +183,15 @@ struct mwl8k_priv { | |||
175 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; | 183 | struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES]; |
176 | struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; | 184 | struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES]; |
177 | 185 | ||
178 | /* PHY parameters */ | ||
179 | struct ieee80211_supported_band band; | ||
180 | struct ieee80211_channel channels[14]; | ||
181 | struct ieee80211_rate rates[14]; | ||
182 | |||
183 | bool radio_on; | 186 | bool radio_on; |
184 | bool radio_short_preamble; | 187 | bool radio_short_preamble; |
185 | bool sniffer_enabled; | 188 | bool sniffer_enabled; |
186 | bool wmm_enabled; | 189 | bool wmm_enabled; |
187 | 190 | ||
191 | struct work_struct sta_notify_worker; | ||
192 | spinlock_t sta_notify_list_lock; | ||
193 | struct list_head sta_notify_list; | ||
194 | |||
188 | /* XXX need to convert this to handle multiple interfaces */ | 195 | /* XXX need to convert this to handle multiple interfaces */ |
189 | bool capture_beacon; | 196 | bool capture_beacon; |
190 | u8 capture_bssid[ETH_ALEN]; | 197 | u8 capture_bssid[ETH_ALEN]; |
@@ -198,28 +205,33 @@ struct mwl8k_priv { | |||
198 | */ | 205 | */ |
199 | struct work_struct finalize_join_worker; | 206 | struct work_struct finalize_join_worker; |
200 | 207 | ||
201 | /* Tasklet to reclaim TX descriptors and buffers after tx */ | 208 | /* Tasklet to perform TX reclaim. */ |
202 | struct tasklet_struct tx_reclaim_task; | 209 | struct tasklet_struct poll_tx_task; |
210 | |||
211 | /* Tasklet to perform RX. */ | ||
212 | struct tasklet_struct poll_rx_task; | ||
203 | }; | 213 | }; |
204 | 214 | ||
205 | /* Per interface specific private data */ | 215 | /* Per interface specific private data */ |
206 | struct mwl8k_vif { | 216 | struct mwl8k_vif { |
207 | /* Local MAC address. */ | 217 | struct list_head list; |
208 | u8 mac_addr[ETH_ALEN]; | 218 | struct ieee80211_vif *vif; |
209 | |||
210 | /* BSSID of AP. */ | ||
211 | u8 bssid[ETH_ALEN]; | ||
212 | 219 | ||
213 | /* Index into station database. Returned by UPDATE_STADB. */ | 220 | /* Firmware macid for this vif. */ |
214 | u8 peer_id; | 221 | int macid; |
215 | 222 | ||
216 | /* Non AMPDU sequence number assigned by driver */ | 223 | /* Non AMPDU sequence number assigned by driver. */ |
217 | u16 seqno; | 224 | u16 seqno; |
218 | }; | 225 | }; |
219 | |||
220 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) | 226 | #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) |
221 | 227 | ||
222 | static const struct ieee80211_channel mwl8k_channels[] = { | 228 | struct mwl8k_sta { |
229 | /* Index into station database. Returned by UPDATE_STADB. */ | ||
230 | u8 peer_id; | ||
231 | }; | ||
232 | #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv)) | ||
233 | |||
234 | static const struct ieee80211_channel mwl8k_channels_24[] = { | ||
223 | { .center_freq = 2412, .hw_value = 1, }, | 235 | { .center_freq = 2412, .hw_value = 1, }, |
224 | { .center_freq = 2417, .hw_value = 2, }, | 236 | { .center_freq = 2417, .hw_value = 2, }, |
225 | { .center_freq = 2422, .hw_value = 3, }, | 237 | { .center_freq = 2422, .hw_value = 3, }, |
@@ -236,7 +248,7 @@ static const struct ieee80211_channel mwl8k_channels[] = { | |||
236 | { .center_freq = 2484, .hw_value = 14, }, | 248 | { .center_freq = 2484, .hw_value = 14, }, |
237 | }; | 249 | }; |
238 | 250 | ||
239 | static const struct ieee80211_rate mwl8k_rates[] = { | 251 | static const struct ieee80211_rate mwl8k_rates_24[] = { |
240 | { .bitrate = 10, .hw_value = 2, }, | 252 | { .bitrate = 10, .hw_value = 2, }, |
241 | { .bitrate = 20, .hw_value = 4, }, | 253 | { .bitrate = 20, .hw_value = 4, }, |
242 | { .bitrate = 55, .hw_value = 11, }, | 254 | { .bitrate = 55, .hw_value = 11, }, |
@@ -253,8 +265,23 @@ static const struct ieee80211_rate mwl8k_rates[] = { | |||
253 | { .bitrate = 720, .hw_value = 144, }, | 265 | { .bitrate = 720, .hw_value = 144, }, |
254 | }; | 266 | }; |
255 | 267 | ||
256 | static const u8 mwl8k_rateids[12] = { | 268 | static const struct ieee80211_channel mwl8k_channels_50[] = { |
257 | 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, | 269 | { .center_freq = 5180, .hw_value = 36, }, |
270 | { .center_freq = 5200, .hw_value = 40, }, | ||
271 | { .center_freq = 5220, .hw_value = 44, }, | ||
272 | { .center_freq = 5240, .hw_value = 48, }, | ||
273 | }; | ||
274 | |||
275 | static const struct ieee80211_rate mwl8k_rates_50[] = { | ||
276 | { .bitrate = 60, .hw_value = 12, }, | ||
277 | { .bitrate = 90, .hw_value = 18, }, | ||
278 | { .bitrate = 120, .hw_value = 24, }, | ||
279 | { .bitrate = 180, .hw_value = 36, }, | ||
280 | { .bitrate = 240, .hw_value = 48, }, | ||
281 | { .bitrate = 360, .hw_value = 72, }, | ||
282 | { .bitrate = 480, .hw_value = 96, }, | ||
283 | { .bitrate = 540, .hw_value = 108, }, | ||
284 | { .bitrate = 720, .hw_value = 144, }, | ||
258 | }; | 285 | }; |
259 | 286 | ||
260 | /* Set or get info from Firmware */ | 287 | /* Set or get info from Firmware */ |
@@ -270,6 +297,7 @@ static const u8 mwl8k_rateids[12] = { | |||
270 | #define MWL8K_CMD_RADIO_CONTROL 0x001c | 297 | #define MWL8K_CMD_RADIO_CONTROL 0x001c |
271 | #define MWL8K_CMD_RF_TX_POWER 0x001e | 298 | #define MWL8K_CMD_RF_TX_POWER 0x001e |
272 | #define MWL8K_CMD_RF_ANTENNA 0x0020 | 299 | #define MWL8K_CMD_RF_ANTENNA 0x0020 |
300 | #define MWL8K_CMD_SET_BEACON 0x0100 /* per-vif */ | ||
273 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 | 301 | #define MWL8K_CMD_SET_PRE_SCAN 0x0107 |
274 | #define MWL8K_CMD_SET_POST_SCAN 0x0108 | 302 | #define MWL8K_CMD_SET_POST_SCAN 0x0108 |
275 | #define MWL8K_CMD_SET_RF_CHANNEL 0x010a | 303 | #define MWL8K_CMD_SET_RF_CHANNEL 0x010a |
@@ -283,8 +311,10 @@ static const u8 mwl8k_rateids[12] = { | |||
283 | #define MWL8K_CMD_MIMO_CONFIG 0x0125 | 311 | #define MWL8K_CMD_MIMO_CONFIG 0x0125 |
284 | #define MWL8K_CMD_USE_FIXED_RATE 0x0126 | 312 | #define MWL8K_CMD_USE_FIXED_RATE 0x0126 |
285 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 | 313 | #define MWL8K_CMD_ENABLE_SNIFFER 0x0150 |
286 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 | 314 | #define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */ |
287 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 | 315 | #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 |
316 | #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ | ||
317 | #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ | ||
288 | #define MWL8K_CMD_UPDATE_STADB 0x1123 | 318 | #define MWL8K_CMD_UPDATE_STADB 0x1123 |
289 | 319 | ||
290 | static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | 320 | static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) |
@@ -302,6 +332,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | |||
302 | MWL8K_CMDNAME(RADIO_CONTROL); | 332 | MWL8K_CMDNAME(RADIO_CONTROL); |
303 | MWL8K_CMDNAME(RF_TX_POWER); | 333 | MWL8K_CMDNAME(RF_TX_POWER); |
304 | MWL8K_CMDNAME(RF_ANTENNA); | 334 | MWL8K_CMDNAME(RF_ANTENNA); |
335 | MWL8K_CMDNAME(SET_BEACON); | ||
305 | MWL8K_CMDNAME(SET_PRE_SCAN); | 336 | MWL8K_CMDNAME(SET_PRE_SCAN); |
306 | MWL8K_CMDNAME(SET_POST_SCAN); | 337 | MWL8K_CMDNAME(SET_POST_SCAN); |
307 | MWL8K_CMDNAME(SET_RF_CHANNEL); | 338 | MWL8K_CMDNAME(SET_RF_CHANNEL); |
@@ -317,6 +348,8 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize) | |||
317 | MWL8K_CMDNAME(ENABLE_SNIFFER); | 348 | MWL8K_CMDNAME(ENABLE_SNIFFER); |
318 | MWL8K_CMDNAME(SET_MAC_ADDR); | 349 | MWL8K_CMDNAME(SET_MAC_ADDR); |
319 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); | 350 | MWL8K_CMDNAME(SET_RATEADAPT_MODE); |
351 | MWL8K_CMDNAME(BSS_START); | ||
352 | MWL8K_CMDNAME(SET_NEW_STN); | ||
320 | MWL8K_CMDNAME(UPDATE_STADB); | 353 | MWL8K_CMDNAME(UPDATE_STADB); |
321 | default: | 354 | default: |
322 | snprintf(buf, bufsize, "0x%x", cmd); | 355 | snprintf(buf, bufsize, "0x%x", cmd); |
@@ -389,13 +422,11 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv) | |||
389 | return 0; | 422 | return 0; |
390 | } | 423 | } |
391 | 424 | ||
392 | MODULE_FIRMWARE("mwl8k/helper_8687.fw"); | ||
393 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); | ||
394 | |||
395 | struct mwl8k_cmd_pkt { | 425 | struct mwl8k_cmd_pkt { |
396 | __le16 code; | 426 | __le16 code; |
397 | __le16 length; | 427 | __le16 length; |
398 | __le16 seq_num; | 428 | __u8 seq_num; |
429 | __u8 macid; | ||
399 | __le16 result; | 430 | __le16 result; |
400 | char payload[0]; | 431 | char payload[0]; |
401 | } __attribute__((packed)); | 432 | } __attribute__((packed)); |
@@ -453,6 +484,7 @@ static int mwl8k_load_fw_image(struct mwl8k_priv *priv, | |||
453 | 484 | ||
454 | cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); | 485 | cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD); |
455 | cmd->seq_num = 0; | 486 | cmd->seq_num = 0; |
487 | cmd->macid = 0; | ||
456 | cmd->result = 0; | 488 | cmd->result = 0; |
457 | 489 | ||
458 | done = 0; | 490 | done = 0; |
@@ -598,54 +630,6 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw) | |||
598 | } | 630 | } |
599 | 631 | ||
600 | 632 | ||
601 | /* | ||
602 | * Defines shared between transmission and reception. | ||
603 | */ | ||
604 | /* HT control fields for firmware */ | ||
605 | struct ewc_ht_info { | ||
606 | __le16 control1; | ||
607 | __le16 control2; | ||
608 | __le16 control3; | ||
609 | } __attribute__((packed)); | ||
610 | |||
611 | /* Firmware Station database operations */ | ||
612 | #define MWL8K_STA_DB_ADD_ENTRY 0 | ||
613 | #define MWL8K_STA_DB_MODIFY_ENTRY 1 | ||
614 | #define MWL8K_STA_DB_DEL_ENTRY 2 | ||
615 | #define MWL8K_STA_DB_FLUSH 3 | ||
616 | |||
617 | /* Peer Entry flags - used to define the type of the peer node */ | ||
618 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 | ||
619 | |||
620 | struct peer_capability_info { | ||
621 | /* Peer type - AP vs. STA. */ | ||
622 | __u8 peer_type; | ||
623 | |||
624 | /* Basic 802.11 capabilities from assoc resp. */ | ||
625 | __le16 basic_caps; | ||
626 | |||
627 | /* Set if peer supports 802.11n high throughput (HT). */ | ||
628 | __u8 ht_support; | ||
629 | |||
630 | /* Valid if HT is supported. */ | ||
631 | __le16 ht_caps; | ||
632 | __u8 extended_ht_caps; | ||
633 | struct ewc_ht_info ewc_info; | ||
634 | |||
635 | /* Legacy rate table. Intersection of our rates and peer rates. */ | ||
636 | __u8 legacy_rates[12]; | ||
637 | |||
638 | /* HT rate table. Intersection of our rates and peer rates. */ | ||
639 | __u8 ht_rates[16]; | ||
640 | __u8 pad[16]; | ||
641 | |||
642 | /* If set, interoperability mode, no proprietary extensions. */ | ||
643 | __u8 interop; | ||
644 | __u8 pad2; | ||
645 | __u8 station_id; | ||
646 | __le16 amsdu_enabled; | ||
647 | } __attribute__((packed)); | ||
648 | |||
649 | /* DMA header used by firmware and hardware. */ | 633 | /* DMA header used by firmware and hardware. */ |
650 | struct mwl8k_dma_data { | 634 | struct mwl8k_dma_data { |
651 | __le16 fwlen; | 635 | __le16 fwlen; |
@@ -779,15 +763,21 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status, | |||
779 | } else { | 763 | } else { |
780 | int i; | 764 | int i; |
781 | 765 | ||
782 | for (i = 0; i < ARRAY_SIZE(mwl8k_rates); i++) { | 766 | for (i = 0; i < ARRAY_SIZE(mwl8k_rates_24); i++) { |
783 | if (mwl8k_rates[i].hw_value == rxd->rate) { | 767 | if (mwl8k_rates_24[i].hw_value == rxd->rate) { |
784 | status->rate_idx = i; | 768 | status->rate_idx = i; |
785 | break; | 769 | break; |
786 | } | 770 | } |
787 | } | 771 | } |
788 | } | 772 | } |
789 | 773 | ||
790 | status->band = IEEE80211_BAND_2GHZ; | 774 | if (rxd->channel > 14) { |
775 | status->band = IEEE80211_BAND_5GHZ; | ||
776 | if (!(status->flag & RX_FLAG_HT)) | ||
777 | status->rate_idx -= 5; | ||
778 | } else { | ||
779 | status->band = IEEE80211_BAND_2GHZ; | ||
780 | } | ||
791 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | 781 | status->freq = ieee80211_channel_to_frequency(rxd->channel); |
792 | 782 | ||
793 | *qos = rxd->qos_control; | 783 | *qos = rxd->qos_control; |
@@ -878,7 +868,13 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status, | |||
878 | if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) | 868 | if (rate_info & MWL8K_STA_RATE_INFO_MCS_FORMAT) |
879 | status->flag |= RX_FLAG_HT; | 869 | status->flag |= RX_FLAG_HT; |
880 | 870 | ||
881 | status->band = IEEE80211_BAND_2GHZ; | 871 | if (rxd->channel > 14) { |
872 | status->band = IEEE80211_BAND_5GHZ; | ||
873 | if (!(status->flag & RX_FLAG_HT)) | ||
874 | status->rate_idx -= 5; | ||
875 | } else { | ||
876 | status->band = IEEE80211_BAND_2GHZ; | ||
877 | } | ||
882 | status->freq = ieee80211_channel_to_frequency(rxd->channel); | 878 | status->freq = ieee80211_channel_to_frequency(rxd->channel); |
883 | 879 | ||
884 | *qos = rxd->qos_control; | 880 | *qos = rxd->qos_control; |
@@ -1225,7 +1221,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw) | |||
1225 | /* | 1221 | /* |
1226 | * Must be called with priv->fw_mutex held and tx queues stopped. | 1222 | * Must be called with priv->fw_mutex held and tx queues stopped. |
1227 | */ | 1223 | */ |
1228 | #define MWL8K_TX_WAIT_TIMEOUT_MS 1000 | 1224 | #define MWL8K_TX_WAIT_TIMEOUT_MS 5000 |
1229 | 1225 | ||
1230 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | 1226 | static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) |
1231 | { | 1227 | { |
@@ -1269,8 +1265,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1269 | } | 1265 | } |
1270 | 1266 | ||
1271 | if (priv->pending_tx_pkts < oldcount) { | 1267 | if (priv->pending_tx_pkts < oldcount) { |
1272 | printk(KERN_NOTICE "%s: timeout waiting for tx " | 1268 | printk(KERN_NOTICE "%s: waiting for tx rings " |
1273 | "rings to drain (%d -> %d pkts), retrying\n", | 1269 | "to drain (%d -> %d pkts)\n", |
1274 | wiphy_name(hw->wiphy), oldcount, | 1270 | wiphy_name(hw->wiphy), oldcount, |
1275 | priv->pending_tx_pkts); | 1271 | priv->pending_tx_pkts); |
1276 | retry = 1; | 1272 | retry = 1; |
@@ -1295,13 +1291,15 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1295 | MWL8K_TXD_STATUS_OK_RETRY | \ | 1291 | MWL8K_TXD_STATUS_OK_RETRY | \ |
1296 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) | 1292 | MWL8K_TXD_STATUS_OK_MORE_RETRY)) |
1297 | 1293 | ||
1298 | static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) | 1294 | static int |
1295 | mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) | ||
1299 | { | 1296 | { |
1300 | struct mwl8k_priv *priv = hw->priv; | 1297 | struct mwl8k_priv *priv = hw->priv; |
1301 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1298 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1302 | int wake = 0; | 1299 | int processed; |
1303 | 1300 | ||
1304 | while (txq->stats.len > 0) { | 1301 | processed = 0; |
1302 | while (txq->stats.len > 0 && limit--) { | ||
1305 | int tx; | 1303 | int tx; |
1306 | struct mwl8k_tx_desc *tx_desc; | 1304 | struct mwl8k_tx_desc *tx_desc; |
1307 | unsigned long addr; | 1305 | unsigned long addr; |
@@ -1348,11 +1346,13 @@ static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force) | |||
1348 | 1346 | ||
1349 | ieee80211_tx_status_irqsafe(hw, skb); | 1347 | ieee80211_tx_status_irqsafe(hw, skb); |
1350 | 1348 | ||
1351 | wake = 1; | 1349 | processed++; |
1352 | } | 1350 | } |
1353 | 1351 | ||
1354 | if (wake && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) | 1352 | if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex)) |
1355 | ieee80211_wake_queue(hw, index); | 1353 | ieee80211_wake_queue(hw, index); |
1354 | |||
1355 | return processed; | ||
1356 | } | 1356 | } |
1357 | 1357 | ||
1358 | /* must be called only when the card's transmit is completely halted */ | 1358 | /* must be called only when the card's transmit is completely halted */ |
@@ -1361,7 +1361,7 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index) | |||
1361 | struct mwl8k_priv *priv = hw->priv; | 1361 | struct mwl8k_priv *priv = hw->priv; |
1362 | struct mwl8k_tx_queue *txq = priv->txq + index; | 1362 | struct mwl8k_tx_queue *txq = priv->txq + index; |
1363 | 1363 | ||
1364 | mwl8k_txq_reclaim(hw, index, 1); | 1364 | mwl8k_txq_reclaim(hw, index, INT_MAX, 1); |
1365 | 1365 | ||
1366 | kfree(txq->skb); | 1366 | kfree(txq->skb); |
1367 | txq->skb = NULL; | 1367 | txq->skb = NULL; |
@@ -1399,11 +1399,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1399 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); | 1399 | mwl8k_vif = MWL8K_VIF(tx_info->control.vif); |
1400 | 1400 | ||
1401 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 1401 | if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
1402 | u16 seqno = mwl8k_vif->seqno; | ||
1403 | |||
1404 | wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | 1402 | wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); |
1405 | wh->seq_ctrl |= cpu_to_le16(seqno << 4); | 1403 | wh->seq_ctrl |= cpu_to_le16(mwl8k_vif->seqno); |
1406 | mwl8k_vif->seqno = seqno++ % 4096; | 1404 | mwl8k_vif->seqno += 0x10; |
1407 | } | 1405 | } |
1408 | 1406 | ||
1409 | /* Setup firmware control bit fields for each frame type. */ | 1407 | /* Setup firmware control bit fields for each frame type. */ |
@@ -1449,7 +1447,10 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) | |||
1449 | tx->pkt_phys_addr = cpu_to_le32(dma); | 1447 | tx->pkt_phys_addr = cpu_to_le32(dma); |
1450 | tx->pkt_len = cpu_to_le16(skb->len); | 1448 | tx->pkt_len = cpu_to_le16(skb->len); |
1451 | tx->rate_info = 0; | 1449 | tx->rate_info = 0; |
1452 | tx->peer_id = mwl8k_vif->peer_id; | 1450 | if (!priv->ap_fw && tx_info->control.sta != NULL) |
1451 | tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; | ||
1452 | else | ||
1453 | tx->peer_id = 0; | ||
1453 | wmb(); | 1454 | wmb(); |
1454 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); | 1455 | tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); |
1455 | 1456 | ||
@@ -1602,6 +1603,56 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) | |||
1602 | return rc; | 1603 | return rc; |
1603 | } | 1604 | } |
1604 | 1605 | ||
1606 | static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, | ||
1607 | struct ieee80211_vif *vif, | ||
1608 | struct mwl8k_cmd_pkt *cmd) | ||
1609 | { | ||
1610 | if (vif != NULL) | ||
1611 | cmd->macid = MWL8K_VIF(vif)->macid; | ||
1612 | return mwl8k_post_cmd(hw, cmd); | ||
1613 | } | ||
1614 | |||
1615 | /* | ||
1616 | * Setup code shared between STA and AP firmware images. | ||
1617 | */ | ||
1618 | static void mwl8k_setup_2ghz_band(struct ieee80211_hw *hw) | ||
1619 | { | ||
1620 | struct mwl8k_priv *priv = hw->priv; | ||
1621 | |||
1622 | BUILD_BUG_ON(sizeof(priv->channels_24) != sizeof(mwl8k_channels_24)); | ||
1623 | memcpy(priv->channels_24, mwl8k_channels_24, sizeof(mwl8k_channels_24)); | ||
1624 | |||
1625 | BUILD_BUG_ON(sizeof(priv->rates_24) != sizeof(mwl8k_rates_24)); | ||
1626 | memcpy(priv->rates_24, mwl8k_rates_24, sizeof(mwl8k_rates_24)); | ||
1627 | |||
1628 | priv->band_24.band = IEEE80211_BAND_2GHZ; | ||
1629 | priv->band_24.channels = priv->channels_24; | ||
1630 | priv->band_24.n_channels = ARRAY_SIZE(mwl8k_channels_24); | ||
1631 | priv->band_24.bitrates = priv->rates_24; | ||
1632 | priv->band_24.n_bitrates = ARRAY_SIZE(mwl8k_rates_24); | ||
1633 | |||
1634 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band_24; | ||
1635 | } | ||
1636 | |||
1637 | static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) | ||
1638 | { | ||
1639 | struct mwl8k_priv *priv = hw->priv; | ||
1640 | |||
1641 | BUILD_BUG_ON(sizeof(priv->channels_50) != sizeof(mwl8k_channels_50)); | ||
1642 | memcpy(priv->channels_50, mwl8k_channels_50, sizeof(mwl8k_channels_50)); | ||
1643 | |||
1644 | BUILD_BUG_ON(sizeof(priv->rates_50) != sizeof(mwl8k_rates_50)); | ||
1645 | memcpy(priv->rates_50, mwl8k_rates_50, sizeof(mwl8k_rates_50)); | ||
1646 | |||
1647 | priv->band_50.band = IEEE80211_BAND_5GHZ; | ||
1648 | priv->band_50.channels = priv->channels_50; | ||
1649 | priv->band_50.n_channels = ARRAY_SIZE(mwl8k_channels_50); | ||
1650 | priv->band_50.bitrates = priv->rates_50; | ||
1651 | priv->band_50.n_bitrates = ARRAY_SIZE(mwl8k_rates_50); | ||
1652 | |||
1653 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->band_50; | ||
1654 | } | ||
1655 | |||
1605 | /* | 1656 | /* |
1606 | * CMD_GET_HW_SPEC (STA version). | 1657 | * CMD_GET_HW_SPEC (STA version). |
1607 | */ | 1658 | */ |
@@ -1624,6 +1675,89 @@ struct mwl8k_cmd_get_hw_spec_sta { | |||
1624 | __le32 total_rxd; | 1675 | __le32 total_rxd; |
1625 | } __attribute__((packed)); | 1676 | } __attribute__((packed)); |
1626 | 1677 | ||
1678 | #define MWL8K_CAP_MAX_AMSDU 0x20000000 | ||
1679 | #define MWL8K_CAP_GREENFIELD 0x08000000 | ||
1680 | #define MWL8K_CAP_AMPDU 0x04000000 | ||
1681 | #define MWL8K_CAP_RX_STBC 0x01000000 | ||
1682 | #define MWL8K_CAP_TX_STBC 0x00800000 | ||
1683 | #define MWL8K_CAP_SHORTGI_40MHZ 0x00400000 | ||
1684 | #define MWL8K_CAP_SHORTGI_20MHZ 0x00200000 | ||
1685 | #define MWL8K_CAP_RX_ANTENNA_MASK 0x000e0000 | ||
1686 | #define MWL8K_CAP_TX_ANTENNA_MASK 0x0001c000 | ||
1687 | #define MWL8K_CAP_DELAY_BA 0x00003000 | ||
1688 | #define MWL8K_CAP_MIMO 0x00000200 | ||
1689 | #define MWL8K_CAP_40MHZ 0x00000100 | ||
1690 | #define MWL8K_CAP_BAND_MASK 0x00000007 | ||
1691 | #define MWL8K_CAP_5GHZ 0x00000004 | ||
1692 | #define MWL8K_CAP_2GHZ4 0x00000001 | ||
1693 | |||
1694 | static void | ||
1695 | mwl8k_set_ht_caps(struct ieee80211_hw *hw, | ||
1696 | struct ieee80211_supported_band *band, u32 cap) | ||
1697 | { | ||
1698 | int rx_streams; | ||
1699 | int tx_streams; | ||
1700 | |||
1701 | band->ht_cap.ht_supported = 1; | ||
1702 | |||
1703 | if (cap & MWL8K_CAP_MAX_AMSDU) | ||
1704 | band->ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; | ||
1705 | if (cap & MWL8K_CAP_GREENFIELD) | ||
1706 | band->ht_cap.cap |= IEEE80211_HT_CAP_GRN_FLD; | ||
1707 | if (cap & MWL8K_CAP_AMPDU) { | ||
1708 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | ||
1709 | band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | ||
1710 | band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; | ||
1711 | } | ||
1712 | if (cap & MWL8K_CAP_RX_STBC) | ||
1713 | band->ht_cap.cap |= IEEE80211_HT_CAP_RX_STBC; | ||
1714 | if (cap & MWL8K_CAP_TX_STBC) | ||
1715 | band->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; | ||
1716 | if (cap & MWL8K_CAP_SHORTGI_40MHZ) | ||
1717 | band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; | ||
1718 | if (cap & MWL8K_CAP_SHORTGI_20MHZ) | ||
1719 | band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; | ||
1720 | if (cap & MWL8K_CAP_DELAY_BA) | ||
1721 | band->ht_cap.cap |= IEEE80211_HT_CAP_DELAY_BA; | ||
1722 | if (cap & MWL8K_CAP_40MHZ) | ||
1723 | band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
1724 | |||
1725 | rx_streams = hweight32(cap & MWL8K_CAP_RX_ANTENNA_MASK); | ||
1726 | tx_streams = hweight32(cap & MWL8K_CAP_TX_ANTENNA_MASK); | ||
1727 | |||
1728 | band->ht_cap.mcs.rx_mask[0] = 0xff; | ||
1729 | if (rx_streams >= 2) | ||
1730 | band->ht_cap.mcs.rx_mask[1] = 0xff; | ||
1731 | if (rx_streams >= 3) | ||
1732 | band->ht_cap.mcs.rx_mask[2] = 0xff; | ||
1733 | band->ht_cap.mcs.rx_mask[4] = 0x01; | ||
1734 | band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | ||
1735 | |||
1736 | if (rx_streams != tx_streams) { | ||
1737 | band->ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | ||
1738 | band->ht_cap.mcs.tx_params |= (tx_streams - 1) << | ||
1739 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | ||
1740 | } | ||
1741 | } | ||
1742 | |||
1743 | static void | ||
1744 | mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps) | ||
1745 | { | ||
1746 | struct mwl8k_priv *priv = hw->priv; | ||
1747 | |||
1748 | if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) { | ||
1749 | mwl8k_setup_2ghz_band(hw); | ||
1750 | if (caps & MWL8K_CAP_MIMO) | ||
1751 | mwl8k_set_ht_caps(hw, &priv->band_24, caps); | ||
1752 | } | ||
1753 | |||
1754 | if (caps & MWL8K_CAP_5GHZ) { | ||
1755 | mwl8k_setup_5ghz_band(hw); | ||
1756 | if (caps & MWL8K_CAP_MIMO) | ||
1757 | mwl8k_set_ht_caps(hw, &priv->band_50, caps); | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1627 | static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | 1761 | static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) |
1628 | { | 1762 | { |
1629 | struct mwl8k_priv *priv = hw->priv; | 1763 | struct mwl8k_priv *priv = hw->priv; |
@@ -1654,6 +1788,9 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | |||
1654 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | 1788 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); |
1655 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 1789 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
1656 | priv->hw_rev = cmd->hw_rev; | 1790 | priv->hw_rev = cmd->hw_rev; |
1791 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); | ||
1792 | priv->ap_macids_supported = 0x00000000; | ||
1793 | priv->sta_macids_supported = 0x00000001; | ||
1657 | } | 1794 | } |
1658 | 1795 | ||
1659 | kfree(cmd); | 1796 | kfree(cmd); |
@@ -1707,6 +1844,9 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
1707 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); | 1844 | priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs); |
1708 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 1845 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
1709 | priv->hw_rev = cmd->hw_rev; | 1846 | priv->hw_rev = cmd->hw_rev; |
1847 | mwl8k_setup_2ghz_band(hw); | ||
1848 | priv->ap_macids_supported = 0x000000ff; | ||
1849 | priv->sta_macids_supported = 0x00000000; | ||
1710 | 1850 | ||
1711 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | 1851 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; |
1712 | iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); | 1852 | iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); |
@@ -1752,7 +1892,9 @@ struct mwl8k_cmd_set_hw_spec { | |||
1752 | __le32 total_rxd; | 1892 | __le32 total_rxd; |
1753 | } __attribute__((packed)); | 1893 | } __attribute__((packed)); |
1754 | 1894 | ||
1755 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 | 1895 | #define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 |
1896 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020 | ||
1897 | #define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010 | ||
1756 | 1898 | ||
1757 | static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | 1899 | static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) |
1758 | { | 1900 | { |
@@ -1773,7 +1915,9 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) | |||
1773 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); | 1915 | cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); |
1774 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 1916 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
1775 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); | 1917 | cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); |
1776 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); | 1918 | cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | |
1919 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | | ||
1920 | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); | ||
1777 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); | 1921 | cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); |
1778 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); | 1922 | cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); |
1779 | 1923 | ||
@@ -2011,6 +2155,36 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) | |||
2011 | } | 2155 | } |
2012 | 2156 | ||
2013 | /* | 2157 | /* |
2158 | * CMD_SET_BEACON. | ||
2159 | */ | ||
2160 | struct mwl8k_cmd_set_beacon { | ||
2161 | struct mwl8k_cmd_pkt header; | ||
2162 | __le16 beacon_len; | ||
2163 | __u8 beacon[0]; | ||
2164 | }; | ||
2165 | |||
2166 | static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, | ||
2167 | struct ieee80211_vif *vif, u8 *beacon, int len) | ||
2168 | { | ||
2169 | struct mwl8k_cmd_set_beacon *cmd; | ||
2170 | int rc; | ||
2171 | |||
2172 | cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL); | ||
2173 | if (cmd == NULL) | ||
2174 | return -ENOMEM; | ||
2175 | |||
2176 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON); | ||
2177 | cmd->header.length = cpu_to_le16(sizeof(*cmd) + len); | ||
2178 | cmd->beacon_len = cpu_to_le16(len); | ||
2179 | memcpy(cmd->beacon, beacon, len); | ||
2180 | |||
2181 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
2182 | kfree(cmd); | ||
2183 | |||
2184 | return rc; | ||
2185 | } | ||
2186 | |||
2187 | /* | ||
2014 | * CMD_SET_PRE_SCAN. | 2188 | * CMD_SET_PRE_SCAN. |
2015 | */ | 2189 | */ |
2016 | struct mwl8k_cmd_set_pre_scan { | 2190 | struct mwl8k_cmd_set_pre_scan { |
@@ -2045,7 +2219,7 @@ struct mwl8k_cmd_set_post_scan { | |||
2045 | } __attribute__((packed)); | 2219 | } __attribute__((packed)); |
2046 | 2220 | ||
2047 | static int | 2221 | static int |
2048 | mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 *mac) | 2222 | mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac) |
2049 | { | 2223 | { |
2050 | struct mwl8k_cmd_set_post_scan *cmd; | 2224 | struct mwl8k_cmd_set_post_scan *cmd; |
2051 | int rc; | 2225 | int rc; |
@@ -2076,8 +2250,9 @@ struct mwl8k_cmd_set_rf_channel { | |||
2076 | } __attribute__((packed)); | 2250 | } __attribute__((packed)); |
2077 | 2251 | ||
2078 | static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, | 2252 | static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, |
2079 | struct ieee80211_channel *channel) | 2253 | struct ieee80211_conf *conf) |
2080 | { | 2254 | { |
2255 | struct ieee80211_channel *channel = conf->channel; | ||
2081 | struct mwl8k_cmd_set_rf_channel *cmd; | 2256 | struct mwl8k_cmd_set_rf_channel *cmd; |
2082 | int rc; | 2257 | int rc; |
2083 | 2258 | ||
@@ -2089,10 +2264,19 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, | |||
2089 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2264 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2090 | cmd->action = cpu_to_le16(MWL8K_CMD_SET); | 2265 | cmd->action = cpu_to_le16(MWL8K_CMD_SET); |
2091 | cmd->current_channel = channel->hw_value; | 2266 | cmd->current_channel = channel->hw_value; |
2267 | |||
2092 | if (channel->band == IEEE80211_BAND_2GHZ) | 2268 | if (channel->band == IEEE80211_BAND_2GHZ) |
2093 | cmd->channel_flags = cpu_to_le32(0x00000081); | 2269 | cmd->channel_flags |= cpu_to_le32(0x00000001); |
2094 | else | 2270 | else if (channel->band == IEEE80211_BAND_5GHZ) |
2095 | cmd->channel_flags = cpu_to_le32(0x00000000); | 2271 | cmd->channel_flags |= cpu_to_le32(0x00000004); |
2272 | |||
2273 | if (conf->channel_type == NL80211_CHAN_NO_HT || | ||
2274 | conf->channel_type == NL80211_CHAN_HT20) | ||
2275 | cmd->channel_flags |= cpu_to_le32(0x00000080); | ||
2276 | else if (conf->channel_type == NL80211_CHAN_HT40MINUS) | ||
2277 | cmd->channel_flags |= cpu_to_le32(0x000001900); | ||
2278 | else if (conf->channel_type == NL80211_CHAN_HT40PLUS) | ||
2279 | cmd->channel_flags |= cpu_to_le32(0x000000900); | ||
2096 | 2280 | ||
2097 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2281 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2098 | kfree(cmd); | 2282 | kfree(cmd); |
@@ -2118,10 +2302,26 @@ struct mwl8k_cmd_update_set_aid { | |||
2118 | __u8 supp_rates[14]; | 2302 | __u8 supp_rates[14]; |
2119 | } __attribute__((packed)); | 2303 | } __attribute__((packed)); |
2120 | 2304 | ||
2305 | static void legacy_rate_mask_to_array(u8 *rates, u32 mask) | ||
2306 | { | ||
2307 | int i; | ||
2308 | int j; | ||
2309 | |||
2310 | /* | ||
2311 | * Clear nonstandard rates 4 and 13. | ||
2312 | */ | ||
2313 | mask &= 0x1fef; | ||
2314 | |||
2315 | for (i = 0, j = 0; i < 14; i++) { | ||
2316 | if (mask & (1 << i)) | ||
2317 | rates[j++] = mwl8k_rates_24[i].hw_value; | ||
2318 | } | ||
2319 | } | ||
2320 | |||
2121 | static int | 2321 | static int |
2122 | mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 2322 | mwl8k_cmd_set_aid(struct ieee80211_hw *hw, |
2323 | struct ieee80211_vif *vif, u32 legacy_rate_mask) | ||
2123 | { | 2324 | { |
2124 | struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); | ||
2125 | struct mwl8k_cmd_update_set_aid *cmd; | 2325 | struct mwl8k_cmd_update_set_aid *cmd; |
2126 | u16 prot_mode; | 2326 | u16 prot_mode; |
2127 | int rc; | 2327 | int rc; |
@@ -2133,8 +2333,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
2133 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); | 2333 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID); |
2134 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2334 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2135 | cmd->aid = cpu_to_le16(vif->bss_conf.aid); | 2335 | cmd->aid = cpu_to_le16(vif->bss_conf.aid); |
2136 | 2336 | memcpy(cmd->bssid, vif->bss_conf.bssid, ETH_ALEN); | |
2137 | memcpy(cmd->bssid, mv_vif->bssid, ETH_ALEN); | ||
2138 | 2337 | ||
2139 | if (vif->bss_conf.use_cts_prot) { | 2338 | if (vif->bss_conf.use_cts_prot) { |
2140 | prot_mode = MWL8K_FRAME_PROT_11G; | 2339 | prot_mode = MWL8K_FRAME_PROT_11G; |
@@ -2154,7 +2353,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
2154 | } | 2353 | } |
2155 | cmd->protection_mode = cpu_to_le16(prot_mode); | 2354 | cmd->protection_mode = cpu_to_le16(prot_mode); |
2156 | 2355 | ||
2157 | memcpy(cmd->supp_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); | 2356 | legacy_rate_mask_to_array(cmd->supp_rates, legacy_rate_mask); |
2158 | 2357 | ||
2159 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2358 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2160 | kfree(cmd); | 2359 | kfree(cmd); |
@@ -2175,7 +2374,8 @@ struct mwl8k_cmd_set_rate { | |||
2175 | } __attribute__((packed)); | 2374 | } __attribute__((packed)); |
2176 | 2375 | ||
2177 | static int | 2376 | static int |
2178 | mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 2377 | mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2378 | u32 legacy_rate_mask, u8 *mcs_rates) | ||
2179 | { | 2379 | { |
2180 | struct mwl8k_cmd_set_rate *cmd; | 2380 | struct mwl8k_cmd_set_rate *cmd; |
2181 | int rc; | 2381 | int rc; |
@@ -2186,7 +2386,8 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
2186 | 2386 | ||
2187 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); | 2387 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE); |
2188 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2388 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2189 | memcpy(cmd->legacy_rates, mwl8k_rateids, sizeof(mwl8k_rateids)); | 2389 | legacy_rate_mask_to_array(cmd->legacy_rates, legacy_rate_mask); |
2390 | memcpy(cmd->mcs_set, mcs_rates, 16); | ||
2190 | 2391 | ||
2191 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2392 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2192 | kfree(cmd); | 2393 | kfree(cmd); |
@@ -2244,8 +2445,8 @@ struct mwl8k_cmd_set_rts_threshold { | |||
2244 | __le16 threshold; | 2445 | __le16 threshold; |
2245 | } __attribute__((packed)); | 2446 | } __attribute__((packed)); |
2246 | 2447 | ||
2247 | static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, | 2448 | static int |
2248 | u16 action, u16 threshold) | 2449 | mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) |
2249 | { | 2450 | { |
2250 | struct mwl8k_cmd_set_rts_threshold *cmd; | 2451 | struct mwl8k_cmd_set_rts_threshold *cmd; |
2251 | int rc; | 2452 | int rc; |
@@ -2256,8 +2457,8 @@ static int mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, | |||
2256 | 2457 | ||
2257 | cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); | 2458 | cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD); |
2258 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2459 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2259 | cmd->action = cpu_to_le16(action); | 2460 | cmd->action = cpu_to_le16(MWL8K_CMD_SET); |
2260 | cmd->threshold = cpu_to_le16(threshold); | 2461 | cmd->threshold = cpu_to_le16(rts_thresh); |
2261 | 2462 | ||
2262 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2463 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2263 | kfree(cmd); | 2464 | kfree(cmd); |
@@ -2357,12 +2558,6 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, | |||
2357 | if (cmd == NULL) | 2558 | if (cmd == NULL) |
2358 | return -ENOMEM; | 2559 | return -ENOMEM; |
2359 | 2560 | ||
2360 | /* | ||
2361 | * Queues 0 (BE) and 1 (BK) are swapped in hardware for | ||
2362 | * this call. | ||
2363 | */ | ||
2364 | qnum ^= !(qnum >> 1); | ||
2365 | |||
2366 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); | 2561 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS); |
2367 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2562 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2368 | cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); | 2563 | cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL); |
@@ -2448,49 +2643,70 @@ static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) | |||
2448 | } | 2643 | } |
2449 | 2644 | ||
2450 | /* | 2645 | /* |
2451 | * CMD_USE_FIXED_RATE. | 2646 | * CMD_USE_FIXED_RATE (STA version). |
2452 | */ | 2647 | */ |
2453 | #define MWL8K_RATE_TABLE_SIZE 8 | 2648 | struct mwl8k_cmd_use_fixed_rate_sta { |
2454 | #define MWL8K_UCAST_RATE 0 | 2649 | struct mwl8k_cmd_pkt header; |
2455 | #define MWL8K_USE_AUTO_RATE 0x0002 | 2650 | __le32 action; |
2651 | __le32 allow_rate_drop; | ||
2652 | __le32 num_rates; | ||
2653 | struct { | ||
2654 | __le32 is_ht_rate; | ||
2655 | __le32 enable_retry; | ||
2656 | __le32 rate; | ||
2657 | __le32 retry_count; | ||
2658 | } rate_entry[8]; | ||
2659 | __le32 rate_type; | ||
2660 | __le32 reserved1; | ||
2661 | __le32 reserved2; | ||
2662 | } __attribute__((packed)); | ||
2456 | 2663 | ||
2457 | struct mwl8k_rate_entry { | 2664 | #define MWL8K_USE_AUTO_RATE 0x0002 |
2458 | /* Set to 1 if HT rate, 0 if legacy. */ | 2665 | #define MWL8K_UCAST_RATE 0 |
2459 | __le32 is_ht_rate; | ||
2460 | 2666 | ||
2461 | /* Set to 1 to use retry_count field. */ | 2667 | static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) |
2462 | __le32 enable_retry; | 2668 | { |
2669 | struct mwl8k_cmd_use_fixed_rate_sta *cmd; | ||
2670 | int rc; | ||
2463 | 2671 | ||
2464 | /* Specified legacy rate or MCS. */ | 2672 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
2465 | __le32 rate; | 2673 | if (cmd == NULL) |
2674 | return -ENOMEM; | ||
2466 | 2675 | ||
2467 | /* Number of allowed retries. */ | 2676 | cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); |
2468 | __le32 retry_count; | 2677 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2469 | } __attribute__((packed)); | 2678 | cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); |
2679 | cmd->rate_type = cpu_to_le32(MWL8K_UCAST_RATE); | ||
2470 | 2680 | ||
2471 | struct mwl8k_rate_table { | 2681 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2472 | /* 1 to allow specified rate and below */ | 2682 | kfree(cmd); |
2473 | __le32 allow_rate_drop; | ||
2474 | __le32 num_rates; | ||
2475 | struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE]; | ||
2476 | } __attribute__((packed)); | ||
2477 | 2683 | ||
2478 | struct mwl8k_cmd_use_fixed_rate { | 2684 | return rc; |
2479 | struct mwl8k_cmd_pkt header; | 2685 | } |
2480 | __le32 action; | ||
2481 | struct mwl8k_rate_table rate_table; | ||
2482 | 2686 | ||
2483 | /* Unicast, Broadcast or Multicast */ | 2687 | /* |
2484 | __le32 rate_type; | 2688 | * CMD_USE_FIXED_RATE (AP version). |
2485 | __le32 reserved1; | 2689 | */ |
2486 | __le32 reserved2; | 2690 | struct mwl8k_cmd_use_fixed_rate_ap { |
2691 | struct mwl8k_cmd_pkt header; | ||
2692 | __le32 action; | ||
2693 | __le32 allow_rate_drop; | ||
2694 | __le32 num_rates; | ||
2695 | struct mwl8k_rate_entry_ap { | ||
2696 | __le32 is_ht_rate; | ||
2697 | __le32 enable_retry; | ||
2698 | __le32 rate; | ||
2699 | __le32 retry_count; | ||
2700 | } rate_entry[4]; | ||
2701 | u8 multicast_rate; | ||
2702 | u8 multicast_rate_type; | ||
2703 | u8 management_rate; | ||
2487 | } __attribute__((packed)); | 2704 | } __attribute__((packed)); |
2488 | 2705 | ||
2489 | static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, | 2706 | static int |
2490 | u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table) | 2707 | mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) |
2491 | { | 2708 | { |
2492 | struct mwl8k_cmd_use_fixed_rate *cmd; | 2709 | struct mwl8k_cmd_use_fixed_rate_ap *cmd; |
2493 | int count; | ||
2494 | int rc; | 2710 | int rc; |
2495 | 2711 | ||
2496 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2712 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -2499,32 +2715,9 @@ static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw, | |||
2499 | 2715 | ||
2500 | cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); | 2716 | cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE); |
2501 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2717 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2502 | 2718 | cmd->action = cpu_to_le32(MWL8K_USE_AUTO_RATE); | |
2503 | cmd->action = cpu_to_le32(action); | 2719 | cmd->multicast_rate = mcast; |
2504 | cmd->rate_type = cpu_to_le32(rate_type); | 2720 | cmd->management_rate = mgmt; |
2505 | |||
2506 | if (rate_table != NULL) { | ||
2507 | /* | ||
2508 | * Copy over each field manually so that endian | ||
2509 | * conversion can be done. | ||
2510 | */ | ||
2511 | cmd->rate_table.allow_rate_drop = | ||
2512 | cpu_to_le32(rate_table->allow_rate_drop); | ||
2513 | cmd->rate_table.num_rates = | ||
2514 | cpu_to_le32(rate_table->num_rates); | ||
2515 | |||
2516 | for (count = 0; count < rate_table->num_rates; count++) { | ||
2517 | struct mwl8k_rate_entry *dst = | ||
2518 | &cmd->rate_table.rate_entry[count]; | ||
2519 | struct mwl8k_rate_entry *src = | ||
2520 | &rate_table->rate_entry[count]; | ||
2521 | |||
2522 | dst->is_ht_rate = cpu_to_le32(src->is_ht_rate); | ||
2523 | dst->enable_retry = cpu_to_le32(src->enable_retry); | ||
2524 | dst->rate = cpu_to_le32(src->rate); | ||
2525 | dst->retry_count = cpu_to_le32(src->retry_count); | ||
2526 | } | ||
2527 | } | ||
2528 | 2721 | ||
2529 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2722 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2530 | kfree(cmd); | 2723 | kfree(cmd); |
@@ -2573,12 +2766,33 @@ struct mwl8k_cmd_set_mac_addr { | |||
2573 | }; | 2766 | }; |
2574 | } __attribute__((packed)); | 2767 | } __attribute__((packed)); |
2575 | 2768 | ||
2576 | static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) | 2769 | #define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 |
2770 | #define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 | ||
2771 | #define MWL8K_MAC_TYPE_PRIMARY_AP 2 | ||
2772 | #define MWL8K_MAC_TYPE_SECONDARY_AP 3 | ||
2773 | |||
2774 | static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, | ||
2775 | struct ieee80211_vif *vif, u8 *mac) | ||
2577 | { | 2776 | { |
2578 | struct mwl8k_priv *priv = hw->priv; | 2777 | struct mwl8k_priv *priv = hw->priv; |
2778 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
2579 | struct mwl8k_cmd_set_mac_addr *cmd; | 2779 | struct mwl8k_cmd_set_mac_addr *cmd; |
2780 | int mac_type; | ||
2580 | int rc; | 2781 | int rc; |
2581 | 2782 | ||
2783 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; | ||
2784 | if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { | ||
2785 | if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) | ||
2786 | mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; | ||
2787 | else | ||
2788 | mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; | ||
2789 | } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { | ||
2790 | if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) | ||
2791 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; | ||
2792 | else | ||
2793 | mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; | ||
2794 | } | ||
2795 | |||
2582 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2796 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
2583 | if (cmd == NULL) | 2797 | if (cmd == NULL) |
2584 | return -ENOMEM; | 2798 | return -ENOMEM; |
@@ -2586,13 +2800,13 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, u8 *mac) | |||
2586 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); | 2800 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); |
2587 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2801 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2588 | if (priv->ap_fw) { | 2802 | if (priv->ap_fw) { |
2589 | cmd->mbss.mac_type = 0; | 2803 | cmd->mbss.mac_type = cpu_to_le16(mac_type); |
2590 | memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); | 2804 | memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); |
2591 | } else { | 2805 | } else { |
2592 | memcpy(cmd->mac_addr, mac, ETH_ALEN); | 2806 | memcpy(cmd->mac_addr, mac, ETH_ALEN); |
2593 | } | 2807 | } |
2594 | 2808 | ||
2595 | rc = mwl8k_post_cmd(hw, &cmd->header); | 2809 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); |
2596 | kfree(cmd); | 2810 | kfree(cmd); |
2597 | 2811 | ||
2598 | return rc; | 2812 | return rc; |
@@ -2628,8 +2842,180 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) | |||
2628 | } | 2842 | } |
2629 | 2843 | ||
2630 | /* | 2844 | /* |
2845 | * CMD_BSS_START. | ||
2846 | */ | ||
2847 | struct mwl8k_cmd_bss_start { | ||
2848 | struct mwl8k_cmd_pkt header; | ||
2849 | __le32 enable; | ||
2850 | } __attribute__((packed)); | ||
2851 | |||
2852 | static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, | ||
2853 | struct ieee80211_vif *vif, int enable) | ||
2854 | { | ||
2855 | struct mwl8k_cmd_bss_start *cmd; | ||
2856 | int rc; | ||
2857 | |||
2858 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2859 | if (cmd == NULL) | ||
2860 | return -ENOMEM; | ||
2861 | |||
2862 | cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START); | ||
2863 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2864 | cmd->enable = cpu_to_le32(enable); | ||
2865 | |||
2866 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
2867 | kfree(cmd); | ||
2868 | |||
2869 | return rc; | ||
2870 | } | ||
2871 | |||
2872 | /* | ||
2873 | * CMD_SET_NEW_STN. | ||
2874 | */ | ||
2875 | struct mwl8k_cmd_set_new_stn { | ||
2876 | struct mwl8k_cmd_pkt header; | ||
2877 | __le16 aid; | ||
2878 | __u8 mac_addr[6]; | ||
2879 | __le16 stn_id; | ||
2880 | __le16 action; | ||
2881 | __le16 rsvd; | ||
2882 | __le32 legacy_rates; | ||
2883 | __u8 ht_rates[4]; | ||
2884 | __le16 cap_info; | ||
2885 | __le16 ht_capabilities_info; | ||
2886 | __u8 mac_ht_param_info; | ||
2887 | __u8 rev; | ||
2888 | __u8 control_channel; | ||
2889 | __u8 add_channel; | ||
2890 | __le16 op_mode; | ||
2891 | __le16 stbc; | ||
2892 | __u8 add_qos_info; | ||
2893 | __u8 is_qos_sta; | ||
2894 | __le32 fw_sta_ptr; | ||
2895 | } __attribute__((packed)); | ||
2896 | |||
2897 | #define MWL8K_STA_ACTION_ADD 0 | ||
2898 | #define MWL8K_STA_ACTION_REMOVE 2 | ||
2899 | |||
2900 | static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw, | ||
2901 | struct ieee80211_vif *vif, | ||
2902 | struct ieee80211_sta *sta) | ||
2903 | { | ||
2904 | struct mwl8k_cmd_set_new_stn *cmd; | ||
2905 | u32 rates; | ||
2906 | int rc; | ||
2907 | |||
2908 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2909 | if (cmd == NULL) | ||
2910 | return -ENOMEM; | ||
2911 | |||
2912 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); | ||
2913 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2914 | cmd->aid = cpu_to_le16(sta->aid); | ||
2915 | memcpy(cmd->mac_addr, sta->addr, ETH_ALEN); | ||
2916 | cmd->stn_id = cpu_to_le16(sta->aid); | ||
2917 | cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD); | ||
2918 | if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
2919 | rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; | ||
2920 | else | ||
2921 | rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; | ||
2922 | cmd->legacy_rates = cpu_to_le32(rates); | ||
2923 | if (sta->ht_cap.ht_supported) { | ||
2924 | cmd->ht_rates[0] = sta->ht_cap.mcs.rx_mask[0]; | ||
2925 | cmd->ht_rates[1] = sta->ht_cap.mcs.rx_mask[1]; | ||
2926 | cmd->ht_rates[2] = sta->ht_cap.mcs.rx_mask[2]; | ||
2927 | cmd->ht_rates[3] = sta->ht_cap.mcs.rx_mask[3]; | ||
2928 | cmd->ht_capabilities_info = cpu_to_le16(sta->ht_cap.cap); | ||
2929 | cmd->mac_ht_param_info = (sta->ht_cap.ampdu_factor & 3) | | ||
2930 | ((sta->ht_cap.ampdu_density & 7) << 2); | ||
2931 | cmd->is_qos_sta = 1; | ||
2932 | } | ||
2933 | |||
2934 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
2935 | kfree(cmd); | ||
2936 | |||
2937 | return rc; | ||
2938 | } | ||
2939 | |||
2940 | static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw, | ||
2941 | struct ieee80211_vif *vif) | ||
2942 | { | ||
2943 | struct mwl8k_cmd_set_new_stn *cmd; | ||
2944 | int rc; | ||
2945 | |||
2946 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2947 | if (cmd == NULL) | ||
2948 | return -ENOMEM; | ||
2949 | |||
2950 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); | ||
2951 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2952 | memcpy(cmd->mac_addr, vif->addr, ETH_ALEN); | ||
2953 | |||
2954 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
2955 | kfree(cmd); | ||
2956 | |||
2957 | return rc; | ||
2958 | } | ||
2959 | |||
2960 | static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, | ||
2961 | struct ieee80211_vif *vif, u8 *addr) | ||
2962 | { | ||
2963 | struct mwl8k_cmd_set_new_stn *cmd; | ||
2964 | int rc; | ||
2965 | |||
2966 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
2967 | if (cmd == NULL) | ||
2968 | return -ENOMEM; | ||
2969 | |||
2970 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN); | ||
2971 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | ||
2972 | memcpy(cmd->mac_addr, addr, ETH_ALEN); | ||
2973 | cmd->action = cpu_to_le16(MWL8K_STA_ACTION_REMOVE); | ||
2974 | |||
2975 | rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); | ||
2976 | kfree(cmd); | ||
2977 | |||
2978 | return rc; | ||
2979 | } | ||
2980 | |||
2981 | /* | ||
2631 | * CMD_UPDATE_STADB. | 2982 | * CMD_UPDATE_STADB. |
2632 | */ | 2983 | */ |
2984 | struct ewc_ht_info { | ||
2985 | __le16 control1; | ||
2986 | __le16 control2; | ||
2987 | __le16 control3; | ||
2988 | } __attribute__((packed)); | ||
2989 | |||
2990 | struct peer_capability_info { | ||
2991 | /* Peer type - AP vs. STA. */ | ||
2992 | __u8 peer_type; | ||
2993 | |||
2994 | /* Basic 802.11 capabilities from assoc resp. */ | ||
2995 | __le16 basic_caps; | ||
2996 | |||
2997 | /* Set if peer supports 802.11n high throughput (HT). */ | ||
2998 | __u8 ht_support; | ||
2999 | |||
3000 | /* Valid if HT is supported. */ | ||
3001 | __le16 ht_caps; | ||
3002 | __u8 extended_ht_caps; | ||
3003 | struct ewc_ht_info ewc_info; | ||
3004 | |||
3005 | /* Legacy rate table. Intersection of our rates and peer rates. */ | ||
3006 | __u8 legacy_rates[12]; | ||
3007 | |||
3008 | /* HT rate table. Intersection of our rates and peer rates. */ | ||
3009 | __u8 ht_rates[16]; | ||
3010 | __u8 pad[16]; | ||
3011 | |||
3012 | /* If set, interoperability mode, no proprietary extensions. */ | ||
3013 | __u8 interop; | ||
3014 | __u8 pad2; | ||
3015 | __u8 station_id; | ||
3016 | __le16 amsdu_enabled; | ||
3017 | } __attribute__((packed)); | ||
3018 | |||
2633 | struct mwl8k_cmd_update_stadb { | 3019 | struct mwl8k_cmd_update_stadb { |
2634 | struct mwl8k_cmd_pkt header; | 3020 | struct mwl8k_cmd_pkt header; |
2635 | 3021 | ||
@@ -2645,12 +3031,19 @@ struct mwl8k_cmd_update_stadb { | |||
2645 | struct peer_capability_info peer_info; | 3031 | struct peer_capability_info peer_info; |
2646 | } __attribute__((packed)); | 3032 | } __attribute__((packed)); |
2647 | 3033 | ||
2648 | static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, | 3034 | #define MWL8K_STA_DB_MODIFY_ENTRY 1 |
2649 | struct ieee80211_vif *vif, __u32 action) | 3035 | #define MWL8K_STA_DB_DEL_ENTRY 2 |
3036 | |||
3037 | /* Peer Entry flags - used to define the type of the peer node */ | ||
3038 | #define MWL8K_PEER_TYPE_ACCESSPOINT 2 | ||
3039 | |||
3040 | static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw, | ||
3041 | struct ieee80211_vif *vif, | ||
3042 | struct ieee80211_sta *sta) | ||
2650 | { | 3043 | { |
2651 | struct mwl8k_vif *mv_vif = MWL8K_VIF(vif); | ||
2652 | struct mwl8k_cmd_update_stadb *cmd; | 3044 | struct mwl8k_cmd_update_stadb *cmd; |
2653 | struct peer_capability_info *peer_info; | 3045 | struct peer_capability_info *p; |
3046 | u32 rates; | ||
2654 | int rc; | 3047 | int rc; |
2655 | 3048 | ||
2656 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 3049 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
@@ -2659,37 +3052,47 @@ static int mwl8k_cmd_update_stadb(struct ieee80211_hw *hw, | |||
2659 | 3052 | ||
2660 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); | 3053 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); |
2661 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 3054 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
3055 | cmd->action = cpu_to_le32(MWL8K_STA_DB_MODIFY_ENTRY); | ||
3056 | memcpy(cmd->peer_addr, sta->addr, ETH_ALEN); | ||
3057 | |||
3058 | p = &cmd->peer_info; | ||
3059 | p->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; | ||
3060 | p->basic_caps = cpu_to_le16(vif->bss_conf.assoc_capability); | ||
3061 | p->ht_support = sta->ht_cap.ht_supported; | ||
3062 | p->ht_caps = sta->ht_cap.cap; | ||
3063 | p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) | | ||
3064 | ((sta->ht_cap.ampdu_density & 7) << 2); | ||
3065 | if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
3066 | rates = sta->supp_rates[IEEE80211_BAND_2GHZ]; | ||
3067 | else | ||
3068 | rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5; | ||
3069 | legacy_rate_mask_to_array(p->legacy_rates, rates); | ||
3070 | memcpy(p->ht_rates, sta->ht_cap.mcs.rx_mask, 16); | ||
3071 | p->interop = 1; | ||
3072 | p->amsdu_enabled = 0; | ||
2662 | 3073 | ||
2663 | cmd->action = cpu_to_le32(action); | 3074 | rc = mwl8k_post_cmd(hw, &cmd->header); |
2664 | peer_info = &cmd->peer_info; | 3075 | kfree(cmd); |
2665 | memcpy(cmd->peer_addr, mv_vif->bssid, ETH_ALEN); | ||
2666 | 3076 | ||
2667 | switch (action) { | 3077 | return rc ? rc : p->station_id; |
2668 | case MWL8K_STA_DB_ADD_ENTRY: | 3078 | } |
2669 | case MWL8K_STA_DB_MODIFY_ENTRY: | ||
2670 | /* Build peer_info block */ | ||
2671 | peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT; | ||
2672 | peer_info->basic_caps = | ||
2673 | cpu_to_le16(vif->bss_conf.assoc_capability); | ||
2674 | memcpy(peer_info->legacy_rates, mwl8k_rateids, | ||
2675 | sizeof(mwl8k_rateids)); | ||
2676 | peer_info->interop = 1; | ||
2677 | peer_info->amsdu_enabled = 0; | ||
2678 | |||
2679 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2680 | if (rc == 0) | ||
2681 | mv_vif->peer_id = peer_info->station_id; | ||
2682 | 3079 | ||
2683 | break; | 3080 | static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw, |
3081 | struct ieee80211_vif *vif, u8 *addr) | ||
3082 | { | ||
3083 | struct mwl8k_cmd_update_stadb *cmd; | ||
3084 | int rc; | ||
2684 | 3085 | ||
2685 | case MWL8K_STA_DB_DEL_ENTRY: | 3086 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
2686 | case MWL8K_STA_DB_FLUSH: | 3087 | if (cmd == NULL) |
2687 | default: | 3088 | return -ENOMEM; |
2688 | rc = mwl8k_post_cmd(hw, &cmd->header); | 3089 | |
2689 | if (rc == 0) | 3090 | cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB); |
2690 | mv_vif->peer_id = 0; | 3091 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2691 | break; | 3092 | cmd->action = cpu_to_le32(MWL8K_STA_DB_DEL_ENTRY); |
2692 | } | 3093 | memcpy(cmd->peer_addr, addr, ETH_ALEN); |
3094 | |||
3095 | rc = mwl8k_post_cmd(hw, &cmd->header); | ||
2693 | kfree(cmd); | 3096 | kfree(cmd); |
2694 | 3097 | ||
2695 | return rc; | 3098 | return rc; |
@@ -2706,19 +3109,22 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
2706 | u32 status; | 3109 | u32 status; |
2707 | 3110 | ||
2708 | status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 3111 | status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
2709 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | ||
2710 | |||
2711 | if (!status) | 3112 | if (!status) |
2712 | return IRQ_NONE; | 3113 | return IRQ_NONE; |
2713 | 3114 | ||
2714 | if (status & MWL8K_A2H_INT_TX_DONE) | 3115 | if (status & MWL8K_A2H_INT_TX_DONE) { |
2715 | tasklet_schedule(&priv->tx_reclaim_task); | 3116 | status &= ~MWL8K_A2H_INT_TX_DONE; |
3117 | tasklet_schedule(&priv->poll_tx_task); | ||
3118 | } | ||
2716 | 3119 | ||
2717 | if (status & MWL8K_A2H_INT_RX_READY) { | 3120 | if (status & MWL8K_A2H_INT_RX_READY) { |
2718 | while (rxq_process(hw, 0, 1)) | 3121 | status &= ~MWL8K_A2H_INT_RX_READY; |
2719 | rxq_refill(hw, 0, 1); | 3122 | tasklet_schedule(&priv->poll_rx_task); |
2720 | } | 3123 | } |
2721 | 3124 | ||
3125 | if (status) | ||
3126 | iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | ||
3127 | |||
2722 | if (status & MWL8K_A2H_INT_OPC_DONE) { | 3128 | if (status & MWL8K_A2H_INT_OPC_DONE) { |
2723 | if (priv->hostcmd_wait != NULL) | 3129 | if (priv->hostcmd_wait != NULL) |
2724 | complete(priv->hostcmd_wait); | 3130 | complete(priv->hostcmd_wait); |
@@ -2733,6 +3139,53 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id) | |||
2733 | return IRQ_HANDLED; | 3139 | return IRQ_HANDLED; |
2734 | } | 3140 | } |
2735 | 3141 | ||
3142 | static void mwl8k_tx_poll(unsigned long data) | ||
3143 | { | ||
3144 | struct ieee80211_hw *hw = (struct ieee80211_hw *)data; | ||
3145 | struct mwl8k_priv *priv = hw->priv; | ||
3146 | int limit; | ||
3147 | int i; | ||
3148 | |||
3149 | limit = 32; | ||
3150 | |||
3151 | spin_lock_bh(&priv->tx_lock); | ||
3152 | |||
3153 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | ||
3154 | limit -= mwl8k_txq_reclaim(hw, i, limit, 0); | ||
3155 | |||
3156 | if (!priv->pending_tx_pkts && priv->tx_wait != NULL) { | ||
3157 | complete(priv->tx_wait); | ||
3158 | priv->tx_wait = NULL; | ||
3159 | } | ||
3160 | |||
3161 | spin_unlock_bh(&priv->tx_lock); | ||
3162 | |||
3163 | if (limit) { | ||
3164 | writel(~MWL8K_A2H_INT_TX_DONE, | ||
3165 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | ||
3166 | } else { | ||
3167 | tasklet_schedule(&priv->poll_tx_task); | ||
3168 | } | ||
3169 | } | ||
3170 | |||
3171 | static void mwl8k_rx_poll(unsigned long data) | ||
3172 | { | ||
3173 | struct ieee80211_hw *hw = (struct ieee80211_hw *)data; | ||
3174 | struct mwl8k_priv *priv = hw->priv; | ||
3175 | int limit; | ||
3176 | |||
3177 | limit = 32; | ||
3178 | limit -= rxq_process(hw, 0, limit); | ||
3179 | limit -= rxq_refill(hw, 0, limit); | ||
3180 | |||
3181 | if (limit) { | ||
3182 | writel(~MWL8K_A2H_INT_RX_READY, | ||
3183 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | ||
3184 | } else { | ||
3185 | tasklet_schedule(&priv->poll_rx_task); | ||
3186 | } | ||
3187 | } | ||
3188 | |||
2736 | 3189 | ||
2737 | /* | 3190 | /* |
2738 | * Core driver operations. | 3191 | * Core driver operations. |
@@ -2743,7 +3196,7 @@ static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2743 | int index = skb_get_queue_mapping(skb); | 3196 | int index = skb_get_queue_mapping(skb); |
2744 | int rc; | 3197 | int rc; |
2745 | 3198 | ||
2746 | if (priv->current_channel == NULL) { | 3199 | if (!priv->radio_on) { |
2747 | printk(KERN_DEBUG "%s: dropped TX frame since radio " | 3200 | printk(KERN_DEBUG "%s: dropped TX frame since radio " |
2748 | "disabled\n", wiphy_name(hw->wiphy)); | 3201 | "disabled\n", wiphy_name(hw->wiphy)); |
2749 | dev_kfree_skb(skb); | 3202 | dev_kfree_skb(skb); |
@@ -2768,8 +3221,9 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
2768 | return -EIO; | 3221 | return -EIO; |
2769 | } | 3222 | } |
2770 | 3223 | ||
2771 | /* Enable tx reclaim tasklet */ | 3224 | /* Enable TX reclaim and RX tasklets. */ |
2772 | tasklet_enable(&priv->tx_reclaim_task); | 3225 | tasklet_enable(&priv->poll_tx_task); |
3226 | tasklet_enable(&priv->poll_rx_task); | ||
2773 | 3227 | ||
2774 | /* Enable interrupts */ | 3228 | /* Enable interrupts */ |
2775 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 3229 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
@@ -2802,7 +3256,8 @@ static int mwl8k_start(struct ieee80211_hw *hw) | |||
2802 | if (rc) { | 3256 | if (rc) { |
2803 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 3257 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
2804 | free_irq(priv->pdev->irq, hw); | 3258 | free_irq(priv->pdev->irq, hw); |
2805 | tasklet_disable(&priv->tx_reclaim_task); | 3259 | tasklet_disable(&priv->poll_tx_task); |
3260 | tasklet_disable(&priv->poll_rx_task); | ||
2806 | } | 3261 | } |
2807 | 3262 | ||
2808 | return rc; | 3263 | return rc; |
@@ -2826,36 +3281,27 @@ static void mwl8k_stop(struct ieee80211_hw *hw) | |||
2826 | if (priv->beacon_skb != NULL) | 3281 | if (priv->beacon_skb != NULL) |
2827 | dev_kfree_skb(priv->beacon_skb); | 3282 | dev_kfree_skb(priv->beacon_skb); |
2828 | 3283 | ||
2829 | /* Stop tx reclaim tasklet */ | 3284 | /* Stop TX reclaim and RX tasklets. */ |
2830 | tasklet_disable(&priv->tx_reclaim_task); | 3285 | tasklet_disable(&priv->poll_tx_task); |
3286 | tasklet_disable(&priv->poll_rx_task); | ||
2831 | 3287 | ||
2832 | /* Return all skbs to mac80211 */ | 3288 | /* Return all skbs to mac80211 */ |
2833 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 3289 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
2834 | mwl8k_txq_reclaim(hw, i, 1); | 3290 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
2835 | } | 3291 | } |
2836 | 3292 | ||
2837 | static int mwl8k_add_interface(struct ieee80211_hw *hw, | 3293 | static int mwl8k_add_interface(struct ieee80211_hw *hw, |
2838 | struct ieee80211_vif *vif) | 3294 | struct ieee80211_vif *vif) |
2839 | { | 3295 | { |
2840 | struct mwl8k_priv *priv = hw->priv; | 3296 | struct mwl8k_priv *priv = hw->priv; |
2841 | struct mwl8k_vif *mwl8k_vif; | 3297 | struct mwl8k_vif *mwl8k_vif; |
2842 | 3298 | u32 macids_supported; | |
2843 | /* | 3299 | int macid; |
2844 | * We only support one active interface at a time. | ||
2845 | */ | ||
2846 | if (priv->vif != NULL) | ||
2847 | return -EBUSY; | ||
2848 | |||
2849 | /* | ||
2850 | * We only support managed interfaces for now. | ||
2851 | */ | ||
2852 | if (vif->type != NL80211_IFTYPE_STATION) | ||
2853 | return -EINVAL; | ||
2854 | 3300 | ||
2855 | /* | 3301 | /* |
2856 | * Reject interface creation if sniffer mode is active, as | 3302 | * Reject interface creation if sniffer mode is active, as |
2857 | * STA operation is mutually exclusive with hardware sniffer | 3303 | * STA operation is mutually exclusive with hardware sniffer |
2858 | * mode. | 3304 | * mode. (Sniffer mode is only used on STA firmware.) |
2859 | */ | 3305 | */ |
2860 | if (priv->sniffer_enabled) { | 3306 | if (priv->sniffer_enabled) { |
2861 | printk(KERN_INFO "%s: unable to create STA " | 3307 | printk(KERN_INFO "%s: unable to create STA " |
@@ -2864,19 +3310,37 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
2864 | return -EINVAL; | 3310 | return -EINVAL; |
2865 | } | 3311 | } |
2866 | 3312 | ||
2867 | /* Clean out driver private area */ | 3313 | |
3314 | switch (vif->type) { | ||
3315 | case NL80211_IFTYPE_AP: | ||
3316 | macids_supported = priv->ap_macids_supported; | ||
3317 | break; | ||
3318 | case NL80211_IFTYPE_STATION: | ||
3319 | macids_supported = priv->sta_macids_supported; | ||
3320 | break; | ||
3321 | default: | ||
3322 | return -EINVAL; | ||
3323 | } | ||
3324 | |||
3325 | macid = ffs(macids_supported & ~priv->macids_used); | ||
3326 | if (!macid--) | ||
3327 | return -EBUSY; | ||
3328 | |||
3329 | /* Setup driver private area. */ | ||
2868 | mwl8k_vif = MWL8K_VIF(vif); | 3330 | mwl8k_vif = MWL8K_VIF(vif); |
2869 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); | 3331 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); |
3332 | mwl8k_vif->vif = vif; | ||
3333 | mwl8k_vif->macid = macid; | ||
3334 | mwl8k_vif->seqno = 0; | ||
2870 | 3335 | ||
2871 | /* Set and save the mac address */ | 3336 | /* Set the mac address. */ |
2872 | mwl8k_cmd_set_mac_addr(hw, vif->addr); | 3337 | mwl8k_cmd_set_mac_addr(hw, vif, vif->addr); |
2873 | memcpy(mwl8k_vif->mac_addr, vif->addr, ETH_ALEN); | ||
2874 | 3338 | ||
2875 | /* Set Initial sequence number to zero */ | 3339 | if (priv->ap_fw) |
2876 | mwl8k_vif->seqno = 0; | 3340 | mwl8k_cmd_set_new_stn_add_self(hw, vif); |
2877 | 3341 | ||
2878 | priv->vif = vif; | 3342 | priv->macids_used |= 1 << mwl8k_vif->macid; |
2879 | priv->current_channel = NULL; | 3343 | list_add_tail(&mwl8k_vif->list, &priv->vif_list); |
2880 | 3344 | ||
2881 | return 0; | 3345 | return 0; |
2882 | } | 3346 | } |
@@ -2885,13 +3349,15 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, | |||
2885 | struct ieee80211_vif *vif) | 3349 | struct ieee80211_vif *vif) |
2886 | { | 3350 | { |
2887 | struct mwl8k_priv *priv = hw->priv; | 3351 | struct mwl8k_priv *priv = hw->priv; |
3352 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
2888 | 3353 | ||
2889 | if (priv->vif == NULL) | 3354 | if (priv->ap_fw) |
2890 | return; | 3355 | mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr); |
2891 | 3356 | ||
2892 | mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); | 3357 | mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); |
2893 | 3358 | ||
2894 | priv->vif = NULL; | 3359 | priv->macids_used &= ~(1 << mwl8k_vif->macid); |
3360 | list_del(&mwl8k_vif->list); | ||
2895 | } | 3361 | } |
2896 | 3362 | ||
2897 | static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | 3363 | static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) |
@@ -2902,7 +3368,6 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
2902 | 3368 | ||
2903 | if (conf->flags & IEEE80211_CONF_IDLE) { | 3369 | if (conf->flags & IEEE80211_CONF_IDLE) { |
2904 | mwl8k_cmd_radio_disable(hw); | 3370 | mwl8k_cmd_radio_disable(hw); |
2905 | priv->current_channel = NULL; | ||
2906 | return 0; | 3371 | return 0; |
2907 | } | 3372 | } |
2908 | 3373 | ||
@@ -2914,12 +3379,10 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) | |||
2914 | if (rc) | 3379 | if (rc) |
2915 | goto out; | 3380 | goto out; |
2916 | 3381 | ||
2917 | rc = mwl8k_cmd_set_rf_channel(hw, conf->channel); | 3382 | rc = mwl8k_cmd_set_rf_channel(hw, conf); |
2918 | if (rc) | 3383 | if (rc) |
2919 | goto out; | 3384 | goto out; |
2920 | 3385 | ||
2921 | priv->current_channel = conf->channel; | ||
2922 | |||
2923 | if (conf->power_level > 18) | 3386 | if (conf->power_level > 18) |
2924 | conf->power_level = 18; | 3387 | conf->power_level = 18; |
2925 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); | 3388 | rc = mwl8k_cmd_rf_tx_power(hw, conf->power_level); |
@@ -2940,75 +3403,160 @@ out: | |||
2940 | return rc; | 3403 | return rc; |
2941 | } | 3404 | } |
2942 | 3405 | ||
2943 | static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, | 3406 | static void |
2944 | struct ieee80211_vif *vif, | 3407 | mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2945 | struct ieee80211_bss_conf *info, | 3408 | struct ieee80211_bss_conf *info, u32 changed) |
2946 | u32 changed) | ||
2947 | { | 3409 | { |
2948 | struct mwl8k_priv *priv = hw->priv; | 3410 | struct mwl8k_priv *priv = hw->priv; |
2949 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | 3411 | u32 ap_legacy_rates; |
3412 | u8 ap_mcs_rates[16]; | ||
2950 | int rc; | 3413 | int rc; |
2951 | 3414 | ||
2952 | if ((changed & BSS_CHANGED_ASSOC) == 0) | 3415 | if (mwl8k_fw_lock(hw)) |
2953 | return; | 3416 | return; |
2954 | 3417 | ||
2955 | priv->capture_beacon = false; | 3418 | /* |
2956 | 3419 | * No need to capture a beacon if we're no longer associated. | |
2957 | rc = mwl8k_fw_lock(hw); | 3420 | */ |
2958 | if (rc) | 3421 | if ((changed & BSS_CHANGED_ASSOC) && !vif->bss_conf.assoc) |
2959 | return; | 3422 | priv->capture_beacon = false; |
2960 | 3423 | ||
3424 | /* | ||
3425 | * Get the AP's legacy and MCS rates. | ||
3426 | */ | ||
2961 | if (vif->bss_conf.assoc) { | 3427 | if (vif->bss_conf.assoc) { |
2962 | memcpy(mwl8k_vif->bssid, vif->bss_conf.bssid, ETH_ALEN); | 3428 | struct ieee80211_sta *ap; |
3429 | |||
3430 | rcu_read_lock(); | ||
3431 | |||
3432 | ap = ieee80211_find_sta(vif, vif->bss_conf.bssid); | ||
3433 | if (ap == NULL) { | ||
3434 | rcu_read_unlock(); | ||
3435 | goto out; | ||
3436 | } | ||
3437 | |||
3438 | if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
3439 | ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ]; | ||
3440 | } else { | ||
3441 | ap_legacy_rates = | ||
3442 | ap->supp_rates[IEEE80211_BAND_5GHZ] << 5; | ||
3443 | } | ||
3444 | memcpy(ap_mcs_rates, ap->ht_cap.mcs.rx_mask, 16); | ||
3445 | |||
3446 | rcu_read_unlock(); | ||
3447 | } | ||
2963 | 3448 | ||
2964 | /* Install rates */ | 3449 | if ((changed & BSS_CHANGED_ASSOC) && vif->bss_conf.assoc) { |
2965 | rc = mwl8k_cmd_set_rate(hw, vif); | 3450 | rc = mwl8k_cmd_set_rate(hw, vif, ap_legacy_rates, ap_mcs_rates); |
2966 | if (rc) | 3451 | if (rc) |
2967 | goto out; | 3452 | goto out; |
2968 | 3453 | ||
2969 | /* Turn on rate adaptation */ | 3454 | rc = mwl8k_cmd_use_fixed_rate_sta(hw); |
2970 | rc = mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE, | ||
2971 | MWL8K_UCAST_RATE, NULL); | ||
2972 | if (rc) | 3455 | if (rc) |
2973 | goto out; | 3456 | goto out; |
3457 | } | ||
2974 | 3458 | ||
2975 | /* Set radio preamble */ | 3459 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { |
2976 | rc = mwl8k_set_radio_preamble(hw, | 3460 | rc = mwl8k_set_radio_preamble(hw, |
2977 | vif->bss_conf.use_short_preamble); | 3461 | vif->bss_conf.use_short_preamble); |
2978 | if (rc) | 3462 | if (rc) |
2979 | goto out; | 3463 | goto out; |
3464 | } | ||
2980 | 3465 | ||
2981 | /* Set slot time */ | 3466 | if (changed & BSS_CHANGED_ERP_SLOT) { |
2982 | rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); | 3467 | rc = mwl8k_cmd_set_slot(hw, vif->bss_conf.use_short_slot); |
2983 | if (rc) | 3468 | if (rc) |
2984 | goto out; | 3469 | goto out; |
3470 | } | ||
2985 | 3471 | ||
2986 | /* Update peer rate info */ | 3472 | if (vif->bss_conf.assoc && |
2987 | rc = mwl8k_cmd_update_stadb(hw, vif, | 3473 | (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT | |
2988 | MWL8K_STA_DB_MODIFY_ENTRY); | 3474 | BSS_CHANGED_HT))) { |
2989 | if (rc) | 3475 | rc = mwl8k_cmd_set_aid(hw, vif, ap_legacy_rates); |
2990 | goto out; | ||
2991 | |||
2992 | /* Set AID */ | ||
2993 | rc = mwl8k_cmd_set_aid(hw, vif); | ||
2994 | if (rc) | 3476 | if (rc) |
2995 | goto out; | 3477 | goto out; |
3478 | } | ||
2996 | 3479 | ||
3480 | if (vif->bss_conf.assoc && | ||
3481 | (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INT))) { | ||
2997 | /* | 3482 | /* |
2998 | * Finalize the join. Tell rx handler to process | 3483 | * Finalize the join. Tell rx handler to process |
2999 | * next beacon from our BSSID. | 3484 | * next beacon from our BSSID. |
3000 | */ | 3485 | */ |
3001 | memcpy(priv->capture_bssid, mwl8k_vif->bssid, ETH_ALEN); | 3486 | memcpy(priv->capture_bssid, vif->bss_conf.bssid, ETH_ALEN); |
3002 | priv->capture_beacon = true; | 3487 | priv->capture_beacon = true; |
3003 | } else { | ||
3004 | rc = mwl8k_cmd_update_stadb(hw, vif, MWL8K_STA_DB_DEL_ENTRY); | ||
3005 | memset(mwl8k_vif->bssid, 0, ETH_ALEN); | ||
3006 | } | 3488 | } |
3007 | 3489 | ||
3008 | out: | 3490 | out: |
3009 | mwl8k_fw_unlock(hw); | 3491 | mwl8k_fw_unlock(hw); |
3010 | } | 3492 | } |
3011 | 3493 | ||
3494 | static void | ||
3495 | mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3496 | struct ieee80211_bss_conf *info, u32 changed) | ||
3497 | { | ||
3498 | int rc; | ||
3499 | |||
3500 | if (mwl8k_fw_lock(hw)) | ||
3501 | return; | ||
3502 | |||
3503 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
3504 | rc = mwl8k_set_radio_preamble(hw, | ||
3505 | vif->bss_conf.use_short_preamble); | ||
3506 | if (rc) | ||
3507 | goto out; | ||
3508 | } | ||
3509 | |||
3510 | if (changed & BSS_CHANGED_BASIC_RATES) { | ||
3511 | int idx; | ||
3512 | int rate; | ||
3513 | |||
3514 | /* | ||
3515 | * Use lowest supported basic rate for multicasts | ||
3516 | * and management frames (such as probe responses -- | ||
3517 | * beacons will always go out at 1 Mb/s). | ||
3518 | */ | ||
3519 | idx = ffs(vif->bss_conf.basic_rates); | ||
3520 | if (idx) | ||
3521 | idx--; | ||
3522 | |||
3523 | if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
3524 | rate = mwl8k_rates_24[idx].hw_value; | ||
3525 | else | ||
3526 | rate = mwl8k_rates_50[idx].hw_value; | ||
3527 | |||
3528 | mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate); | ||
3529 | } | ||
3530 | |||
3531 | if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) { | ||
3532 | struct sk_buff *skb; | ||
3533 | |||
3534 | skb = ieee80211_beacon_get(hw, vif); | ||
3535 | if (skb != NULL) { | ||
3536 | mwl8k_cmd_set_beacon(hw, vif, skb->data, skb->len); | ||
3537 | kfree_skb(skb); | ||
3538 | } | ||
3539 | } | ||
3540 | |||
3541 | if (changed & BSS_CHANGED_BEACON_ENABLED) | ||
3542 | mwl8k_cmd_bss_start(hw, vif, info->enable_beacon); | ||
3543 | |||
3544 | out: | ||
3545 | mwl8k_fw_unlock(hw); | ||
3546 | } | ||
3547 | |||
3548 | static void | ||
3549 | mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3550 | struct ieee80211_bss_conf *info, u32 changed) | ||
3551 | { | ||
3552 | struct mwl8k_priv *priv = hw->priv; | ||
3553 | |||
3554 | if (!priv->ap_fw) | ||
3555 | mwl8k_bss_info_changed_sta(hw, vif, info, changed); | ||
3556 | else | ||
3557 | mwl8k_bss_info_changed_ap(hw, vif, info, changed); | ||
3558 | } | ||
3559 | |||
3012 | static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, | 3560 | static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, |
3013 | int mc_count, struct dev_addr_list *mclist) | 3561 | int mc_count, struct dev_addr_list *mclist) |
3014 | { | 3562 | { |
@@ -3038,7 +3586,7 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, | |||
3038 | * operation, so refuse to enable sniffer mode if a STA | 3586 | * operation, so refuse to enable sniffer mode if a STA |
3039 | * interface is active. | 3587 | * interface is active. |
3040 | */ | 3588 | */ |
3041 | if (priv->vif != NULL) { | 3589 | if (!list_empty(&priv->vif_list)) { |
3042 | if (net_ratelimit()) | 3590 | if (net_ratelimit()) |
3043 | printk(KERN_INFO "%s: not enabling sniffer " | 3591 | printk(KERN_INFO "%s: not enabling sniffer " |
3044 | "mode because STA interface is active\n", | 3592 | "mode because STA interface is active\n", |
@@ -3059,6 +3607,14 @@ mwl8k_configure_filter_sniffer(struct ieee80211_hw *hw, | |||
3059 | return 1; | 3607 | return 1; |
3060 | } | 3608 | } |
3061 | 3609 | ||
3610 | static struct mwl8k_vif *mwl8k_first_vif(struct mwl8k_priv *priv) | ||
3611 | { | ||
3612 | if (!list_empty(&priv->vif_list)) | ||
3613 | return list_entry(priv->vif_list.next, struct mwl8k_vif, list); | ||
3614 | |||
3615 | return NULL; | ||
3616 | } | ||
3617 | |||
3062 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, | 3618 | static void mwl8k_configure_filter(struct ieee80211_hw *hw, |
3063 | unsigned int changed_flags, | 3619 | unsigned int changed_flags, |
3064 | unsigned int *total_flags, | 3620 | unsigned int *total_flags, |
@@ -3090,8 +3646,10 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, | |||
3090 | /* Clear unsupported feature flags */ | 3646 | /* Clear unsupported feature flags */ |
3091 | *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; | 3647 | *total_flags &= FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC; |
3092 | 3648 | ||
3093 | if (mwl8k_fw_lock(hw)) | 3649 | if (mwl8k_fw_lock(hw)) { |
3650 | kfree(cmd); | ||
3094 | return; | 3651 | return; |
3652 | } | ||
3095 | 3653 | ||
3096 | if (priv->sniffer_enabled) { | 3654 | if (priv->sniffer_enabled) { |
3097 | mwl8k_cmd_enable_sniffer(hw, 0); | 3655 | mwl8k_cmd_enable_sniffer(hw, 0); |
@@ -3105,7 +3663,8 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, | |||
3105 | */ | 3663 | */ |
3106 | mwl8k_cmd_set_pre_scan(hw); | 3664 | mwl8k_cmd_set_pre_scan(hw); |
3107 | } else { | 3665 | } else { |
3108 | u8 *bssid; | 3666 | struct mwl8k_vif *mwl8k_vif; |
3667 | const u8 *bssid; | ||
3109 | 3668 | ||
3110 | /* | 3669 | /* |
3111 | * Enable the BSS filter. | 3670 | * Enable the BSS filter. |
@@ -3115,9 +3674,11 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, | |||
3115 | * (where the OUI part needs to be nonzero for | 3674 | * (where the OUI part needs to be nonzero for |
3116 | * the BSSID to be accepted by POST_SCAN). | 3675 | * the BSSID to be accepted by POST_SCAN). |
3117 | */ | 3676 | */ |
3118 | bssid = "\x01\x00\x00\x00\x00\x00"; | 3677 | mwl8k_vif = mwl8k_first_vif(priv); |
3119 | if (priv->vif != NULL) | 3678 | if (mwl8k_vif != NULL) |
3120 | bssid = MWL8K_VIF(priv->vif)->bssid; | 3679 | bssid = mwl8k_vif->vif->bss_conf.bssid; |
3680 | else | ||
3681 | bssid = "\x01\x00\x00\x00\x00\x00"; | ||
3121 | 3682 | ||
3122 | mwl8k_cmd_set_post_scan(hw, bssid); | 3683 | mwl8k_cmd_set_post_scan(hw, bssid); |
3123 | } | 3684 | } |
@@ -3144,7 +3705,93 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, | |||
3144 | 3705 | ||
3145 | static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | 3706 | static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
3146 | { | 3707 | { |
3147 | return mwl8k_cmd_set_rts_threshold(hw, MWL8K_CMD_SET, value); | 3708 | return mwl8k_cmd_set_rts_threshold(hw, value); |
3709 | } | ||
3710 | |||
3711 | struct mwl8k_sta_notify_item | ||
3712 | { | ||
3713 | struct list_head list; | ||
3714 | struct ieee80211_vif *vif; | ||
3715 | enum sta_notify_cmd cmd; | ||
3716 | struct ieee80211_sta sta; | ||
3717 | }; | ||
3718 | |||
3719 | static void | ||
3720 | mwl8k_do_sta_notify(struct ieee80211_hw *hw, struct mwl8k_sta_notify_item *s) | ||
3721 | { | ||
3722 | struct mwl8k_priv *priv = hw->priv; | ||
3723 | |||
3724 | /* | ||
3725 | * STA firmware uses UPDATE_STADB, AP firmware uses SET_NEW_STN. | ||
3726 | */ | ||
3727 | if (!priv->ap_fw && s->cmd == STA_NOTIFY_ADD) { | ||
3728 | int rc; | ||
3729 | |||
3730 | rc = mwl8k_cmd_update_stadb_add(hw, s->vif, &s->sta); | ||
3731 | if (rc >= 0) { | ||
3732 | struct ieee80211_sta *sta; | ||
3733 | |||
3734 | rcu_read_lock(); | ||
3735 | sta = ieee80211_find_sta(s->vif, s->sta.addr); | ||
3736 | if (sta != NULL) | ||
3737 | MWL8K_STA(sta)->peer_id = rc; | ||
3738 | rcu_read_unlock(); | ||
3739 | } | ||
3740 | } else if (!priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) { | ||
3741 | mwl8k_cmd_update_stadb_del(hw, s->vif, s->sta.addr); | ||
3742 | } else if (priv->ap_fw && s->cmd == STA_NOTIFY_ADD) { | ||
3743 | mwl8k_cmd_set_new_stn_add(hw, s->vif, &s->sta); | ||
3744 | } else if (priv->ap_fw && s->cmd == STA_NOTIFY_REMOVE) { | ||
3745 | mwl8k_cmd_set_new_stn_del(hw, s->vif, s->sta.addr); | ||
3746 | } | ||
3747 | } | ||
3748 | |||
3749 | static void mwl8k_sta_notify_worker(struct work_struct *work) | ||
3750 | { | ||
3751 | struct mwl8k_priv *priv = | ||
3752 | container_of(work, struct mwl8k_priv, sta_notify_worker); | ||
3753 | struct ieee80211_hw *hw = priv->hw; | ||
3754 | |||
3755 | spin_lock_bh(&priv->sta_notify_list_lock); | ||
3756 | while (!list_empty(&priv->sta_notify_list)) { | ||
3757 | struct mwl8k_sta_notify_item *s; | ||
3758 | |||
3759 | s = list_entry(priv->sta_notify_list.next, | ||
3760 | struct mwl8k_sta_notify_item, list); | ||
3761 | list_del(&s->list); | ||
3762 | |||
3763 | spin_unlock_bh(&priv->sta_notify_list_lock); | ||
3764 | |||
3765 | mwl8k_do_sta_notify(hw, s); | ||
3766 | kfree(s); | ||
3767 | |||
3768 | spin_lock_bh(&priv->sta_notify_list_lock); | ||
3769 | } | ||
3770 | spin_unlock_bh(&priv->sta_notify_list_lock); | ||
3771 | } | ||
3772 | |||
3773 | static void | ||
3774 | mwl8k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3775 | enum sta_notify_cmd cmd, struct ieee80211_sta *sta) | ||
3776 | { | ||
3777 | struct mwl8k_priv *priv = hw->priv; | ||
3778 | struct mwl8k_sta_notify_item *s; | ||
3779 | |||
3780 | if (cmd != STA_NOTIFY_ADD && cmd != STA_NOTIFY_REMOVE) | ||
3781 | return; | ||
3782 | |||
3783 | s = kmalloc(sizeof(*s), GFP_ATOMIC); | ||
3784 | if (s != NULL) { | ||
3785 | s->vif = vif; | ||
3786 | s->cmd = cmd; | ||
3787 | s->sta = *sta; | ||
3788 | |||
3789 | spin_lock(&priv->sta_notify_list_lock); | ||
3790 | list_add_tail(&s->list, &priv->sta_notify_list); | ||
3791 | spin_unlock(&priv->sta_notify_list_lock); | ||
3792 | |||
3793 | ieee80211_queue_work(hw, &priv->sta_notify_worker); | ||
3794 | } | ||
3148 | } | 3795 | } |
3149 | 3796 | ||
3150 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, | 3797 | static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, |
@@ -3195,6 +3842,22 @@ static int mwl8k_get_stats(struct ieee80211_hw *hw, | |||
3195 | return mwl8k_cmd_get_stat(hw, stats); | 3842 | return mwl8k_cmd_get_stat(hw, stats); |
3196 | } | 3843 | } |
3197 | 3844 | ||
3845 | static int | ||
3846 | mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
3847 | enum ieee80211_ampdu_mlme_action action, | ||
3848 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | ||
3849 | { | ||
3850 | switch (action) { | ||
3851 | case IEEE80211_AMPDU_RX_START: | ||
3852 | case IEEE80211_AMPDU_RX_STOP: | ||
3853 | if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) | ||
3854 | return -ENOTSUPP; | ||
3855 | return 0; | ||
3856 | default: | ||
3857 | return -ENOTSUPP; | ||
3858 | } | ||
3859 | } | ||
3860 | |||
3198 | static const struct ieee80211_ops mwl8k_ops = { | 3861 | static const struct ieee80211_ops mwl8k_ops = { |
3199 | .tx = mwl8k_tx, | 3862 | .tx = mwl8k_tx, |
3200 | .start = mwl8k_start, | 3863 | .start = mwl8k_start, |
@@ -3206,47 +3869,41 @@ static const struct ieee80211_ops mwl8k_ops = { | |||
3206 | .prepare_multicast = mwl8k_prepare_multicast, | 3869 | .prepare_multicast = mwl8k_prepare_multicast, |
3207 | .configure_filter = mwl8k_configure_filter, | 3870 | .configure_filter = mwl8k_configure_filter, |
3208 | .set_rts_threshold = mwl8k_set_rts_threshold, | 3871 | .set_rts_threshold = mwl8k_set_rts_threshold, |
3872 | .sta_notify = mwl8k_sta_notify, | ||
3209 | .conf_tx = mwl8k_conf_tx, | 3873 | .conf_tx = mwl8k_conf_tx, |
3210 | .get_tx_stats = mwl8k_get_tx_stats, | 3874 | .get_tx_stats = mwl8k_get_tx_stats, |
3211 | .get_stats = mwl8k_get_stats, | 3875 | .get_stats = mwl8k_get_stats, |
3876 | .ampdu_action = mwl8k_ampdu_action, | ||
3212 | }; | 3877 | }; |
3213 | 3878 | ||
3214 | static void mwl8k_tx_reclaim_handler(unsigned long data) | ||
3215 | { | ||
3216 | int i; | ||
3217 | struct ieee80211_hw *hw = (struct ieee80211_hw *) data; | ||
3218 | struct mwl8k_priv *priv = hw->priv; | ||
3219 | |||
3220 | spin_lock_bh(&priv->tx_lock); | ||
3221 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | ||
3222 | mwl8k_txq_reclaim(hw, i, 0); | ||
3223 | |||
3224 | if (priv->tx_wait != NULL && !priv->pending_tx_pkts) { | ||
3225 | complete(priv->tx_wait); | ||
3226 | priv->tx_wait = NULL; | ||
3227 | } | ||
3228 | spin_unlock_bh(&priv->tx_lock); | ||
3229 | } | ||
3230 | |||
3231 | static void mwl8k_finalize_join_worker(struct work_struct *work) | 3879 | static void mwl8k_finalize_join_worker(struct work_struct *work) |
3232 | { | 3880 | { |
3233 | struct mwl8k_priv *priv = | 3881 | struct mwl8k_priv *priv = |
3234 | container_of(work, struct mwl8k_priv, finalize_join_worker); | 3882 | container_of(work, struct mwl8k_priv, finalize_join_worker); |
3235 | struct sk_buff *skb = priv->beacon_skb; | 3883 | struct sk_buff *skb = priv->beacon_skb; |
3884 | struct mwl8k_vif *mwl8k_vif; | ||
3236 | 3885 | ||
3237 | mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, | 3886 | mwl8k_vif = mwl8k_first_vif(priv); |
3238 | priv->vif->bss_conf.dtim_period); | 3887 | if (mwl8k_vif != NULL) |
3239 | dev_kfree_skb(skb); | 3888 | mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, |
3889 | mwl8k_vif->vif->bss_conf.dtim_period); | ||
3240 | 3890 | ||
3891 | dev_kfree_skb(skb); | ||
3241 | priv->beacon_skb = NULL; | 3892 | priv->beacon_skb = NULL; |
3242 | } | 3893 | } |
3243 | 3894 | ||
3244 | enum { | 3895 | enum { |
3245 | MWL8687 = 0, | 3896 | MWL8363 = 0, |
3897 | MWL8687, | ||
3246 | MWL8366, | 3898 | MWL8366, |
3247 | }; | 3899 | }; |
3248 | 3900 | ||
3249 | static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { | 3901 | static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { |
3902 | [MWL8363] = { | ||
3903 | .part_name = "88w8363", | ||
3904 | .helper_image = "mwl8k/helper_8363.fw", | ||
3905 | .fw_image = "mwl8k/fmimage_8363.fw", | ||
3906 | }, | ||
3250 | [MWL8687] = { | 3907 | [MWL8687] = { |
3251 | .part_name = "88w8687", | 3908 | .part_name = "88w8687", |
3252 | .helper_image = "mwl8k/helper_8687.fw", | 3909 | .helper_image = "mwl8k/helper_8687.fw", |
@@ -3260,10 +3917,20 @@ static struct mwl8k_device_info mwl8k_info_tbl[] __devinitdata = { | |||
3260 | }, | 3917 | }, |
3261 | }; | 3918 | }; |
3262 | 3919 | ||
3920 | MODULE_FIRMWARE("mwl8k/helper_8363.fw"); | ||
3921 | MODULE_FIRMWARE("mwl8k/fmimage_8363.fw"); | ||
3922 | MODULE_FIRMWARE("mwl8k/helper_8687.fw"); | ||
3923 | MODULE_FIRMWARE("mwl8k/fmimage_8687.fw"); | ||
3924 | MODULE_FIRMWARE("mwl8k/helper_8366.fw"); | ||
3925 | MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); | ||
3926 | |||
3263 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { | 3927 | static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = { |
3928 | { PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, }, | ||
3929 | { PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, }, | ||
3264 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, | 3930 | { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = MWL8687, }, |
3265 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, | 3931 | { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = MWL8687, }, |
3266 | { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, | 3932 | { PCI_VDEVICE(MARVELL, 0x2a40), .driver_data = MWL8366, }, |
3933 | { PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, }, | ||
3267 | { }, | 3934 | { }, |
3268 | }; | 3935 | }; |
3269 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); | 3936 | MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table); |
@@ -3361,27 +4028,23 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3361 | mwl8k_release_firmware(priv); | 4028 | mwl8k_release_firmware(priv); |
3362 | 4029 | ||
3363 | 4030 | ||
3364 | if (priv->ap_fw) | 4031 | if (priv->ap_fw) { |
3365 | priv->rxd_ops = priv->device_info->ap_rxd_ops; | 4032 | priv->rxd_ops = priv->device_info->ap_rxd_ops; |
3366 | else | 4033 | if (priv->rxd_ops == NULL) { |
4034 | printk(KERN_ERR "%s: Driver does not have AP " | ||
4035 | "firmware image support for this hardware\n", | ||
4036 | wiphy_name(hw->wiphy)); | ||
4037 | goto err_stop_firmware; | ||
4038 | } | ||
4039 | } else { | ||
3367 | priv->rxd_ops = &rxd_sta_ops; | 4040 | priv->rxd_ops = &rxd_sta_ops; |
4041 | } | ||
3368 | 4042 | ||
3369 | priv->sniffer_enabled = false; | 4043 | priv->sniffer_enabled = false; |
3370 | priv->wmm_enabled = false; | 4044 | priv->wmm_enabled = false; |
3371 | priv->pending_tx_pkts = 0; | 4045 | priv->pending_tx_pkts = 0; |
3372 | 4046 | ||
3373 | 4047 | ||
3374 | memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels)); | ||
3375 | priv->band.band = IEEE80211_BAND_2GHZ; | ||
3376 | priv->band.channels = priv->channels; | ||
3377 | priv->band.n_channels = ARRAY_SIZE(mwl8k_channels); | ||
3378 | priv->band.bitrates = priv->rates; | ||
3379 | priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates); | ||
3380 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; | ||
3381 | |||
3382 | BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates)); | ||
3383 | memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates)); | ||
3384 | |||
3385 | /* | 4048 | /* |
3386 | * Extra headroom is the size of the required DMA header | 4049 | * Extra headroom is the size of the required DMA header |
3387 | * minus the size of the smallest 802.11 frame (CTS frame). | 4050 | * minus the size of the smallest 802.11 frame (CTS frame). |
@@ -3396,19 +4059,28 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3396 | /* Set rssi and noise values to dBm */ | 4059 | /* Set rssi and noise values to dBm */ |
3397 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; | 4060 | hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; |
3398 | hw->vif_data_size = sizeof(struct mwl8k_vif); | 4061 | hw->vif_data_size = sizeof(struct mwl8k_vif); |
3399 | priv->vif = NULL; | 4062 | hw->sta_data_size = sizeof(struct mwl8k_sta); |
4063 | |||
4064 | priv->macids_used = 0; | ||
4065 | INIT_LIST_HEAD(&priv->vif_list); | ||
3400 | 4066 | ||
3401 | /* Set default radio state and preamble */ | 4067 | /* Set default radio state and preamble */ |
3402 | priv->radio_on = 0; | 4068 | priv->radio_on = 0; |
3403 | priv->radio_short_preamble = 0; | 4069 | priv->radio_short_preamble = 0; |
3404 | 4070 | ||
4071 | /* Station database handling */ | ||
4072 | INIT_WORK(&priv->sta_notify_worker, mwl8k_sta_notify_worker); | ||
4073 | spin_lock_init(&priv->sta_notify_list_lock); | ||
4074 | INIT_LIST_HEAD(&priv->sta_notify_list); | ||
4075 | |||
3405 | /* Finalize join worker */ | 4076 | /* Finalize join worker */ |
3406 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); | 4077 | INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker); |
3407 | 4078 | ||
3408 | /* TX reclaim tasklet */ | 4079 | /* TX reclaim and RX tasklets. */ |
3409 | tasklet_init(&priv->tx_reclaim_task, | 4080 | tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw); |
3410 | mwl8k_tx_reclaim_handler, (unsigned long)hw); | 4081 | tasklet_disable(&priv->poll_tx_task); |
3411 | tasklet_disable(&priv->tx_reclaim_task); | 4082 | tasklet_init(&priv->poll_rx_task, mwl8k_rx_poll, (unsigned long)hw); |
4083 | tasklet_disable(&priv->poll_rx_task); | ||
3412 | 4084 | ||
3413 | /* Power management cookie */ | 4085 | /* Power management cookie */ |
3414 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); | 4086 | priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma); |
@@ -3437,7 +4109,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3437 | 4109 | ||
3438 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); | 4110 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS); |
3439 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4111 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
3440 | iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | 4112 | iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY, |
4113 | priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL); | ||
3441 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); | 4114 | iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK); |
3442 | 4115 | ||
3443 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, | 4116 | rc = request_irq(priv->pdev->irq, mwl8k_interrupt, |
@@ -3450,7 +4123,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3450 | 4123 | ||
3451 | /* | 4124 | /* |
3452 | * Temporarily enable interrupts. Initial firmware host | 4125 | * Temporarily enable interrupts. Initial firmware host |
3453 | * commands use interrupts and avoids polling. Disable | 4126 | * commands use interrupts and avoid polling. Disable |
3454 | * interrupts when done. | 4127 | * interrupts when done. |
3455 | */ | 4128 | */ |
3456 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); | 4129 | iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); |
@@ -3462,8 +4135,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3462 | rc = mwl8k_cmd_set_hw_spec(hw); | 4135 | rc = mwl8k_cmd_set_hw_spec(hw); |
3463 | } else { | 4136 | } else { |
3464 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | 4137 | rc = mwl8k_cmd_get_hw_spec_sta(hw); |
3465 | |||
3466 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
3467 | } | 4138 | } |
3468 | if (rc) { | 4139 | if (rc) { |
3469 | printk(KERN_ERR "%s: Cannot initialise firmware\n", | 4140 | printk(KERN_ERR "%s: Cannot initialise firmware\n", |
@@ -3471,6 +4142,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3471 | goto err_free_irq; | 4142 | goto err_free_irq; |
3472 | } | 4143 | } |
3473 | 4144 | ||
4145 | hw->wiphy->interface_modes = 0; | ||
4146 | if (priv->ap_macids_supported) | ||
4147 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
4148 | if (priv->sta_macids_supported) | ||
4149 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
4150 | |||
4151 | |||
3474 | /* Turn radio off */ | 4152 | /* Turn radio off */ |
3475 | rc = mwl8k_cmd_radio_disable(hw); | 4153 | rc = mwl8k_cmd_radio_disable(hw); |
3476 | if (rc) { | 4154 | if (rc) { |
@@ -3479,7 +4157,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3479 | } | 4157 | } |
3480 | 4158 | ||
3481 | /* Clear MAC address */ | 4159 | /* Clear MAC address */ |
3482 | rc = mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); | 4160 | rc = mwl8k_cmd_set_mac_addr(hw, NULL, "\x00\x00\x00\x00\x00\x00"); |
3483 | if (rc) { | 4161 | if (rc) { |
3484 | printk(KERN_ERR "%s: Cannot clear MAC address\n", | 4162 | printk(KERN_ERR "%s: Cannot clear MAC address\n", |
3485 | wiphy_name(hw->wiphy)); | 4163 | wiphy_name(hw->wiphy)); |
@@ -3494,7 +4172,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
3494 | if (rc) { | 4172 | if (rc) { |
3495 | printk(KERN_ERR "%s: Cannot register device\n", | 4173 | printk(KERN_ERR "%s: Cannot register device\n", |
3496 | wiphy_name(hw->wiphy)); | 4174 | wiphy_name(hw->wiphy)); |
3497 | goto err_free_irq; | 4175 | goto err_free_queues; |
3498 | } | 4176 | } |
3499 | 4177 | ||
3500 | printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", | 4178 | printk(KERN_INFO "%s: %s v%d, %pM, %s firmware %u.%u.%u.%u\n", |
@@ -3562,15 +4240,16 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev) | |||
3562 | 4240 | ||
3563 | ieee80211_unregister_hw(hw); | 4241 | ieee80211_unregister_hw(hw); |
3564 | 4242 | ||
3565 | /* Remove tx reclaim tasklet */ | 4243 | /* Remove TX reclaim and RX tasklets. */ |
3566 | tasklet_kill(&priv->tx_reclaim_task); | 4244 | tasklet_kill(&priv->poll_tx_task); |
4245 | tasklet_kill(&priv->poll_rx_task); | ||
3567 | 4246 | ||
3568 | /* Stop hardware */ | 4247 | /* Stop hardware */ |
3569 | mwl8k_hw_reset(priv); | 4248 | mwl8k_hw_reset(priv); |
3570 | 4249 | ||
3571 | /* Return all skbs to mac80211 */ | 4250 | /* Return all skbs to mac80211 */ |
3572 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4251 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
3573 | mwl8k_txq_reclaim(hw, i, 1); | 4252 | mwl8k_txq_reclaim(hw, i, INT_MAX, 1); |
3574 | 4253 | ||
3575 | for (i = 0; i < MWL8K_TX_QUEUES; i++) | 4254 | for (i = 0; i < MWL8K_TX_QUEUES; i++) |
3576 | mwl8k_txq_deinit(hw, i); | 4255 | mwl8k_txq_deinit(hw, i); |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 8ff7db853286..529a37364eb0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -245,6 +245,25 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); | 246 | EXPORT_SYMBOL_GPL(rt2800_mcu_request); |
247 | 247 | ||
248 | int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) | ||
249 | { | ||
250 | unsigned int i; | ||
251 | u32 reg; | ||
252 | |||
253 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | ||
254 | rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); | ||
255 | if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && | ||
256 | !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) | ||
257 | return 0; | ||
258 | |||
259 | msleep(1); | ||
260 | } | ||
261 | |||
262 | ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); | ||
263 | return -EACCES; | ||
264 | } | ||
265 | EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready); | ||
266 | |||
248 | #ifdef CONFIG_RT2X00_LIB_DEBUGFS | 267 | #ifdef CONFIG_RT2X00_LIB_DEBUGFS |
249 | const struct rt2x00debug rt2800_rt2x00debug = { | 268 | const struct rt2x00debug rt2800_rt2x00debug = { |
250 | .owner = THIS_MODULE, | 269 | .owner = THIS_MODULE, |
@@ -339,7 +358,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev, | |||
339 | rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); | 358 | rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); |
340 | rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); | 359 | rt2x00_set_field32(®, LED_CFG_SLOW_BLINK_PERIOD, 3); |
341 | rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); | 360 | rt2x00_set_field32(®, LED_CFG_R_LED_MODE, 3); |
342 | rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 12); | 361 | rt2x00_set_field32(®, LED_CFG_G_LED_MODE, 3); |
343 | rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); | 362 | rt2x00_set_field32(®, LED_CFG_Y_LED_MODE, 3); |
344 | rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); | 363 | rt2x00_set_field32(®, LED_CFG_LED_POLAR, 1); |
345 | rt2800_register_write(led->rt2x00dev, LED_CFG, reg); | 364 | rt2800_register_write(led->rt2x00dev, LED_CFG, reg); |
@@ -347,7 +366,7 @@ static int rt2800_blink_set(struct led_classdev *led_cdev, | |||
347 | return 0; | 366 | return 0; |
348 | } | 367 | } |
349 | 368 | ||
350 | void rt2800_init_led(struct rt2x00_dev *rt2x00dev, | 369 | static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, |
351 | struct rt2x00_led *led, enum led_type type) | 370 | struct rt2x00_led *led, enum led_type type) |
352 | { | 371 | { |
353 | led->rt2x00dev = rt2x00dev; | 372 | led->rt2x00dev = rt2x00dev; |
@@ -356,7 +375,6 @@ void rt2800_init_led(struct rt2x00_dev *rt2x00dev, | |||
356 | led->led_dev.blink_set = rt2800_blink_set; | 375 | led->led_dev.blink_set = rt2800_blink_set; |
357 | led->flags = LED_INITIALIZED; | 376 | led->flags = LED_INITIALIZED; |
358 | } | 377 | } |
359 | EXPORT_SYMBOL_GPL(rt2800_init_led); | ||
360 | #endif /* CONFIG_RT2X00_LIB_LEDS */ | 378 | #endif /* CONFIG_RT2X00_LIB_LEDS */ |
361 | 379 | ||
362 | /* | 380 | /* |
@@ -1862,7 +1880,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | |||
1862 | !rt2x00_rf(rt2x00dev, RF3020) && | 1880 | !rt2x00_rf(rt2x00dev, RF3020) && |
1863 | !rt2x00_rf(rt2x00dev, RF2020) && | 1881 | !rt2x00_rf(rt2x00dev, RF2020) && |
1864 | !rt2x00_rf(rt2x00dev, RF3021) && | 1882 | !rt2x00_rf(rt2x00dev, RF3021) && |
1865 | !rt2x00_rf(rt2x00dev, RF3022)) { | 1883 | !rt2x00_rf(rt2x00dev, RF3022) && |
1884 | !rt2x00_rf(rt2x00dev, RF3052)) { | ||
1866 | ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | 1885 | ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); |
1867 | return -ENODEV; | 1886 | return -ENODEV; |
1868 | } | 1887 | } |
@@ -2047,7 +2066,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | |||
2047 | 2066 | ||
2048 | if (rt2x00_rf(rt2x00dev, RF2820) || | 2067 | if (rt2x00_rf(rt2x00dev, RF2820) || |
2049 | rt2x00_rf(rt2x00dev, RF2720) || | 2068 | rt2x00_rf(rt2x00dev, RF2720) || |
2050 | (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) { | 2069 | rt2x00_rf(rt2x00dev, RF3052)) { |
2051 | spec->num_channels = 14; | 2070 | spec->num_channels = 14; |
2052 | spec->channels = rf_vals; | 2071 | spec->channels = rf_vals; |
2053 | } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { | 2072 | } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 535ce22f2ac8..ebabeae62d1b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h | |||
@@ -114,8 +114,6 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, | |||
114 | extern const struct rt2x00debug rt2800_rt2x00debug; | 114 | extern const struct rt2x00debug rt2800_rt2x00debug; |
115 | 115 | ||
116 | int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev); | 116 | int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev); |
117 | void rt2800_init_led(struct rt2x00_dev *rt2x00dev, | ||
118 | struct rt2x00_led *led, enum led_type type); | ||
119 | int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, | 117 | int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, |
120 | struct rt2x00lib_crypto *crypto, | 118 | struct rt2x00lib_crypto *crypto, |
121 | struct ieee80211_key_conf *key); | 119 | struct ieee80211_key_conf *key); |
@@ -139,6 +137,7 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, | |||
139 | int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); | 137 | int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); |
140 | int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); | 138 | int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); |
141 | int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); | 139 | int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); |
140 | int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); | ||
142 | 141 | ||
143 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); | 142 | int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); |
144 | void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); | 143 | void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 99095e1ee13b..d64181cbc9cb 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -453,24 +453,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
453 | rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); | 453 | rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); |
454 | } | 454 | } |
455 | 455 | ||
456 | static int rt2800pci_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) | ||
457 | { | ||
458 | unsigned int i; | ||
459 | u32 reg; | ||
460 | |||
461 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | ||
462 | rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); | ||
463 | if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && | ||
464 | !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) | ||
465 | return 0; | ||
466 | |||
467 | msleep(1); | ||
468 | } | ||
469 | |||
470 | ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); | ||
471 | return -EACCES; | ||
472 | } | ||
473 | |||
474 | static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) | 456 | static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) |
475 | { | 457 | { |
476 | u32 reg; | 458 | u32 reg; |
@@ -479,10 +461,10 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
479 | /* | 461 | /* |
480 | * Initialize all registers. | 462 | * Initialize all registers. |
481 | */ | 463 | */ |
482 | if (unlikely(rt2800pci_wait_wpdma_ready(rt2x00dev) || | 464 | if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || |
483 | rt2800pci_init_queues(rt2x00dev) || | 465 | rt2800pci_init_queues(rt2x00dev) || |
484 | rt2800_init_registers(rt2x00dev) || | 466 | rt2800_init_registers(rt2x00dev) || |
485 | rt2800pci_wait_wpdma_ready(rt2x00dev) || | 467 | rt2800_wait_wpdma_ready(rt2x00dev) || |
486 | rt2800_init_bbp(rt2x00dev) || | 468 | rt2800_init_bbp(rt2x00dev) || |
487 | rt2800_init_rfcsr(rt2x00dev))) | 469 | rt2800_init_rfcsr(rt2x00dev))) |
488 | return -EIO; | 470 | return -EIO; |
@@ -562,7 +544,7 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
562 | rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); | 544 | rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); |
563 | 545 | ||
564 | /* Wait for DMA, ignore error */ | 546 | /* Wait for DMA, ignore error */ |
565 | rt2800pci_wait_wpdma_ready(rt2x00dev); | 547 | rt2800_wait_wpdma_ready(rt2x00dev); |
566 | } | 548 | } |
567 | 549 | ||
568 | static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, | 550 | static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0510f020dcf5..82755cf8b73e 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -248,24 +248,6 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, | |||
248 | rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); | 248 | rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); |
249 | } | 249 | } |
250 | 250 | ||
251 | static int rt2800usb_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) | ||
252 | { | ||
253 | unsigned int i; | ||
254 | u32 reg; | ||
255 | |||
256 | for (i = 0; i < REGISTER_BUSY_COUNT; i++) { | ||
257 | rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); | ||
258 | if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && | ||
259 | !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) | ||
260 | return 0; | ||
261 | |||
262 | msleep(1); | ||
263 | } | ||
264 | |||
265 | ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); | ||
266 | return -EACCES; | ||
267 | } | ||
268 | |||
269 | static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) | 251 | static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) |
270 | { | 252 | { |
271 | u32 reg; | 253 | u32 reg; |
@@ -274,7 +256,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
274 | /* | 256 | /* |
275 | * Initialize all registers. | 257 | * Initialize all registers. |
276 | */ | 258 | */ |
277 | if (unlikely(rt2800usb_wait_wpdma_ready(rt2x00dev) || | 259 | if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || |
278 | rt2800_init_registers(rt2x00dev) || | 260 | rt2800_init_registers(rt2x00dev) || |
279 | rt2800_init_bbp(rt2x00dev) || | 261 | rt2800_init_bbp(rt2x00dev) || |
280 | rt2800_init_rfcsr(rt2x00dev))) | 262 | rt2800_init_rfcsr(rt2x00dev))) |
@@ -344,7 +326,7 @@ static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
344 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); | 326 | rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); |
345 | 327 | ||
346 | /* Wait for DMA, ignore error */ | 328 | /* Wait for DMA, ignore error */ |
347 | rt2800usb_wait_wpdma_ready(rt2x00dev); | 329 | rt2800_wait_wpdma_ready(rt2x00dev); |
348 | 330 | ||
349 | rt2x00usb_disable_radio(rt2x00dev); | 331 | rt2x00usb_disable_radio(rt2x00dev); |
350 | } | 332 | } |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index b4c6e0a6d7e0..096da85a66fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -119,6 +119,12 @@ | |||
119 | ( ((unsigned long)((__skb)->data + (__header))) & 3 ) | 119 | ( ((unsigned long)((__skb)->data + (__header))) & 3 ) |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * Constants for extra TX headroom for alignment purposes. | ||
123 | */ | ||
124 | #define RT2X00_ALIGN_SIZE 4 /* Only whole frame needs alignment */ | ||
125 | #define RT2X00_L2PAD_SIZE 8 /* Both header & payload need alignment */ | ||
126 | |||
127 | /* | ||
122 | * Standard timing and size defines. | 128 | * Standard timing and size defines. |
123 | * These values should follow the ieee80211 specifications. | 129 | * These values should follow the ieee80211 specifications. |
124 | */ | 130 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index d7711e4d4751..b93731b79903 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -688,7 +688,17 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
688 | /* | 688 | /* |
689 | * Initialize extra TX headroom required. | 689 | * Initialize extra TX headroom required. |
690 | */ | 690 | */ |
691 | rt2x00dev->hw->extra_tx_headroom = rt2x00dev->ops->extra_tx_headroom; | 691 | rt2x00dev->hw->extra_tx_headroom = |
692 | max_t(unsigned int, IEEE80211_TX_STATUS_HEADROOM, | ||
693 | rt2x00dev->ops->extra_tx_headroom); | ||
694 | |||
695 | /* | ||
696 | * Take TX headroom required for alignment into account. | ||
697 | */ | ||
698 | if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags)) | ||
699 | rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE; | ||
700 | else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) | ||
701 | rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; | ||
692 | 702 | ||
693 | /* | 703 | /* |
694 | * Register HW. | 704 | * Register HW. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 3d8fb684b4eb..0b4801a14601 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -104,7 +104,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
104 | * is also mapped to the DMA so it can be used for transfering | 104 | * is also mapped to the DMA so it can be used for transfering |
105 | * additional descriptor information to the hardware. | 105 | * additional descriptor information to the hardware. |
106 | */ | 106 | */ |
107 | skb_push(skb, rt2x00dev->hw->extra_tx_headroom); | 107 | skb_push(skb, rt2x00dev->ops->extra_tx_headroom); |
108 | 108 | ||
109 | skbdesc->skb_dma = | 109 | skbdesc->skb_dma = |
110 | dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); | 110 | dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); |
@@ -112,7 +112,7 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
112 | /* | 112 | /* |
113 | * Restore data pointer to original location again. | 113 | * Restore data pointer to original location again. |
114 | */ | 114 | */ |
115 | skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); | 115 | skb_pull(skb, rt2x00dev->ops->extra_tx_headroom); |
116 | 116 | ||
117 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; | 117 | skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; |
118 | } | 118 | } |
@@ -134,7 +134,7 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) | |||
134 | * by the driver, but it was actually mapped to DMA. | 134 | * by the driver, but it was actually mapped to DMA. |
135 | */ | 135 | */ |
136 | dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, | 136 | dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, |
137 | skb->len + rt2x00dev->hw->extra_tx_headroom, | 137 | skb->len + rt2x00dev->ops->extra_tx_headroom, |
138 | DMA_TO_DEVICE); | 138 | DMA_TO_DEVICE); |
139 | skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; | 139 | skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; |
140 | } | 140 | } |
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c index 770f260726bd..0320b478bb3f 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c | |||
@@ -410,3 +410,86 @@ out: | |||
410 | kfree(cmd); | 410 | kfree(cmd); |
411 | return ret; | 411 | return ret; |
412 | } | 412 | } |
413 | |||
414 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
415 | struct ieee80211_channel *channels[], | ||
416 | unsigned int n_channels, unsigned int n_probes) | ||
417 | { | ||
418 | struct wl1251_cmd_scan *cmd; | ||
419 | int i, ret = 0; | ||
420 | |||
421 | wl1251_debug(DEBUG_CMD, "cmd scan"); | ||
422 | |||
423 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
424 | if (!cmd) | ||
425 | return -ENOMEM; | ||
426 | |||
427 | cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
428 | cmd->params.rx_filter_options = cpu_to_le32(CFG_RX_PRSP_EN | | ||
429 | CFG_RX_MGMT_EN | | ||
430 | CFG_RX_BCN_EN); | ||
431 | cmd->params.scan_options = 0; | ||
432 | cmd->params.num_channels = n_channels; | ||
433 | cmd->params.num_probe_requests = n_probes; | ||
434 | cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
435 | cmd->params.tid_trigger = 0; | ||
436 | |||
437 | for (i = 0; i < n_channels; i++) { | ||
438 | cmd->channels[i].min_duration = | ||
439 | cpu_to_le32(WL1251_SCAN_MIN_DURATION); | ||
440 | cmd->channels[i].max_duration = | ||
441 | cpu_to_le32(WL1251_SCAN_MAX_DURATION); | ||
442 | memset(&cmd->channels[i].bssid_lsb, 0xff, 4); | ||
443 | memset(&cmd->channels[i].bssid_msb, 0xff, 2); | ||
444 | cmd->channels[i].early_termination = 0; | ||
445 | cmd->channels[i].tx_power_att = 0; | ||
446 | cmd->channels[i].channel = channels[i]->hw_value; | ||
447 | } | ||
448 | |||
449 | cmd->params.ssid_len = ssid_len; | ||
450 | if (ssid) | ||
451 | memcpy(cmd->params.ssid, ssid, ssid_len); | ||
452 | |||
453 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
454 | if (ret < 0) { | ||
455 | wl1251_error("cmd scan failed: %d", ret); | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); | ||
460 | |||
461 | if (cmd->header.status != CMD_STATUS_SUCCESS) { | ||
462 | wl1251_error("cmd scan status wasn't success: %d", | ||
463 | cmd->header.status); | ||
464 | ret = -EIO; | ||
465 | goto out; | ||
466 | } | ||
467 | |||
468 | out: | ||
469 | kfree(cmd); | ||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout) | ||
474 | { | ||
475 | struct wl1251_cmd_trigger_scan_to *cmd; | ||
476 | int ret; | ||
477 | |||
478 | wl1251_debug(DEBUG_CMD, "cmd trigger scan to"); | ||
479 | |||
480 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
481 | if (!cmd) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | cmd->timeout = timeout; | ||
485 | |||
486 | ret = wl1251_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd)); | ||
487 | if (ret < 0) { | ||
488 | wl1251_error("cmd trigger scan to failed: %d", ret); | ||
489 | goto out; | ||
490 | } | ||
491 | |||
492 | out: | ||
493 | kfree(cmd); | ||
494 | return ret; | ||
495 | } | ||
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h index dff798ad0ef5..4ad67cae94d2 100644 --- a/drivers/net/wireless/wl12xx/wl1251_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | #include "wl1251.h" | 28 | #include "wl1251.h" |
29 | 29 | ||
30 | #include <net/cfg80211.h> | ||
31 | |||
30 | struct acx_header; | 32 | struct acx_header; |
31 | 33 | ||
32 | int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); | 34 | int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); |
@@ -43,6 +45,10 @@ int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, | |||
43 | size_t len); | 45 | size_t len); |
44 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, | 46 | int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, |
45 | void *buf, size_t buf_len); | 47 | void *buf, size_t buf_len); |
48 | int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, | ||
49 | struct ieee80211_channel *channels[], | ||
50 | unsigned int n_channels, unsigned int n_probes); | ||
51 | int wl1251_cmd_trigger_scan_to(struct wl1251 *wl, u32 timeout); | ||
46 | 52 | ||
47 | /* unit ms */ | 53 | /* unit ms */ |
48 | #define WL1251_COMMAND_TIMEOUT 2000 | 54 | #define WL1251_COMMAND_TIMEOUT 2000 |
@@ -163,8 +169,12 @@ struct cmd_read_write_memory { | |||
163 | #define CMDMBOX_HEADER_LEN 4 | 169 | #define CMDMBOX_HEADER_LEN 4 |
164 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 | 170 | #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 |
165 | 171 | ||
172 | #define WL1251_SCAN_MIN_DURATION 30000 | ||
173 | #define WL1251_SCAN_MAX_DURATION 60000 | ||
174 | |||
175 | #define WL1251_SCAN_NUM_PROBES 3 | ||
166 | 176 | ||
167 | struct basic_scan_parameters { | 177 | struct wl1251_scan_parameters { |
168 | u32 rx_config_options; | 178 | u32 rx_config_options; |
169 | u32 rx_filter_options; | 179 | u32 rx_filter_options; |
170 | 180 | ||
@@ -189,11 +199,11 @@ struct basic_scan_parameters { | |||
189 | 199 | ||
190 | u8 tid_trigger; | 200 | u8 tid_trigger; |
191 | u8 ssid_len; | 201 | u8 ssid_len; |
192 | u32 ssid[8]; | 202 | u8 ssid[32]; |
193 | 203 | ||
194 | } __attribute__ ((packed)); | 204 | } __attribute__ ((packed)); |
195 | 205 | ||
196 | struct basic_scan_channel_parameters { | 206 | struct wl1251_scan_ch_parameters { |
197 | u32 min_duration; /* in TU */ | 207 | u32 min_duration; /* in TU */ |
198 | u32 max_duration; /* in TU */ | 208 | u32 max_duration; /* in TU */ |
199 | u32 bssid_lsb; | 209 | u32 bssid_lsb; |
@@ -213,11 +223,11 @@ struct basic_scan_channel_parameters { | |||
213 | /* SCAN parameters */ | 223 | /* SCAN parameters */ |
214 | #define SCAN_MAX_NUM_OF_CHANNELS 16 | 224 | #define SCAN_MAX_NUM_OF_CHANNELS 16 |
215 | 225 | ||
216 | struct cmd_scan { | 226 | struct wl1251_cmd_scan { |
217 | struct wl1251_cmd_header header; | 227 | struct wl1251_cmd_header header; |
218 | 228 | ||
219 | struct basic_scan_parameters params; | 229 | struct wl1251_scan_parameters params; |
220 | struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; | 230 | struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS]; |
221 | } __attribute__ ((packed)); | 231 | } __attribute__ ((packed)); |
222 | 232 | ||
223 | enum { | 233 | enum { |
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c index 4e373f3dbc43..595f0f94d16e 100644 --- a/drivers/net/wireless/wl12xx/wl1251_main.c +++ b/drivers/net/wireless/wl12xx/wl1251_main.c | |||
@@ -563,43 +563,25 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | |||
563 | mutex_unlock(&wl->mutex); | 563 | mutex_unlock(&wl->mutex); |
564 | } | 564 | } |
565 | 565 | ||
566 | static int wl1251_build_null_data(struct wl1251 *wl) | 566 | static int wl1251_build_qos_null_data(struct wl1251 *wl) |
567 | { | 567 | { |
568 | struct wl12xx_null_data_template template; | 568 | struct ieee80211_qos_hdr template; |
569 | 569 | ||
570 | if (!is_zero_ether_addr(wl->bssid)) { | 570 | memset(&template, 0, sizeof(template)); |
571 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
572 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
573 | } else { | ||
574 | memset(template.header.da, 0xff, ETH_ALEN); | ||
575 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
576 | } | ||
577 | |||
578 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
579 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
580 | IEEE80211_STYPE_NULLFUNC | | ||
581 | IEEE80211_FCTL_TODS); | ||
582 | |||
583 | return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template, | ||
584 | sizeof(template)); | ||
585 | |||
586 | } | ||
587 | |||
588 | static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid) | ||
589 | { | ||
590 | struct wl12xx_ps_poll_template template; | ||
591 | 571 | ||
592 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | 572 | memcpy(template.addr1, wl->bssid, ETH_ALEN); |
593 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | 573 | memcpy(template.addr2, wl->mac_addr, ETH_ALEN); |
574 | memcpy(template.addr3, wl->bssid, ETH_ALEN); | ||
594 | 575 | ||
595 | /* aid in PS-Poll has its two MSBs each set to 1 */ | 576 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | |
596 | template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); | 577 | IEEE80211_STYPE_QOS_NULLFUNC | |
578 | IEEE80211_FCTL_TODS); | ||
597 | 579 | ||
598 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | 580 | /* FIXME: not sure what priority to use here */ |
581 | template.qos_ctrl = cpu_to_le16(0); | ||
599 | 582 | ||
600 | return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template, | 583 | return wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, &template, |
601 | sizeof(template)); | 584 | sizeof(template)); |
602 | |||
603 | } | 585 | } |
604 | 586 | ||
605 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) | 587 | static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) |
@@ -870,199 +852,61 @@ out: | |||
870 | return ret; | 852 | return ret; |
871 | } | 853 | } |
872 | 854 | ||
873 | static int wl1251_build_basic_rates(char *rates) | 855 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, |
874 | { | 856 | struct cfg80211_scan_request *req) |
875 | u8 index = 0; | ||
876 | |||
877 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
878 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
879 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
880 | rates[index++] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
881 | |||
882 | return index; | ||
883 | } | ||
884 | |||
885 | static int wl1251_build_extended_rates(char *rates) | ||
886 | { | 857 | { |
887 | u8 index = 0; | 858 | struct wl1251 *wl = hw->priv; |
888 | 859 | struct sk_buff *skb; | |
889 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | 860 | size_t ssid_len = 0; |
890 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | 861 | u8 *ssid = NULL; |
891 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | 862 | int ret; |
892 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
893 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
894 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
895 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
896 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
897 | |||
898 | return index; | ||
899 | } | ||
900 | |||
901 | 863 | ||
902 | static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len) | 864 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); |
903 | { | ||
904 | struct wl12xx_probe_req_template template; | ||
905 | struct wl12xx_ie_rates *rates; | ||
906 | char *ptr; | ||
907 | u16 size; | ||
908 | |||
909 | ptr = (char *)&template; | ||
910 | size = sizeof(struct ieee80211_header); | ||
911 | |||
912 | memset(template.header.da, 0xff, ETH_ALEN); | ||
913 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
914 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
915 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
916 | |||
917 | /* IEs */ | ||
918 | /* SSID */ | ||
919 | template.ssid.header.id = WLAN_EID_SSID; | ||
920 | template.ssid.header.len = ssid_len; | ||
921 | if (ssid_len && ssid) | ||
922 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
923 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
924 | ptr += size; | ||
925 | |||
926 | /* Basic Rates */ | ||
927 | rates = (struct wl12xx_ie_rates *)ptr; | ||
928 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
929 | rates->header.len = wl1251_build_basic_rates(rates->rates); | ||
930 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
931 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
932 | |||
933 | /* Extended rates */ | ||
934 | rates = (struct wl12xx_ie_rates *)ptr; | ||
935 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
936 | rates->header.len = wl1251_build_extended_rates(rates->rates); | ||
937 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
938 | |||
939 | wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
940 | |||
941 | return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template, | ||
942 | size); | ||
943 | } | ||
944 | 865 | ||
945 | static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len, | 866 | if (req->n_ssids) { |
946 | u8 active_scan, u8 high_prio, u8 num_channels, | 867 | ssid = req->ssids[0].ssid; |
947 | u8 probe_requests) | 868 | ssid_len = req->ssids[0].ssid_len; |
948 | { | ||
949 | struct wl1251_cmd_trigger_scan_to *trigger = NULL; | ||
950 | struct cmd_scan *params = NULL; | ||
951 | int i, ret; | ||
952 | u16 scan_options = 0; | ||
953 | |||
954 | if (wl->scanning) | ||
955 | return -EINVAL; | ||
956 | |||
957 | params = kzalloc(sizeof(*params), GFP_KERNEL); | ||
958 | if (!params) | ||
959 | return -ENOMEM; | ||
960 | |||
961 | params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); | ||
962 | params->params.rx_filter_options = | ||
963 | cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); | ||
964 | |||
965 | /* High priority scan */ | ||
966 | if (!active_scan) | ||
967 | scan_options |= SCAN_PASSIVE; | ||
968 | if (high_prio) | ||
969 | scan_options |= SCAN_PRIORITY_HIGH; | ||
970 | params->params.scan_options = scan_options; | ||
971 | |||
972 | params->params.num_channels = num_channels; | ||
973 | params->params.num_probe_requests = probe_requests; | ||
974 | params->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ | ||
975 | params->params.tid_trigger = 0; | ||
976 | |||
977 | for (i = 0; i < num_channels; i++) { | ||
978 | params->channels[i].min_duration = cpu_to_le32(30000); | ||
979 | params->channels[i].max_duration = cpu_to_le32(60000); | ||
980 | memset(¶ms->channels[i].bssid_lsb, 0xff, 4); | ||
981 | memset(¶ms->channels[i].bssid_msb, 0xff, 2); | ||
982 | params->channels[i].early_termination = 0; | ||
983 | params->channels[i].tx_power_att = 0; | ||
984 | params->channels[i].channel = i + 1; | ||
985 | memset(params->channels[i].pad, 0, 3); | ||
986 | } | 869 | } |
987 | 870 | ||
988 | for (i = num_channels; i < SCAN_MAX_NUM_OF_CHANNELS; i++) | 871 | mutex_lock(&wl->mutex); |
989 | memset(¶ms->channels[i], 0, | ||
990 | sizeof(struct basic_scan_channel_parameters)); | ||
991 | |||
992 | if (len && ssid) { | ||
993 | params->params.ssid_len = len; | ||
994 | memcpy(params->params.ssid, ssid, len); | ||
995 | } else { | ||
996 | params->params.ssid_len = 0; | ||
997 | memset(params->params.ssid, 0, 32); | ||
998 | } | ||
999 | 872 | ||
1000 | ret = wl1251_build_probe_req(wl, ssid, len); | 873 | if (wl->scanning) { |
1001 | if (ret < 0) { | 874 | wl1251_debug(DEBUG_SCAN, "scan already in progress"); |
1002 | wl1251_error("PROBE request template failed"); | 875 | ret = -EINVAL; |
1003 | goto out; | 876 | goto out; |
1004 | } | 877 | } |
1005 | 878 | ||
1006 | trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); | 879 | ret = wl1251_ps_elp_wakeup(wl); |
1007 | if (!trigger) | 880 | if (ret < 0) |
1008 | goto out; | 881 | goto out; |
1009 | 882 | ||
1010 | trigger->timeout = 0; | 883 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, |
1011 | 884 | req->ie, req->ie_len); | |
1012 | ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, | 885 | if (!skb) { |
1013 | sizeof(*trigger)); | 886 | ret = -ENOMEM; |
1014 | if (ret < 0) { | ||
1015 | wl1251_error("trigger scan to failed for hw scan"); | ||
1016 | goto out; | 887 | goto out; |
1017 | } | 888 | } |
1018 | 889 | ||
1019 | wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | 890 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, skb->data, |
1020 | 891 | skb->len); | |
1021 | wl->scanning = true; | 892 | dev_kfree_skb(skb); |
893 | if (ret < 0) | ||
894 | goto out_sleep; | ||
1022 | 895 | ||
1023 | ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); | 896 | ret = wl1251_cmd_trigger_scan_to(wl, 0); |
1024 | if (ret < 0) | 897 | if (ret < 0) |
1025 | wl1251_error("SCAN failed"); | 898 | goto out_sleep; |
1026 | 899 | ||
1027 | wl1251_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params)); | 900 | wl->scanning = true; |
1028 | 901 | ||
1029 | if (params->header.status != CMD_STATUS_SUCCESS) { | 902 | ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, |
1030 | wl1251_error("TEST command answer error: %d", | 903 | req->n_channels, WL1251_SCAN_NUM_PROBES); |
1031 | params->header.status); | 904 | if (ret < 0) { |
1032 | wl->scanning = false; | 905 | wl->scanning = false; |
1033 | ret = -EIO; | 906 | goto out_sleep; |
1034 | goto out; | ||
1035 | } | ||
1036 | |||
1037 | out: | ||
1038 | kfree(params); | ||
1039 | return ret; | ||
1040 | |||
1041 | } | ||
1042 | |||
1043 | static int wl1251_op_hw_scan(struct ieee80211_hw *hw, | ||
1044 | struct cfg80211_scan_request *req) | ||
1045 | { | ||
1046 | struct wl1251 *wl = hw->priv; | ||
1047 | int ret; | ||
1048 | u8 *ssid = NULL; | ||
1049 | size_t ssid_len = 0; | ||
1050 | |||
1051 | wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan"); | ||
1052 | |||
1053 | if (req->n_ssids) { | ||
1054 | ssid = req->ssids[0].ssid; | ||
1055 | ssid_len = req->ssids[0].ssid_len; | ||
1056 | } | 907 | } |
1057 | 908 | ||
1058 | mutex_lock(&wl->mutex); | 909 | out_sleep: |
1059 | |||
1060 | ret = wl1251_ps_elp_wakeup(wl); | ||
1061 | if (ret < 0) | ||
1062 | goto out; | ||
1063 | |||
1064 | ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3); | ||
1065 | |||
1066 | wl1251_ps_elp_sleep(wl); | 910 | wl1251_ps_elp_sleep(wl); |
1067 | 911 | ||
1068 | out: | 912 | out: |
@@ -1101,7 +945,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1101 | { | 945 | { |
1102 | enum wl1251_cmd_ps_mode mode; | 946 | enum wl1251_cmd_ps_mode mode; |
1103 | struct wl1251 *wl = hw->priv; | 947 | struct wl1251 *wl = hw->priv; |
1104 | struct sk_buff *beacon; | 948 | struct sk_buff *beacon, *skb; |
1105 | int ret; | 949 | int ret; |
1106 | 950 | ||
1107 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); | 951 | wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); |
@@ -1115,7 +959,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1115 | if (changed & BSS_CHANGED_BSSID) { | 959 | if (changed & BSS_CHANGED_BSSID) { |
1116 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | 960 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); |
1117 | 961 | ||
1118 | ret = wl1251_build_null_data(wl); | 962 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); |
963 | if (!skb) | ||
964 | goto out_sleep; | ||
965 | |||
966 | ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, | ||
967 | skb->data, skb->len); | ||
968 | dev_kfree_skb(skb); | ||
969 | if (ret < 0) | ||
970 | goto out_sleep; | ||
971 | |||
972 | ret = wl1251_build_qos_null_data(wl); | ||
1119 | if (ret < 0) | 973 | if (ret < 0) |
1120 | goto out; | 974 | goto out; |
1121 | 975 | ||
@@ -1136,7 +990,14 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1136 | wl->dtim_period); | 990 | wl->dtim_period); |
1137 | wl->aid = bss_conf->aid; | 991 | wl->aid = bss_conf->aid; |
1138 | 992 | ||
1139 | ret = wl1251_build_ps_poll(wl, wl->aid); | 993 | skb = ieee80211_pspoll_get(wl->hw, wl->vif); |
994 | if (!skb) | ||
995 | goto out_sleep; | ||
996 | |||
997 | ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, | ||
998 | skb->data, | ||
999 | skb->len); | ||
1000 | dev_kfree_skb(skb); | ||
1140 | if (ret < 0) | 1001 | if (ret < 0) |
1141 | goto out_sleep; | 1002 | goto out_sleep; |
1142 | 1003 | ||
@@ -1182,7 +1043,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1182 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); | 1043 | ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE); |
1183 | if (ret < 0) { | 1044 | if (ret < 0) { |
1184 | wl1251_warning("Set ctsprotect failed %d", ret); | 1045 | wl1251_warning("Set ctsprotect failed %d", ret); |
1185 | goto out; | 1046 | goto out_sleep; |
1186 | } | 1047 | } |
1187 | } | 1048 | } |
1188 | 1049 | ||
@@ -1193,7 +1054,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1193 | 1054 | ||
1194 | if (ret < 0) { | 1055 | if (ret < 0) { |
1195 | dev_kfree_skb(beacon); | 1056 | dev_kfree_skb(beacon); |
1196 | goto out; | 1057 | goto out_sleep; |
1197 | } | 1058 | } |
1198 | 1059 | ||
1199 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, | 1060 | ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data, |
@@ -1202,13 +1063,13 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1202 | dev_kfree_skb(beacon); | 1063 | dev_kfree_skb(beacon); |
1203 | 1064 | ||
1204 | if (ret < 0) | 1065 | if (ret < 0) |
1205 | goto out; | 1066 | goto out_sleep; |
1206 | 1067 | ||
1207 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, | 1068 | ret = wl1251_join(wl, wl->bss_type, wl->beacon_int, |
1208 | wl->channel, wl->dtim_period); | 1069 | wl->channel, wl->dtim_period); |
1209 | 1070 | ||
1210 | if (ret < 0) | 1071 | if (ret < 0) |
1211 | goto out; | 1072 | goto out_sleep; |
1212 | } | 1073 | } |
1213 | 1074 | ||
1214 | out_sleep: | 1075 | out_sleep: |
@@ -1282,6 +1143,7 @@ static struct ieee80211_channel wl1251_channels[] = { | |||
1282 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | 1143 | static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, |
1283 | const struct ieee80211_tx_queue_params *params) | 1144 | const struct ieee80211_tx_queue_params *params) |
1284 | { | 1145 | { |
1146 | enum wl1251_acx_ps_scheme ps_scheme; | ||
1285 | struct wl1251 *wl = hw->priv; | 1147 | struct wl1251 *wl = hw->priv; |
1286 | int ret; | 1148 | int ret; |
1287 | 1149 | ||
@@ -1299,10 +1161,14 @@ static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1299 | if (ret < 0) | 1161 | if (ret < 0) |
1300 | goto out_sleep; | 1162 | goto out_sleep; |
1301 | 1163 | ||
1164 | if (params->uapsd) | ||
1165 | ps_scheme = WL1251_ACX_PS_SCHEME_UPSD_TRIGGER; | ||
1166 | else | ||
1167 | ps_scheme = WL1251_ACX_PS_SCHEME_LEGACY; | ||
1168 | |||
1302 | ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), | 1169 | ret = wl1251_acx_tid_cfg(wl, wl1251_tx_get_queue(queue), |
1303 | CHANNEL_TYPE_EDCF, | 1170 | CHANNEL_TYPE_EDCF, |
1304 | wl1251_tx_get_queue(queue), | 1171 | wl1251_tx_get_queue(queue), ps_scheme, |
1305 | WL1251_ACX_PS_SCHEME_LEGACY, | ||
1306 | WL1251_ACX_ACK_POLICY_LEGACY); | 1172 | WL1251_ACX_ACK_POLICY_LEGACY); |
1307 | if (ret < 0) | 1173 | if (ret < 0) |
1308 | goto out_sleep; | 1174 | goto out_sleep; |
@@ -1376,7 +1242,8 @@ int wl1251_init_ieee80211(struct wl1251 *wl) | |||
1376 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | | 1242 | wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | |
1377 | IEEE80211_HW_NOISE_DBM | | 1243 | IEEE80211_HW_NOISE_DBM | |
1378 | IEEE80211_HW_SUPPORTS_PS | | 1244 | IEEE80211_HW_SUPPORTS_PS | |
1379 | IEEE80211_HW_BEACON_FILTER; | 1245 | IEEE80211_HW_BEACON_FILTER | |
1246 | IEEE80211_HW_SUPPORTS_UAPSD; | ||
1380 | 1247 | ||
1381 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | 1248 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
1382 | wl->hw->wiphy->max_scan_ssids = 1; | 1249 | wl->hw->wiphy->max_scan_ssids = 1; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_reg.h b/drivers/net/wireless/wl12xx/wl1271_reg.h index 1f237389d1c7..990960771528 100644 --- a/drivers/net/wireless/wl12xx/wl1271_reg.h +++ b/drivers/net/wireless/wl12xx/wl1271_reg.h | |||
@@ -62,73 +62,10 @@ | |||
62 | #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) | 62 | #define WL1271_SLV_REG_DATA (REGISTERS_BASE + 0x0008) |
63 | #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) | 63 | #define WL1271_SLV_REG_ADATA (REGISTERS_BASE + 0x000c) |
64 | #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) | 64 | #define WL1271_SLV_MEM_DATA (REGISTERS_BASE + 0x0018) |
65 | /* | ||
66 | * Interrupt registers. | ||
67 | * 64 bit interrupt sources registers ws ced. | ||
68 | * sme interupts were removed and new ones were added. | ||
69 | * Order was changed. | ||
70 | */ | ||
71 | #define FIQ_MASK (REGISTERS_BASE + 0x0400) | ||
72 | #define FIQ_MASK_L (REGISTERS_BASE + 0x0400) | ||
73 | #define FIQ_MASK_H (REGISTERS_BASE + 0x0404) | ||
74 | #define FIQ_MASK_SET (REGISTERS_BASE + 0x0408) | ||
75 | #define FIQ_MASK_SET_L (REGISTERS_BASE + 0x0408) | ||
76 | #define FIQ_MASK_SET_H (REGISTERS_BASE + 0x040C) | ||
77 | #define FIQ_MASK_CLR (REGISTERS_BASE + 0x0410) | ||
78 | #define FIQ_MASK_CLR_L (REGISTERS_BASE + 0x0410) | ||
79 | #define FIQ_MASK_CLR_H (REGISTERS_BASE + 0x0414) | ||
80 | #define IRQ_MASK (REGISTERS_BASE + 0x0418) | ||
81 | #define IRQ_MASK_L (REGISTERS_BASE + 0x0418) | ||
82 | #define IRQ_MASK_H (REGISTERS_BASE + 0x041C) | ||
83 | #define IRQ_MASK_SET (REGISTERS_BASE + 0x0420) | ||
84 | #define IRQ_MASK_SET_L (REGISTERS_BASE + 0x0420) | ||
85 | #define IRQ_MASK_SET_H (REGISTERS_BASE + 0x0424) | ||
86 | #define IRQ_MASK_CLR (REGISTERS_BASE + 0x0428) | ||
87 | #define IRQ_MASK_CLR_L (REGISTERS_BASE + 0x0428) | ||
88 | #define IRQ_MASK_CLR_H (REGISTERS_BASE + 0x042C) | ||
89 | #define ECPU_MASK (REGISTERS_BASE + 0x0448) | ||
90 | #define FIQ_STS_L (REGISTERS_BASE + 0x044C) | ||
91 | #define FIQ_STS_H (REGISTERS_BASE + 0x0450) | ||
92 | #define IRQ_STS_L (REGISTERS_BASE + 0x0454) | ||
93 | #define IRQ_STS_H (REGISTERS_BASE + 0x0458) | ||
94 | #define INT_STS_ND (REGISTERS_BASE + 0x0464) | ||
95 | #define INT_STS_RAW_L (REGISTERS_BASE + 0x0464) | ||
96 | #define INT_STS_RAW_H (REGISTERS_BASE + 0x0468) | ||
97 | #define INT_STS_CLR (REGISTERS_BASE + 0x04B4) | ||
98 | #define INT_STS_CLR_L (REGISTERS_BASE + 0x04B4) | ||
99 | #define INT_STS_CLR_H (REGISTERS_BASE + 0x04B8) | ||
100 | #define INT_ACK (REGISTERS_BASE + 0x046C) | ||
101 | #define INT_ACK_L (REGISTERS_BASE + 0x046C) | ||
102 | #define INT_ACK_H (REGISTERS_BASE + 0x0470) | ||
103 | #define INT_TRIG (REGISTERS_BASE + 0x0474) | ||
104 | #define INT_TRIG_L (REGISTERS_BASE + 0x0474) | ||
105 | #define INT_TRIG_H (REGISTERS_BASE + 0x0478) | ||
106 | #define HOST_STS_L (REGISTERS_BASE + 0x045C) | ||
107 | #define HOST_STS_H (REGISTERS_BASE + 0x0460) | ||
108 | #define HOST_MASK (REGISTERS_BASE + 0x0430) | ||
109 | #define HOST_MASK_L (REGISTERS_BASE + 0x0430) | ||
110 | #define HOST_MASK_H (REGISTERS_BASE + 0x0434) | ||
111 | #define HOST_MASK_SET (REGISTERS_BASE + 0x0438) | ||
112 | #define HOST_MASK_SET_L (REGISTERS_BASE + 0x0438) | ||
113 | #define HOST_MASK_SET_H (REGISTERS_BASE + 0x043C) | ||
114 | #define HOST_MASK_CLR (REGISTERS_BASE + 0x0440) | ||
115 | #define HOST_MASK_CLR_L (REGISTERS_BASE + 0x0440) | ||
116 | #define HOST_MASK_CLR_H (REGISTERS_BASE + 0x0444) | ||
117 | 65 | ||
118 | #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) | 66 | #define ACX_REG_INTERRUPT_TRIG (REGISTERS_BASE + 0x0474) |
119 | #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) | 67 | #define ACX_REG_INTERRUPT_TRIG_H (REGISTERS_BASE + 0x0478) |
120 | 68 | ||
121 | /* Host Interrupts*/ | ||
122 | #define HINT_MASK (REGISTERS_BASE + 0x0494) | ||
123 | #define HINT_MASK_SET (REGISTERS_BASE + 0x0498) | ||
124 | #define HINT_MASK_CLR (REGISTERS_BASE + 0x049C) | ||
125 | #define HINT_STS_ND_MASKED (REGISTERS_BASE + 0x04A0) | ||
126 | /*1150 spec calls this HINT_STS_RAW*/ | ||
127 | #define HINT_STS_ND (REGISTERS_BASE + 0x04B0) | ||
128 | #define HINT_STS_CLR (REGISTERS_BASE + 0x04A4) | ||
129 | #define HINT_ACK (REGISTERS_BASE + 0x04A8) | ||
130 | #define HINT_TRIG (REGISTERS_BASE + 0x04AC) | ||
131 | |||
132 | /*============================================= | 69 | /*============================================= |
133 | Host Interrupt Mask Register - 32bit (RW) | 70 | Host Interrupt Mask Register - 32bit (RW) |
134 | ------------------------------------------ | 71 | ------------------------------------------ |
@@ -433,16 +370,6 @@ | |||
433 | 370 | ||
434 | 371 | ||
435 | /*=============================================== | 372 | /*=============================================== |
436 | Phy regs | ||
437 | ===============================================*/ | ||
438 | #define ACX_PHY_ADDR_REG SBB_ADDR | ||
439 | #define ACX_PHY_DATA_REG SBB_DATA | ||
440 | #define ACX_PHY_CTRL_REG SBB_CTL | ||
441 | #define ACX_PHY_REG_WR_MASK 0x00000001ul | ||
442 | #define ACX_PHY_REG_RD_MASK 0x00000002ul | ||
443 | |||
444 | |||
445 | /*=============================================== | ||
446 | EEPROM Read/Write Request 32bit RW | 373 | EEPROM Read/Write Request 32bit RW |
447 | ------------------------------------------ | 374 | ------------------------------------------ |
448 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit | 375 | 1 EE_READ - EEPROM Read Request 1 - Setting this bit |
@@ -511,28 +438,6 @@ | |||
511 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f | 438 | #define ACX_CONT_WIND_MIN_MASK 0x0000007f |
512 | #define ACX_CONT_WIND_MAX 0x03ff0000 | 439 | #define ACX_CONT_WIND_MAX 0x03ff0000 |
513 | 440 | ||
514 | /* | ||
515 | * Indirect slave register/memory registers | ||
516 | * ---------------------------------------- | ||
517 | */ | ||
518 | #define HW_SLAVE_REG_ADDR_REG 0x00000004 | ||
519 | #define HW_SLAVE_REG_DATA_REG 0x00000008 | ||
520 | #define HW_SLAVE_REG_CTRL_REG 0x0000000c | ||
521 | |||
522 | #define SLAVE_AUTO_INC 0x00010000 | ||
523 | #define SLAVE_NO_AUTO_INC 0x00000000 | ||
524 | #define SLAVE_HOST_LITTLE_ENDIAN 0x00000000 | ||
525 | |||
526 | #define HW_SLAVE_MEM_ADDR_REG SLV_MEM_ADDR | ||
527 | #define HW_SLAVE_MEM_DATA_REG SLV_MEM_DATA | ||
528 | #define HW_SLAVE_MEM_CTRL_REG SLV_MEM_CTL | ||
529 | #define HW_SLAVE_MEM_ENDIAN_REG SLV_END_CTL | ||
530 | |||
531 | #define HW_FUNC_EVENT_INT_EN 0x8000 | ||
532 | #define HW_FUNC_EVENT_MASK_REG 0x00000034 | ||
533 | |||
534 | #define ACX_MAC_TIMESTAMP_REG (MAC_TIMESTAMP) | ||
535 | |||
536 | /*=============================================== | 441 | /*=============================================== |
537 | HI_CFG Interface Configuration Register Values | 442 | HI_CFG Interface Configuration Register Values |
538 | ------------------------------------------ | 443 | ------------------------------------------ |
@@ -647,10 +552,6 @@ b12-b0 - Supported Rate indicator bits as defined below. | |||
647 | ******************************************************************************/ | 552 | ******************************************************************************/ |
648 | 553 | ||
649 | 554 | ||
650 | #define TNETW1251_CHIP_ID_PG1_0 0x07010101 | ||
651 | #define TNETW1251_CHIP_ID_PG1_1 0x07020101 | ||
652 | #define TNETW1251_CHIP_ID_PG1_2 0x07030101 | ||
653 | |||
654 | /************************************************************************* | 555 | /************************************************************************* |
655 | 556 | ||
656 | Interrupt Trigger Register (Host -> WiLink) | 557 | Interrupt Trigger Register (Host -> WiLink) |
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index 02978a16e732..ee9564aa6ecc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -397,8 +397,7 @@ u16 wl1271_top_reg_read(struct wl1271 *wl, int addr) | |||
397 | /* poll for data ready */ | 397 | /* poll for data ready */ |
398 | do { | 398 | do { |
399 | val = wl1271_spi_read32(wl, OCP_DATA_READ); | 399 | val = wl1271_spi_read32(wl, OCP_DATA_READ); |
400 | timeout--; | 400 | } while (!(val & OCP_READY_MASK) && --timeout); |
401 | } while (!(val & OCP_READY_MASK) && timeout); | ||
402 | 401 | ||
403 | if (!timeout) { | 402 | if (!timeout) { |
404 | wl1271_warning("Top register access timed out."); | 403 | wl1271_warning("Top register access timed out."); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 709fe5e06f73..2d555cc30508 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -987,12 +987,13 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, | |||
987 | changed_flags &= SUPPORTED_FIF_FLAGS; | 987 | changed_flags &= SUPPORTED_FIF_FLAGS; |
988 | *new_flags &= SUPPORTED_FIF_FLAGS; | 988 | *new_flags &= SUPPORTED_FIF_FLAGS; |
989 | 989 | ||
990 | /* changed_flags is always populated but this driver | 990 | /* |
991 | * doesn't support all FIF flags so its possible we don't | 991 | * If multicast parameter (as returned by zd_op_prepare_multicast) |
992 | * need to do anything */ | 992 | * has changed, no bit in changed_flags is set. To handle this |
993 | if (!changed_flags) | 993 | * situation, we do not return if changed_flags is 0. If we do so, |
994 | return; | 994 | * we will have some issue with IPv6 which uses multicast for link |
995 | 995 | * layer address resolution. | |
996 | */ | ||
996 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) | 997 | if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) |
997 | zd_mc_add_all(&hash); | 998 | zd_mc_add_all(&hash); |
998 | 999 | ||
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 0d490c164db6..9086047c32d4 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h | |||
@@ -482,15 +482,6 @@ struct ieee80211_header_data { | |||
482 | u16 seq_ctrl; | 482 | u16 seq_ctrl; |
483 | }; | 483 | }; |
484 | 484 | ||
485 | struct ieee80211_hdr_3addr { | ||
486 | u16 frame_ctl; | ||
487 | u16 duration_id; | ||
488 | u8 addr1[ETH_ALEN]; | ||
489 | u8 addr2[ETH_ALEN]; | ||
490 | u8 addr3[ETH_ALEN]; | ||
491 | u16 seq_ctl; | ||
492 | } __attribute__ ((packed)); | ||
493 | |||
494 | struct ieee80211_hdr_4addr { | 485 | struct ieee80211_hdr_4addr { |
495 | u16 frame_ctl; | 486 | u16 frame_ctl; |
496 | u16 duration_id; | 487 | u16 duration_id; |
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index c7c645af0ebb..a2150670ef56 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c | |||
@@ -203,7 +203,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee | |||
203 | 203 | ||
204 | enqueue_mgmt(ieee,skb); | 204 | enqueue_mgmt(ieee,skb); |
205 | }else{ | 205 | }else{ |
206 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); | 206 | header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4); |
207 | 207 | ||
208 | if (ieee->seq_ctrl[0] == 0xFFF) | 208 | if (ieee->seq_ctrl[0] == 0xFFF) |
209 | ieee->seq_ctrl[0] = 0; | 209 | ieee->seq_ctrl[0] = 0; |
@@ -220,7 +220,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee | |||
220 | spin_unlock_irqrestore(&ieee->lock, flags); | 220 | spin_unlock_irqrestore(&ieee->lock, flags); |
221 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); | 221 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); |
222 | 222 | ||
223 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | 223 | header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); |
224 | 224 | ||
225 | if (ieee->seq_ctrl[0] == 0xFFF) | 225 | if (ieee->seq_ctrl[0] == 0xFFF) |
226 | ieee->seq_ctrl[0] = 0; | 226 | ieee->seq_ctrl[0] = 0; |
@@ -246,7 +246,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i | |||
246 | 246 | ||
247 | if(single){ | 247 | if(single){ |
248 | 248 | ||
249 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | 249 | header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); |
250 | 250 | ||
251 | if (ieee->seq_ctrl[0] == 0xFFF) | 251 | if (ieee->seq_ctrl[0] == 0xFFF) |
252 | ieee->seq_ctrl[0] = 0; | 252 | ieee->seq_ctrl[0] = 0; |
@@ -259,7 +259,7 @@ inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *i | |||
259 | 259 | ||
260 | }else{ | 260 | }else{ |
261 | 261 | ||
262 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | 262 | header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); |
263 | 263 | ||
264 | if (ieee->seq_ctrl[0] == 0xFFF) | 264 | if (ieee->seq_ctrl[0] == 0xFFF) |
265 | ieee->seq_ctrl[0] = 0; | 265 | ieee->seq_ctrl[0] = 0; |
@@ -287,7 +287,7 @@ inline struct sk_buff *ieee80211_disassociate_skb( | |||
287 | return NULL; | 287 | return NULL; |
288 | 288 | ||
289 | disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); | 289 | disass = (struct ieee80211_disassoc_frame *) skb_put(skb,sizeof(struct ieee80211_disassoc_frame)); |
290 | disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC); | 290 | disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); |
291 | disass->header.duration_id = 0; | 291 | disass->header.duration_id = 0; |
292 | 292 | ||
293 | memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); | 293 | memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); |
@@ -905,7 +905,7 @@ struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest) | |||
905 | assoc = (struct ieee80211_assoc_response_frame *) | 905 | assoc = (struct ieee80211_assoc_response_frame *) |
906 | skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); | 906 | skb_put(skb,sizeof(struct ieee80211_assoc_response_frame)); |
907 | 907 | ||
908 | assoc->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); | 908 | assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); |
909 | memcpy(assoc->header.addr1, dest,ETH_ALEN); | 909 | memcpy(assoc->header.addr1, dest,ETH_ALEN); |
910 | memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); | 910 | memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); |
911 | memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | 911 | memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); |
@@ -981,7 +981,7 @@ struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr) | |||
981 | memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); | 981 | memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); |
982 | memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); | 982 | memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); |
983 | 983 | ||
984 | hdr->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | 984 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | |
985 | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | | 985 | IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | |
986 | (pwr ? IEEE80211_FCTL_PM:0)); | 986 | (pwr ? IEEE80211_FCTL_PM:0)); |
987 | 987 | ||
@@ -1084,7 +1084,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco | |||
1084 | skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); | 1084 | skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); |
1085 | 1085 | ||
1086 | 1086 | ||
1087 | hdr->header.frame_ctl = IEEE80211_STYPE_ASSOC_REQ; | 1087 | hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ; |
1088 | hdr->header.duration_id= 37; //FIXME | 1088 | hdr->header.duration_id= 37; //FIXME |
1089 | memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); | 1089 | memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); |
1090 | memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | 1090 | memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); |
@@ -1786,11 +1786,11 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
1786 | 1786 | ||
1787 | tasklet_schedule(&ieee->ps_task); | 1787 | tasklet_schedule(&ieee->ps_task); |
1788 | 1788 | ||
1789 | if(WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_PROBE_RESP && | 1789 | if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP && |
1790 | WLAN_FC_GET_STYPE(header->frame_ctl) != IEEE80211_STYPE_BEACON) | 1790 | WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON) |
1791 | ieee->last_rx_ps_time = jiffies; | 1791 | ieee->last_rx_ps_time = jiffies; |
1792 | 1792 | ||
1793 | switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { | 1793 | switch (WLAN_FC_GET_STYPE(header->frame_control)) { |
1794 | 1794 | ||
1795 | case IEEE80211_STYPE_ASSOC_RESP: | 1795 | case IEEE80211_STYPE_ASSOC_RESP: |
1796 | case IEEE80211_STYPE_REASSOC_RESP: | 1796 | case IEEE80211_STYPE_REASSOC_RESP: |
@@ -2064,7 +2064,7 @@ void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee) | |||
2064 | 2064 | ||
2065 | header = (struct ieee80211_hdr_3addr *) skb->data; | 2065 | header = (struct ieee80211_hdr_3addr *) skb->data; |
2066 | 2066 | ||
2067 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | 2067 | header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); |
2068 | 2068 | ||
2069 | if (ieee->seq_ctrl[0] == 0xFFF) | 2069 | if (ieee->seq_ctrl[0] == 0xFFF) |
2070 | ieee->seq_ctrl[0] = 0; | 2070 | ieee->seq_ctrl[0] = 0; |
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index e0f13efdb15a..1847f38b9f22 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c | |||
@@ -1890,7 +1890,7 @@ rate) | |||
1890 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); | 1890 | struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); |
1891 | int mode; | 1891 | int mode; |
1892 | struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; | 1892 | struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; |
1893 | short morefrag = (h->frame_ctl) & IEEE80211_FCTL_MOREFRAGS; | 1893 | short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS; |
1894 | unsigned long flags; | 1894 | unsigned long flags; |
1895 | int priority; | 1895 | int priority; |
1896 | 1896 | ||
@@ -2158,7 +2158,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority, | |||
2158 | TxDescDuration = ThisFrameTime + aSifsTime + AckTime; | 2158 | TxDescDuration = ThisFrameTime + aSifsTime + AckTime; |
2159 | } | 2159 | } |
2160 | 2160 | ||
2161 | if(!(frag_hdr->frame_ctl & IEEE80211_FCTL_MOREFRAGS)) { //no more fragment | 2161 | if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) { |
2162 | // ThisFrame-ACK. | 2162 | // ThisFrame-ACK. |
2163 | Duration = aSifsTime + AckTime; | 2163 | Duration = aSifsTime + AckTime; |
2164 | } else { // One or more fragments remained. | 2164 | } else { // One or more fragments remained. |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index aeea282bd2fe..842701906ae9 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -120,6 +120,24 @@ | |||
120 | #define IEEE80211_QOS_CTL_TID_MASK 0x000F | 120 | #define IEEE80211_QOS_CTL_TID_MASK 0x000F |
121 | #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 | 121 | #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 |
122 | 122 | ||
123 | /* U-APSD queue for WMM IEs sent by AP */ | ||
124 | #define IEEE80211_WMM_IE_AP_QOSINFO_UAPSD (1<<7) | ||
125 | |||
126 | /* U-APSD queues for WMM IEs sent by STA */ | ||
127 | #define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO (1<<0) | ||
128 | #define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI (1<<1) | ||
129 | #define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK (1<<2) | ||
130 | #define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE (1<<3) | ||
131 | #define IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK 0x0f | ||
132 | |||
133 | /* U-APSD max SP length for WMM IEs sent by STA */ | ||
134 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0x00 | ||
135 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_2 0x01 | ||
136 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_4 0x02 | ||
137 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_6 0x03 | ||
138 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK 0x03 | ||
139 | #define IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT 5 | ||
140 | |||
123 | struct ieee80211_hdr { | 141 | struct ieee80211_hdr { |
124 | __le16 frame_control; | 142 | __le16 frame_control; |
125 | __le16 duration_id; | 143 | __le16 duration_id; |
@@ -130,6 +148,25 @@ struct ieee80211_hdr { | |||
130 | u8 addr4[6]; | 148 | u8 addr4[6]; |
131 | } __attribute__ ((packed)); | 149 | } __attribute__ ((packed)); |
132 | 150 | ||
151 | struct ieee80211_hdr_3addr { | ||
152 | __le16 frame_control; | ||
153 | __le16 duration_id; | ||
154 | u8 addr1[6]; | ||
155 | u8 addr2[6]; | ||
156 | u8 addr3[6]; | ||
157 | __le16 seq_ctrl; | ||
158 | } __attribute__ ((packed)); | ||
159 | |||
160 | struct ieee80211_qos_hdr { | ||
161 | __le16 frame_control; | ||
162 | __le16 duration_id; | ||
163 | u8 addr1[6]; | ||
164 | u8 addr2[6]; | ||
165 | u8 addr3[6]; | ||
166 | __le16 seq_ctrl; | ||
167 | __le16 qos_ctrl; | ||
168 | } __attribute__ ((packed)); | ||
169 | |||
133 | /** | 170 | /** |
134 | * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set | 171 | * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set |
135 | * @fc: frame control bytes in little-endian byteorder | 172 | * @fc: frame control bytes in little-endian byteorder |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2bfbe88837ef..127a73015760 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -295,6 +295,10 @@ | |||
295 | * This command is also used as an event to notify when a requested | 295 | * This command is also used as an event to notify when a requested |
296 | * remain-on-channel duration has expired. | 296 | * remain-on-channel duration has expired. |
297 | * | 297 | * |
298 | * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX | ||
299 | * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface | ||
300 | * and @NL80211_ATTR_TX_RATES the set of allowed rates. | ||
301 | * | ||
298 | * @NL80211_CMD_MAX: highest used command number | 302 | * @NL80211_CMD_MAX: highest used command number |
299 | * @__NL80211_CMD_AFTER_LAST: internal use | 303 | * @__NL80211_CMD_AFTER_LAST: internal use |
300 | */ | 304 | */ |
@@ -381,6 +385,8 @@ enum nl80211_commands { | |||
381 | NL80211_CMD_REMAIN_ON_CHANNEL, | 385 | NL80211_CMD_REMAIN_ON_CHANNEL, |
382 | NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 386 | NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
383 | 387 | ||
388 | NL80211_CMD_SET_TX_BITRATE_MASK, | ||
389 | |||
384 | /* add new commands above here */ | 390 | /* add new commands above here */ |
385 | 391 | ||
386 | /* used to define NL80211_CMD_MAX below */ | 392 | /* used to define NL80211_CMD_MAX below */ |
@@ -430,6 +436,8 @@ enum nl80211_commands { | |||
430 | * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length | 436 | * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length |
431 | * larger than or equal to this use RTS/CTS handshake); allowed range: | 437 | * larger than or equal to this use RTS/CTS handshake); allowed range: |
432 | * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 | 438 | * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32 |
439 | * @NL80211_ATTR_WIPHY_COVERAGE_CLASS: Coverage Class as defined by IEEE 802.11 | ||
440 | * section 7.3.2.9; dot11CoverageClass; u8 | ||
433 | * | 441 | * |
434 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on | 442 | * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on |
435 | * @NL80211_ATTR_IFNAME: network interface name | 443 | * @NL80211_ATTR_IFNAME: network interface name |
@@ -638,6 +646,13 @@ enum nl80211_commands { | |||
638 | * | 646 | * |
639 | * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. | 647 | * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. |
640 | * | 648 | * |
649 | * @NL80211_ATTR_TX_RATES: Nested set of attributes | ||
650 | * (enum nl80211_tx_rate_attributes) describing TX rates per band. The | ||
651 | * enum nl80211_band value is used as the index (nla_type() of the nested | ||
652 | * data. If a band is not included, it will be configured to allow all | ||
653 | * rates based on negotiated supported rates information. This attribute | ||
654 | * is used with %NL80211_CMD_SET_TX_BITRATE_MASK. | ||
655 | * | ||
641 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 656 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
642 | * @__NL80211_ATTR_AFTER_LAST: internal use | 657 | * @__NL80211_ATTR_AFTER_LAST: internal use |
643 | */ | 658 | */ |
@@ -779,6 +794,10 @@ enum nl80211_attrs { | |||
779 | 794 | ||
780 | NL80211_ATTR_COOKIE, | 795 | NL80211_ATTR_COOKIE, |
781 | 796 | ||
797 | NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
798 | |||
799 | NL80211_ATTR_TX_RATES, | ||
800 | |||
782 | /* add attributes here, update the policy in nl80211.c */ | 801 | /* add attributes here, update the policy in nl80211.c */ |
783 | 802 | ||
784 | __NL80211_ATTR_AFTER_LAST, | 803 | __NL80211_ATTR_AFTER_LAST, |
@@ -1359,13 +1378,20 @@ enum nl80211_channel_type { | |||
1359 | * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) | 1378 | * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) |
1360 | * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) | 1379 | * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) |
1361 | * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the | 1380 | * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the |
1362 | * raw information elements from the probe response/beacon (bin) | 1381 | * raw information elements from the probe response/beacon (bin); |
1382 | * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are | ||
1383 | * from a Probe Response frame; otherwise they are from a Beacon frame. | ||
1384 | * However, if the driver does not indicate the source of the IEs, these | ||
1385 | * IEs may be from either frame subtype. | ||
1363 | * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon | 1386 | * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon |
1364 | * in mBm (100 * dBm) (s32) | 1387 | * in mBm (100 * dBm) (s32) |
1365 | * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon | 1388 | * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon |
1366 | * in unspecified units, scaled to 0..100 (u8) | 1389 | * in unspecified units, scaled to 0..100 (u8) |
1367 | * @NL80211_BSS_STATUS: status, if this BSS is "used" | 1390 | * @NL80211_BSS_STATUS: status, if this BSS is "used" |
1368 | * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms | 1391 | * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms |
1392 | * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information | ||
1393 | * elements from a Beacon frame (bin); not present if no Beacon frame has | ||
1394 | * yet been received | ||
1369 | * @__NL80211_BSS_AFTER_LAST: internal | 1395 | * @__NL80211_BSS_AFTER_LAST: internal |
1370 | * @NL80211_BSS_MAX: highest BSS attribute | 1396 | * @NL80211_BSS_MAX: highest BSS attribute |
1371 | */ | 1397 | */ |
@@ -1381,6 +1407,7 @@ enum nl80211_bss { | |||
1381 | NL80211_BSS_SIGNAL_UNSPEC, | 1407 | NL80211_BSS_SIGNAL_UNSPEC, |
1382 | NL80211_BSS_STATUS, | 1408 | NL80211_BSS_STATUS, |
1383 | NL80211_BSS_SEEN_MS_AGO, | 1409 | NL80211_BSS_SEEN_MS_AGO, |
1410 | NL80211_BSS_BEACON_IES, | ||
1384 | 1411 | ||
1385 | /* keep last */ | 1412 | /* keep last */ |
1386 | __NL80211_BSS_AFTER_LAST, | 1413 | __NL80211_BSS_AFTER_LAST, |
@@ -1478,4 +1505,33 @@ enum nl80211_key_attributes { | |||
1478 | NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 | 1505 | NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 |
1479 | }; | 1506 | }; |
1480 | 1507 | ||
1508 | /** | ||
1509 | * enum nl80211_tx_rate_attributes - TX rate set attributes | ||
1510 | * @__NL80211_TXRATE_INVALID: invalid | ||
1511 | * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection | ||
1512 | * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with | ||
1513 | * 1 = 500 kbps) but without the IE length restriction (at most | ||
1514 | * %NL80211_MAX_SUPP_RATES in a single array). | ||
1515 | * @__NL80211_TXRATE_AFTER_LAST: internal | ||
1516 | * @NL80211_TXRATE_MAX: highest TX rate attribute | ||
1517 | */ | ||
1518 | enum nl80211_tx_rate_attributes { | ||
1519 | __NL80211_TXRATE_INVALID, | ||
1520 | NL80211_TXRATE_LEGACY, | ||
1521 | |||
1522 | /* keep last */ | ||
1523 | __NL80211_TXRATE_AFTER_LAST, | ||
1524 | NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 | ||
1525 | }; | ||
1526 | |||
1527 | /** | ||
1528 | * enum nl80211_band - Frequency band | ||
1529 | * @NL80211_BAND_2GHZ - 2.4 GHz ISM band | ||
1530 | * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz) | ||
1531 | */ | ||
1532 | enum nl80211_band { | ||
1533 | NL80211_BAND_2GHZ, | ||
1534 | NL80211_BAND_5GHZ, | ||
1535 | }; | ||
1536 | |||
1481 | #endif /* __LINUX_NL80211_H */ | 1537 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index add79930f47d..2af52704e670 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -39,8 +39,8 @@ | |||
39 | * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) | 39 | * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) |
40 | */ | 40 | */ |
41 | enum ieee80211_band { | 41 | enum ieee80211_band { |
42 | IEEE80211_BAND_2GHZ, | 42 | IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, |
43 | IEEE80211_BAND_5GHZ, | 43 | IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, |
44 | 44 | ||
45 | /* keep last */ | 45 | /* keep last */ |
46 | IEEE80211_NUM_BANDS | 46 | IEEE80211_NUM_BANDS |
@@ -626,8 +626,14 @@ enum cfg80211_signal_type { | |||
626 | * @beacon_interval: the beacon interval as from the frame | 626 | * @beacon_interval: the beacon interval as from the frame |
627 | * @capability: the capability field in host byte order | 627 | * @capability: the capability field in host byte order |
628 | * @information_elements: the information elements (Note that there | 628 | * @information_elements: the information elements (Note that there |
629 | * is no guarantee that these are well-formed!) | 629 | * is no guarantee that these are well-formed!); this is a pointer to |
630 | * either the beacon_ies or proberesp_ies depending on whether Probe | ||
631 | * Response frame has been received | ||
630 | * @len_information_elements: total length of the information elements | 632 | * @len_information_elements: total length of the information elements |
633 | * @beacon_ies: the information elements from the last Beacon frame | ||
634 | * @len_beacon_ies: total length of the beacon_ies | ||
635 | * @proberesp_ies: the information elements from the last Probe Response frame | ||
636 | * @len_proberesp_ies: total length of the proberesp_ies | ||
631 | * @signal: signal strength value (type depends on the wiphy's signal_type) | 637 | * @signal: signal strength value (type depends on the wiphy's signal_type) |
632 | * @free_priv: function pointer to free private data | 638 | * @free_priv: function pointer to free private data |
633 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes | 639 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes |
@@ -641,6 +647,10 @@ struct cfg80211_bss { | |||
641 | u16 capability; | 647 | u16 capability; |
642 | u8 *information_elements; | 648 | u8 *information_elements; |
643 | size_t len_information_elements; | 649 | size_t len_information_elements; |
650 | u8 *beacon_ies; | ||
651 | size_t len_beacon_ies; | ||
652 | u8 *proberesp_ies; | ||
653 | size_t len_proberesp_ies; | ||
644 | 654 | ||
645 | s32 signal; | 655 | s32 signal; |
646 | 656 | ||
@@ -837,6 +847,7 @@ enum wiphy_params_flags { | |||
837 | WIPHY_PARAM_RETRY_LONG = 1 << 1, | 847 | WIPHY_PARAM_RETRY_LONG = 1 << 1, |
838 | WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, | 848 | WIPHY_PARAM_FRAG_THRESHOLD = 1 << 2, |
839 | WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, | 849 | WIPHY_PARAM_RTS_THRESHOLD = 1 << 3, |
850 | WIPHY_PARAM_COVERAGE_CLASS = 1 << 4, | ||
840 | }; | 851 | }; |
841 | 852 | ||
842 | /** | 853 | /** |
@@ -856,20 +867,11 @@ enum tx_power_setting { | |||
856 | * cfg80211_bitrate_mask - masks for bitrate control | 867 | * cfg80211_bitrate_mask - masks for bitrate control |
857 | */ | 868 | */ |
858 | struct cfg80211_bitrate_mask { | 869 | struct cfg80211_bitrate_mask { |
859 | /* | ||
860 | * As discussed in Berlin, this struct really | ||
861 | * should look like this: | ||
862 | |||
863 | struct { | 870 | struct { |
864 | u32 legacy; | 871 | u32 legacy; |
865 | u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; | 872 | /* TODO: add support for masking MCS rates; e.g.: */ |
873 | /* u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; */ | ||
866 | } control[IEEE80211_NUM_BANDS]; | 874 | } control[IEEE80211_NUM_BANDS]; |
867 | |||
868 | * Since we can always fix in-kernel users, let's keep | ||
869 | * it simpler for now: | ||
870 | */ | ||
871 | u32 fixed; /* fixed bitrate, 0 == not fixed */ | ||
872 | u32 maxrate; /* in kbps, 0 == no limit */ | ||
873 | }; | 875 | }; |
874 | /** | 876 | /** |
875 | * struct cfg80211_pmksa - PMK Security Association | 877 | * struct cfg80211_pmksa - PMK Security Association |
@@ -1236,6 +1238,7 @@ struct wiphy { | |||
1236 | u8 retry_long; | 1238 | u8 retry_long; |
1237 | u32 frag_threshold; | 1239 | u32 frag_threshold; |
1238 | u32 rts_threshold; | 1240 | u32 rts_threshold; |
1241 | u8 coverage_class; | ||
1239 | 1242 | ||
1240 | char fw_version[ETHTOOL_BUSINFO_LEN]; | 1243 | char fw_version[ETHTOOL_BUSINFO_LEN]; |
1241 | u32 hw_version; | 1244 | u32 hw_version; |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f073a2a50574..c90047de4428 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -107,12 +107,14 @@ enum ieee80211_max_queues { | |||
107 | * 2^n-1 in the range 1..32767] | 107 | * 2^n-1 in the range 1..32767] |
108 | * @cw_max: maximum contention window [like @cw_min] | 108 | * @cw_max: maximum contention window [like @cw_min] |
109 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled | 109 | * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled |
110 | * @uapsd: is U-APSD mode enabled for the queue | ||
110 | */ | 111 | */ |
111 | struct ieee80211_tx_queue_params { | 112 | struct ieee80211_tx_queue_params { |
112 | u16 txop; | 113 | u16 txop; |
113 | u16 cw_min; | 114 | u16 cw_min; |
114 | u16 cw_max; | 115 | u16 cw_max; |
115 | u8 aifs; | 116 | u8 aifs; |
117 | bool uapsd; | ||
116 | }; | 118 | }; |
117 | 119 | ||
118 | /** | 120 | /** |
@@ -255,9 +257,6 @@ struct ieee80211_bss_conf { | |||
255 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be | 257 | * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be |
256 | * set by rate control algorithms to indicate probe rate, will | 258 | * set by rate control algorithms to indicate probe rate, will |
257 | * be cleared for fragmented frames (except on the last fragment) | 259 | * be cleared for fragmented frames (except on the last fragment) |
258 | * @IEEE80211_TX_INTFL_RCALGO: mac80211 internal flag, do not test or | ||
259 | * set this flag in the driver; indicates that the rate control | ||
260 | * algorithm was used and should be notified of TX status | ||
261 | * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, | 260 | * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, |
262 | * used to indicate that a pending frame requires TX processing before | 261 | * used to indicate that a pending frame requires TX processing before |
263 | * it can be sent out. | 262 | * it can be sent out. |
@@ -287,7 +286,6 @@ enum mac80211_tx_control_flags { | |||
287 | IEEE80211_TX_STAT_AMPDU = BIT(10), | 286 | IEEE80211_TX_STAT_AMPDU = BIT(10), |
288 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), | 287 | IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), |
289 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), | 288 | IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), |
290 | IEEE80211_TX_INTFL_RCALGO = BIT(13), | ||
291 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), | 289 | IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), |
292 | IEEE80211_TX_INTFL_RETRIED = BIT(15), | 290 | IEEE80211_TX_INTFL_RETRIED = BIT(15), |
293 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), | 291 | IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), |
@@ -571,7 +569,13 @@ struct ieee80211_rx_status { | |||
571 | * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this | 569 | * @IEEE80211_CONF_MONITOR: there's a monitor interface present -- use this |
572 | * to determine for example whether to calculate timestamps for packets | 570 | * to determine for example whether to calculate timestamps for packets |
573 | * or not, do not use instead of filter flags! | 571 | * or not, do not use instead of filter flags! |
574 | * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only) | 572 | * @IEEE80211_CONF_PS: Enable 802.11 power save mode (managed mode only). |
573 | * This is the power save mode defined by IEEE 802.11-2007 section 11.2, | ||
574 | * meaning that the hardware still wakes up for beacons, is able to | ||
575 | * transmit frames and receive the possible acknowledgment frames. | ||
576 | * Not to be confused with hardware specific wakeup/sleep states, | ||
577 | * driver is responsible for that. See the section "Powersave support" | ||
578 | * for more. | ||
575 | * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set | 579 | * @IEEE80211_CONF_IDLE: The device is running, but idle; if the flag is set |
576 | * the driver should be prepared to handle configuration requests but | 580 | * the driver should be prepared to handle configuration requests but |
577 | * may turn the device off as much as possible. Typically, this flag will | 581 | * may turn the device off as much as possible. Typically, this flag will |
@@ -611,7 +615,11 @@ enum ieee80211_conf_changed { | |||
611 | /** | 615 | /** |
612 | * enum ieee80211_smps_mode - spatial multiplexing power save mode | 616 | * enum ieee80211_smps_mode - spatial multiplexing power save mode |
613 | * | 617 | * |
614 | * @ | 618 | * @IEEE80211_SMPS_AUTOMATIC: automatic |
619 | * @IEEE80211_SMPS_OFF: off | ||
620 | * @IEEE80211_SMPS_STATIC: static | ||
621 | * @IEEE80211_SMPS_DYNAMIC: dynamic | ||
622 | * @IEEE80211_SMPS_NUM_MODES: internal, don't use | ||
615 | */ | 623 | */ |
616 | enum ieee80211_smps_mode { | 624 | enum ieee80211_smps_mode { |
617 | IEEE80211_SMPS_AUTOMATIC, | 625 | IEEE80211_SMPS_AUTOMATIC, |
@@ -933,6 +941,11 @@ enum ieee80211_tkip_key_type { | |||
933 | * Hardware supports dynamic spatial multiplexing powersave, | 941 | * Hardware supports dynamic spatial multiplexing powersave, |
934 | * ie. can turn off all but one chain and then wake the rest | 942 | * ie. can turn off all but one chain and then wake the rest |
935 | * up as required after, for example, rts/cts handshake. | 943 | * up as required after, for example, rts/cts handshake. |
944 | * | ||
945 | * @IEEE80211_HW_SUPPORTS_UAPSD: | ||
946 | * Hardware supports Unscheduled Automatic Power Save Delivery | ||
947 | * (U-APSD) in managed mode. The mode is configured with | ||
948 | * conf_tx() operation. | ||
936 | */ | 949 | */ |
937 | enum ieee80211_hw_flags { | 950 | enum ieee80211_hw_flags { |
938 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 951 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
@@ -952,6 +965,7 @@ enum ieee80211_hw_flags { | |||
952 | IEEE80211_HW_BEACON_FILTER = 1<<14, | 965 | IEEE80211_HW_BEACON_FILTER = 1<<14, |
953 | IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, | 966 | IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15, |
954 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, | 967 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16, |
968 | IEEE80211_HW_SUPPORTS_UAPSD = 1<<17, | ||
955 | }; | 969 | }; |
956 | 970 | ||
957 | /** | 971 | /** |
@@ -1130,18 +1144,24 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
1130 | * | 1144 | * |
1131 | * mac80211 has support for various powersave implementations. | 1145 | * mac80211 has support for various powersave implementations. |
1132 | * | 1146 | * |
1133 | * First, it can support hardware that handles all powersaving by | 1147 | * First, it can support hardware that handles all powersaving by itself, |
1134 | * itself, such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS | 1148 | * such hardware should simply set the %IEEE80211_HW_SUPPORTS_PS hardware |
1135 | * hardware flag. In that case, it will be told about the desired | 1149 | * flag. In that case, it will be told about the desired powersave mode |
1136 | * powersave mode depending on the association status, and the driver | 1150 | * with the %IEEE80211_CONF_PS flag depending on the association status. |
1137 | * must take care of sending nullfunc frames when necessary, i.e. when | 1151 | * The hardware must take care of sending nullfunc frames when necessary, |
1138 | * entering and leaving powersave mode. The driver is required to look at | 1152 | * i.e. when entering and leaving powersave mode. The hardware is required |
1139 | * the AID in beacons and signal to the AP that it woke up when it finds | 1153 | * to look at the AID in beacons and signal to the AP that it woke up when |
1140 | * traffic directed to it. This mode supports dynamic PS by simply | 1154 | * it finds traffic directed to it. |
1141 | * enabling/disabling PS. | 1155 | * |
1142 | * | 1156 | * %IEEE80211_CONF_PS flag enabled means that the powersave mode defined in |
1143 | * Additionally, such hardware may set the %IEEE80211_HW_SUPPORTS_DYNAMIC_PS | 1157 | * IEEE 802.11-2007 section 11.2 is enabled. This is not to be confused |
1144 | * flag to indicate that it can support dynamic PS mode itself (see below). | 1158 | * with hardware wakeup and sleep states. Driver is responsible for waking |
1159 | * up the hardware before issueing commands to the hardware and putting it | ||
1160 | * back to sleep at approriate times. | ||
1161 | * | ||
1162 | * When PS is enabled, hardware needs to wakeup for beacons and receive the | ||
1163 | * buffered multicast/broadcast frames after the beacon. Also it must be | ||
1164 | * possible to send frames and receive the acknowledment frame. | ||
1145 | * | 1165 | * |
1146 | * Other hardware designs cannot send nullfunc frames by themselves and also | 1166 | * Other hardware designs cannot send nullfunc frames by themselves and also |
1147 | * need software support for parsing the TIM bitmap. This is also supported | 1167 | * need software support for parsing the TIM bitmap. This is also supported |
@@ -1149,14 +1169,35 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, | |||
1149 | * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still | 1169 | * %IEEE80211_HW_PS_NULLFUNC_STACK flags. The hardware is of course still |
1150 | * required to pass up beacons. The hardware is still required to handle | 1170 | * required to pass up beacons. The hardware is still required to handle |
1151 | * waking up for multicast traffic; if it cannot the driver must handle that | 1171 | * waking up for multicast traffic; if it cannot the driver must handle that |
1152 | * as best as it can, mac80211 is too slow. | 1172 | * as best as it can, mac80211 is too slow to do that. |
1153 | * | 1173 | * |
1154 | * Dynamic powersave mode is an extension to normal powersave mode in which | 1174 | * Dynamic powersave is an extension to normal powersave in which the |
1155 | * the hardware stays awake for a user-specified period of time after sending | 1175 | * hardware stays awake for a user-specified period of time after sending a |
1156 | * a frame so that reply frames need not be buffered and therefore delayed | 1176 | * frame so that reply frames need not be buffered and therefore delayed to |
1157 | * to the next wakeup. This can either be supported by hardware, in which case | 1177 | * the next wakeup. It's compromise of getting good enough latency when |
1158 | * the driver needs to look at the @dynamic_ps_timeout hardware configuration | 1178 | * there's data traffic and still saving significantly power in idle |
1159 | * value, or by the stack if all nullfunc handling is in the stack. | 1179 | * periods. |
1180 | * | ||
1181 | * Dynamic powersave is supported by simply mac80211 enabling and disabling | ||
1182 | * PS based on traffic. Driver needs to only set %IEEE80211_HW_SUPPORTS_PS | ||
1183 | * flag and mac80211 will handle everything automatically. Additionally, | ||
1184 | * hardware having support for the dynamic PS feature may set the | ||
1185 | * %IEEE80211_HW_SUPPORTS_DYNAMIC_PS flag to indicate that it can support | ||
1186 | * dynamic PS mode itself. The driver needs to look at the | ||
1187 | * @dynamic_ps_timeout hardware configuration value and use it that value | ||
1188 | * whenever %IEEE80211_CONF_PS is set. In this case mac80211 will disable | ||
1189 | * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS | ||
1190 | * enabled whenever user has enabled powersave. | ||
1191 | * | ||
1192 | * Driver informs U-APSD client support by enabling | ||
1193 | * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the | ||
1194 | * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS | ||
1195 | * Nullfunc frames and stay awake until the service period has ended. To | ||
1196 | * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames | ||
1197 | * from that AC are transmitted with powersave enabled. | ||
1198 | * | ||
1199 | * Note: U-APSD client mode is not yet supported with | ||
1200 | * %IEEE80211_HW_PS_NULLFUNC_STACK. | ||
1160 | */ | 1201 | */ |
1161 | 1202 | ||
1162 | /** | 1203 | /** |
@@ -1533,6 +1574,10 @@ enum ieee80211_ampdu_mlme_action { | |||
1533 | * and need to call wiphy_rfkill_set_hw_state() in the callback. | 1574 | * and need to call wiphy_rfkill_set_hw_state() in the callback. |
1534 | * The callback can sleep. | 1575 | * The callback can sleep. |
1535 | * | 1576 | * |
1577 | * @set_coverage_class: Set slot time for given coverage class as specified | ||
1578 | * in IEEE 802.11-2007 section 17.3.8.6 and modify ACK timeout | ||
1579 | * accordingly. This callback is not required and may sleep. | ||
1580 | * | ||
1536 | * @testmode_cmd: Implement a cfg80211 test mode command. | 1581 | * @testmode_cmd: Implement a cfg80211 test mode command. |
1537 | * The callback can sleep. | 1582 | * The callback can sleep. |
1538 | * | 1583 | * |
@@ -1592,6 +1637,7 @@ struct ieee80211_ops { | |||
1592 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); | 1637 | struct ieee80211_sta *sta, u16 tid, u16 *ssn); |
1593 | 1638 | ||
1594 | void (*rfkill_poll)(struct ieee80211_hw *hw); | 1639 | void (*rfkill_poll)(struct ieee80211_hw *hw); |
1640 | void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class); | ||
1595 | #ifdef CONFIG_NL80211_TESTMODE | 1641 | #ifdef CONFIG_NL80211_TESTMODE |
1596 | int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); | 1642 | int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); |
1597 | #endif | 1643 | #endif |
@@ -1874,6 +1920,53 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1874 | } | 1920 | } |
1875 | 1921 | ||
1876 | /** | 1922 | /** |
1923 | * ieee80211_pspoll_get - retrieve a PS Poll template | ||
1924 | * @hw: pointer obtained from ieee80211_alloc_hw(). | ||
1925 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
1926 | * | ||
1927 | * Creates a PS Poll a template which can, for example, uploaded to | ||
1928 | * hardware. The template must be updated after association so that correct | ||
1929 | * AID, BSSID and MAC address is used. | ||
1930 | * | ||
1931 | * Note: Caller (or hardware) is responsible for setting the | ||
1932 | * &IEEE80211_FCTL_PM bit. | ||
1933 | */ | ||
1934 | struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, | ||
1935 | struct ieee80211_vif *vif); | ||
1936 | |||
1937 | /** | ||
1938 | * ieee80211_nullfunc_get - retrieve a nullfunc template | ||
1939 | * @hw: pointer obtained from ieee80211_alloc_hw(). | ||
1940 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
1941 | * | ||
1942 | * Creates a Nullfunc template which can, for example, uploaded to | ||
1943 | * hardware. The template must be updated after association so that correct | ||
1944 | * BSSID and address is used. | ||
1945 | * | ||
1946 | * Note: Caller (or hardware) is responsible for setting the | ||
1947 | * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. | ||
1948 | */ | ||
1949 | struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | ||
1950 | struct ieee80211_vif *vif); | ||
1951 | |||
1952 | /** | ||
1953 | * ieee80211_probereq_get - retrieve a Probe Request template | ||
1954 | * @hw: pointer obtained from ieee80211_alloc_hw(). | ||
1955 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||
1956 | * @ssid: SSID buffer | ||
1957 | * @ssid_len: length of SSID | ||
1958 | * @ie: buffer containing all IEs except SSID for the template | ||
1959 | * @ie_len: length of the IE buffer | ||
1960 | * | ||
1961 | * Creates a Probe Request template which can, for example, be uploaded to | ||
1962 | * hardware. | ||
1963 | */ | ||
1964 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | ||
1965 | struct ieee80211_vif *vif, | ||
1966 | const u8 *ssid, size_t ssid_len, | ||
1967 | const u8 *ie, size_t ie_len); | ||
1968 | |||
1969 | /** | ||
1877 | * ieee80211_rts_get - RTS frame generation function | 1970 | * ieee80211_rts_get - RTS frame generation function |
1878 | * @hw: pointer obtained from ieee80211_alloc_hw(). | 1971 | * @hw: pointer obtained from ieee80211_alloc_hw(). |
1879 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. | 1972 | * @vif: &struct ieee80211_vif pointer from the add_interface callback. |
@@ -2292,8 +2385,12 @@ enum rate_control_changed { | |||
2292 | * @short_preamble: whether mac80211 will request short-preamble transmission | 2385 | * @short_preamble: whether mac80211 will request short-preamble transmission |
2293 | * if the selected rate supports it | 2386 | * if the selected rate supports it |
2294 | * @max_rate_idx: user-requested maximum rate (not MCS for now) | 2387 | * @max_rate_idx: user-requested maximum rate (not MCS for now) |
2388 | * (deprecated; this will be removed once drivers get updated to use | ||
2389 | * rate_idx_mask) | ||
2390 | * @rate_idx_mask: user-requested rate mask (not MCS for now) | ||
2295 | * @skb: the skb that will be transmitted, the control information in it needs | 2391 | * @skb: the skb that will be transmitted, the control information in it needs |
2296 | * to be filled in | 2392 | * to be filled in |
2393 | * @ap: whether this frame is sent out in AP mode | ||
2297 | */ | 2394 | */ |
2298 | struct ieee80211_tx_rate_control { | 2395 | struct ieee80211_tx_rate_control { |
2299 | struct ieee80211_hw *hw; | 2396 | struct ieee80211_hw *hw; |
@@ -2303,6 +2400,8 @@ struct ieee80211_tx_rate_control { | |||
2303 | struct ieee80211_tx_rate reported_rate; | 2400 | struct ieee80211_tx_rate reported_rate; |
2304 | bool rts, short_preamble; | 2401 | bool rts, short_preamble; |
2305 | u8 max_rate_idx; | 2402 | u8 max_rate_idx; |
2403 | u32 rate_idx_mask; | ||
2404 | bool ap; | ||
2306 | }; | 2405 | }; |
2307 | 2406 | ||
2308 | struct rate_control_ops { | 2407 | struct rate_control_ops { |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index ceda36618d3c..718fbcff84d2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -179,7 +179,8 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
179 | 179 | ||
180 | /* check if the TID waits for addBA response */ | 180 | /* check if the TID waits for addBA response */ |
181 | spin_lock_bh(&sta->lock); | 181 | spin_lock_bh(&sta->lock); |
182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != | 182 | if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | |
183 | HT_AGG_STATE_REQ_STOP_BA_MSK)) != | ||
183 | HT_ADDBA_REQUESTED_MSK) { | 184 | HT_ADDBA_REQUESTED_MSK) { |
184 | spin_unlock_bh(&sta->lock); | 185 | spin_unlock_bh(&sta->lock); |
185 | *state = HT_AGG_STATE_IDLE; | 186 | *state = HT_AGG_STATE_IDLE; |
@@ -301,7 +302,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
301 | * call back right away, it must see that the flow has begun */ | 302 | * call back right away, it must see that the flow has begun */ |
302 | *state |= HT_ADDBA_REQUESTED_MSK; | 303 | *state |= HT_ADDBA_REQUESTED_MSK; |
303 | 304 | ||
304 | start_seq_num = sta->tid_seq[tid]; | 305 | start_seq_num = sta->tid_seq[tid] >> 4; |
305 | 306 | ||
306 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | 307 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, |
307 | pubsta, tid, &start_seq_num); | 308 | pubsta, tid, &start_seq_num); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2e5e841e9b7b..b0102c538b30 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -148,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
148 | rcu_read_lock(); | 148 | rcu_read_lock(); |
149 | 149 | ||
150 | if (mac_addr) { | 150 | if (mac_addr) { |
151 | sta = sta_info_get(sdata, mac_addr); | 151 | sta = sta_info_get_bss(sdata, mac_addr); |
152 | if (!sta) { | 152 | if (!sta) { |
153 | ieee80211_key_free(key); | 153 | ieee80211_key_free(key); |
154 | err = -ENOENT; | 154 | err = -ENOENT; |
@@ -179,7 +179,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
179 | if (mac_addr) { | 179 | if (mac_addr) { |
180 | ret = -ENOENT; | 180 | ret = -ENOENT; |
181 | 181 | ||
182 | sta = sta_info_get(sdata, mac_addr); | 182 | sta = sta_info_get_bss(sdata, mac_addr); |
183 | if (!sta) | 183 | if (!sta) |
184 | goto out_unlock; | 184 | goto out_unlock; |
185 | 185 | ||
@@ -226,7 +226,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
226 | rcu_read_lock(); | 226 | rcu_read_lock(); |
227 | 227 | ||
228 | if (mac_addr) { | 228 | if (mac_addr) { |
229 | sta = sta_info_get(sdata, mac_addr); | 229 | sta = sta_info_get_bss(sdata, mac_addr); |
230 | if (!sta) | 230 | if (!sta) |
231 | goto out; | 231 | goto out; |
232 | 232 | ||
@@ -419,7 +419,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
419 | 419 | ||
420 | rcu_read_lock(); | 420 | rcu_read_lock(); |
421 | 421 | ||
422 | sta = sta_info_get(sdata, mac); | 422 | sta = sta_info_get_bss(sdata, mac); |
423 | if (sta) { | 423 | if (sta) { |
424 | ret = 0; | 424 | ret = 0; |
425 | sta_set_sinfo(sta, sinfo); | 425 | sta_set_sinfo(sta, sinfo); |
@@ -775,7 +775,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
775 | if (mac) { | 775 | if (mac) { |
776 | rcu_read_lock(); | 776 | rcu_read_lock(); |
777 | 777 | ||
778 | sta = sta_info_get(sdata, mac); | 778 | sta = sta_info_get_bss(sdata, mac); |
779 | if (!sta) { | 779 | if (!sta) { |
780 | rcu_read_unlock(); | 780 | rcu_read_unlock(); |
781 | return -ENOENT; | 781 | return -ENOENT; |
@@ -803,7 +803,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
803 | 803 | ||
804 | rcu_read_lock(); | 804 | rcu_read_lock(); |
805 | 805 | ||
806 | sta = sta_info_get(sdata, mac); | 806 | sta = sta_info_get_bss(sdata, mac); |
807 | if (!sta) { | 807 | if (!sta) { |
808 | rcu_read_unlock(); | 808 | rcu_read_unlock(); |
809 | return -ENOENT; | 809 | return -ENOENT; |
@@ -1085,6 +1085,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1085 | params->use_short_preamble; | 1085 | params->use_short_preamble; |
1086 | changed |= BSS_CHANGED_ERP_PREAMBLE; | 1086 | changed |= BSS_CHANGED_ERP_PREAMBLE; |
1087 | } | 1087 | } |
1088 | |||
1089 | if (!sdata->vif.bss_conf.use_short_slot && | ||
1090 | sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
1091 | sdata->vif.bss_conf.use_short_slot = true; | ||
1092 | changed |= BSS_CHANGED_ERP_SLOT; | ||
1093 | } | ||
1094 | |||
1088 | if (params->use_short_slot_time >= 0) { | 1095 | if (params->use_short_slot_time >= 0) { |
1089 | sdata->vif.bss_conf.use_short_slot = | 1096 | sdata->vif.bss_conf.use_short_slot = |
1090 | params->use_short_slot_time; | 1097 | params->use_short_slot_time; |
@@ -1128,6 +1135,13 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1128 | p.cw_max = params->cwmax; | 1135 | p.cw_max = params->cwmax; |
1129 | p.cw_min = params->cwmin; | 1136 | p.cw_min = params->cwmin; |
1130 | p.txop = params->txop; | 1137 | p.txop = params->txop; |
1138 | |||
1139 | /* | ||
1140 | * Setting tx queue params disables u-apsd because it's only | ||
1141 | * called in master mode. | ||
1142 | */ | ||
1143 | p.uapsd = false; | ||
1144 | |||
1131 | if (drv_conf_tx(local, params->queue, &p)) { | 1145 | if (drv_conf_tx(local, params->queue, &p)) { |
1132 | printk(KERN_DEBUG "%s: failed to set TX queue " | 1146 | printk(KERN_DEBUG "%s: failed to set TX queue " |
1133 | "parameters for queue %d\n", | 1147 | "parameters for queue %d\n", |
@@ -1230,6 +1244,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1230 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1244 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1231 | int err; | 1245 | int err; |
1232 | 1246 | ||
1247 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | ||
1248 | err = drv_set_coverage_class(local, wiphy->coverage_class); | ||
1249 | |||
1250 | if (err) | ||
1251 | return err; | ||
1252 | } | ||
1253 | |||
1233 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { | 1254 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) { |
1234 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); | 1255 | err = drv_set_rts_threshold(local, wiphy->rts_threshold); |
1235 | 1256 | ||
@@ -1399,8 +1420,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1399 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1420 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1400 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1421 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1401 | int i; | 1422 | int i; |
1402 | u32 target_rate; | ||
1403 | struct ieee80211_supported_band *sband; | ||
1404 | 1423 | ||
1405 | /* | 1424 | /* |
1406 | * This _could_ be supported by providing a hook for | 1425 | * This _could_ be supported by providing a hook for |
@@ -1410,35 +1429,11 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1410 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | 1429 | if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) |
1411 | return -EOPNOTSUPP; | 1430 | return -EOPNOTSUPP; |
1412 | 1431 | ||
1413 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1414 | |||
1415 | /* | ||
1416 | * target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1417 | * target_rate = X, rate->fixed = 1 means only rate X | ||
1418 | * target_rate = X, rate->fixed = 0 means all rates <= X | ||
1419 | */ | ||
1420 | sdata->max_ratectrl_rateidx = -1; | ||
1421 | sdata->force_unicast_rateidx = -1; | ||
1422 | |||
1423 | if (mask->fixed) | ||
1424 | target_rate = mask->fixed / 100; | ||
1425 | else if (mask->maxrate) | ||
1426 | target_rate = mask->maxrate / 100; | ||
1427 | else | ||
1428 | return 0; | ||
1429 | |||
1430 | for (i = 0; i< sband->n_bitrates; i++) { | ||
1431 | if (target_rate != sband->bitrates[i].bitrate) | ||
1432 | continue; | ||
1433 | 1432 | ||
1434 | /* requested bitrate found */ | 1433 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
1435 | sdata->max_ratectrl_rateidx = i; | 1434 | sdata->rc_rateidx_mask[i] = mask->control[i].legacy; |
1436 | if (mask->fixed) | ||
1437 | sdata->force_unicast_rateidx = i; | ||
1438 | return 0; | ||
1439 | } | ||
1440 | 1435 | ||
1441 | return -EINVAL; | 1436 | return 0; |
1442 | } | 1437 | } |
1443 | 1438 | ||
1444 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 1439 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e4b54093d41b..b3bc32b62a5a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -158,6 +158,98 @@ static const struct file_operations noack_ops = { | |||
158 | .open = mac80211_open_file_generic | 158 | .open = mac80211_open_file_generic |
159 | }; | 159 | }; |
160 | 160 | ||
161 | static ssize_t uapsd_queues_read(struct file *file, char __user *user_buf, | ||
162 | size_t count, loff_t *ppos) | ||
163 | { | ||
164 | struct ieee80211_local *local = file->private_data; | ||
165 | int res; | ||
166 | char buf[10]; | ||
167 | |||
168 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_queues); | ||
169 | |||
170 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
171 | } | ||
172 | |||
173 | static ssize_t uapsd_queues_write(struct file *file, | ||
174 | const char __user *user_buf, | ||
175 | size_t count, loff_t *ppos) | ||
176 | { | ||
177 | struct ieee80211_local *local = file->private_data; | ||
178 | unsigned long val; | ||
179 | char buf[10]; | ||
180 | size_t len; | ||
181 | int ret; | ||
182 | |||
183 | len = min(count, sizeof(buf) - 1); | ||
184 | if (copy_from_user(buf, user_buf, len)) | ||
185 | return -EFAULT; | ||
186 | buf[len] = '\0'; | ||
187 | |||
188 | ret = strict_strtoul(buf, 0, &val); | ||
189 | |||
190 | if (ret) | ||
191 | return -EINVAL; | ||
192 | |||
193 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
194 | return -ERANGE; | ||
195 | |||
196 | local->uapsd_queues = val; | ||
197 | |||
198 | return count; | ||
199 | } | ||
200 | |||
201 | static const struct file_operations uapsd_queues_ops = { | ||
202 | .read = uapsd_queues_read, | ||
203 | .write = uapsd_queues_write, | ||
204 | .open = mac80211_open_file_generic | ||
205 | }; | ||
206 | |||
207 | static ssize_t uapsd_max_sp_len_read(struct file *file, char __user *user_buf, | ||
208 | size_t count, loff_t *ppos) | ||
209 | { | ||
210 | struct ieee80211_local *local = file->private_data; | ||
211 | int res; | ||
212 | char buf[10]; | ||
213 | |||
214 | res = scnprintf(buf, sizeof(buf), "0x%x\n", local->uapsd_max_sp_len); | ||
215 | |||
216 | return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||
217 | } | ||
218 | |||
219 | static ssize_t uapsd_max_sp_len_write(struct file *file, | ||
220 | const char __user *user_buf, | ||
221 | size_t count, loff_t *ppos) | ||
222 | { | ||
223 | struct ieee80211_local *local = file->private_data; | ||
224 | unsigned long val; | ||
225 | char buf[10]; | ||
226 | size_t len; | ||
227 | int ret; | ||
228 | |||
229 | len = min(count, sizeof(buf) - 1); | ||
230 | if (copy_from_user(buf, user_buf, len)) | ||
231 | return -EFAULT; | ||
232 | buf[len] = '\0'; | ||
233 | |||
234 | ret = strict_strtoul(buf, 0, &val); | ||
235 | |||
236 | if (ret) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (val & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
240 | return -ERANGE; | ||
241 | |||
242 | local->uapsd_max_sp_len = val; | ||
243 | |||
244 | return count; | ||
245 | } | ||
246 | |||
247 | static const struct file_operations uapsd_max_sp_len_ops = { | ||
248 | .read = uapsd_max_sp_len_read, | ||
249 | .write = uapsd_max_sp_len_write, | ||
250 | .open = mac80211_open_file_generic | ||
251 | }; | ||
252 | |||
161 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 253 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
162 | size_t count, loff_t *ppos) | 254 | size_t count, loff_t *ppos) |
163 | { | 255 | { |
@@ -314,6 +406,8 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
314 | DEBUGFS_ADD(queues); | 406 | DEBUGFS_ADD(queues); |
315 | DEBUGFS_ADD_MODE(reset, 0200); | 407 | DEBUGFS_ADD_MODE(reset, 0200); |
316 | DEBUGFS_ADD(noack); | 408 | DEBUGFS_ADD(noack); |
409 | DEBUGFS_ADD(uapsd_queues); | ||
410 | DEBUGFS_ADD(uapsd_max_sp_len); | ||
317 | 411 | ||
318 | statsd = debugfs_create_dir("statistics", phyd); | 412 | statsd = debugfs_create_dir("statistics", phyd); |
319 | 413 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 59f6e3bcbd09..9affe2cd185f 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -127,8 +127,10 @@ __IEEE80211_IF_FILE(name, ieee80211_if_write_##name) | |||
127 | 127 | ||
128 | /* common attributes */ | 128 | /* common attributes */ |
129 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | 129 | IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); |
130 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 130 | IEEE80211_IF_FILE(rc_rateidx_mask_2ghz, rc_rateidx_mask[IEEE80211_BAND_2GHZ], |
131 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 131 | HEX); |
132 | IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | ||
133 | HEX); | ||
132 | 134 | ||
133 | /* STA attributes */ | 135 | /* STA attributes */ |
134 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 136 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
@@ -253,7 +255,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
253 | #endif | 255 | #endif |
254 | 256 | ||
255 | 257 | ||
256 | #define DEBUGFS_ADD(name, type) \ | 258 | #define DEBUGFS_ADD(name) \ |
257 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ | 259 | debugfs_create_file(#name, 0400, sdata->debugfs.dir, \ |
258 | sdata, &name##_ops); | 260 | sdata, &name##_ops); |
259 | 261 | ||
@@ -263,40 +265,40 @@ IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | |||
263 | 265 | ||
264 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 266 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
265 | { | 267 | { |
266 | DEBUGFS_ADD(drop_unencrypted, sta); | 268 | DEBUGFS_ADD(drop_unencrypted); |
267 | DEBUGFS_ADD(force_unicast_rateidx, sta); | 269 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
268 | DEBUGFS_ADD(max_ratectrl_rateidx, sta); | 270 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
269 | 271 | ||
270 | DEBUGFS_ADD(bssid, sta); | 272 | DEBUGFS_ADD(bssid); |
271 | DEBUGFS_ADD(aid, sta); | 273 | DEBUGFS_ADD(aid); |
272 | DEBUGFS_ADD_MODE(smps, 0600); | 274 | DEBUGFS_ADD_MODE(smps, 0600); |
273 | } | 275 | } |
274 | 276 | ||
275 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 277 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
276 | { | 278 | { |
277 | DEBUGFS_ADD(drop_unencrypted, ap); | 279 | DEBUGFS_ADD(drop_unencrypted); |
278 | DEBUGFS_ADD(force_unicast_rateidx, ap); | 280 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
279 | DEBUGFS_ADD(max_ratectrl_rateidx, ap); | 281 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
280 | 282 | ||
281 | DEBUGFS_ADD(num_sta_ps, ap); | 283 | DEBUGFS_ADD(num_sta_ps); |
282 | DEBUGFS_ADD(dtim_count, ap); | 284 | DEBUGFS_ADD(dtim_count); |
283 | DEBUGFS_ADD(num_buffered_multicast, ap); | 285 | DEBUGFS_ADD(num_buffered_multicast); |
284 | } | 286 | } |
285 | 287 | ||
286 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 288 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
287 | { | 289 | { |
288 | DEBUGFS_ADD(drop_unencrypted, wds); | 290 | DEBUGFS_ADD(drop_unencrypted); |
289 | DEBUGFS_ADD(force_unicast_rateidx, wds); | 291 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
290 | DEBUGFS_ADD(max_ratectrl_rateidx, wds); | 292 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
291 | 293 | ||
292 | DEBUGFS_ADD(peer, wds); | 294 | DEBUGFS_ADD(peer); |
293 | } | 295 | } |
294 | 296 | ||
295 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | 297 | static void add_vlan_files(struct ieee80211_sub_if_data *sdata) |
296 | { | 298 | { |
297 | DEBUGFS_ADD(drop_unencrypted, vlan); | 299 | DEBUGFS_ADD(drop_unencrypted); |
298 | DEBUGFS_ADD(force_unicast_rateidx, vlan); | 300 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
299 | DEBUGFS_ADD(max_ratectrl_rateidx, vlan); | 301 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
300 | } | 302 | } |
301 | 303 | ||
302 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | 304 | static void add_monitor_files(struct ieee80211_sub_if_data *sdata) |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 8757ea73d544..de91d39e0276 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -214,6 +214,21 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, | |||
214 | return ret; | 214 | return ret; |
215 | } | 215 | } |
216 | 216 | ||
217 | static inline int drv_set_coverage_class(struct ieee80211_local *local, | ||
218 | u8 value) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | might_sleep(); | ||
222 | |||
223 | if (local->ops->set_coverage_class) | ||
224 | local->ops->set_coverage_class(&local->hw, value); | ||
225 | else | ||
226 | ret = -EOPNOTSUPP; | ||
227 | |||
228 | trace_drv_set_coverage_class(local, value, ret); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
217 | static inline void drv_sta_notify(struct ieee80211_local *local, | 232 | static inline void drv_sta_notify(struct ieee80211_local *local, |
218 | struct ieee80211_sub_if_data *sdata, | 233 | struct ieee80211_sub_if_data *sdata, |
219 | enum sta_notify_cmd cmd, | 234 | enum sta_notify_cmd cmd, |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 977cc7528bc6..0ea258123b8e 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -491,6 +491,29 @@ TRACE_EVENT(drv_set_rts_threshold, | |||
491 | ) | 491 | ) |
492 | ); | 492 | ); |
493 | 493 | ||
494 | TRACE_EVENT(drv_set_coverage_class, | ||
495 | TP_PROTO(struct ieee80211_local *local, u8 value, int ret), | ||
496 | |||
497 | TP_ARGS(local, value, ret), | ||
498 | |||
499 | TP_STRUCT__entry( | ||
500 | LOCAL_ENTRY | ||
501 | __field(u8, value) | ||
502 | __field(int, ret) | ||
503 | ), | ||
504 | |||
505 | TP_fast_assign( | ||
506 | LOCAL_ASSIGN; | ||
507 | __entry->ret = ret; | ||
508 | __entry->value = value; | ||
509 | ), | ||
510 | |||
511 | TP_printk( | ||
512 | LOCAL_PR_FMT " value:%d ret:%d", | ||
513 | LOCAL_PR_ARG, __entry->value, __entry->ret | ||
514 | ) | ||
515 | ); | ||
516 | |||
494 | TRACE_EVENT(drv_sta_notify, | 517 | TRACE_EVENT(drv_sta_notify, |
495 | TP_PROTO(struct ieee80211_local *local, | 518 | TP_PROTO(struct ieee80211_local *local, |
496 | struct ieee80211_sub_if_data *sdata, | 519 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a27921ee6e63..c18f576f1848 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -58,6 +58,15 @@ struct ieee80211_local; | |||
58 | 58 | ||
59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) | 59 | #define TU_TO_EXP_TIME(x) (jiffies + usecs_to_jiffies((x) * 1024)) |
60 | 60 | ||
61 | #define IEEE80211_DEFAULT_UAPSD_QUEUES \ | ||
62 | (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ | ||
63 | IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ | ||
64 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ | ||
65 | IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
66 | |||
67 | #define IEEE80211_DEFAULT_MAX_SP_LEN \ | ||
68 | IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL | ||
69 | |||
61 | struct ieee80211_fragment_entry { | 70 | struct ieee80211_fragment_entry { |
62 | unsigned long first_frag_time; | 71 | unsigned long first_frag_time; |
63 | unsigned int seq; | 72 | unsigned int seq; |
@@ -78,6 +87,7 @@ struct ieee80211_bss { | |||
78 | u8 dtim_period; | 87 | u8 dtim_period; |
79 | 88 | ||
80 | bool wmm_used; | 89 | bool wmm_used; |
90 | bool uapsd_supported; | ||
81 | 91 | ||
82 | unsigned long last_probe_resp; | 92 | unsigned long last_probe_resp; |
83 | 93 | ||
@@ -285,7 +295,7 @@ struct ieee80211_work { | |||
285 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 295 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
286 | u8 ssid_len; | 296 | u8 ssid_len; |
287 | u8 supp_rates_len; | 297 | u8 supp_rates_len; |
288 | bool wmm_used, use_11n; | 298 | bool wmm_used, use_11n, uapsd_used; |
289 | } assoc; | 299 | } assoc; |
290 | struct { | 300 | struct { |
291 | u32 duration; | 301 | u32 duration; |
@@ -306,6 +316,7 @@ enum ieee80211_sta_flags { | |||
306 | IEEE80211_STA_DISABLE_11N = BIT(4), | 316 | IEEE80211_STA_DISABLE_11N = BIT(4), |
307 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 317 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
308 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 318 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
319 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | ||
309 | }; | 320 | }; |
310 | 321 | ||
311 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
@@ -494,8 +505,8 @@ struct ieee80211_sub_if_data { | |||
494 | */ | 505 | */ |
495 | struct ieee80211_if_ap *bss; | 506 | struct ieee80211_if_ap *bss; |
496 | 507 | ||
497 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 508 | /* bitmap of allowed (non-MCS) rate indexes for rate control */ |
498 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 509 | u32 rc_rateidx_mask[IEEE80211_NUM_BANDS]; |
499 | 510 | ||
500 | union { | 511 | union { |
501 | struct ieee80211_if_ap ap; | 512 | struct ieee80211_if_ap ap; |
@@ -797,6 +808,20 @@ struct ieee80211_local { | |||
797 | int wifi_wme_noack_test; | 808 | int wifi_wme_noack_test; |
798 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | 809 | unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ |
799 | 810 | ||
811 | /* | ||
812 | * Bitmask of enabled u-apsd queues, | ||
813 | * IEEE80211_WMM_IE_STA_QOSINFO_AC_BE & co. Needs a new association | ||
814 | * to take effect. | ||
815 | */ | ||
816 | unsigned int uapsd_queues; | ||
817 | |||
818 | /* | ||
819 | * Maximum number of buffered frames AP can deliver during a | ||
820 | * service period, IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL or similar. | ||
821 | * Needs a new association to take effect. | ||
822 | */ | ||
823 | unsigned int uapsd_max_sp_len; | ||
824 | |||
800 | bool pspolling; | 825 | bool pspolling; |
801 | bool offchannel_ps_enabled; | 826 | bool offchannel_ps_enabled; |
802 | /* | 827 | /* |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 00a1f4ccdaf1..fe140bf033f9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -15,12 +15,14 @@ | |||
15 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
16 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
17 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
18 | #include <net/ieee80211_radiotap.h> | ||
18 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
19 | #include "sta_info.h" | 20 | #include "sta_info.h" |
20 | #include "debugfs_netdev.h" | 21 | #include "debugfs_netdev.h" |
21 | #include "mesh.h" | 22 | #include "mesh.h" |
22 | #include "led.h" | 23 | #include "led.h" |
23 | #include "driver-ops.h" | 24 | #include "driver-ops.h" |
25 | #include "wme.h" | ||
24 | 26 | ||
25 | /** | 27 | /** |
26 | * DOC: Interface list locking | 28 | * DOC: Interface list locking |
@@ -63,15 +65,16 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
63 | static int ieee80211_change_mac(struct net_device *dev, void *addr) | 65 | static int ieee80211_change_mac(struct net_device *dev, void *addr) |
64 | { | 66 | { |
65 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 67 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
68 | struct sockaddr *sa = addr; | ||
66 | int ret; | 69 | int ret; |
67 | 70 | ||
68 | if (ieee80211_sdata_running(sdata)) | 71 | if (ieee80211_sdata_running(sdata)) |
69 | return -EBUSY; | 72 | return -EBUSY; |
70 | 73 | ||
71 | ret = eth_mac_addr(dev, addr); | 74 | ret = eth_mac_addr(dev, sa); |
72 | 75 | ||
73 | if (ret == 0) | 76 | if (ret == 0) |
74 | memcpy(sdata->vif.addr, addr, ETH_ALEN); | 77 | memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); |
75 | 78 | ||
76 | return ret; | 79 | return ret; |
77 | } | 80 | } |
@@ -326,7 +329,7 @@ static int ieee80211_open(struct net_device *dev) | |||
326 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 329 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
327 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); | 330 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); |
328 | 331 | ||
329 | netif_start_queue(dev); | 332 | netif_tx_start_all_queues(dev); |
330 | 333 | ||
331 | return 0; | 334 | return 0; |
332 | err_del_interface: | 335 | err_del_interface: |
@@ -354,7 +357,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
354 | /* | 357 | /* |
355 | * Stop TX on this interface first. | 358 | * Stop TX on this interface first. |
356 | */ | 359 | */ |
357 | netif_stop_queue(dev); | 360 | netif_tx_stop_all_queues(dev); |
358 | 361 | ||
359 | /* | 362 | /* |
360 | * Purge work for this interface. | 363 | * Purge work for this interface. |
@@ -657,6 +660,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
657 | WARN_ON(flushed); | 660 | WARN_ON(flushed); |
658 | } | 661 | } |
659 | 662 | ||
663 | static u16 ieee80211_netdev_select_queue(struct net_device *dev, | ||
664 | struct sk_buff *skb) | ||
665 | { | ||
666 | return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); | ||
667 | } | ||
668 | |||
660 | static const struct net_device_ops ieee80211_dataif_ops = { | 669 | static const struct net_device_ops ieee80211_dataif_ops = { |
661 | .ndo_open = ieee80211_open, | 670 | .ndo_open = ieee80211_open, |
662 | .ndo_stop = ieee80211_stop, | 671 | .ndo_stop = ieee80211_stop, |
@@ -665,8 +674,34 @@ static const struct net_device_ops ieee80211_dataif_ops = { | |||
665 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 674 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
666 | .ndo_change_mtu = ieee80211_change_mtu, | 675 | .ndo_change_mtu = ieee80211_change_mtu, |
667 | .ndo_set_mac_address = ieee80211_change_mac, | 676 | .ndo_set_mac_address = ieee80211_change_mac, |
677 | .ndo_select_queue = ieee80211_netdev_select_queue, | ||
668 | }; | 678 | }; |
669 | 679 | ||
680 | static u16 ieee80211_monitor_select_queue(struct net_device *dev, | ||
681 | struct sk_buff *skb) | ||
682 | { | ||
683 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
684 | struct ieee80211_local *local = sdata->local; | ||
685 | struct ieee80211_hdr *hdr; | ||
686 | struct ieee80211_radiotap_header *rtap = (void *)skb->data; | ||
687 | |||
688 | if (local->hw.queues < 4) | ||
689 | return 0; | ||
690 | |||
691 | if (skb->len < 4 || | ||
692 | skb->len < rtap->it_len + 2 /* frame control */) | ||
693 | return 0; /* doesn't matter, frame will be dropped */ | ||
694 | |||
695 | hdr = (void *)((u8 *)skb->data + rtap->it_len); | ||
696 | |||
697 | if (!ieee80211_is_data(hdr->frame_control)) { | ||
698 | skb->priority = 7; | ||
699 | return ieee802_1d_to_ac[skb->priority]; | ||
700 | } | ||
701 | |||
702 | return ieee80211_downgrade_queue(local, skb); | ||
703 | } | ||
704 | |||
670 | static const struct net_device_ops ieee80211_monitorif_ops = { | 705 | static const struct net_device_ops ieee80211_monitorif_ops = { |
671 | .ndo_open = ieee80211_open, | 706 | .ndo_open = ieee80211_open, |
672 | .ndo_stop = ieee80211_stop, | 707 | .ndo_stop = ieee80211_stop, |
@@ -675,6 +710,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { | |||
675 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 710 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
676 | .ndo_change_mtu = ieee80211_change_mtu, | 711 | .ndo_change_mtu = ieee80211_change_mtu, |
677 | .ndo_set_mac_address = eth_mac_addr, | 712 | .ndo_set_mac_address = eth_mac_addr, |
713 | .ndo_select_queue = ieee80211_monitor_select_queue, | ||
678 | }; | 714 | }; |
679 | 715 | ||
680 | static void ieee80211_if_setup(struct net_device *dev) | 716 | static void ieee80211_if_setup(struct net_device *dev) |
@@ -781,8 +817,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
781 | 817 | ||
782 | ASSERT_RTNL(); | 818 | ASSERT_RTNL(); |
783 | 819 | ||
784 | ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, | 820 | ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size, |
785 | name, ieee80211_if_setup); | 821 | name, ieee80211_if_setup, local->hw.queues); |
786 | if (!ndev) | 822 | if (!ndev) |
787 | return -ENOMEM; | 823 | return -ENOMEM; |
788 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); | 824 | dev_net_set(ndev, wiphy_net(local->hw.wiphy)); |
@@ -820,8 +856,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
820 | 856 | ||
821 | INIT_LIST_HEAD(&sdata->key_list); | 857 | INIT_LIST_HEAD(&sdata->key_list); |
822 | 858 | ||
823 | sdata->force_unicast_rateidx = -1; | 859 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
824 | sdata->max_ratectrl_rateidx = -1; | 860 | struct ieee80211_supported_band *sband; |
861 | sband = local->hw.wiphy->bands[i]; | ||
862 | sdata->rc_rateidx_mask[i] = | ||
863 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
864 | } | ||
825 | 865 | ||
826 | /* setup type-dependent data */ | 866 | /* setup type-dependent data */ |
827 | ieee80211_setup_sdata(sdata, type); | 867 | ieee80211_setup_sdata(sdata, type); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d0a14d953f08..ec8f767ba95b 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/if_arp.h> | 19 | #include <linux/if_arp.h> |
20 | #include <linux/wireless.h> | ||
21 | #include <linux/rtnetlink.h> | 20 | #include <linux/rtnetlink.h> |
22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
23 | #include <linux/pm_qos_params.h> | 22 | #include <linux/pm_qos_params.h> |
@@ -385,6 +384,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
385 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; | 384 | local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; |
386 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; | 385 | local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; |
387 | local->user_power_level = -1; | 386 | local->user_power_level = -1; |
387 | local->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; | ||
388 | local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; | ||
388 | 389 | ||
389 | INIT_LIST_HEAD(&local->interfaces); | 390 | INIT_LIST_HEAD(&local->interfaces); |
390 | mutex_init(&local->iflist_mtx); | 391 | mutex_init(&local->iflist_mtx); |
@@ -492,6 +493,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
492 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | 493 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
493 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | 494 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; |
494 | 495 | ||
496 | WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) | ||
497 | && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK), | ||
498 | "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"); | ||
499 | |||
495 | /* | 500 | /* |
496 | * Calculate scan IE length -- we need this to alloc | 501 | * Calculate scan IE length -- we need this to alloc |
497 | * memory and to subtract from the driver limit. It | 502 | * memory and to subtract from the driver limit. It |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 72920ee07885..a82564e73d91 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -249,30 +249,15 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
249 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 249 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
250 | struct ieee80211_sub_if_data *sdata) | 250 | struct ieee80211_sub_if_data *sdata) |
251 | { | 251 | { |
252 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
253 | struct ieee80211_pspoll *pspoll; | 252 | struct ieee80211_pspoll *pspoll; |
254 | struct sk_buff *skb; | 253 | struct sk_buff *skb; |
255 | u16 fc; | ||
256 | 254 | ||
257 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | 255 | skb = ieee80211_pspoll_get(&local->hw, &sdata->vif); |
258 | if (!skb) { | 256 | if (!skb) |
259 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
260 | "pspoll frame\n", sdata->name); | ||
261 | return; | 257 | return; |
262 | } | ||
263 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
264 | |||
265 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
266 | memset(pspoll, 0, sizeof(*pspoll)); | ||
267 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | ||
268 | pspoll->frame_control = cpu_to_le16(fc); | ||
269 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
270 | |||
271 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
272 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
273 | 258 | ||
274 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | 259 | pspoll = (struct ieee80211_pspoll *) skb->data; |
275 | memcpy(pspoll->ta, sdata->vif.addr, ETH_ALEN); | 260 | pspoll->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
276 | 261 | ||
277 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 262 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
278 | ieee80211_tx_skb(sdata, skb); | 263 | ieee80211_tx_skb(sdata, skb); |
@@ -283,30 +268,47 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
283 | int powersave) | 268 | int powersave) |
284 | { | 269 | { |
285 | struct sk_buff *skb; | 270 | struct sk_buff *skb; |
271 | struct ieee80211_hdr_3addr *nullfunc; | ||
272 | |||
273 | skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); | ||
274 | if (!skb) | ||
275 | return; | ||
276 | |||
277 | nullfunc = (struct ieee80211_hdr_3addr *) skb->data; | ||
278 | if (powersave) | ||
279 | nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
280 | |||
281 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
282 | ieee80211_tx_skb(sdata, skb); | ||
283 | } | ||
284 | |||
285 | static void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, | ||
286 | struct ieee80211_sub_if_data *sdata) | ||
287 | { | ||
288 | struct sk_buff *skb; | ||
286 | struct ieee80211_hdr *nullfunc; | 289 | struct ieee80211_hdr *nullfunc; |
287 | __le16 fc; | 290 | __le16 fc; |
288 | 291 | ||
289 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 292 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
290 | return; | 293 | return; |
291 | 294 | ||
292 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | 295 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 30); |
293 | if (!skb) { | 296 | if (!skb) { |
294 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | 297 | printk(KERN_DEBUG "%s: failed to allocate buffer for 4addr " |
295 | "frame\n", sdata->name); | 298 | "nullfunc frame\n", sdata->name); |
296 | return; | 299 | return; |
297 | } | 300 | } |
298 | skb_reserve(skb, local->hw.extra_tx_headroom); | 301 | skb_reserve(skb, local->hw.extra_tx_headroom); |
299 | 302 | ||
300 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | 303 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 30); |
301 | memset(nullfunc, 0, 24); | 304 | memset(nullfunc, 0, 30); |
302 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | 305 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | |
303 | IEEE80211_FCTL_TODS); | 306 | IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
304 | if (powersave) | ||
305 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
306 | nullfunc->frame_control = fc; | 307 | nullfunc->frame_control = fc; |
307 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | 308 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); |
308 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | 309 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); |
309 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | 310 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); |
311 | memcpy(nullfunc->addr4, sdata->vif.addr, ETH_ALEN); | ||
310 | 312 | ||
311 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 313 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
312 | ieee80211_tx_skb(sdata, skb); | 314 | ieee80211_tx_skb(sdata, skb); |
@@ -567,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
567 | struct ieee80211_tx_queue_params params; | 569 | struct ieee80211_tx_queue_params params; |
568 | size_t left; | 570 | size_t left; |
569 | int count; | 571 | int count; |
570 | u8 *pos; | 572 | u8 *pos, uapsd_queues = 0; |
571 | 573 | ||
572 | if (local->hw.queues < 4) | 574 | if (local->hw.queues < 4) |
573 | return; | 575 | return; |
@@ -577,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
577 | 579 | ||
578 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 580 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
579 | return; | 581 | return; |
582 | |||
583 | if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
584 | uapsd_queues = local->uapsd_queues; | ||
585 | |||
580 | count = wmm_param[6] & 0x0f; | 586 | count = wmm_param[6] & 0x0f; |
581 | if (count == ifmgd->wmm_last_param_set) | 587 | if (count == ifmgd->wmm_last_param_set) |
582 | return; | 588 | return; |
@@ -591,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
591 | for (; left >= 4; left -= 4, pos += 4) { | 597 | for (; left >= 4; left -= 4, pos += 4) { |
592 | int aci = (pos[0] >> 5) & 0x03; | 598 | int aci = (pos[0] >> 5) & 0x03; |
593 | int acm = (pos[0] >> 4) & 0x01; | 599 | int acm = (pos[0] >> 4) & 0x01; |
600 | bool uapsd = false; | ||
594 | int queue; | 601 | int queue; |
595 | 602 | ||
596 | switch (aci) { | 603 | switch (aci) { |
@@ -598,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
598 | queue = 3; | 605 | queue = 3; |
599 | if (acm) | 606 | if (acm) |
600 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ | 607 | local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ |
608 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) | ||
609 | uapsd = true; | ||
601 | break; | 610 | break; |
602 | case 2: /* AC_VI */ | 611 | case 2: /* AC_VI */ |
603 | queue = 1; | 612 | queue = 1; |
604 | if (acm) | 613 | if (acm) |
605 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ | 614 | local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ |
615 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) | ||
616 | uapsd = true; | ||
606 | break; | 617 | break; |
607 | case 3: /* AC_VO */ | 618 | case 3: /* AC_VO */ |
608 | queue = 0; | 619 | queue = 0; |
609 | if (acm) | 620 | if (acm) |
610 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ | 621 | local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ |
622 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
623 | uapsd = true; | ||
611 | break; | 624 | break; |
612 | case 0: /* AC_BE */ | 625 | case 0: /* AC_BE */ |
613 | default: | 626 | default: |
614 | queue = 2; | 627 | queue = 2; |
615 | if (acm) | 628 | if (acm) |
616 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ | 629 | local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ |
630 | if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) | ||
631 | uapsd = true; | ||
617 | break; | 632 | break; |
618 | } | 633 | } |
619 | 634 | ||
@@ -621,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
621 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); | 636 | params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); |
622 | params.cw_min = ecw2cw(pos[1] & 0x0f); | 637 | params.cw_min = ecw2cw(pos[1] & 0x0f); |
623 | params.txop = get_unaligned_le16(pos + 2); | 638 | params.txop = get_unaligned_le16(pos + 2); |
639 | params.uapsd = uapsd; | ||
640 | |||
624 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 641 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
625 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " | 642 | printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " |
626 | "cWmin=%d cWmax=%d txop=%d\n", | 643 | "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", |
627 | wiphy_name(local->hw.wiphy), queue, aci, acm, | 644 | wiphy_name(local->hw.wiphy), queue, aci, acm, |
628 | params.aifs, params.cw_min, params.cw_max, params.txop); | 645 | params.aifs, params.cw_min, params.cw_max, params.txop, |
646 | params.uapsd); | ||
629 | #endif | 647 | #endif |
630 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) | 648 | if (drv_conf_tx(local, queue, ¶ms) && local->ops->conf_tx) |
631 | printk(KERN_DEBUG "%s: failed to set TX queue " | 649 | printk(KERN_DEBUG "%s: failed to set TX queue " |
@@ -652,6 +670,8 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
652 | } | 670 | } |
653 | 671 | ||
654 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); | 672 | use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); |
673 | if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) | ||
674 | use_short_slot = true; | ||
655 | 675 | ||
656 | if (use_protection != bss_conf->use_cts_prot) { | 676 | if (use_protection != bss_conf->use_cts_prot) { |
657 | bss_conf->use_cts_prot = use_protection; | 677 | bss_conf->use_cts_prot = use_protection; |
@@ -723,7 +743,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
723 | ieee80211_recalc_smps(local, sdata); | 743 | ieee80211_recalc_smps(local, sdata); |
724 | mutex_unlock(&local->iflist_mtx); | 744 | mutex_unlock(&local->iflist_mtx); |
725 | 745 | ||
726 | netif_start_queue(sdata->dev); | 746 | netif_tx_start_all_queues(sdata->dev); |
727 | netif_carrier_on(sdata->dev); | 747 | netif_carrier_on(sdata->dev); |
728 | } | 748 | } |
729 | 749 | ||
@@ -759,7 +779,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
759 | * time -- we don't want the scan code to enable queues. | 779 | * time -- we don't want the scan code to enable queues. |
760 | */ | 780 | */ |
761 | 781 | ||
762 | netif_stop_queue(sdata->dev); | 782 | netif_tx_stop_all_queues(sdata->dev); |
763 | netif_carrier_off(sdata->dev); | 783 | netif_carrier_off(sdata->dev); |
764 | 784 | ||
765 | rcu_read_lock(); | 785 | rcu_read_lock(); |
@@ -1096,7 +1116,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1096 | if (err) { | 1116 | if (err) { |
1097 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1117 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
1098 | " the AP (error %d)\n", sdata->name, err); | 1118 | " the AP (error %d)\n", sdata->name, err); |
1099 | return RX_MGMT_CFG80211_ASSOC_ERROR; | 1119 | return false; |
1100 | } | 1120 | } |
1101 | 1121 | ||
1102 | if (elems.wmm_param) | 1122 | if (elems.wmm_param) |
@@ -1120,6 +1140,13 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1120 | ieee80211_set_associated(sdata, cbss, changed); | 1140 | ieee80211_set_associated(sdata, cbss, changed); |
1121 | 1141 | ||
1122 | /* | 1142 | /* |
1143 | * If we're using 4-addr mode, let the AP know that we're | ||
1144 | * doing so, so that it can create the STA VLAN on its side | ||
1145 | */ | ||
1146 | if (ifmgd->use_4addr) | ||
1147 | ieee80211_send_4addr_nullfunc(local, sdata); | ||
1148 | |||
1149 | /* | ||
1123 | * Start timer to probe the connection to the AP now. | 1150 | * Start timer to probe the connection to the AP now. |
1124 | * Also start the timer that will detect beacon loss. | 1151 | * Also start the timer that will detect beacon loss. |
1125 | */ | 1152 | */ |
@@ -1774,7 +1801,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
1774 | if (!wk) | 1801 | if (!wk) |
1775 | return -ENOMEM; | 1802 | return -ENOMEM; |
1776 | 1803 | ||
1777 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; | 1804 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); |
1778 | 1805 | ||
1779 | if (req->ie && req->ie_len) { | 1806 | if (req->ie && req->ie_len) { |
1780 | memcpy(wk->ie, req->ie, req->ie_len); | 1807 | memcpy(wk->ie, req->ie, req->ie_len); |
@@ -1897,6 +1924,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1897 | wk->assoc.ht_information_ie = | 1924 | wk->assoc.ht_information_ie = |
1898 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 1925 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); |
1899 | 1926 | ||
1927 | if (bss->wmm_used && bss->uapsd_supported && | ||
1928 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | ||
1929 | wk->assoc.uapsd_used = true; | ||
1930 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | ||
1931 | } else { | ||
1932 | wk->assoc.uapsd_used = false; | ||
1933 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | ||
1934 | } | ||
1935 | |||
1900 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1936 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
1901 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | 1937 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); |
1902 | wk->assoc.ssid_len = ssid[1]; | 1938 | wk->assoc.ssid_len = ssid[1]; |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index a7bbfc40a648..c36b1911987a 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -113,7 +113,7 @@ void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | |||
113 | */ | 113 | */ |
114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 114 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) | 115 | sdata->vif.type != NL80211_IFTYPE_MONITOR) |
116 | netif_stop_queue(sdata->dev); | 116 | netif_tx_stop_all_queues(sdata->dev); |
117 | } | 117 | } |
118 | mutex_unlock(&local->iflist_mtx); | 118 | mutex_unlock(&local->iflist_mtx); |
119 | } | 119 | } |
@@ -131,7 +131,7 @@ void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | |||
131 | continue; | 131 | continue; |
132 | 132 | ||
133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 133 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
134 | netif_stop_queue(sdata->dev); | 134 | netif_tx_stop_all_queues(sdata->dev); |
135 | if (sdata->u.mgd.associated) | 135 | if (sdata->u.mgd.associated) |
136 | ieee80211_offchannel_ps_enable(sdata); | 136 | ieee80211_offchannel_ps_enable(sdata); |
137 | } | 137 | } |
@@ -153,9 +153,11 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 153 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
154 | if (sdata->u.mgd.associated) | 154 | if (sdata->u.mgd.associated) |
155 | ieee80211_offchannel_ps_disable(sdata); | 155 | ieee80211_offchannel_ps_disable(sdata); |
156 | netif_wake_queue(sdata->dev); | ||
157 | } | 156 | } |
158 | 157 | ||
158 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||
159 | netif_tx_wake_all_queues(sdata->dev); | ||
160 | |||
159 | /* re-enable beaconing */ | 161 | /* re-enable beaconing */ |
160 | if (enable_beaconing && | 162 | if (enable_beaconing && |
161 | (sdata->vif.type == NL80211_IFTYPE_AP || | 163 | (sdata->vif.type == NL80211_IFTYPE_AP || |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index b9007f80cb92..c74b7c85403c 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -207,6 +207,27 @@ static bool rc_no_data_or_no_ack(struct ieee80211_tx_rate_control *txrc) | |||
207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); | 207 | return ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !ieee80211_is_data(fc)); |
208 | } | 208 | } |
209 | 209 | ||
210 | static void rc_send_low_broadcast(s8 *idx, u32 basic_rates, u8 max_rate_idx) | ||
211 | { | ||
212 | u8 i; | ||
213 | |||
214 | if (basic_rates == 0) | ||
215 | return; /* assume basic rates unknown and accept rate */ | ||
216 | if (*idx < 0) | ||
217 | return; | ||
218 | if (basic_rates & (1 << *idx)) | ||
219 | return; /* selected rate is a basic rate */ | ||
220 | |||
221 | for (i = *idx + 1; i <= max_rate_idx; i++) { | ||
222 | if (basic_rates & (1 << i)) { | ||
223 | *idx = i; | ||
224 | return; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* could not find a basic rate; use original selection */ | ||
229 | } | ||
230 | |||
210 | bool rate_control_send_low(struct ieee80211_sta *sta, | 231 | bool rate_control_send_low(struct ieee80211_sta *sta, |
211 | void *priv_sta, | 232 | void *priv_sta, |
212 | struct ieee80211_tx_rate_control *txrc) | 233 | struct ieee80211_tx_rate_control *txrc) |
@@ -218,12 +239,48 @@ bool rate_control_send_low(struct ieee80211_sta *sta, | |||
218 | info->control.rates[0].count = | 239 | info->control.rates[0].count = |
219 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? | 240 | (info->flags & IEEE80211_TX_CTL_NO_ACK) ? |
220 | 1 : txrc->hw->max_rate_tries; | 241 | 1 : txrc->hw->max_rate_tries; |
242 | if (!sta && txrc->ap) | ||
243 | rc_send_low_broadcast(&info->control.rates[0].idx, | ||
244 | txrc->bss_conf->basic_rates, | ||
245 | txrc->sband->n_bitrates); | ||
221 | return true; | 246 | return true; |
222 | } | 247 | } |
223 | return false; | 248 | return false; |
224 | } | 249 | } |
225 | EXPORT_SYMBOL(rate_control_send_low); | 250 | EXPORT_SYMBOL(rate_control_send_low); |
226 | 251 | ||
252 | static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | ||
253 | int n_bitrates, u32 mask) | ||
254 | { | ||
255 | int j; | ||
256 | |||
257 | /* See whether the selected rate or anything below it is allowed. */ | ||
258 | for (j = rate->idx; j >= 0; j--) { | ||
259 | if (mask & (1 << j)) { | ||
260 | /* Okay, found a suitable rate. Use it. */ | ||
261 | rate->idx = j; | ||
262 | return; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | /* Try to find a higher rate that would be allowed */ | ||
267 | for (j = rate->idx + 1; j < n_bitrates; j++) { | ||
268 | if (mask & (1 << j)) { | ||
269 | /* Okay, found a suitable rate. Use it. */ | ||
270 | rate->idx = j; | ||
271 | return; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Uh.. No suitable rate exists. This should not really happen with | ||
277 | * sane TX rate mask configurations. However, should someone manage to | ||
278 | * configure supported rates and TX rate mask in incompatible way, | ||
279 | * allow the frame to be transmitted with whatever the rate control | ||
280 | * selected. | ||
281 | */ | ||
282 | } | ||
283 | |||
227 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 284 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
228 | struct sta_info *sta, | 285 | struct sta_info *sta, |
229 | struct ieee80211_tx_rate_control *txrc) | 286 | struct ieee80211_tx_rate_control *txrc) |
@@ -233,6 +290,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
233 | struct ieee80211_sta *ista = NULL; | 290 | struct ieee80211_sta *ista = NULL; |
234 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); | 291 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); |
235 | int i; | 292 | int i; |
293 | u32 mask; | ||
236 | 294 | ||
237 | if (sta) { | 295 | if (sta) { |
238 | ista = &sta->sta; | 296 | ista = &sta->sta; |
@@ -245,23 +303,31 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
245 | info->control.rates[i].count = 1; | 303 | info->control.rates[i].count = 1; |
246 | } | 304 | } |
247 | 305 | ||
248 | if (sta && sdata->force_unicast_rateidx > -1) { | 306 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
249 | info->control.rates[0].idx = sdata->force_unicast_rateidx; | ||
250 | } else { | ||
251 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | ||
252 | info->flags |= IEEE80211_TX_INTFL_RCALGO; | ||
253 | } | ||
254 | 307 | ||
255 | /* | 308 | /* |
256 | * try to enforce the maximum rate the user wanted | 309 | * Try to enforce the rateidx mask the user wanted. skip this if the |
310 | * default mask (allow all rates) is used to save some processing for | ||
311 | * the common case. | ||
257 | */ | 312 | */ |
258 | if (sdata->max_ratectrl_rateidx > -1) | 313 | mask = sdata->rc_rateidx_mask[info->band]; |
314 | if (mask != (1 << txrc->sband->n_bitrates) - 1) { | ||
315 | if (sta) { | ||
316 | /* Filter out rates that the STA does not support */ | ||
317 | mask &= sta->sta.supp_rates[info->band]; | ||
318 | } | ||
319 | /* | ||
320 | * Make sure the rate index selected for each TX rate is | ||
321 | * included in the configured mask and change the rate indexes | ||
322 | * if needed. | ||
323 | */ | ||
259 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | 324 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { |
325 | /* Rate masking supports only legacy rates for now */ | ||
260 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) | 326 | if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) |
261 | continue; | 327 | continue; |
262 | info->control.rates[i].idx = | 328 | rate_idx_match_mask(&info->control.rates[i], |
263 | min_t(s8, info->control.rates[i].idx, | 329 | txrc->sband->n_bitrates, mask); |
264 | sdata->max_ratectrl_rateidx); | 330 | } |
265 | } | 331 | } |
266 | 332 | ||
267 | BUG_ON(info->control.rates[0].idx < 0); | 333 | BUG_ON(info->control.rates[0].idx < 0); |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index cb9bd1f65e27..669dddd40521 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -44,10 +44,7 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
44 | struct rate_control_ref *ref = local->rate_ctrl; | 44 | struct rate_control_ref *ref = local->rate_ctrl; |
45 | struct ieee80211_sta *ista = &sta->sta; | 45 | struct ieee80211_sta *ista = &sta->sta; |
46 | void *priv_sta = sta->rate_ctrl_priv; | 46 | void *priv_sta = sta->rate_ctrl_priv; |
47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 47 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); |
48 | |||
49 | if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) | ||
50 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | ||
51 | } | 48 | } |
52 | 49 | ||
53 | 50 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bfcf09eb64b4..efa6d3689c5e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1111,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1111 | if (ieee80211_is_nullfunc(hdr->frame_control) || | 1111 | if (ieee80211_is_nullfunc(hdr->frame_control) || |
1112 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 1112 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
1113 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); | 1113 | I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); |
1114 | |||
1115 | /* | ||
1116 | * If we receive a 4-addr nullfunc frame from a STA | ||
1117 | * that was not moved to a 4-addr STA vlan yet, drop | ||
1118 | * the frame to the monitor interface, to make sure | ||
1119 | * that hostapd sees it | ||
1120 | */ | ||
1121 | if (ieee80211_has_a4(hdr->frame_control) && | ||
1122 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | ||
1123 | (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | ||
1124 | !rx->sdata->u.vlan.sta))) | ||
1125 | return RX_DROP_MONITOR; | ||
1114 | /* | 1126 | /* |
1115 | * Update counter and free packet here to avoid | 1127 | * Update counter and free packet here to avoid |
1116 | * counting this as a dropped packed. | 1128 | * counting this as a dropped packed. |
@@ -1665,7 +1677,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1665 | memset(info, 0, sizeof(*info)); | 1677 | memset(info, 0, sizeof(*info)); |
1666 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1678 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1667 | info->control.vif = &rx->sdata->vif; | 1679 | info->control.vif = &rx->sdata->vif; |
1668 | ieee80211_select_queue(local, fwd_skb); | 1680 | skb_set_queue_mapping(skb, |
1681 | ieee80211_select_queue(rx->sdata, fwd_skb)); | ||
1682 | ieee80211_set_qos_hdr(local, skb); | ||
1669 | if (is_multicast_ether_addr(fwd_hdr->addr1)) | 1683 | if (is_multicast_ether_addr(fwd_hdr->addr1)) |
1670 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, | 1684 | IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, |
1671 | fwded_mcast); | 1685 | fwded_mcast); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 365f40975511..9afe2f9885dc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -12,7 +12,6 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/wireless.h> | ||
16 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
17 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
18 | #include <net/mac80211.h> | 17 | #include <net/mac80211.h> |
@@ -55,6 +54,23 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, | |||
55 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | 54 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); |
56 | } | 55 | } |
57 | 56 | ||
57 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) | ||
58 | { | ||
59 | u8 qos_info; | ||
60 | |||
61 | if (elems->wmm_info && elems->wmm_info_len == 7 | ||
62 | && elems->wmm_info[5] == 1) | ||
63 | qos_info = elems->wmm_info[6]; | ||
64 | else if (elems->wmm_param && elems->wmm_param_len == 24 | ||
65 | && elems->wmm_param[5] == 1) | ||
66 | qos_info = elems->wmm_param[6]; | ||
67 | else | ||
68 | /* no valid wmm information or parameter element found */ | ||
69 | return false; | ||
70 | |||
71 | return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; | ||
72 | } | ||
73 | |||
58 | struct ieee80211_bss * | 74 | struct ieee80211_bss * |
59 | ieee80211_bss_info_update(struct ieee80211_local *local, | 75 | ieee80211_bss_info_update(struct ieee80211_local *local, |
60 | struct ieee80211_rx_status *rx_status, | 76 | struct ieee80211_rx_status *rx_status, |
@@ -118,6 +134,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
118 | } | 134 | } |
119 | 135 | ||
120 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | 136 | bss->wmm_used = elems->wmm_param || elems->wmm_info; |
137 | bss->uapsd_supported = is_uapsd_supported(elems); | ||
121 | 138 | ||
122 | if (!beacon) | 139 | if (!beacon) |
123 | bss->last_probe_resp = jiffies; | 140 | bss->last_probe_resp = jiffies; |
@@ -285,6 +302,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
285 | ieee80211_mlme_notify_scan_completed(local); | 302 | ieee80211_mlme_notify_scan_completed(local); |
286 | ieee80211_ibss_notify_scan_completed(local); | 303 | ieee80211_ibss_notify_scan_completed(local); |
287 | ieee80211_mesh_notify_scan_completed(local); | 304 | ieee80211_mesh_notify_scan_completed(local); |
305 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
288 | } | 306 | } |
289 | EXPORT_SYMBOL(ieee80211_scan_completed); | 307 | EXPORT_SYMBOL(ieee80211_scan_completed); |
290 | 308 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 47da552ce8a6..f735826f055c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -119,6 +119,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
119 | return sta; | 119 | return sta; |
120 | } | 120 | } |
121 | 121 | ||
122 | /* | ||
123 | * Get sta info either from the specified interface | ||
124 | * or from one of its vlans | ||
125 | */ | ||
126 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
127 | const u8 *addr) | ||
128 | { | ||
129 | struct ieee80211_local *local = sdata->local; | ||
130 | struct sta_info *sta; | ||
131 | |||
132 | sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); | ||
133 | while (sta) { | ||
134 | if ((sta->sdata == sdata || | ||
135 | sta->sdata->bss == sdata->bss) && | ||
136 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
137 | break; | ||
138 | sta = rcu_dereference(sta->hnext); | ||
139 | } | ||
140 | return sta; | ||
141 | } | ||
142 | |||
122 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, | 143 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, |
123 | int idx) | 144 | int idx) |
124 | { | 145 | { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index c8208236e896..6f79bba5706e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -408,6 +408,9 @@ static inline u32 get_sta_flags(struct sta_info *sta) | |||
408 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 408 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
409 | const u8 *addr); | 409 | const u8 *addr); |
410 | 410 | ||
411 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | ||
412 | const u8 *addr); | ||
413 | |||
411 | static inline | 414 | static inline |
412 | void for_each_sta_info_type_check(struct ieee80211_local *local, | 415 | void for_each_sta_info_type_check(struct ieee80211_local *local, |
413 | const u8 *addr, | 416 | const u8 *addr, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7bba49d2b6ca..daf81048c1f7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -180,6 +180,71 @@ static int inline is_ieee80211_device(struct ieee80211_local *local, | |||
180 | } | 180 | } |
181 | 181 | ||
182 | /* tx handlers */ | 182 | /* tx handlers */ |
183 | static ieee80211_tx_result debug_noinline | ||
184 | ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) | ||
185 | { | ||
186 | struct ieee80211_local *local = tx->local; | ||
187 | struct ieee80211_if_managed *ifmgd; | ||
188 | |||
189 | /* driver doesn't support power save */ | ||
190 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
191 | return TX_CONTINUE; | ||
192 | |||
193 | /* hardware does dynamic power save */ | ||
194 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
195 | return TX_CONTINUE; | ||
196 | |||
197 | /* dynamic power save disabled */ | ||
198 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
199 | return TX_CONTINUE; | ||
200 | |||
201 | /* we are scanning, don't enable power save */ | ||
202 | if (local->scanning) | ||
203 | return TX_CONTINUE; | ||
204 | |||
205 | if (!local->ps_sdata) | ||
206 | return TX_CONTINUE; | ||
207 | |||
208 | /* No point if we're going to suspend */ | ||
209 | if (local->quiescing) | ||
210 | return TX_CONTINUE; | ||
211 | |||
212 | /* dynamic ps is supported only in managed mode */ | ||
213 | if (tx->sdata->vif.type != NL80211_IFTYPE_STATION) | ||
214 | return TX_CONTINUE; | ||
215 | |||
216 | ifmgd = &tx->sdata->u.mgd; | ||
217 | |||
218 | /* | ||
219 | * Don't wakeup from power save if u-apsd is enabled, voip ac has | ||
220 | * u-apsd enabled and the frame is in voip class. This effectively | ||
221 | * means that even if all access categories have u-apsd enabled, in | ||
222 | * practise u-apsd is only used with the voip ac. This is a | ||
223 | * workaround for the case when received voip class packets do not | ||
224 | * have correct qos tag for some reason, due the network or the | ||
225 | * peer application. | ||
226 | * | ||
227 | * Note: local->uapsd_queues access is racy here. If the value is | ||
228 | * changed via debugfs, user needs to reassociate manually to have | ||
229 | * everything in sync. | ||
230 | */ | ||
231 | if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) | ||
232 | && (local->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) | ||
233 | && skb_get_queue_mapping(tx->skb) == 0) | ||
234 | return TX_CONTINUE; | ||
235 | |||
236 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
237 | ieee80211_stop_queues_by_reason(&local->hw, | ||
238 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
239 | ieee80211_queue_work(&local->hw, | ||
240 | &local->dynamic_ps_disable_work); | ||
241 | } | ||
242 | |||
243 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
244 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
245 | |||
246 | return TX_CONTINUE; | ||
247 | } | ||
183 | 248 | ||
184 | static ieee80211_tx_result debug_noinline | 249 | static ieee80211_tx_result debug_noinline |
185 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | 250 | ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) |
@@ -519,7 +584,12 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
519 | txrc.bss_conf = &tx->sdata->vif.bss_conf; | 584 | txrc.bss_conf = &tx->sdata->vif.bss_conf; |
520 | txrc.skb = tx->skb; | 585 | txrc.skb = tx->skb; |
521 | txrc.reported_rate.idx = -1; | 586 | txrc.reported_rate.idx = -1; |
522 | txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; | 587 | txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[tx->channel->band]; |
588 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | ||
589 | txrc.max_rate_idx = -1; | ||
590 | else | ||
591 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
592 | txrc.ap = tx->sdata->vif.type == NL80211_IFTYPE_AP; | ||
523 | 593 | ||
524 | /* set up RTS protection if desired */ | 594 | /* set up RTS protection if desired */ |
525 | if (len > tx->local->hw.wiphy->rts_threshold) { | 595 | if (len > tx->local->hw.wiphy->rts_threshold) { |
@@ -1051,8 +1121,11 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1051 | 1121 | ||
1052 | hdr = (struct ieee80211_hdr *) skb->data; | 1122 | hdr = (struct ieee80211_hdr *) skb->data; |
1053 | 1123 | ||
1054 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1124 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
1055 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | 1125 | tx->sta = rcu_dereference(sdata->u.vlan.sta); |
1126 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) | ||
1127 | return TX_DROP; | ||
1128 | } | ||
1056 | if (!tx->sta) | 1129 | if (!tx->sta) |
1057 | tx->sta = sta_info_get(sdata, hdr->addr1); | 1130 | tx->sta = sta_info_get(sdata, hdr->addr1); |
1058 | 1131 | ||
@@ -1215,6 +1288,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1215 | goto txh_done; \ | 1288 | goto txh_done; \ |
1216 | } while (0) | 1289 | } while (0) |
1217 | 1290 | ||
1291 | CALL_TXH(ieee80211_tx_h_dynamic_ps); | ||
1218 | CALL_TXH(ieee80211_tx_h_check_assoc); | 1292 | CALL_TXH(ieee80211_tx_h_check_assoc); |
1219 | CALL_TXH(ieee80211_tx_h_ps_buf); | 1293 | CALL_TXH(ieee80211_tx_h_ps_buf); |
1220 | CALL_TXH(ieee80211_tx_h_select_key); | 1294 | CALL_TXH(ieee80211_tx_h_select_key); |
@@ -1397,34 +1471,6 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, | |||
1397 | return 0; | 1471 | return 0; |
1398 | } | 1472 | } |
1399 | 1473 | ||
1400 | static bool need_dynamic_ps(struct ieee80211_local *local) | ||
1401 | { | ||
1402 | /* driver doesn't support power save */ | ||
1403 | if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) | ||
1404 | return false; | ||
1405 | |||
1406 | /* hardware does dynamic power save */ | ||
1407 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | ||
1408 | return false; | ||
1409 | |||
1410 | /* dynamic power save disabled */ | ||
1411 | if (local->hw.conf.dynamic_ps_timeout <= 0) | ||
1412 | return false; | ||
1413 | |||
1414 | /* we are scanning, don't enable power save */ | ||
1415 | if (local->scanning) | ||
1416 | return false; | ||
1417 | |||
1418 | if (!local->ps_sdata) | ||
1419 | return false; | ||
1420 | |||
1421 | /* No point if we're going to suspend */ | ||
1422 | if (local->quiescing) | ||
1423 | return false; | ||
1424 | |||
1425 | return true; | ||
1426 | } | ||
1427 | |||
1428 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | 1474 | static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, |
1429 | struct sk_buff *skb) | 1475 | struct sk_buff *skb) |
1430 | { | 1476 | { |
@@ -1435,18 +1481,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1435 | int headroom; | 1481 | int headroom; |
1436 | bool may_encrypt; | 1482 | bool may_encrypt; |
1437 | 1483 | ||
1438 | if (need_dynamic_ps(local)) { | ||
1439 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
1440 | ieee80211_stop_queues_by_reason(&local->hw, | ||
1441 | IEEE80211_QUEUE_STOP_REASON_PS); | ||
1442 | ieee80211_queue_work(&local->hw, | ||
1443 | &local->dynamic_ps_disable_work); | ||
1444 | } | ||
1445 | |||
1446 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1447 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1448 | } | ||
1449 | |||
1450 | rcu_read_lock(); | 1484 | rcu_read_lock(); |
1451 | 1485 | ||
1452 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { | 1486 | if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) { |
@@ -1511,7 +1545,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1511 | return; | 1545 | return; |
1512 | } | 1546 | } |
1513 | 1547 | ||
1514 | ieee80211_select_queue(local, skb); | 1548 | ieee80211_set_qos_hdr(local, skb); |
1515 | ieee80211_tx(sdata, skb, false); | 1549 | ieee80211_tx(sdata, skb, false); |
1516 | rcu_read_unlock(); | 1550 | rcu_read_unlock(); |
1517 | } | 1551 | } |
@@ -2060,6 +2094,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2060 | struct beacon_data *beacon; | 2094 | struct beacon_data *beacon; |
2061 | struct ieee80211_supported_band *sband; | 2095 | struct ieee80211_supported_band *sband; |
2062 | enum ieee80211_band band = local->hw.conf.channel->band; | 2096 | enum ieee80211_band band = local->hw.conf.channel->band; |
2097 | struct ieee80211_tx_rate_control txrc; | ||
2063 | 2098 | ||
2064 | sband = local->hw.wiphy->bands[band]; | 2099 | sband = local->hw.wiphy->bands[band]; |
2065 | 2100 | ||
@@ -2167,21 +2202,25 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2167 | info = IEEE80211_SKB_CB(skb); | 2202 | info = IEEE80211_SKB_CB(skb); |
2168 | 2203 | ||
2169 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 2204 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
2205 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
2170 | info->band = band; | 2206 | info->band = band; |
2171 | /* | 2207 | |
2172 | * XXX: For now, always use the lowest rate | 2208 | memset(&txrc, 0, sizeof(txrc)); |
2173 | */ | 2209 | txrc.hw = hw; |
2174 | info->control.rates[0].idx = 0; | 2210 | txrc.sband = sband; |
2175 | info->control.rates[0].count = 1; | 2211 | txrc.bss_conf = &sdata->vif.bss_conf; |
2176 | info->control.rates[1].idx = -1; | 2212 | txrc.skb = skb; |
2177 | info->control.rates[2].idx = -1; | 2213 | txrc.reported_rate.idx = -1; |
2178 | info->control.rates[3].idx = -1; | 2214 | txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; |
2179 | info->control.rates[4].idx = -1; | 2215 | if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) |
2180 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | 2216 | txrc.max_rate_idx = -1; |
2217 | else | ||
2218 | txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | ||
2219 | txrc.ap = true; | ||
2220 | rate_control_get_rate(sdata, NULL, &txrc); | ||
2181 | 2221 | ||
2182 | info->control.vif = vif; | 2222 | info->control.vif = vif; |
2183 | 2223 | ||
2184 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||
2185 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; | 2224 | info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; |
2186 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; | 2225 | info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; |
2187 | out: | 2226 | out: |
@@ -2190,6 +2229,134 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2190 | } | 2229 | } |
2191 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); | 2230 | EXPORT_SYMBOL(ieee80211_beacon_get_tim); |
2192 | 2231 | ||
2232 | struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, | ||
2233 | struct ieee80211_vif *vif) | ||
2234 | { | ||
2235 | struct ieee80211_sub_if_data *sdata; | ||
2236 | struct ieee80211_if_managed *ifmgd; | ||
2237 | struct ieee80211_pspoll *pspoll; | ||
2238 | struct ieee80211_local *local; | ||
2239 | struct sk_buff *skb; | ||
2240 | |||
2241 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
2242 | return NULL; | ||
2243 | |||
2244 | sdata = vif_to_sdata(vif); | ||
2245 | ifmgd = &sdata->u.mgd; | ||
2246 | local = sdata->local; | ||
2247 | |||
2248 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll)); | ||
2249 | if (!skb) { | ||
2250 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | ||
2251 | "pspoll template\n", sdata->name); | ||
2252 | return NULL; | ||
2253 | } | ||
2254 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2255 | |||
2256 | pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll)); | ||
2257 | memset(pspoll, 0, sizeof(*pspoll)); | ||
2258 | pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | | ||
2259 | IEEE80211_STYPE_PSPOLL); | ||
2260 | pspoll->aid = cpu_to_le16(ifmgd->aid); | ||
2261 | |||
2262 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
2263 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | ||
2264 | |||
2265 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); | ||
2266 | memcpy(pspoll->ta, vif->addr, ETH_ALEN); | ||
2267 | |||
2268 | return skb; | ||
2269 | } | ||
2270 | EXPORT_SYMBOL(ieee80211_pspoll_get); | ||
2271 | |||
2272 | struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | ||
2273 | struct ieee80211_vif *vif) | ||
2274 | { | ||
2275 | struct ieee80211_hdr_3addr *nullfunc; | ||
2276 | struct ieee80211_sub_if_data *sdata; | ||
2277 | struct ieee80211_if_managed *ifmgd; | ||
2278 | struct ieee80211_local *local; | ||
2279 | struct sk_buff *skb; | ||
2280 | |||
2281 | if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) | ||
2282 | return NULL; | ||
2283 | |||
2284 | sdata = vif_to_sdata(vif); | ||
2285 | ifmgd = &sdata->u.mgd; | ||
2286 | local = sdata->local; | ||
2287 | |||
2288 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); | ||
2289 | if (!skb) { | ||
2290 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2291 | "template\n", sdata->name); | ||
2292 | return NULL; | ||
2293 | } | ||
2294 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2295 | |||
2296 | nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb, | ||
2297 | sizeof(*nullfunc)); | ||
2298 | memset(nullfunc, 0, sizeof(*nullfunc)); | ||
2299 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2300 | IEEE80211_STYPE_NULLFUNC | | ||
2301 | IEEE80211_FCTL_TODS); | ||
2302 | memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); | ||
2303 | memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); | ||
2304 | memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); | ||
2305 | |||
2306 | return skb; | ||
2307 | } | ||
2308 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | ||
2309 | |||
2310 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | ||
2311 | struct ieee80211_vif *vif, | ||
2312 | const u8 *ssid, size_t ssid_len, | ||
2313 | const u8 *ie, size_t ie_len) | ||
2314 | { | ||
2315 | struct ieee80211_sub_if_data *sdata; | ||
2316 | struct ieee80211_local *local; | ||
2317 | struct ieee80211_hdr_3addr *hdr; | ||
2318 | struct sk_buff *skb; | ||
2319 | size_t ie_ssid_len; | ||
2320 | u8 *pos; | ||
2321 | |||
2322 | sdata = vif_to_sdata(vif); | ||
2323 | local = sdata->local; | ||
2324 | ie_ssid_len = 2 + ssid_len; | ||
2325 | |||
2326 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | ||
2327 | ie_ssid_len + ie_len); | ||
2328 | if (!skb) { | ||
2329 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
2330 | "request template\n", sdata->name); | ||
2331 | return NULL; | ||
2332 | } | ||
2333 | |||
2334 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2335 | |||
2336 | hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); | ||
2337 | memset(hdr, 0, sizeof(*hdr)); | ||
2338 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2339 | IEEE80211_STYPE_PROBE_REQ); | ||
2340 | memset(hdr->addr1, 0xff, ETH_ALEN); | ||
2341 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | ||
2342 | memset(hdr->addr3, 0xff, ETH_ALEN); | ||
2343 | |||
2344 | pos = skb_put(skb, ie_ssid_len); | ||
2345 | *pos++ = WLAN_EID_SSID; | ||
2346 | *pos++ = ssid_len; | ||
2347 | if (ssid) | ||
2348 | memcpy(pos, ssid, ssid_len); | ||
2349 | pos += ssid_len; | ||
2350 | |||
2351 | if (ie) { | ||
2352 | pos = skb_put(skb, ie_len); | ||
2353 | memcpy(pos, ie, ie_len); | ||
2354 | } | ||
2355 | |||
2356 | return skb; | ||
2357 | } | ||
2358 | EXPORT_SYMBOL(ieee80211_probereq_get); | ||
2359 | |||
2193 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 2360 | void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
2194 | const void *frame, size_t frame_len, | 2361 | const void *frame, size_t frame_len, |
2195 | const struct ieee80211_tx_info *frame_txctl, | 2362 | const struct ieee80211_tx_info *frame_txctl, |
@@ -2289,6 +2456,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
2289 | skb_set_network_header(skb, 0); | 2456 | skb_set_network_header(skb, 0); |
2290 | skb_set_transport_header(skb, 0); | 2457 | skb_set_transport_header(skb, 0); |
2291 | 2458 | ||
2459 | /* send all internal mgmt frames on VO */ | ||
2460 | skb_set_queue_mapping(skb, 0); | ||
2461 | |||
2292 | /* | 2462 | /* |
2293 | * The other path calling ieee80211_xmit is from the tasklet, | 2463 | * The other path calling ieee80211_xmit is from the tasklet, |
2294 | * and while we can handle concurrent transmissions locking | 2464 | * and while we can handle concurrent transmissions locking |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7e38858a9280..ca170b417da6 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/skbuff.h> | 18 | #include <linux/skbuff.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/wireless.h> | ||
22 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
23 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
24 | #include <net/net_namespace.h> | 23 | #include <net/net_namespace.h> |
@@ -269,6 +268,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
269 | enum queue_stop_reason reason) | 268 | enum queue_stop_reason reason) |
270 | { | 269 | { |
271 | struct ieee80211_local *local = hw_to_local(hw); | 270 | struct ieee80211_local *local = hw_to_local(hw); |
271 | struct ieee80211_sub_if_data *sdata; | ||
272 | 272 | ||
273 | if (WARN_ON(queue >= hw->queues)) | 273 | if (WARN_ON(queue >= hw->queues)) |
274 | return; | 274 | return; |
@@ -281,6 +281,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
281 | 281 | ||
282 | if (!skb_queue_empty(&local->pending[queue])) | 282 | if (!skb_queue_empty(&local->pending[queue])) |
283 | tasklet_schedule(&local->tx_pending_tasklet); | 283 | tasklet_schedule(&local->tx_pending_tasklet); |
284 | |||
285 | rcu_read_lock(); | ||
286 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
287 | netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
288 | rcu_read_unlock(); | ||
284 | } | 289 | } |
285 | 290 | ||
286 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 291 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -305,11 +310,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
305 | enum queue_stop_reason reason) | 310 | enum queue_stop_reason reason) |
306 | { | 311 | { |
307 | struct ieee80211_local *local = hw_to_local(hw); | 312 | struct ieee80211_local *local = hw_to_local(hw); |
313 | struct ieee80211_sub_if_data *sdata; | ||
308 | 314 | ||
309 | if (WARN_ON(queue >= hw->queues)) | 315 | if (WARN_ON(queue >= hw->queues)) |
310 | return; | 316 | return; |
311 | 317 | ||
312 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 318 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
319 | |||
320 | rcu_read_lock(); | ||
321 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
322 | netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue)); | ||
323 | rcu_read_unlock(); | ||
313 | } | 324 | } |
314 | 325 | ||
315 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 326 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -781,6 +792,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
781 | break; | 792 | break; |
782 | } | 793 | } |
783 | 794 | ||
795 | qparam.uapsd = false; | ||
796 | |||
784 | drv_conf_tx(local, queue, &qparam); | 797 | drv_conf_tx(local, queue, &qparam); |
785 | } | 798 | } |
786 | } | 799 | } |
@@ -989,40 +1002,33 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
989 | struct ieee80211_local *local = sdata->local; | 1002 | struct ieee80211_local *local = sdata->local; |
990 | struct sk_buff *skb; | 1003 | struct sk_buff *skb; |
991 | struct ieee80211_mgmt *mgmt; | 1004 | struct ieee80211_mgmt *mgmt; |
992 | u8 *pos; | 1005 | size_t buf_len; |
993 | 1006 | u8 *buf; | |
994 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 1007 | |
995 | ie_len); | 1008 | /* FIXME: come up with a proper value */ |
996 | if (!skb) { | 1009 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
997 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1010 | if (!buf) { |
998 | "request\n", sdata->name); | 1011 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " |
1012 | "buffer\n", sdata->name); | ||
999 | return; | 1013 | return; |
1000 | } | 1014 | } |
1001 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1002 | 1015 | ||
1003 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 1016 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, |
1004 | memset(mgmt, 0, 24); | 1017 | local->hw.conf.channel->band); |
1005 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1018 | |
1006 | IEEE80211_STYPE_PROBE_REQ); | 1019 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1007 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | 1020 | ssid, ssid_len, |
1021 | buf, buf_len); | ||
1022 | |||
1008 | if (dst) { | 1023 | if (dst) { |
1024 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
1009 | memcpy(mgmt->da, dst, ETH_ALEN); | 1025 | memcpy(mgmt->da, dst, ETH_ALEN); |
1010 | memcpy(mgmt->bssid, dst, ETH_ALEN); | 1026 | memcpy(mgmt->bssid, dst, ETH_ALEN); |
1011 | } else { | ||
1012 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1013 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
1014 | } | 1027 | } |
1015 | pos = skb_put(skb, 2 + ssid_len); | ||
1016 | *pos++ = WLAN_EID_SSID; | ||
1017 | *pos++ = ssid_len; | ||
1018 | memcpy(pos, ssid, ssid_len); | ||
1019 | pos += ssid_len; | ||
1020 | |||
1021 | skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len, | ||
1022 | local->hw.conf.channel->band)); | ||
1023 | 1028 | ||
1024 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1029 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1025 | ieee80211_tx_skb(sdata, skb); | 1030 | ieee80211_tx_skb(sdata, skb); |
1031 | kfree(buf); | ||
1026 | } | 1032 | } |
1027 | 1033 | ||
1028 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 1034 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
@@ -1066,9 +1072,9 @@ void ieee80211_stop_device(struct ieee80211_local *local) | |||
1066 | ieee80211_led_radio(local, false); | 1072 | ieee80211_led_radio(local, false); |
1067 | 1073 | ||
1068 | cancel_work_sync(&local->reconfig_filter); | 1074 | cancel_work_sync(&local->reconfig_filter); |
1069 | drv_stop(local); | ||
1070 | 1075 | ||
1071 | flush_workqueue(local->workqueue); | 1076 | flush_workqueue(local->workqueue); |
1077 | drv_stop(local); | ||
1072 | } | 1078 | } |
1073 | 1079 | ||
1074 | int ieee80211_reconfig(struct ieee80211_local *local) | 1080 | int ieee80211_reconfig(struct ieee80211_local *local) |
@@ -1094,7 +1100,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1094 | if (res) { | 1100 | if (res) { |
1095 | WARN(local->suspended, "Harware became unavailable " | 1101 | WARN(local->suspended, "Harware became unavailable " |
1096 | "upon resume. This is could be a software issue" | 1102 | "upon resume. This is could be a software issue" |
1097 | "prior to suspend or a harware issue\n"); | 1103 | "prior to suspend or a hardware issue\n"); |
1098 | return res; | 1104 | return res; |
1099 | } | 1105 | } |
1100 | 1106 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index b19b7696f3a2..34e6d02da779 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -44,22 +44,69 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
44 | } | 44 | } |
45 | 45 | ||
46 | 46 | ||
47 | /* Indicate which queue to use. */ | 47 | /* Indicate which queue to use. */ |
48 | static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | 48 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
49 | struct sk_buff *skb) | ||
49 | { | 50 | { |
50 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 51 | struct ieee80211_local *local = sdata->local; |
52 | struct sta_info *sta = NULL; | ||
53 | u32 sta_flags = 0; | ||
54 | const u8 *ra = NULL; | ||
55 | bool qos = false; | ||
51 | 56 | ||
52 | if (!ieee80211_is_data(hdr->frame_control)) { | 57 | if (local->hw.queues < 4 || skb->len < 6) { |
53 | /* management frames go on AC_VO queue, but are sent | 58 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
54 | * without QoS control fields */ | 59 | return min_t(u16, local->hw.queues - 1, |
55 | return 0; | 60 | ieee802_1d_to_ac[skb->priority]); |
61 | } | ||
62 | |||
63 | rcu_read_lock(); | ||
64 | switch (sdata->vif.type) { | ||
65 | case NL80211_IFTYPE_AP_VLAN: | ||
66 | rcu_read_lock(); | ||
67 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
68 | if (sta) | ||
69 | sta_flags = get_sta_flags(sta); | ||
70 | rcu_read_unlock(); | ||
71 | if (sta) | ||
72 | break; | ||
73 | case NL80211_IFTYPE_AP: | ||
74 | ra = skb->data; | ||
75 | break; | ||
76 | case NL80211_IFTYPE_WDS: | ||
77 | ra = sdata->u.wds.remote_addr; | ||
78 | break; | ||
79 | #ifdef CONFIG_MAC80211_MESH | ||
80 | case NL80211_IFTYPE_MESH_POINT: | ||
81 | /* | ||
82 | * XXX: This is clearly broken ... but already was before, | ||
83 | * because ieee80211_fill_mesh_addresses() would clear A1 | ||
84 | * except for multicast addresses. | ||
85 | */ | ||
86 | break; | ||
87 | #endif | ||
88 | case NL80211_IFTYPE_STATION: | ||
89 | ra = sdata->u.mgd.bssid; | ||
90 | break; | ||
91 | case NL80211_IFTYPE_ADHOC: | ||
92 | ra = skb->data; | ||
93 | break; | ||
94 | default: | ||
95 | break; | ||
56 | } | 96 | } |
57 | 97 | ||
58 | if (0 /* injected */) { | 98 | if (!sta && ra && !is_multicast_ether_addr(ra)) { |
59 | /* use AC from radiotap */ | 99 | sta = sta_info_get(sdata, ra); |
100 | if (sta) | ||
101 | sta_flags = get_sta_flags(sta); | ||
60 | } | 102 | } |
61 | 103 | ||
62 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 104 | if (sta_flags & WLAN_STA_WME) |
105 | qos = true; | ||
106 | |||
107 | rcu_read_unlock(); | ||
108 | |||
109 | if (!qos) { | ||
63 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 110 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
64 | return ieee802_1d_to_ac[skb->priority]; | 111 | return ieee802_1d_to_ac[skb->priority]; |
65 | } | 112 | } |
@@ -68,6 +115,12 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | |||
68 | * data frame has */ | 115 | * data frame has */ |
69 | skb->priority = cfg80211_classify8021d(skb); | 116 | skb->priority = cfg80211_classify8021d(skb); |
70 | 117 | ||
118 | return ieee80211_downgrade_queue(local, skb); | ||
119 | } | ||
120 | |||
121 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
122 | struct sk_buff *skb) | ||
123 | { | ||
71 | /* in case we are a client verify acm is not set for this ac */ | 124 | /* in case we are a client verify acm is not set for this ac */ |
72 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { | 125 | while (unlikely(local->wmm_acm & BIT(skb->priority))) { |
73 | if (wme_downgrade_ac(skb)) { | 126 | if (wme_downgrade_ac(skb)) { |
@@ -85,24 +138,17 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) | |||
85 | return ieee802_1d_to_ac[skb->priority]; | 138 | return ieee802_1d_to_ac[skb->priority]; |
86 | } | 139 | } |
87 | 140 | ||
88 | void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) | 141 | void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb) |
89 | { | 142 | { |
90 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 143 | struct ieee80211_hdr *hdr = (void *)skb->data; |
91 | u16 queue; | 144 | |
92 | u8 tid; | 145 | /* Fill in the QoS header if there is one. */ |
93 | |||
94 | queue = classify80211(local, skb); | ||
95 | if (unlikely(queue >= local->hw.queues)) | ||
96 | queue = local->hw.queues - 1; | ||
97 | |||
98 | /* | ||
99 | * Now we know the 1d priority, fill in the QoS header if | ||
100 | * there is one (and we haven't done this before). | ||
101 | */ | ||
102 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 146 | if (ieee80211_is_data_qos(hdr->frame_control)) { |
103 | u8 *p = ieee80211_get_qos_ctl(hdr); | 147 | u8 *p = ieee80211_get_qos_ctl(hdr); |
104 | u8 ack_policy = 0; | 148 | u8 ack_policy = 0, tid; |
149 | |||
105 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 150 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
151 | |||
106 | if (unlikely(local->wifi_wme_noack_test)) | 152 | if (unlikely(local->wifi_wme_noack_test)) |
107 | ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << | 153 | ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << |
108 | QOS_CONTROL_ACK_POLICY_SHIFT; | 154 | QOS_CONTROL_ACK_POLICY_SHIFT; |
@@ -110,6 +156,4 @@ void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) | |||
110 | *p++ = ack_policy | tid; | 156 | *p++ = ack_policy | tid; |
111 | *p = 0; | 157 | *p = 0; |
112 | } | 158 | } |
113 | |||
114 | skb_set_queue_mapping(skb, queue); | ||
115 | } | 159 | } |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index d4fd87ca5118..6053b1c9feee 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -20,7 +20,11 @@ | |||
20 | 20 | ||
21 | extern const int ieee802_1d_to_ac[8]; | 21 | extern const int ieee802_1d_to_ac[8]; |
22 | 22 | ||
23 | void ieee80211_select_queue(struct ieee80211_local *local, | 23 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
24 | struct sk_buff *skb); | 24 | struct sk_buff *skb); |
25 | void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb); | ||
26 | u16 ieee80211_downgrade_queue(struct ieee80211_local *local, | ||
27 | struct sk_buff *skb); | ||
28 | |||
25 | 29 | ||
26 | #endif /* _WME_H */ | 30 | #endif /* _WME_H */ |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index ea89ed70734d..81bd5d592bb4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -202,7 +202,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
202 | struct ieee80211_local *local = sdata->local; | 202 | struct ieee80211_local *local = sdata->local; |
203 | struct sk_buff *skb; | 203 | struct sk_buff *skb; |
204 | struct ieee80211_mgmt *mgmt; | 204 | struct ieee80211_mgmt *mgmt; |
205 | u8 *pos; | 205 | u8 *pos, qos_info; |
206 | const u8 *ies; | 206 | const u8 *ies; |
207 | size_t offset = 0, noffset; | 207 | size_t offset = 0, noffset; |
208 | int i, len, count, rates_len, supp_rates_len; | 208 | int i, len, count, rates_len, supp_rates_len; |
@@ -375,6 +375,14 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
375 | } | 375 | } |
376 | 376 | ||
377 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { | 377 | if (wk->assoc.wmm_used && local->hw.queues >= 4) { |
378 | if (wk->assoc.uapsd_used) { | ||
379 | qos_info = local->uapsd_queues; | ||
380 | qos_info |= (local->uapsd_max_sp_len << | ||
381 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
382 | } else { | ||
383 | qos_info = 0; | ||
384 | } | ||
385 | |||
378 | pos = skb_put(skb, 9); | 386 | pos = skb_put(skb, 9); |
379 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 387 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
380 | *pos++ = 7; /* len */ | 388 | *pos++ = 7; /* len */ |
@@ -384,7 +392,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
384 | *pos++ = 2; /* WME */ | 392 | *pos++ = 2; /* WME */ |
385 | *pos++ = 0; /* WME info */ | 393 | *pos++ = 0; /* WME info */ |
386 | *pos++ = 1; /* WME ver */ | 394 | *pos++ = 1; /* WME ver */ |
387 | *pos++ = 0; | 395 | *pos++ = qos_info; |
388 | } | 396 | } |
389 | 397 | ||
390 | /* add any remaining custom (i.e. vendor specific here) IEs */ | 398 | /* add any remaining custom (i.e. vendor specific here) IEs */ |
@@ -531,9 +539,9 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | |||
531 | wk->remain.started = true; | 539 | wk->remain.started = true; |
532 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); | 540 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); |
533 | 541 | ||
534 | cfg80211_ready_on_channel(wk->sdata->dev, (u64)wk, wk->chan, | 542 | cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, |
535 | wk->chan_type, wk->remain.duration, | 543 | wk->chan, wk->chan_type, |
536 | GFP_KERNEL); | 544 | wk->remain.duration, GFP_KERNEL); |
537 | 545 | ||
538 | return WORK_ACT_NONE; | 546 | return WORK_ACT_NONE; |
539 | } | 547 | } |
@@ -818,6 +826,7 @@ static void ieee80211_work_work(struct work_struct *work) | |||
818 | wk->chan == local->tmp_channel && | 826 | wk->chan == local->tmp_channel && |
819 | wk->chan_type == local->tmp_channel_type) { | 827 | wk->chan_type == local->tmp_channel_type) { |
820 | wk->started = true; | 828 | wk->started = true; |
829 | wk->timeout = jiffies; | ||
821 | } | 830 | } |
822 | 831 | ||
823 | if (!wk->started && !local->tmp_channel) { | 832 | if (!wk->started && !local->tmp_channel) { |
@@ -935,6 +944,9 @@ void ieee80211_add_work(struct ieee80211_work *wk) | |||
935 | if (WARN_ON(!wk->done)) | 944 | if (WARN_ON(!wk->done)) |
936 | return; | 945 | return; |
937 | 946 | ||
947 | if (WARN_ON(!ieee80211_sdata_running(wk->sdata))) | ||
948 | return; | ||
949 | |||
938 | wk->started = false; | 950 | wk->started = false; |
939 | 951 | ||
940 | local = wk->sdata->local; | 952 | local = wk->sdata->local; |
@@ -1027,7 +1039,7 @@ static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, | |||
1027 | /* | 1039 | /* |
1028 | * We are done serving the remain-on-channel command. | 1040 | * We are done serving the remain-on-channel command. |
1029 | */ | 1041 | */ |
1030 | cfg80211_remain_on_channel_expired(wk->sdata->dev, (u64)wk, | 1042 | cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk, |
1031 | wk->chan, wk->chan_type, | 1043 | wk->chan, wk->chan_type, |
1032 | GFP_KERNEL); | 1044 | GFP_KERNEL); |
1033 | 1045 | ||
@@ -1053,7 +1065,7 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1053 | 1065 | ||
1054 | wk->remain.duration = duration; | 1066 | wk->remain.duration = duration; |
1055 | 1067 | ||
1056 | *cookie = (u64)wk; | 1068 | *cookie = (unsigned long) wk; |
1057 | 1069 | ||
1058 | ieee80211_add_work(wk); | 1070 | ieee80211_add_work(wk); |
1059 | 1071 | ||
@@ -1069,7 +1081,7 @@ int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata, | |||
1069 | 1081 | ||
1070 | mutex_lock(&local->work_mtx); | 1082 | mutex_lock(&local->work_mtx); |
1071 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 1083 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
1072 | if ((u64)wk == cookie) { | 1084 | if ((unsigned long) wk == cookie) { |
1073 | wk->timeout = jiffies; | 1085 | wk->timeout = jiffies; |
1074 | found = true; | 1086 | found = true; |
1075 | break; | 1087 | break; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index c2a2c563d21a..0a545bb6ed05 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
402 | rdev->wiphy.retry_long = 4; | 402 | rdev->wiphy.retry_long = 4; |
403 | rdev->wiphy.frag_threshold = (u32) -1; | 403 | rdev->wiphy.frag_threshold = (u32) -1; |
404 | rdev->wiphy.rts_threshold = (u32) -1; | 404 | rdev->wiphy.rts_threshold = (u32) -1; |
405 | rdev->wiphy.coverage_class = 0; | ||
405 | 406 | ||
406 | return &rdev->wiphy; | 407 | return &rdev->wiphy; |
407 | } | 408 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 30ec95f05b52..2d6a6b9c0c43 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -111,7 +111,8 @@ struct cfg80211_internal_bss { | |||
111 | unsigned long ts; | 111 | unsigned long ts; |
112 | struct kref ref; | 112 | struct kref ref; |
113 | atomic_t hold; | 113 | atomic_t hold; |
114 | bool ies_allocated; | 114 | bool beacon_ies_allocated; |
115 | bool proberesp_ies_allocated; | ||
115 | 116 | ||
116 | /* must be last because of priv member */ | 117 | /* must be last because of priv member */ |
117 | struct cfg80211_bss pub; | 118 | struct cfg80211_bss pub; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3bee3cecdfa..4af7991a9ec8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | 69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, |
70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, |
71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, | 71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, |
72 | [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, | ||
72 | 73 | ||
73 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 74 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
74 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 75 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -143,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
143 | .len = WLAN_PMKID_LEN }, | 144 | .len = WLAN_PMKID_LEN }, |
144 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, | 145 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, |
145 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, | 146 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, |
147 | [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, | ||
146 | }; | 148 | }; |
147 | 149 | ||
148 | /* policy for the attributes */ | 150 | /* policy for the attributes */ |
@@ -444,6 +446,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
444 | dev->wiphy.frag_threshold); | 446 | dev->wiphy.frag_threshold); |
445 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | 447 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, |
446 | dev->wiphy.rts_threshold); | 448 | dev->wiphy.rts_threshold); |
449 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
450 | dev->wiphy.coverage_class); | ||
447 | 451 | ||
448 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 452 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
449 | dev->wiphy.max_scan_ssids); | 453 | dev->wiphy.max_scan_ssids); |
@@ -572,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
572 | CMD(del_pmksa, DEL_PMKSA); | 576 | CMD(del_pmksa, DEL_PMKSA); |
573 | CMD(flush_pmksa, FLUSH_PMKSA); | 577 | CMD(flush_pmksa, FLUSH_PMKSA); |
574 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 578 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
579 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
575 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 580 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
576 | i++; | 581 | i++; |
577 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 582 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -684,6 +689,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
684 | u32 changed; | 689 | u32 changed; |
685 | u8 retry_short = 0, retry_long = 0; | 690 | u8 retry_short = 0, retry_long = 0; |
686 | u32 frag_threshold = 0, rts_threshold = 0; | 691 | u32 frag_threshold = 0, rts_threshold = 0; |
692 | u8 coverage_class = 0; | ||
687 | 693 | ||
688 | rtnl_lock(); | 694 | rtnl_lock(); |
689 | 695 | ||
@@ -806,9 +812,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
806 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | 812 | changed |= WIPHY_PARAM_RTS_THRESHOLD; |
807 | } | 813 | } |
808 | 814 | ||
815 | if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { | ||
816 | coverage_class = nla_get_u8( | ||
817 | info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); | ||
818 | changed |= WIPHY_PARAM_COVERAGE_CLASS; | ||
819 | } | ||
820 | |||
809 | if (changed) { | 821 | if (changed) { |
810 | u8 old_retry_short, old_retry_long; | 822 | u8 old_retry_short, old_retry_long; |
811 | u32 old_frag_threshold, old_rts_threshold; | 823 | u32 old_frag_threshold, old_rts_threshold; |
824 | u8 old_coverage_class; | ||
812 | 825 | ||
813 | if (!rdev->ops->set_wiphy_params) { | 826 | if (!rdev->ops->set_wiphy_params) { |
814 | result = -EOPNOTSUPP; | 827 | result = -EOPNOTSUPP; |
@@ -819,6 +832,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
819 | old_retry_long = rdev->wiphy.retry_long; | 832 | old_retry_long = rdev->wiphy.retry_long; |
820 | old_frag_threshold = rdev->wiphy.frag_threshold; | 833 | old_frag_threshold = rdev->wiphy.frag_threshold; |
821 | old_rts_threshold = rdev->wiphy.rts_threshold; | 834 | old_rts_threshold = rdev->wiphy.rts_threshold; |
835 | old_coverage_class = rdev->wiphy.coverage_class; | ||
822 | 836 | ||
823 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 837 | if (changed & WIPHY_PARAM_RETRY_SHORT) |
824 | rdev->wiphy.retry_short = retry_short; | 838 | rdev->wiphy.retry_short = retry_short; |
@@ -828,6 +842,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
828 | rdev->wiphy.frag_threshold = frag_threshold; | 842 | rdev->wiphy.frag_threshold = frag_threshold; |
829 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | 843 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
830 | rdev->wiphy.rts_threshold = rts_threshold; | 844 | rdev->wiphy.rts_threshold = rts_threshold; |
845 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) | ||
846 | rdev->wiphy.coverage_class = coverage_class; | ||
831 | 847 | ||
832 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | 848 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); |
833 | if (result) { | 849 | if (result) { |
@@ -835,6 +851,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
835 | rdev->wiphy.retry_long = old_retry_long; | 851 | rdev->wiphy.retry_long = old_retry_long; |
836 | rdev->wiphy.frag_threshold = old_frag_threshold; | 852 | rdev->wiphy.frag_threshold = old_frag_threshold; |
837 | rdev->wiphy.rts_threshold = old_rts_threshold; | 853 | rdev->wiphy.rts_threshold = old_rts_threshold; |
854 | rdev->wiphy.coverage_class = old_coverage_class; | ||
838 | } | 855 | } |
839 | } | 856 | } |
840 | 857 | ||
@@ -3146,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3146 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 3163 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, |
3147 | res->len_information_elements, | 3164 | res->len_information_elements, |
3148 | res->information_elements); | 3165 | res->information_elements); |
3166 | if (res->beacon_ies && res->len_beacon_ies && | ||
3167 | res->beacon_ies != res->information_elements) | ||
3168 | NLA_PUT(msg, NL80211_BSS_BEACON_IES, | ||
3169 | res->len_beacon_ies, res->beacon_ies); | ||
3149 | if (res->tsf) | 3170 | if (res->tsf) |
3150 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); | 3171 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); |
3151 | if (res->beacon_interval) | 3172 | if (res->beacon_interval) |
@@ -4423,6 +4444,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
4423 | return err; | 4444 | return err; |
4424 | } | 4445 | } |
4425 | 4446 | ||
4447 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | ||
4448 | u8 *rates, u8 rates_len) | ||
4449 | { | ||
4450 | u8 i; | ||
4451 | u32 mask = 0; | ||
4452 | |||
4453 | for (i = 0; i < rates_len; i++) { | ||
4454 | int rate = (rates[i] & 0x7f) * 5; | ||
4455 | int ridx; | ||
4456 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
4457 | struct ieee80211_rate *srate = | ||
4458 | &sband->bitrates[ridx]; | ||
4459 | if (rate == srate->bitrate) { | ||
4460 | mask |= 1 << ridx; | ||
4461 | break; | ||
4462 | } | ||
4463 | } | ||
4464 | if (ridx == sband->n_bitrates) | ||
4465 | return 0; /* rate not found */ | ||
4466 | } | ||
4467 | |||
4468 | return mask; | ||
4469 | } | ||
4470 | |||
4471 | static struct nla_policy | ||
4472 | nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { | ||
4473 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
4474 | .len = NL80211_MAX_SUPP_RATES }, | ||
4475 | }; | ||
4476 | |||
4477 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | ||
4478 | struct genl_info *info) | ||
4479 | { | ||
4480 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | ||
4481 | struct cfg80211_registered_device *rdev; | ||
4482 | struct cfg80211_bitrate_mask mask; | ||
4483 | int err, rem, i; | ||
4484 | struct net_device *dev; | ||
4485 | struct nlattr *tx_rates; | ||
4486 | struct ieee80211_supported_band *sband; | ||
4487 | |||
4488 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | ||
4489 | return -EINVAL; | ||
4490 | |||
4491 | rtnl_lock(); | ||
4492 | |||
4493 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4494 | if (err) | ||
4495 | goto unlock_rtnl; | ||
4496 | |||
4497 | if (!rdev->ops->set_bitrate_mask) { | ||
4498 | err = -EOPNOTSUPP; | ||
4499 | goto unlock; | ||
4500 | } | ||
4501 | |||
4502 | memset(&mask, 0, sizeof(mask)); | ||
4503 | /* Default to all rates enabled */ | ||
4504 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
4505 | sband = rdev->wiphy.bands[i]; | ||
4506 | mask.control[i].legacy = | ||
4507 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
4508 | } | ||
4509 | |||
4510 | /* | ||
4511 | * The nested attribute uses enum nl80211_band as the index. This maps | ||
4512 | * directly to the enum ieee80211_band values used in cfg80211. | ||
4513 | */ | ||
4514 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | ||
4515 | { | ||
4516 | enum ieee80211_band band = nla_type(tx_rates); | ||
4517 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | ||
4518 | err = -EINVAL; | ||
4519 | goto unlock; | ||
4520 | } | ||
4521 | sband = rdev->wiphy.bands[band]; | ||
4522 | if (sband == NULL) { | ||
4523 | err = -EINVAL; | ||
4524 | goto unlock; | ||
4525 | } | ||
4526 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | ||
4527 | nla_len(tx_rates), nl80211_txattr_policy); | ||
4528 | if (tb[NL80211_TXRATE_LEGACY]) { | ||
4529 | mask.control[band].legacy = rateset_to_mask( | ||
4530 | sband, | ||
4531 | nla_data(tb[NL80211_TXRATE_LEGACY]), | ||
4532 | nla_len(tb[NL80211_TXRATE_LEGACY])); | ||
4533 | if (mask.control[band].legacy == 0) { | ||
4534 | err = -EINVAL; | ||
4535 | goto unlock; | ||
4536 | } | ||
4537 | } | ||
4538 | } | ||
4539 | |||
4540 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | ||
4541 | |||
4542 | unlock: | ||
4543 | dev_put(dev); | ||
4544 | cfg80211_unlock_rdev(rdev); | ||
4545 | unlock_rtnl: | ||
4546 | rtnl_unlock(); | ||
4547 | return err; | ||
4548 | } | ||
4549 | |||
4426 | static struct genl_ops nl80211_ops[] = { | 4550 | static struct genl_ops nl80211_ops[] = { |
4427 | { | 4551 | { |
4428 | .cmd = NL80211_CMD_GET_WIPHY, | 4552 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4697,6 +4821,12 @@ static struct genl_ops nl80211_ops[] = { | |||
4697 | .policy = nl80211_policy, | 4821 | .policy = nl80211_policy, |
4698 | .flags = GENL_ADMIN_PERM, | 4822 | .flags = GENL_ADMIN_PERM, |
4699 | }, | 4823 | }, |
4824 | { | ||
4825 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | ||
4826 | .doit = nl80211_set_tx_bitrate_mask, | ||
4827 | .policy = nl80211_policy, | ||
4828 | .flags = GENL_ADMIN_PERM, | ||
4829 | }, | ||
4700 | }; | 4830 | }; |
4701 | 4831 | ||
4702 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4832 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 87ea60d84c3c..5f8071de7950 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -43,6 +43,15 @@ | |||
43 | #include "regdb.h" | 43 | #include "regdb.h" |
44 | #include "nl80211.h" | 44 | #include "nl80211.h" |
45 | 45 | ||
46 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
47 | #define REG_DBG_PRINT(format, args...) \ | ||
48 | do { \ | ||
49 | printk(KERN_DEBUG format , ## args); \ | ||
50 | } while (0) | ||
51 | #else | ||
52 | #define REG_DBG_PRINT(args...) | ||
53 | #endif | ||
54 | |||
46 | /* Receipt of information from last regulatory request */ | 55 | /* Receipt of information from last regulatory request */ |
47 | static struct regulatory_request *last_request; | 56 | static struct regulatory_request *last_request; |
48 | 57 | ||
@@ -476,12 +485,212 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
476 | } | 485 | } |
477 | 486 | ||
478 | /* | 487 | /* |
488 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
489 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
490 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
491 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
492 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
493 | * channel. | ||
494 | * | ||
495 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
496 | */ | ||
497 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
498 | { | ||
499 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
500 | |||
501 | switch (band) { | ||
502 | case IEEE80211_BAND_2GHZ: | ||
503 | if (center_freq <= 2484) | ||
504 | return true; | ||
505 | return false; | ||
506 | case IEEE80211_BAND_5GHZ: | ||
507 | if (center_freq >= 5005) | ||
508 | return true; | ||
509 | return false; | ||
510 | default: | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Some APs may send a country IE triplet for each channel they | ||
517 | * support and while this is completely overkill and silly we still | ||
518 | * need to support it. We avoid making a single rule for each channel | ||
519 | * though and to help us with this we use this helper to find the | ||
520 | * actual subband end channel. These type of country IE triplet | ||
521 | * scenerios are handled then, all yielding two regulaotry rules from | ||
522 | * parsing a country IE: | ||
523 | * | ||
524 | * [1] | ||
525 | * [2] | ||
526 | * [36] | ||
527 | * [40] | ||
528 | * | ||
529 | * [1] | ||
530 | * [2-4] | ||
531 | * [5-12] | ||
532 | * [36] | ||
533 | * [40-44] | ||
534 | * | ||
535 | * [1-4] | ||
536 | * [5-7] | ||
537 | * [36-44] | ||
538 | * [48-64] | ||
539 | * | ||
540 | * [36-36] | ||
541 | * [40-40] | ||
542 | * [44-44] | ||
543 | * [48-48] | ||
544 | * [52-52] | ||
545 | * [56-56] | ||
546 | * [60-60] | ||
547 | * [64-64] | ||
548 | * [100-100] | ||
549 | * [104-104] | ||
550 | * [108-108] | ||
551 | * [112-112] | ||
552 | * [116-116] | ||
553 | * [120-120] | ||
554 | * [124-124] | ||
555 | * [128-128] | ||
556 | * [132-132] | ||
557 | * [136-136] | ||
558 | * [140-140] | ||
559 | * | ||
560 | * Returns 0 if the IE has been found to be invalid in the middle | ||
561 | * somewhere. | ||
562 | */ | ||
563 | static int max_subband_chan(enum ieee80211_band band, | ||
564 | int orig_cur_chan, | ||
565 | int orig_end_channel, | ||
566 | s8 orig_max_power, | ||
567 | u8 **country_ie, | ||
568 | u8 *country_ie_len) | ||
569 | { | ||
570 | u8 *triplets_start = *country_ie; | ||
571 | u8 len_at_triplet = *country_ie_len; | ||
572 | int end_subband_chan = orig_end_channel; | ||
573 | |||
574 | /* | ||
575 | * We'll deal with padding for the caller unless | ||
576 | * its not immediate and we don't process any channels | ||
577 | */ | ||
578 | if (*country_ie_len == 1) { | ||
579 | *country_ie += 1; | ||
580 | *country_ie_len -= 1; | ||
581 | return orig_end_channel; | ||
582 | } | ||
583 | |||
584 | /* Move to the next triplet and then start search */ | ||
585 | *country_ie += 3; | ||
586 | *country_ie_len -= 3; | ||
587 | |||
588 | if (!chan_in_band(orig_cur_chan, band)) | ||
589 | return 0; | ||
590 | |||
591 | while (*country_ie_len >= 3) { | ||
592 | int end_channel = 0; | ||
593 | struct ieee80211_country_ie_triplet *triplet = | ||
594 | (struct ieee80211_country_ie_triplet *) *country_ie; | ||
595 | int cur_channel = 0, next_expected_chan; | ||
596 | |||
597 | /* means last triplet is completely unrelated to this one */ | ||
598 | if (triplet->ext.reg_extension_id >= | ||
599 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
600 | *country_ie -= 3; | ||
601 | *country_ie_len += 3; | ||
602 | break; | ||
603 | } | ||
604 | |||
605 | if (triplet->chans.first_channel == 0) { | ||
606 | *country_ie += 1; | ||
607 | *country_ie_len -= 1; | ||
608 | if (*country_ie_len != 0) | ||
609 | return 0; | ||
610 | break; | ||
611 | } | ||
612 | |||
613 | if (triplet->chans.num_channels == 0) | ||
614 | return 0; | ||
615 | |||
616 | /* Monitonically increasing channel order */ | ||
617 | if (triplet->chans.first_channel <= end_subband_chan) | ||
618 | return 0; | ||
619 | |||
620 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
621 | return 0; | ||
622 | |||
623 | /* 2 GHz */ | ||
624 | if (triplet->chans.first_channel <= 14) { | ||
625 | end_channel = triplet->chans.first_channel + | ||
626 | triplet->chans.num_channels - 1; | ||
627 | } | ||
628 | else { | ||
629 | end_channel = triplet->chans.first_channel + | ||
630 | (4 * (triplet->chans.num_channels - 1)); | ||
631 | } | ||
632 | |||
633 | if (!chan_in_band(end_channel, band)) | ||
634 | return 0; | ||
635 | |||
636 | if (orig_max_power != triplet->chans.max_power) { | ||
637 | *country_ie -= 3; | ||
638 | *country_ie_len += 3; | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | cur_channel = triplet->chans.first_channel; | ||
643 | |||
644 | /* The key is finding the right next expected channel */ | ||
645 | if (band == IEEE80211_BAND_2GHZ) | ||
646 | next_expected_chan = end_subband_chan + 1; | ||
647 | else | ||
648 | next_expected_chan = end_subband_chan + 4; | ||
649 | |||
650 | if (cur_channel != next_expected_chan) { | ||
651 | *country_ie -= 3; | ||
652 | *country_ie_len += 3; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | end_subband_chan = end_channel; | ||
657 | |||
658 | /* Move to the next one */ | ||
659 | *country_ie += 3; | ||
660 | *country_ie_len -= 3; | ||
661 | |||
662 | /* | ||
663 | * Padding needs to be dealt with if we processed | ||
664 | * some channels. | ||
665 | */ | ||
666 | if (*country_ie_len == 1) { | ||
667 | *country_ie += 1; | ||
668 | *country_ie_len -= 1; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | /* If seen, the IE is invalid */ | ||
673 | if (*country_ie_len == 2) | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | if (end_subband_chan == orig_end_channel) { | ||
678 | *country_ie = triplets_start; | ||
679 | *country_ie_len = len_at_triplet; | ||
680 | return orig_end_channel; | ||
681 | } | ||
682 | |||
683 | return end_subband_chan; | ||
684 | } | ||
685 | |||
686 | /* | ||
479 | * Converts a country IE to a regulatory domain. A regulatory domain | 687 | * Converts a country IE to a regulatory domain. A regulatory domain |
480 | * structure has a lot of information which the IE doesn't yet have, | 688 | * structure has a lot of information which the IE doesn't yet have, |
481 | * so for the other values we use upper max values as we will intersect | 689 | * so for the other values we use upper max values as we will intersect |
482 | * with our userspace regulatory agent to get lower bounds. | 690 | * with our userspace regulatory agent to get lower bounds. |
483 | */ | 691 | */ |
484 | static struct ieee80211_regdomain *country_ie_2_rd( | 692 | static struct ieee80211_regdomain *country_ie_2_rd( |
693 | enum ieee80211_band band, | ||
485 | u8 *country_ie, | 694 | u8 *country_ie, |
486 | u8 country_ie_len, | 695 | u8 country_ie_len, |
487 | u32 *checksum) | 696 | u32 *checksum) |
@@ -543,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
543 | continue; | 752 | continue; |
544 | } | 753 | } |
545 | 754 | ||
755 | /* | ||
756 | * APs can add padding to make length divisible | ||
757 | * by two, required by the spec. | ||
758 | */ | ||
759 | if (triplet->chans.first_channel == 0) { | ||
760 | country_ie++; | ||
761 | country_ie_len--; | ||
762 | /* This is expected to be at the very end only */ | ||
763 | if (country_ie_len != 0) | ||
764 | return NULL; | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | if (triplet->chans.num_channels == 0) | ||
769 | return NULL; | ||
770 | |||
771 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
772 | return NULL; | ||
773 | |||
546 | /* 2 GHz */ | 774 | /* 2 GHz */ |
547 | if (triplet->chans.first_channel <= 14) | 775 | if (band == IEEE80211_BAND_2GHZ) |
548 | end_channel = triplet->chans.first_channel + | 776 | end_channel = triplet->chans.first_channel + |
549 | triplet->chans.num_channels; | 777 | triplet->chans.num_channels - 1; |
550 | else | 778 | else |
551 | /* | 779 | /* |
552 | * 5 GHz -- For example in country IEs if the first | 780 | * 5 GHz -- For example in country IEs if the first |
@@ -561,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
561 | (4 * (triplet->chans.num_channels - 1)); | 789 | (4 * (triplet->chans.num_channels - 1)); |
562 | 790 | ||
563 | cur_channel = triplet->chans.first_channel; | 791 | cur_channel = triplet->chans.first_channel; |
792 | |||
793 | /* | ||
794 | * Enhancement for APs that send a triplet for every channel | ||
795 | * or for whatever reason sends triplets with multiple channels | ||
796 | * separated when in fact they should be together. | ||
797 | */ | ||
798 | end_channel = max_subband_chan(band, | ||
799 | cur_channel, | ||
800 | end_channel, | ||
801 | triplet->chans.max_power, | ||
802 | &country_ie, | ||
803 | &country_ie_len); | ||
804 | if (!end_channel) | ||
805 | return NULL; | ||
806 | |||
807 | if (!chan_in_band(end_channel, band)) | ||
808 | return NULL; | ||
809 | |||
564 | cur_sub_max_channel = end_channel; | 810 | cur_sub_max_channel = end_channel; |
565 | 811 | ||
566 | /* Basic sanity check */ | 812 | /* Basic sanity check */ |
@@ -591,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
591 | 837 | ||
592 | last_sub_max_channel = cur_sub_max_channel; | 838 | last_sub_max_channel = cur_sub_max_channel; |
593 | 839 | ||
594 | country_ie += 3; | ||
595 | country_ie_len -= 3; | ||
596 | num_rules++; | 840 | num_rules++; |
597 | 841 | ||
842 | if (country_ie_len >= 3) { | ||
843 | country_ie += 3; | ||
844 | country_ie_len -= 3; | ||
845 | } | ||
846 | |||
598 | /* | 847 | /* |
599 | * Note: this is not a IEEE requirement but | 848 | * Note: this is not a IEEE requirement but |
600 | * simply a memory requirement | 849 | * simply a memory requirement |
@@ -637,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
637 | continue; | 886 | continue; |
638 | } | 887 | } |
639 | 888 | ||
889 | if (triplet->chans.first_channel == 0) { | ||
890 | country_ie++; | ||
891 | country_ie_len--; | ||
892 | break; | ||
893 | } | ||
894 | |||
640 | reg_rule = &rd->reg_rules[i]; | 895 | reg_rule = &rd->reg_rules[i]; |
641 | freq_range = ®_rule->freq_range; | 896 | freq_range = ®_rule->freq_range; |
642 | power_rule = ®_rule->power_rule; | 897 | power_rule = ®_rule->power_rule; |
@@ -644,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
644 | reg_rule->flags = flags; | 899 | reg_rule->flags = flags; |
645 | 900 | ||
646 | /* 2 GHz */ | 901 | /* 2 GHz */ |
647 | if (triplet->chans.first_channel <= 14) | 902 | if (band == IEEE80211_BAND_2GHZ) |
648 | end_channel = triplet->chans.first_channel + | 903 | end_channel = triplet->chans.first_channel + |
649 | triplet->chans.num_channels; | 904 | triplet->chans.num_channels -1; |
650 | else | 905 | else |
651 | end_channel = triplet->chans.first_channel + | 906 | end_channel = triplet->chans.first_channel + |
652 | (4 * (triplet->chans.num_channels - 1)); | 907 | (4 * (triplet->chans.num_channels - 1)); |
653 | 908 | ||
909 | end_channel = max_subband_chan(band, | ||
910 | triplet->chans.first_channel, | ||
911 | end_channel, | ||
912 | triplet->chans.max_power, | ||
913 | &country_ie, | ||
914 | &country_ie_len); | ||
915 | |||
654 | /* | 916 | /* |
655 | * The +10 is since the regulatory domain expects | 917 | * The +10 is since the regulatory domain expects |
656 | * the actual band edge, not the center of freq for | 918 | * the actual band edge, not the center of freq for |
@@ -671,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
671 | */ | 933 | */ |
672 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | 934 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); |
673 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | 935 | power_rule->max_antenna_gain = DBI_TO_MBI(100); |
674 | power_rule->max_eirp = DBM_TO_MBM(100); | 936 | power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); |
675 | 937 | ||
676 | country_ie += 3; | ||
677 | country_ie_len -= 3; | ||
678 | i++; | 938 | i++; |
679 | 939 | ||
940 | if (country_ie_len >= 3) { | ||
941 | country_ie += 3; | ||
942 | country_ie_len -= 3; | ||
943 | } | ||
944 | |||
680 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); | 945 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); |
681 | } | 946 | } |
682 | 947 | ||
@@ -972,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
972 | if (r == -ERANGE && | 1237 | if (r == -ERANGE && |
973 | last_request->initiator == | 1238 | last_request->initiator == |
974 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1239 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { |
975 | #ifdef CONFIG_CFG80211_REG_DEBUG | 1240 | REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " |
976 | printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz " | ||
977 | "intact on %s - no rule found in band on " | 1241 | "intact on %s - no rule found in band on " |
978 | "Country IE\n", | 1242 | "Country IE\n", |
979 | chan->center_freq, wiphy_name(wiphy)); | 1243 | chan->center_freq, wiphy_name(wiphy)); |
980 | #endif | ||
981 | } else { | 1244 | } else { |
982 | /* | 1245 | /* |
983 | * In this case we know the country IE has at least one reg rule | 1246 | * In this case we know the country IE has at least one reg rule |
984 | * for the band so we respect its band definitions | 1247 | * for the band so we respect its band definitions |
985 | */ | 1248 | */ |
986 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
987 | if (last_request->initiator == | 1249 | if (last_request->initiator == |
988 | NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1250 | NL80211_REGDOM_SET_BY_COUNTRY_IE) |
989 | printk(KERN_DEBUG "cfg80211: Disabling " | 1251 | REG_DBG_PRINT("cfg80211: Disabling " |
990 | "channel %d MHz on %s due to " | 1252 | "channel %d MHz on %s due to " |
991 | "Country IE\n", | 1253 | "Country IE\n", |
992 | chan->center_freq, wiphy_name(wiphy)); | 1254 | chan->center_freq, wiphy_name(wiphy)); |
993 | #endif | ||
994 | flags |= IEEE80211_CHAN_DISABLED; | 1255 | flags |= IEEE80211_CHAN_DISABLED; |
995 | chan->flags = flags; | 1256 | chan->flags = flags; |
996 | } | 1257 | } |
@@ -1685,7 +1946,7 @@ int regulatory_hint_user(const char *alpha2) | |||
1685 | request->wiphy_idx = WIPHY_IDX_STALE; | 1946 | request->wiphy_idx = WIPHY_IDX_STALE; |
1686 | request->alpha2[0] = alpha2[0]; | 1947 | request->alpha2[0] = alpha2[0]; |
1687 | request->alpha2[1] = alpha2[1]; | 1948 | request->alpha2[1] = alpha2[1]; |
1688 | request->initiator = NL80211_REGDOM_SET_BY_USER, | 1949 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
1689 | 1950 | ||
1690 | queue_regulatory_request(request); | 1951 | queue_regulatory_request(request); |
1691 | 1952 | ||
@@ -1753,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1753 | * therefore cannot iterate over the rdev list here. | 2014 | * therefore cannot iterate over the rdev list here. |
1754 | */ | 2015 | */ |
1755 | void regulatory_hint_11d(struct wiphy *wiphy, | 2016 | void regulatory_hint_11d(struct wiphy *wiphy, |
1756 | u8 *country_ie, | 2017 | enum ieee80211_band band, |
1757 | u8 country_ie_len) | 2018 | u8 *country_ie, |
2019 | u8 country_ie_len) | ||
1758 | { | 2020 | { |
1759 | struct ieee80211_regdomain *rd = NULL; | 2021 | struct ieee80211_regdomain *rd = NULL; |
1760 | char alpha2[2]; | 2022 | char alpha2[2]; |
@@ -1800,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1800 | wiphy_idx_valid(last_request->wiphy_idx))) | 2062 | wiphy_idx_valid(last_request->wiphy_idx))) |
1801 | goto out; | 2063 | goto out; |
1802 | 2064 | ||
1803 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 2065 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); |
1804 | if (!rd) | 2066 | if (!rd) { |
2067 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | ||
1805 | goto out; | 2068 | goto out; |
2069 | } | ||
1806 | 2070 | ||
1807 | /* | 2071 | /* |
1808 | * This will not happen right now but we leave it here for the | 2072 | * This will not happen right now but we leave it here for the |
@@ -1870,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
1870 | if (!reg_beacon) | 2134 | if (!reg_beacon) |
1871 | return -ENOMEM; | 2135 | return -ENOMEM; |
1872 | 2136 | ||
1873 | #ifdef CONFIG_CFG80211_REG_DEBUG | 2137 | REG_DBG_PRINT("cfg80211: Found new beacon on " |
1874 | printk(KERN_DEBUG "cfg80211: Found new beacon on " | 2138 | "frequency: %d MHz (Ch %d) on %s\n", |
1875 | "frequency: %d MHz (Ch %d) on %s\n", | 2139 | beacon_chan->center_freq, |
1876 | beacon_chan->center_freq, | 2140 | ieee80211_frequency_to_channel(beacon_chan->center_freq), |
1877 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | 2141 | wiphy_name(wiphy)); |
1878 | wiphy_name(wiphy)); | 2142 | |
1879 | #endif | ||
1880 | memcpy(®_beacon->chan, beacon_chan, | 2143 | memcpy(®_beacon->chan, beacon_chan, |
1881 | sizeof(struct ieee80211_channel)); | 2144 | sizeof(struct ieee80211_channel)); |
1882 | 2145 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3362c7c069b2..3018508226ab 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
41 | * regulatory_hint_11d - hints a country IE as a regulatory domain | 41 | * regulatory_hint_11d - hints a country IE as a regulatory domain |
42 | * @wiphy: the wireless device giving the hint (used only for reporting | 42 | * @wiphy: the wireless device giving the hint (used only for reporting |
43 | * conflicts) | 43 | * conflicts) |
44 | * @band: the band on which the country IE was received on. This determines | ||
45 | * the band we'll process the country IE channel triplets for. | ||
44 | * @country_ie: pointer to the country IE | 46 | * @country_ie: pointer to the country IE |
45 | * @country_ie_len: length of the country IE | 47 | * @country_ie_len: length of the country IE |
46 | * | 48 | * |
47 | * We will intersect the rd with the what CRDA tells us should apply | 49 | * We will intersect the rd with the what CRDA tells us should apply |
48 | * for the alpha2 this country IE belongs to, this prevents APs from | 50 | * for the alpha2 this country IE belongs to, this prevents APs from |
49 | * sending us incorrect or outdated information against a country. | 51 | * sending us incorrect or outdated information against a country. |
52 | * | ||
53 | * The AP is expected to provide Country IE channel triplets for the | ||
54 | * band it is on. It is technically possible for APs to send channel | ||
55 | * country IE triplets even for channels outside of the band they are | ||
56 | * in but for that they would have to use the regulatory extension | ||
57 | * in combination with a triplet but this behaviour is currently | ||
58 | * not observed. For this reason if a triplet is seen with channel | ||
59 | * information for a band the BSS is not present in it will be ignored. | ||
50 | */ | 60 | */ |
51 | void regulatory_hint_11d(struct wiphy *wiphy, | 61 | void regulatory_hint_11d(struct wiphy *wiphy, |
62 | enum ieee80211_band band, | ||
52 | u8 *country_ie, | 63 | u8 *country_ie, |
53 | u8 country_ie_len); | 64 | u8 country_ie_len); |
54 | 65 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0c2cbbebca95..06b0231ee5e3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -100,8 +100,10 @@ static void bss_release(struct kref *ref) | |||
100 | if (bss->pub.free_priv) | 100 | if (bss->pub.free_priv) |
101 | bss->pub.free_priv(&bss->pub); | 101 | bss->pub.free_priv(&bss->pub); |
102 | 102 | ||
103 | if (bss->ies_allocated) | 103 | if (bss->beacon_ies_allocated) |
104 | kfree(bss->pub.information_elements); | 104 | kfree(bss->pub.beacon_ies); |
105 | if (bss->proberesp_ies_allocated) | ||
106 | kfree(bss->pub.proberesp_ies); | ||
105 | 107 | ||
106 | BUG_ON(atomic_read(&bss->hold)); | 108 | BUG_ON(atomic_read(&bss->hold)); |
107 | 109 | ||
@@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, | |||
375 | 377 | ||
376 | static struct cfg80211_internal_bss * | 378 | static struct cfg80211_internal_bss * |
377 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | 379 | cfg80211_bss_update(struct cfg80211_registered_device *dev, |
378 | struct cfg80211_internal_bss *res, | 380 | struct cfg80211_internal_bss *res) |
379 | bool overwrite) | ||
380 | { | 381 | { |
381 | struct cfg80211_internal_bss *found = NULL; | 382 | struct cfg80211_internal_bss *found = NULL; |
382 | const u8 *meshid, *meshcfg; | 383 | const u8 *meshid, *meshcfg; |
@@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
418 | found->pub.capability = res->pub.capability; | 419 | found->pub.capability = res->pub.capability; |
419 | found->ts = res->ts; | 420 | found->ts = res->ts; |
420 | 421 | ||
421 | /* overwrite IEs */ | 422 | /* Update IEs */ |
422 | if (overwrite) { | 423 | if (res->pub.proberesp_ies) { |
423 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | 424 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); |
424 | size_t ielen = res->pub.len_information_elements; | 425 | size_t ielen = res->pub.len_proberesp_ies; |
426 | |||
427 | if (found->pub.proberesp_ies && | ||
428 | !found->proberesp_ies_allocated && | ||
429 | ksize(found) >= used + ielen) { | ||
430 | memcpy(found->pub.proberesp_ies, | ||
431 | res->pub.proberesp_ies, ielen); | ||
432 | found->pub.len_proberesp_ies = ielen; | ||
433 | } else { | ||
434 | u8 *ies = found->pub.proberesp_ies; | ||
435 | |||
436 | if (found->proberesp_ies_allocated) | ||
437 | ies = krealloc(ies, ielen, GFP_ATOMIC); | ||
438 | else | ||
439 | ies = kmalloc(ielen, GFP_ATOMIC); | ||
440 | |||
441 | if (ies) { | ||
442 | memcpy(ies, res->pub.proberesp_ies, | ||
443 | ielen); | ||
444 | found->proberesp_ies_allocated = true; | ||
445 | found->pub.proberesp_ies = ies; | ||
446 | found->pub.len_proberesp_ies = ielen; | ||
447 | } | ||
448 | } | ||
425 | 449 | ||
426 | if (!found->ies_allocated && ksize(found) >= used + ielen) { | 450 | /* Override possible earlier Beacon frame IEs */ |
427 | memcpy(found->pub.information_elements, | 451 | found->pub.information_elements = |
428 | res->pub.information_elements, ielen); | 452 | found->pub.proberesp_ies; |
429 | found->pub.len_information_elements = ielen; | 453 | found->pub.len_information_elements = |
454 | found->pub.len_proberesp_ies; | ||
455 | } | ||
456 | if (res->pub.beacon_ies) { | ||
457 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | ||
458 | size_t ielen = res->pub.len_beacon_ies; | ||
459 | |||
460 | if (found->pub.beacon_ies && | ||
461 | !found->beacon_ies_allocated && | ||
462 | ksize(found) >= used + ielen) { | ||
463 | memcpy(found->pub.beacon_ies, | ||
464 | res->pub.beacon_ies, ielen); | ||
465 | found->pub.len_beacon_ies = ielen; | ||
430 | } else { | 466 | } else { |
431 | u8 *ies = found->pub.information_elements; | 467 | u8 *ies = found->pub.beacon_ies; |
432 | 468 | ||
433 | if (found->ies_allocated) | 469 | if (found->beacon_ies_allocated) |
434 | ies = krealloc(ies, ielen, GFP_ATOMIC); | 470 | ies = krealloc(ies, ielen, GFP_ATOMIC); |
435 | else | 471 | else |
436 | ies = kmalloc(ielen, GFP_ATOMIC); | 472 | ies = kmalloc(ielen, GFP_ATOMIC); |
437 | 473 | ||
438 | if (ies) { | 474 | if (ies) { |
439 | memcpy(ies, res->pub.information_elements, ielen); | 475 | memcpy(ies, res->pub.beacon_ies, |
440 | found->ies_allocated = true; | 476 | ielen); |
441 | found->pub.information_elements = ies; | 477 | found->beacon_ies_allocated = true; |
442 | found->pub.len_information_elements = ielen; | 478 | found->pub.beacon_ies = ies; |
479 | found->pub.len_beacon_ies = ielen; | ||
443 | } | 480 | } |
444 | } | 481 | } |
445 | } | 482 | } |
@@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
489 | res->pub.tsf = timestamp; | 526 | res->pub.tsf = timestamp; |
490 | res->pub.beacon_interval = beacon_interval; | 527 | res->pub.beacon_interval = beacon_interval; |
491 | res->pub.capability = capability; | 528 | res->pub.capability = capability; |
492 | /* point to after the private area */ | 529 | /* |
493 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 530 | * Since we do not know here whether the IEs are from a Beacon or Probe |
494 | memcpy(res->pub.information_elements, ie, ielen); | 531 | * Response frame, we need to pick one of the options and only use it |
495 | res->pub.len_information_elements = ielen; | 532 | * with the driver that does not provide the full Beacon/Probe Response |
533 | * frame. Use Beacon frame pointer to avoid indicating that this should | ||
534 | * override the information_elements pointer should we have received an | ||
535 | * earlier indication of Probe Response data. | ||
536 | * | ||
537 | * The initial buffer for the IEs is allocated with the BSS entry and | ||
538 | * is located after the private area. | ||
539 | */ | ||
540 | res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; | ||
541 | memcpy(res->pub.beacon_ies, ie, ielen); | ||
542 | res->pub.len_beacon_ies = ielen; | ||
543 | res->pub.information_elements = res->pub.beacon_ies; | ||
544 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
496 | 545 | ||
497 | kref_init(&res->ref); | 546 | kref_init(&res->ref); |
498 | 547 | ||
499 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); | 548 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
500 | if (!res) | 549 | if (!res) |
501 | return NULL; | 550 | return NULL; |
502 | 551 | ||
@@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
517 | struct cfg80211_internal_bss *res; | 566 | struct cfg80211_internal_bss *res; |
518 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 567 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
519 | u.probe_resp.variable); | 568 | u.probe_resp.variable); |
520 | bool overwrite; | ||
521 | size_t privsz = wiphy->bss_priv_size; | 569 | size_t privsz = wiphy->bss_priv_size; |
522 | 570 | ||
523 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && | 571 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && |
@@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
538 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | 586 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); |
539 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 587 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
540 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | 588 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
541 | /* point to after the private area */ | 589 | /* |
542 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 590 | * The initial buffer for the IEs is allocated with the BSS entry and |
543 | memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); | 591 | * is located after the private area. |
544 | res->pub.len_information_elements = ielen; | 592 | */ |
593 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
594 | res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; | ||
595 | memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, | ||
596 | ielen); | ||
597 | res->pub.len_proberesp_ies = ielen; | ||
598 | res->pub.information_elements = res->pub.proberesp_ies; | ||
599 | res->pub.len_information_elements = res->pub.len_proberesp_ies; | ||
600 | } else { | ||
601 | res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; | ||
602 | memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); | ||
603 | res->pub.len_beacon_ies = ielen; | ||
604 | res->pub.information_elements = res->pub.beacon_ies; | ||
605 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
606 | } | ||
545 | 607 | ||
546 | kref_init(&res->ref); | 608 | kref_init(&res->ref); |
547 | 609 | ||
548 | overwrite = ieee80211_is_probe_resp(mgmt->frame_control); | 610 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
549 | |||
550 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); | ||
551 | if (!res) | 611 | if (!res) |
552 | return NULL; | 612 | return NULL; |
553 | 613 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2333d78187e4..2ce5e1609a3d 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
454 | * - and country_ie[1] which is the IE length | 454 | * - and country_ie[1] which is the IE length |
455 | */ | 455 | */ |
456 | regulatory_hint_11d(wdev->wiphy, | 456 | regulatory_hint_11d(wdev->wiphy, |
457 | bss->channel->band, | ||
457 | country_ie + 2, | 458 | country_ie + 2, |
458 | country_ie[1]); | 459 | country_ie[1]); |
459 | } | 460 | } |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4198243a3dff..966d2f01beac 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev, | |||
1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1206 | struct cfg80211_bitrate_mask mask; | 1206 | struct cfg80211_bitrate_mask mask; |
1207 | u32 fixed, maxrate; | ||
1208 | struct ieee80211_supported_band *sband; | ||
1209 | int band, ridx; | ||
1210 | bool match = false; | ||
1207 | 1211 | ||
1208 | if (!rdev->ops->set_bitrate_mask) | 1212 | if (!rdev->ops->set_bitrate_mask) |
1209 | return -EOPNOTSUPP; | 1213 | return -EOPNOTSUPP; |
1210 | 1214 | ||
1211 | mask.fixed = 0; | 1215 | memset(&mask, 0, sizeof(mask)); |
1212 | mask.maxrate = 0; | 1216 | fixed = 0; |
1217 | maxrate = 0; | ||
1213 | 1218 | ||
1214 | if (rate->value < 0) { | 1219 | if (rate->value < 0) { |
1215 | /* nothing */ | 1220 | /* nothing */ |
1216 | } else if (rate->fixed) { | 1221 | } else if (rate->fixed) { |
1217 | mask.fixed = rate->value / 1000; /* kbps */ | 1222 | fixed = rate->value / 100000; |
1218 | } else { | 1223 | } else { |
1219 | mask.maxrate = rate->value / 1000; /* kbps */ | 1224 | maxrate = rate->value / 100000; |
1225 | } | ||
1226 | |||
1227 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1228 | sband = wdev->wiphy->bands[band]; | ||
1229 | if (sband == NULL) | ||
1230 | continue; | ||
1231 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
1232 | struct ieee80211_rate *srate = &sband->bitrates[ridx]; | ||
1233 | if (fixed == srate->bitrate) { | ||
1234 | mask.control[band].legacy = 1 << ridx; | ||
1235 | match = true; | ||
1236 | break; | ||
1237 | } | ||
1238 | if (srate->bitrate <= maxrate) { | ||
1239 | mask.control[band].legacy |= 1 << ridx; | ||
1240 | match = true; | ||
1241 | } | ||
1242 | } | ||
1220 | } | 1243 | } |
1221 | 1244 | ||
1245 | if (!match) | ||
1246 | return -EINVAL; | ||
1247 | |||
1222 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | 1248 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1223 | } | 1249 | } |
1224 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | 1250 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |