diff options
author | David S. Miller <davem@davemloft.net> | 2010-03-29 16:50:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-29 16:50:10 -0400 |
commit | 7905e357ebe67a26d9dc8caa1a0b8346431b5f0d (patch) | |
tree | 134442df2f062caa6cebda1b352948b8209efcec /drivers | |
parent | 083ba279d52bcad20f1dfa3cefd4255cbe82d521 (diff) | |
parent | 76232ebf898c4d5e657f2b663fbf7108bca80ded (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers')
69 files changed, 8589 insertions, 1421 deletions
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 505f9a194369..a9153a3481e1 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c | |||
@@ -2279,26 +2279,25 @@ void gelic_wl_interrupt(struct net_device *netdev, u64 status) | |||
2279 | /* | 2279 | /* |
2280 | * driver helpers | 2280 | * driver helpers |
2281 | */ | 2281 | */ |
2282 | #define IW_IOCTL(n) [(n) - SIOCSIWCOMMIT] | ||
2283 | static const iw_handler gelic_wl_wext_handler[] = | 2282 | static const iw_handler gelic_wl_wext_handler[] = |
2284 | { | 2283 | { |
2285 | IW_IOCTL(SIOCGIWNAME) = gelic_wl_get_name, | 2284 | IW_HANDLER(SIOCGIWNAME, gelic_wl_get_name), |
2286 | IW_IOCTL(SIOCGIWRANGE) = gelic_wl_get_range, | 2285 | IW_HANDLER(SIOCGIWRANGE, gelic_wl_get_range), |
2287 | IW_IOCTL(SIOCSIWSCAN) = gelic_wl_set_scan, | 2286 | IW_HANDLER(SIOCSIWSCAN, gelic_wl_set_scan), |
2288 | IW_IOCTL(SIOCGIWSCAN) = gelic_wl_get_scan, | 2287 | IW_HANDLER(SIOCGIWSCAN, gelic_wl_get_scan), |
2289 | IW_IOCTL(SIOCSIWAUTH) = gelic_wl_set_auth, | 2288 | IW_HANDLER(SIOCSIWAUTH, gelic_wl_set_auth), |
2290 | IW_IOCTL(SIOCGIWAUTH) = gelic_wl_get_auth, | 2289 | IW_HANDLER(SIOCGIWAUTH, gelic_wl_get_auth), |
2291 | IW_IOCTL(SIOCSIWESSID) = gelic_wl_set_essid, | 2290 | IW_HANDLER(SIOCSIWESSID, gelic_wl_set_essid), |
2292 | IW_IOCTL(SIOCGIWESSID) = gelic_wl_get_essid, | 2291 | IW_HANDLER(SIOCGIWESSID, gelic_wl_get_essid), |
2293 | IW_IOCTL(SIOCSIWENCODE) = gelic_wl_set_encode, | 2292 | IW_HANDLER(SIOCSIWENCODE, gelic_wl_set_encode), |
2294 | IW_IOCTL(SIOCGIWENCODE) = gelic_wl_get_encode, | 2293 | IW_HANDLER(SIOCGIWENCODE, gelic_wl_get_encode), |
2295 | IW_IOCTL(SIOCSIWAP) = gelic_wl_set_ap, | 2294 | IW_HANDLER(SIOCSIWAP, gelic_wl_set_ap), |
2296 | IW_IOCTL(SIOCGIWAP) = gelic_wl_get_ap, | 2295 | IW_HANDLER(SIOCGIWAP, gelic_wl_get_ap), |
2297 | IW_IOCTL(SIOCSIWENCODEEXT) = gelic_wl_set_encodeext, | 2296 | IW_HANDLER(SIOCSIWENCODEEXT, gelic_wl_set_encodeext), |
2298 | IW_IOCTL(SIOCGIWENCODEEXT) = gelic_wl_get_encodeext, | 2297 | IW_HANDLER(SIOCGIWENCODEEXT, gelic_wl_get_encodeext), |
2299 | IW_IOCTL(SIOCSIWMODE) = gelic_wl_set_mode, | 2298 | IW_HANDLER(SIOCSIWMODE, gelic_wl_set_mode), |
2300 | IW_IOCTL(SIOCGIWMODE) = gelic_wl_get_mode, | 2299 | IW_HANDLER(SIOCGIWMODE, gelic_wl_get_mode), |
2301 | IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, | 2300 | IW_HANDLER(SIOCGIWNICKN, gelic_wl_get_nick), |
2302 | }; | 2301 | }; |
2303 | 2302 | ||
2304 | static const struct iw_handler_def gelic_wl_wext_handler_def = { | 2303 | static const struct iw_handler_def gelic_wl_wext_handler_def = { |
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 4e7a7fd695c8..0a75be027afa 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig | |||
@@ -3,7 +3,7 @@ menuconfig ATH_COMMON | |||
3 | depends on CFG80211 | 3 | depends on CFG80211 |
4 | ---help--- | 4 | ---help--- |
5 | This will enable the support for the Atheros wireless drivers. | 5 | This will enable the support for the Atheros wireless drivers. |
6 | ath5k, ath9k and ar9170 drivers share some common code, this option | 6 | ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option |
7 | enables the common ath.ko module which shares common helpers. | 7 | enables the common ath.ko module which shares common helpers. |
8 | 8 | ||
9 | For more information and documentation on this module you can visit: | 9 | For more information and documentation on this module you can visit: |
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 5774cea23a3b..35f23bdc442f 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -32,3 +32,24 @@ config ATH9K_DEBUGFS | |||
32 | 32 | ||
33 | Also required for changing debug message flags at run time. | 33 | Also required for changing debug message flags at run time. |
34 | 34 | ||
35 | config ATH9K_HTC | ||
36 | tristate "Atheros HTC based wireless cards support" | ||
37 | depends on USB && MAC80211 | ||
38 | select ATH9K_HW | ||
39 | select MAC80211_LEDS | ||
40 | select LEDS_CLASS | ||
41 | select NEW_LEDS | ||
42 | select ATH9K_COMMON | ||
43 | ---help--- | ||
44 | Support for Atheros HTC based cards. | ||
45 | Chipsets supported: AR9271 | ||
46 | |||
47 | For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc | ||
48 | |||
49 | The built module will be ath9k_htc. | ||
50 | |||
51 | config ATH9K_HTC_DEBUGFS | ||
52 | bool "Atheros ath9k_htc debugging" | ||
53 | depends on ATH9K_HTC && DEBUG_FS | ||
54 | ---help--- | ||
55 | Say Y, if you need access to ath9k_htc's statistics. | ||
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 6b50d5eb9ec3..97133beda269 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile | |||
@@ -28,3 +28,13 @@ obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o | |||
28 | 28 | ||
29 | obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o | 29 | obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o |
30 | ath9k_common-y:= common.o | 30 | ath9k_common-y:= common.o |
31 | |||
32 | ath9k_htc-y += htc_hst.o \ | ||
33 | hif_usb.o \ | ||
34 | wmi.o \ | ||
35 | htc_drv_txrx.o \ | ||
36 | htc_drv_main.o \ | ||
37 | htc_drv_beacon.o \ | ||
38 | htc_drv_init.o | ||
39 | |||
40 | obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o | ||
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 238a5744d8e9..d5026e4f484b 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c | |||
@@ -101,9 +101,13 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, | |||
101 | nf = 0 - ((nf ^ 0x1ff) + 1); | 101 | nf = 0 - ((nf ^ 0x1ff) + 1); |
102 | ath_print(common, ATH_DBG_CALIBRATE, | 102 | ath_print(common, ATH_DBG_CALIBRATE, |
103 | "NF calibrated [ctl] [chain 0] is %d\n", nf); | 103 | "NF calibrated [ctl] [chain 0] is %d\n", nf); |
104 | |||
105 | if (AR_SREV_9271(ah) && (nf >= -114)) | ||
106 | nf = -116; | ||
107 | |||
104 | nfarray[0] = nf; | 108 | nfarray[0] = nf; |
105 | 109 | ||
106 | if (!AR_SREV_9285(ah)) { | 110 | if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) { |
107 | if (AR_SREV_9280_10_OR_LATER(ah)) | 111 | if (AR_SREV_9280_10_OR_LATER(ah)) |
108 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), | 112 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), |
109 | AR9280_PHY_CH1_MINCCA_PWR); | 113 | AR9280_PHY_CH1_MINCCA_PWR); |
@@ -139,9 +143,13 @@ static void ath9k_hw_do_getnf(struct ath_hw *ah, | |||
139 | nf = 0 - ((nf ^ 0x1ff) + 1); | 143 | nf = 0 - ((nf ^ 0x1ff) + 1); |
140 | ath_print(common, ATH_DBG_CALIBRATE, | 144 | ath_print(common, ATH_DBG_CALIBRATE, |
141 | "NF calibrated [ext] [chain 0] is %d\n", nf); | 145 | "NF calibrated [ext] [chain 0] is %d\n", nf); |
146 | |||
147 | if (AR_SREV_9271(ah) && (nf >= -114)) | ||
148 | nf = -116; | ||
149 | |||
142 | nfarray[3] = nf; | 150 | nfarray[3] = nf; |
143 | 151 | ||
144 | if (!AR_SREV_9285(ah)) { | 152 | if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) { |
145 | if (AR_SREV_9280_10_OR_LATER(ah)) | 153 | if (AR_SREV_9280_10_OR_LATER(ah)) |
146 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), | 154 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), |
147 | AR9280_PHY_CH1_EXT_MINCCA_PWR); | 155 | AR9280_PHY_CH1_EXT_MINCCA_PWR); |
@@ -621,7 +629,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
621 | u8 chainmask, rx_chain_status; | 629 | u8 chainmask, rx_chain_status; |
622 | 630 | ||
623 | rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK); | 631 | rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK); |
624 | if (AR_SREV_9285(ah)) | 632 | if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) |
625 | chainmask = 0x9; | 633 | chainmask = 0x9; |
626 | else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) { | 634 | else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) { |
627 | if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4)) | 635 | if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4)) |
@@ -715,7 +723,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) | |||
715 | 723 | ||
716 | if (AR_SREV_9280(ah)) | 724 | if (AR_SREV_9280(ah)) |
717 | noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; | 725 | noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; |
718 | else if (AR_SREV_9285(ah)) | 726 | else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) |
719 | noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; | 727 | noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; |
720 | else if (AR_SREV_9287(ah)) | 728 | else if (AR_SREV_9287(ah)) |
721 | noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE; | 729 | noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE; |
@@ -1051,9 +1059,12 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1051 | /* Do NF cal only at longer intervals */ | 1059 | /* Do NF cal only at longer intervals */ |
1052 | if (longcal) { | 1060 | if (longcal) { |
1053 | /* Do periodic PAOffset Cal */ | 1061 | /* Do periodic PAOffset Cal */ |
1054 | if (AR_SREV_9271(ah)) | 1062 | if (AR_SREV_9271(ah)) { |
1055 | ath9k_hw_9271_pa_cal(ah, false); | 1063 | if (!ah->pacal_info.skipcount) |
1056 | else if (AR_SREV_9285_11_OR_LATER(ah)) { | 1064 | ath9k_hw_9271_pa_cal(ah, false); |
1065 | else | ||
1066 | ah->pacal_info.skipcount--; | ||
1067 | } else if (AR_SREV_9285_11_OR_LATER(ah)) { | ||
1057 | if (!ah->pacal_info.skipcount) | 1068 | if (!ah->pacal_info.skipcount) |
1058 | ath9k_hw_9285_pa_cal(ah, false); | 1069 | ath9k_hw_9285_pa_cal(ah, false); |
1059 | else | 1070 | else |
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 4d775ae141db..7902d287f671 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -286,6 +286,427 @@ int ath9k_cmn_padpos(__le16 frame_control) | |||
286 | } | 286 | } |
287 | EXPORT_SYMBOL(ath9k_cmn_padpos); | 287 | EXPORT_SYMBOL(ath9k_cmn_padpos); |
288 | 288 | ||
289 | int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) | ||
290 | { | ||
291 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
292 | |||
293 | if (tx_info->control.hw_key) { | ||
294 | if (tx_info->control.hw_key->alg == ALG_WEP) | ||
295 | return ATH9K_KEY_TYPE_WEP; | ||
296 | else if (tx_info->control.hw_key->alg == ALG_TKIP) | ||
297 | return ATH9K_KEY_TYPE_TKIP; | ||
298 | else if (tx_info->control.hw_key->alg == ALG_CCMP) | ||
299 | return ATH9K_KEY_TYPE_AES; | ||
300 | } | ||
301 | |||
302 | return ATH9K_KEY_TYPE_CLEAR; | ||
303 | } | ||
304 | EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); | ||
305 | |||
306 | /* | ||
307 | * Calculate the RX filter to be set in the HW. | ||
308 | */ | ||
309 | u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
310 | unsigned int rxfilter) | ||
311 | { | ||
312 | #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) | ||
313 | |||
314 | u32 rfilt; | ||
315 | |||
316 | rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) | ||
317 | | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ||
318 | | ATH9K_RX_FILTER_MCAST; | ||
319 | |||
320 | /* If not a STA, enable processing of Probe Requests */ | ||
321 | if (ah->opmode != NL80211_IFTYPE_STATION) | ||
322 | rfilt |= ATH9K_RX_FILTER_PROBEREQ; | ||
323 | |||
324 | /* | ||
325 | * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station | ||
326 | * mode interface or when in monitor mode. AP mode does not need this | ||
327 | * since it receives all in-BSS frames anyway. | ||
328 | */ | ||
329 | if (((ah->opmode != NL80211_IFTYPE_AP) && | ||
330 | (rxfilter & FIF_PROMISC_IN_BSS)) || | ||
331 | (ah->opmode == NL80211_IFTYPE_MONITOR)) | ||
332 | rfilt |= ATH9K_RX_FILTER_PROM; | ||
333 | |||
334 | if (rxfilter & FIF_CONTROL) | ||
335 | rfilt |= ATH9K_RX_FILTER_CONTROL; | ||
336 | |||
337 | if ((ah->opmode == NL80211_IFTYPE_STATION) && | ||
338 | !(rxfilter & FIF_BCN_PRBRESP_PROMISC)) | ||
339 | rfilt |= ATH9K_RX_FILTER_MYBEACON; | ||
340 | else | ||
341 | rfilt |= ATH9K_RX_FILTER_BEACON; | ||
342 | |||
343 | if ((AR_SREV_9280_10_OR_LATER(ah) || | ||
344 | AR_SREV_9285_10_OR_LATER(ah)) && | ||
345 | (ah->opmode == NL80211_IFTYPE_AP) && | ||
346 | (rxfilter & FIF_PSPOLL)) | ||
347 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | ||
348 | |||
349 | if (conf_is_ht(&hw->conf)) | ||
350 | rfilt |= ATH9K_RX_FILTER_COMP_BAR; | ||
351 | |||
352 | return rfilt; | ||
353 | |||
354 | #undef RX_FILTER_PRESERVE | ||
355 | } | ||
356 | EXPORT_SYMBOL(ath9k_cmn_calcrxfilter); | ||
357 | |||
358 | /* | ||
359 | * Recv initialization for opmode change. | ||
360 | */ | ||
361 | void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
362 | unsigned int rxfilter) | ||
363 | { | ||
364 | struct ath_common *common = ath9k_hw_common(ah); | ||
365 | |||
366 | u32 rfilt, mfilt[2]; | ||
367 | |||
368 | /* configure rx filter */ | ||
369 | rfilt = ath9k_cmn_calcrxfilter(hw, ah, rxfilter); | ||
370 | ath9k_hw_setrxfilter(ah, rfilt); | ||
371 | |||
372 | /* configure bssid mask */ | ||
373 | if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | ||
374 | ath_hw_setbssidmask(common); | ||
375 | |||
376 | /* configure operational mode */ | ||
377 | ath9k_hw_setopmode(ah); | ||
378 | |||
379 | /* Handle any link-level address change. */ | ||
380 | ath9k_hw_setmac(ah, common->macaddr); | ||
381 | |||
382 | /* calculate and install multicast filter */ | ||
383 | mfilt[0] = mfilt[1] = ~0; | ||
384 | ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); | ||
385 | } | ||
386 | EXPORT_SYMBOL(ath9k_cmn_opmode_init); | ||
387 | |||
388 | static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, | ||
389 | enum nl80211_channel_type channel_type) | ||
390 | { | ||
391 | u32 chanmode = 0; | ||
392 | |||
393 | switch (chan->band) { | ||
394 | case IEEE80211_BAND_2GHZ: | ||
395 | switch (channel_type) { | ||
396 | case NL80211_CHAN_NO_HT: | ||
397 | case NL80211_CHAN_HT20: | ||
398 | chanmode = CHANNEL_G_HT20; | ||
399 | break; | ||
400 | case NL80211_CHAN_HT40PLUS: | ||
401 | chanmode = CHANNEL_G_HT40PLUS; | ||
402 | break; | ||
403 | case NL80211_CHAN_HT40MINUS: | ||
404 | chanmode = CHANNEL_G_HT40MINUS; | ||
405 | break; | ||
406 | } | ||
407 | break; | ||
408 | case IEEE80211_BAND_5GHZ: | ||
409 | switch (channel_type) { | ||
410 | case NL80211_CHAN_NO_HT: | ||
411 | case NL80211_CHAN_HT20: | ||
412 | chanmode = CHANNEL_A_HT20; | ||
413 | break; | ||
414 | case NL80211_CHAN_HT40PLUS: | ||
415 | chanmode = CHANNEL_A_HT40PLUS; | ||
416 | break; | ||
417 | case NL80211_CHAN_HT40MINUS: | ||
418 | chanmode = CHANNEL_A_HT40MINUS; | ||
419 | break; | ||
420 | } | ||
421 | break; | ||
422 | default: | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | return chanmode; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Update internal channel flags. | ||
431 | */ | ||
432 | void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, | ||
433 | struct ath9k_channel *ichan) | ||
434 | { | ||
435 | struct ieee80211_channel *chan = hw->conf.channel; | ||
436 | struct ieee80211_conf *conf = &hw->conf; | ||
437 | |||
438 | ichan->channel = chan->center_freq; | ||
439 | ichan->chan = chan; | ||
440 | |||
441 | if (chan->band == IEEE80211_BAND_2GHZ) { | ||
442 | ichan->chanmode = CHANNEL_G; | ||
443 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; | ||
444 | } else { | ||
445 | ichan->chanmode = CHANNEL_A; | ||
446 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | ||
447 | } | ||
448 | |||
449 | if (conf_is_ht(conf)) | ||
450 | ichan->chanmode = ath9k_get_extchanmode(chan, | ||
451 | conf->channel_type); | ||
452 | } | ||
453 | EXPORT_SYMBOL(ath9k_cmn_update_ichannel); | ||
454 | |||
455 | /* | ||
456 | * Get the internal channel reference. | ||
457 | */ | ||
458 | struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, | ||
459 | struct ath_hw *ah) | ||
460 | { | ||
461 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
462 | struct ath9k_channel *channel; | ||
463 | u8 chan_idx; | ||
464 | |||
465 | chan_idx = curchan->hw_value; | ||
466 | channel = &ah->channels[chan_idx]; | ||
467 | ath9k_cmn_update_ichannel(hw, channel); | ||
468 | |||
469 | return channel; | ||
470 | } | ||
471 | EXPORT_SYMBOL(ath9k_cmn_get_curchannel); | ||
472 | |||
473 | static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, | ||
474 | struct ath9k_keyval *hk, const u8 *addr, | ||
475 | bool authenticator) | ||
476 | { | ||
477 | struct ath_hw *ah = common->ah; | ||
478 | const u8 *key_rxmic; | ||
479 | const u8 *key_txmic; | ||
480 | |||
481 | key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
482 | key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
483 | |||
484 | if (addr == NULL) { | ||
485 | /* | ||
486 | * Group key installation - only two key cache entries are used | ||
487 | * regardless of splitmic capability since group key is only | ||
488 | * used either for TX or RX. | ||
489 | */ | ||
490 | if (authenticator) { | ||
491 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
492 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); | ||
493 | } else { | ||
494 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
495 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); | ||
496 | } | ||
497 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
498 | } | ||
499 | if (!common->splitmic) { | ||
500 | /* TX and RX keys share the same key cache entry. */ | ||
501 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
502 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | ||
503 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
504 | } | ||
505 | |||
506 | /* Separate key cache entries for TX and RX */ | ||
507 | |||
508 | /* TX key goes at first index, RX key at +32. */ | ||
509 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
510 | if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { | ||
511 | /* TX MIC entry failed. No need to proceed further */ | ||
512 | ath_print(common, ATH_DBG_FATAL, | ||
513 | "Setting TX MIC Key Failed\n"); | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
518 | /* XXX delete tx key on failure? */ | ||
519 | return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); | ||
520 | } | ||
521 | |||
522 | static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) | ||
523 | { | ||
524 | int i; | ||
525 | |||
526 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
527 | if (test_bit(i, common->keymap) || | ||
528 | test_bit(i + 64, common->keymap)) | ||
529 | continue; /* At least one part of TKIP key allocated */ | ||
530 | if (common->splitmic && | ||
531 | (test_bit(i + 32, common->keymap) || | ||
532 | test_bit(i + 64 + 32, common->keymap))) | ||
533 | continue; /* At least one part of TKIP key allocated */ | ||
534 | |||
535 | /* Found a free slot for a TKIP key */ | ||
536 | return i; | ||
537 | } | ||
538 | return -1; | ||
539 | } | ||
540 | |||
541 | static int ath_reserve_key_cache_slot(struct ath_common *common) | ||
542 | { | ||
543 | int i; | ||
544 | |||
545 | /* First, try to find slots that would not be available for TKIP. */ | ||
546 | if (common->splitmic) { | ||
547 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { | ||
548 | if (!test_bit(i, common->keymap) && | ||
549 | (test_bit(i + 32, common->keymap) || | ||
550 | test_bit(i + 64, common->keymap) || | ||
551 | test_bit(i + 64 + 32, common->keymap))) | ||
552 | return i; | ||
553 | if (!test_bit(i + 32, common->keymap) && | ||
554 | (test_bit(i, common->keymap) || | ||
555 | test_bit(i + 64, common->keymap) || | ||
556 | test_bit(i + 64 + 32, common->keymap))) | ||
557 | return i + 32; | ||
558 | if (!test_bit(i + 64, common->keymap) && | ||
559 | (test_bit(i , common->keymap) || | ||
560 | test_bit(i + 32, common->keymap) || | ||
561 | test_bit(i + 64 + 32, common->keymap))) | ||
562 | return i + 64; | ||
563 | if (!test_bit(i + 64 + 32, common->keymap) && | ||
564 | (test_bit(i, common->keymap) || | ||
565 | test_bit(i + 32, common->keymap) || | ||
566 | test_bit(i + 64, common->keymap))) | ||
567 | return i + 64 + 32; | ||
568 | } | ||
569 | } else { | ||
570 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
571 | if (!test_bit(i, common->keymap) && | ||
572 | test_bit(i + 64, common->keymap)) | ||
573 | return i; | ||
574 | if (test_bit(i, common->keymap) && | ||
575 | !test_bit(i + 64, common->keymap)) | ||
576 | return i + 64; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /* No partially used TKIP slots, pick any available slot */ | ||
581 | for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { | ||
582 | /* Do not allow slots that could be needed for TKIP group keys | ||
583 | * to be used. This limitation could be removed if we know that | ||
584 | * TKIP will not be used. */ | ||
585 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) | ||
586 | continue; | ||
587 | if (common->splitmic) { | ||
588 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) | ||
589 | continue; | ||
590 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) | ||
591 | continue; | ||
592 | } | ||
593 | |||
594 | if (!test_bit(i, common->keymap)) | ||
595 | return i; /* Found a free slot for a key */ | ||
596 | } | ||
597 | |||
598 | /* No free slot found */ | ||
599 | return -1; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * Configure encryption in the HW. | ||
604 | */ | ||
605 | int ath9k_cmn_key_config(struct ath_common *common, | ||
606 | struct ieee80211_vif *vif, | ||
607 | struct ieee80211_sta *sta, | ||
608 | struct ieee80211_key_conf *key) | ||
609 | { | ||
610 | struct ath_hw *ah = common->ah; | ||
611 | struct ath9k_keyval hk; | ||
612 | const u8 *mac = NULL; | ||
613 | int ret = 0; | ||
614 | int idx; | ||
615 | |||
616 | memset(&hk, 0, sizeof(hk)); | ||
617 | |||
618 | switch (key->alg) { | ||
619 | case ALG_WEP: | ||
620 | hk.kv_type = ATH9K_CIPHER_WEP; | ||
621 | break; | ||
622 | case ALG_TKIP: | ||
623 | hk.kv_type = ATH9K_CIPHER_TKIP; | ||
624 | break; | ||
625 | case ALG_CCMP: | ||
626 | hk.kv_type = ATH9K_CIPHER_AES_CCM; | ||
627 | break; | ||
628 | default: | ||
629 | return -EOPNOTSUPP; | ||
630 | } | ||
631 | |||
632 | hk.kv_len = key->keylen; | ||
633 | memcpy(hk.kv_val, key->key, key->keylen); | ||
634 | |||
635 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
636 | /* For now, use the default keys for broadcast keys. This may | ||
637 | * need to change with virtual interfaces. */ | ||
638 | idx = key->keyidx; | ||
639 | } else if (key->keyidx) { | ||
640 | if (WARN_ON(!sta)) | ||
641 | return -EOPNOTSUPP; | ||
642 | mac = sta->addr; | ||
643 | |||
644 | if (vif->type != NL80211_IFTYPE_AP) { | ||
645 | /* Only keyidx 0 should be used with unicast key, but | ||
646 | * allow this for client mode for now. */ | ||
647 | idx = key->keyidx; | ||
648 | } else | ||
649 | return -EIO; | ||
650 | } else { | ||
651 | if (WARN_ON(!sta)) | ||
652 | return -EOPNOTSUPP; | ||
653 | mac = sta->addr; | ||
654 | |||
655 | if (key->alg == ALG_TKIP) | ||
656 | idx = ath_reserve_key_cache_slot_tkip(common); | ||
657 | else | ||
658 | idx = ath_reserve_key_cache_slot(common); | ||
659 | if (idx < 0) | ||
660 | return -ENOSPC; /* no free key cache entries */ | ||
661 | } | ||
662 | |||
663 | if (key->alg == ALG_TKIP) | ||
664 | ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, | ||
665 | vif->type == NL80211_IFTYPE_AP); | ||
666 | else | ||
667 | ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); | ||
668 | |||
669 | if (!ret) | ||
670 | return -EIO; | ||
671 | |||
672 | set_bit(idx, common->keymap); | ||
673 | if (key->alg == ALG_TKIP) { | ||
674 | set_bit(idx + 64, common->keymap); | ||
675 | if (common->splitmic) { | ||
676 | set_bit(idx + 32, common->keymap); | ||
677 | set_bit(idx + 64 + 32, common->keymap); | ||
678 | } | ||
679 | } | ||
680 | |||
681 | return idx; | ||
682 | } | ||
683 | EXPORT_SYMBOL(ath9k_cmn_key_config); | ||
684 | |||
685 | /* | ||
686 | * Delete Key. | ||
687 | */ | ||
688 | void ath9k_cmn_key_delete(struct ath_common *common, | ||
689 | struct ieee80211_key_conf *key) | ||
690 | { | ||
691 | struct ath_hw *ah = common->ah; | ||
692 | |||
693 | ath9k_hw_keyreset(ah, key->hw_key_idx); | ||
694 | if (key->hw_key_idx < IEEE80211_WEP_NKID) | ||
695 | return; | ||
696 | |||
697 | clear_bit(key->hw_key_idx, common->keymap); | ||
698 | if (key->alg != ALG_TKIP) | ||
699 | return; | ||
700 | |||
701 | clear_bit(key->hw_key_idx + 64, common->keymap); | ||
702 | if (common->splitmic) { | ||
703 | ath9k_hw_keyreset(ah, key->hw_key_idx + 32); | ||
704 | clear_bit(key->hw_key_idx + 32, common->keymap); | ||
705 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); | ||
706 | } | ||
707 | } | ||
708 | EXPORT_SYMBOL(ath9k_cmn_key_delete); | ||
709 | |||
289 | static int __init ath9k_cmn_init(void) | 710 | static int __init ath9k_cmn_init(void) |
290 | { | 711 | { |
291 | return 0; | 712 | return 0; |
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 042999c2fe9c..bbcc57f6eba3 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | /* Common header for Atheros 802.11n base driver cores */ | 24 | /* Common header for Atheros 802.11n base driver cores */ |
25 | 25 | ||
26 | #define IEEE80211_WEP_NKID 4 | ||
27 | |||
26 | #define WME_NUM_TID 16 | 28 | #define WME_NUM_TID 16 |
27 | #define WME_BA_BMP_SIZE 64 | 29 | #define WME_BA_BMP_SIZE 64 |
28 | #define WME_MAX_BA WME_BA_BMP_SIZE | 30 | #define WME_MAX_BA WME_BA_BMP_SIZE |
@@ -125,3 +127,18 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, | |||
125 | bool decrypt_error); | 127 | bool decrypt_error); |
126 | 128 | ||
127 | int ath9k_cmn_padpos(__le16 frame_control); | 129 | int ath9k_cmn_padpos(__le16 frame_control); |
130 | int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); | ||
131 | u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
132 | unsigned int rxfilter); | ||
133 | void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
134 | unsigned int rxfilter); | ||
135 | void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, | ||
136 | struct ath9k_channel *ichan); | ||
137 | struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, | ||
138 | struct ath_hw *ah); | ||
139 | int ath9k_cmn_key_config(struct ath_common *common, | ||
140 | struct ieee80211_vif *vif, | ||
141 | struct ieee80211_sta *sta, | ||
142 | struct ieee80211_key_conf *key); | ||
143 | void ath9k_cmn_key_delete(struct ath_common *common, | ||
144 | struct ieee80211_key_conf *key); | ||
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c new file mode 100644 index 000000000000..fc4f6e8c9ef3 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -0,0 +1,993 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | #define ATH9K_FW_USB_DEV(devid, fw) \ | ||
20 | { USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw } | ||
21 | |||
22 | static struct usb_device_id ath9k_hif_usb_ids[] = { | ||
23 | ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"), | ||
24 | { }, | ||
25 | }; | ||
26 | |||
27 | MODULE_DEVICE_TABLE(usb, ath9k_hif_usb_ids); | ||
28 | |||
29 | static int __hif_usb_tx(struct hif_device_usb *hif_dev); | ||
30 | |||
31 | static void hif_usb_regout_cb(struct urb *urb) | ||
32 | { | ||
33 | struct cmd_buf *cmd = (struct cmd_buf *)urb->context; | ||
34 | struct hif_device_usb *hif_dev = cmd->hif_dev; | ||
35 | |||
36 | if (!hif_dev) { | ||
37 | usb_free_urb(urb); | ||
38 | if (cmd) { | ||
39 | if (cmd->skb) | ||
40 | dev_kfree_skb_any(cmd->skb); | ||
41 | kfree(cmd); | ||
42 | } | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | switch (urb->status) { | ||
47 | case 0: | ||
48 | break; | ||
49 | case -ENOENT: | ||
50 | case -ECONNRESET: | ||
51 | break; | ||
52 | case -ENODEV: | ||
53 | case -ESHUTDOWN: | ||
54 | return; | ||
55 | default: | ||
56 | break; | ||
57 | } | ||
58 | |||
59 | if (cmd) { | ||
60 | ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, | ||
61 | cmd->skb, 1); | ||
62 | kfree(cmd); | ||
63 | usb_free_urb(urb); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static int hif_usb_send_regout(struct hif_device_usb *hif_dev, | ||
68 | struct sk_buff *skb) | ||
69 | { | ||
70 | struct urb *urb; | ||
71 | struct cmd_buf *cmd; | ||
72 | int ret = 0; | ||
73 | |||
74 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
75 | if (urb == NULL) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
79 | if (cmd == NULL) { | ||
80 | usb_free_urb(urb); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | cmd->skb = skb; | ||
85 | cmd->hif_dev = hif_dev; | ||
86 | |||
87 | usb_fill_int_urb(urb, hif_dev->udev, | ||
88 | usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE), | ||
89 | skb->data, skb->len, | ||
90 | hif_usb_regout_cb, cmd, 1); | ||
91 | |||
92 | ret = usb_submit_urb(urb, GFP_KERNEL); | ||
93 | if (ret) { | ||
94 | usb_free_urb(urb); | ||
95 | kfree(cmd); | ||
96 | } | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static void hif_usb_tx_cb(struct urb *urb) | ||
102 | { | ||
103 | struct tx_buf *tx_buf = (struct tx_buf *) urb->context; | ||
104 | struct hif_device_usb *hif_dev = tx_buf->hif_dev; | ||
105 | struct sk_buff *skb; | ||
106 | bool drop, flush; | ||
107 | |||
108 | if (!hif_dev) | ||
109 | return; | ||
110 | |||
111 | switch (urb->status) { | ||
112 | case 0: | ||
113 | break; | ||
114 | case -ENOENT: | ||
115 | case -ECONNRESET: | ||
116 | break; | ||
117 | case -ENODEV: | ||
118 | case -ESHUTDOWN: | ||
119 | return; | ||
120 | default: | ||
121 | break; | ||
122 | } | ||
123 | |||
124 | if (tx_buf) { | ||
125 | spin_lock(&hif_dev->tx.tx_lock); | ||
126 | drop = !!(hif_dev->tx.flags & HIF_USB_TX_STOP); | ||
127 | flush = !!(hif_dev->tx.flags & HIF_USB_TX_FLUSH); | ||
128 | spin_unlock(&hif_dev->tx.tx_lock); | ||
129 | |||
130 | while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { | ||
131 | if (!drop && !flush) { | ||
132 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | ||
133 | skb, 1); | ||
134 | TX_STAT_INC(skb_completed); | ||
135 | } else { | ||
136 | dev_kfree_skb_any(skb); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | if (flush) | ||
141 | return; | ||
142 | |||
143 | tx_buf->len = tx_buf->offset = 0; | ||
144 | __skb_queue_head_init(&tx_buf->skb_queue); | ||
145 | |||
146 | spin_lock(&hif_dev->tx.tx_lock); | ||
147 | list_del(&tx_buf->list); | ||
148 | list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | ||
149 | hif_dev->tx.tx_buf_cnt++; | ||
150 | if (!drop) | ||
151 | __hif_usb_tx(hif_dev); /* Check for pending SKBs */ | ||
152 | TX_STAT_INC(buf_completed); | ||
153 | spin_unlock(&hif_dev->tx.tx_lock); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /* TX lock has to be taken */ | ||
158 | static int __hif_usb_tx(struct hif_device_usb *hif_dev) | ||
159 | { | ||
160 | struct tx_buf *tx_buf = NULL; | ||
161 | struct sk_buff *nskb = NULL; | ||
162 | int ret = 0, i; | ||
163 | u16 *hdr, tx_skb_cnt = 0; | ||
164 | u8 *buf; | ||
165 | |||
166 | if (hif_dev->tx.tx_skb_cnt == 0) | ||
167 | return 0; | ||
168 | |||
169 | /* Check if a free TX buffer is available */ | ||
170 | if (list_empty(&hif_dev->tx.tx_buf)) | ||
171 | return 0; | ||
172 | |||
173 | tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list); | ||
174 | list_del(&tx_buf->list); | ||
175 | list_add_tail(&tx_buf->list, &hif_dev->tx.tx_pending); | ||
176 | hif_dev->tx.tx_buf_cnt--; | ||
177 | |||
178 | tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); | ||
179 | |||
180 | for (i = 0; i < tx_skb_cnt; i++) { | ||
181 | nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue); | ||
182 | |||
183 | /* Should never be NULL */ | ||
184 | BUG_ON(!nskb); | ||
185 | |||
186 | hif_dev->tx.tx_skb_cnt--; | ||
187 | |||
188 | buf = tx_buf->buf; | ||
189 | buf += tx_buf->offset; | ||
190 | hdr = (u16 *)buf; | ||
191 | *hdr++ = nskb->len; | ||
192 | *hdr++ = ATH_USB_TX_STREAM_MODE_TAG; | ||
193 | buf += 4; | ||
194 | memcpy(buf, nskb->data, nskb->len); | ||
195 | tx_buf->len = nskb->len + 4; | ||
196 | |||
197 | if (i < (tx_skb_cnt - 1)) | ||
198 | tx_buf->offset += (((tx_buf->len - 1) / 4) + 1) * 4; | ||
199 | |||
200 | if (i == (tx_skb_cnt - 1)) | ||
201 | tx_buf->len += tx_buf->offset; | ||
202 | |||
203 | __skb_queue_tail(&tx_buf->skb_queue, nskb); | ||
204 | TX_STAT_INC(skb_queued); | ||
205 | } | ||
206 | |||
207 | usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev, | ||
208 | usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE), | ||
209 | tx_buf->buf, tx_buf->len, | ||
210 | hif_usb_tx_cb, tx_buf); | ||
211 | |||
212 | ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); | ||
213 | if (ret) { | ||
214 | tx_buf->len = tx_buf->offset = 0; | ||
215 | __skb_queue_purge(&tx_buf->skb_queue); | ||
216 | __skb_queue_head_init(&tx_buf->skb_queue); | ||
217 | list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | ||
218 | hif_dev->tx.tx_buf_cnt++; | ||
219 | } | ||
220 | |||
221 | if (!ret) | ||
222 | TX_STAT_INC(buf_queued); | ||
223 | |||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb, | ||
228 | struct ath9k_htc_tx_ctl *tx_ctl) | ||
229 | { | ||
230 | unsigned long flags; | ||
231 | |||
232 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
233 | |||
234 | if (hif_dev->tx.flags & HIF_USB_TX_STOP) { | ||
235 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
236 | return -ENODEV; | ||
237 | } | ||
238 | |||
239 | /* Check if the max queue count has been reached */ | ||
240 | if (hif_dev->tx.tx_skb_cnt > MAX_TX_BUF_NUM) { | ||
241 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
242 | return -ENOMEM; | ||
243 | } | ||
244 | |||
245 | __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); | ||
246 | hif_dev->tx.tx_skb_cnt++; | ||
247 | |||
248 | /* Send normal frames immediately */ | ||
249 | if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL))) | ||
250 | __hif_usb_tx(hif_dev); | ||
251 | |||
252 | /* Check if AMPDUs have to be sent immediately */ | ||
253 | if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) && | ||
254 | (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) && | ||
255 | (hif_dev->tx.tx_skb_cnt < 2)) { | ||
256 | __hif_usb_tx(hif_dev); | ||
257 | } | ||
258 | |||
259 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static void hif_usb_start(void *hif_handle, u8 pipe_id) | ||
265 | { | ||
266 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; | ||
267 | unsigned long flags; | ||
268 | |||
269 | hif_dev->flags |= HIF_USB_START; | ||
270 | |||
271 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
272 | hif_dev->tx.flags &= ~HIF_USB_TX_STOP; | ||
273 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
274 | } | ||
275 | |||
276 | static void hif_usb_stop(void *hif_handle, u8 pipe_id) | ||
277 | { | ||
278 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; | ||
279 | unsigned long flags; | ||
280 | |||
281 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
282 | __skb_queue_purge(&hif_dev->tx.tx_skb_queue); | ||
283 | hif_dev->tx.tx_skb_cnt = 0; | ||
284 | hif_dev->tx.flags |= HIF_USB_TX_STOP; | ||
285 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
286 | } | ||
287 | |||
288 | static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, | ||
289 | struct ath9k_htc_tx_ctl *tx_ctl) | ||
290 | { | ||
291 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; | ||
292 | int ret = 0; | ||
293 | |||
294 | switch (pipe_id) { | ||
295 | case USB_WLAN_TX_PIPE: | ||
296 | ret = hif_usb_send_tx(hif_dev, skb, tx_ctl); | ||
297 | break; | ||
298 | case USB_REG_OUT_PIPE: | ||
299 | ret = hif_usb_send_regout(hif_dev, skb); | ||
300 | break; | ||
301 | default: | ||
302 | ret = -EINVAL; | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static struct ath9k_htc_hif hif_usb = { | ||
310 | .transport = ATH9K_HIF_USB, | ||
311 | .name = "ath9k_hif_usb", | ||
312 | |||
313 | .control_ul_pipe = USB_REG_OUT_PIPE, | ||
314 | .control_dl_pipe = USB_REG_IN_PIPE, | ||
315 | |||
316 | .start = hif_usb_start, | ||
317 | .stop = hif_usb_stop, | ||
318 | .send = hif_usb_send, | ||
319 | }; | ||
320 | |||
321 | static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev, | ||
322 | struct sk_buff *skb) | ||
323 | { | ||
324 | struct sk_buff *nskb, *skb_pool[8]; | ||
325 | int index = 0, i = 0, chk_idx, len = skb->len; | ||
326 | int rx_remain_len = 0, rx_pkt_len = 0; | ||
327 | u16 pkt_len, pkt_tag, pool_index = 0; | ||
328 | u8 *ptr; | ||
329 | |||
330 | rx_remain_len = hif_dev->rx_remain_len; | ||
331 | rx_pkt_len = hif_dev->rx_transfer_len; | ||
332 | |||
333 | if (rx_remain_len != 0) { | ||
334 | struct sk_buff *remain_skb = hif_dev->remain_skb; | ||
335 | |||
336 | if (remain_skb) { | ||
337 | ptr = (u8 *) remain_skb->data; | ||
338 | |||
339 | index = rx_remain_len; | ||
340 | rx_remain_len -= hif_dev->rx_pad_len; | ||
341 | ptr += rx_pkt_len; | ||
342 | |||
343 | memcpy(ptr, skb->data, rx_remain_len); | ||
344 | |||
345 | rx_pkt_len += rx_remain_len; | ||
346 | hif_dev->rx_remain_len = 0; | ||
347 | skb_put(remain_skb, rx_pkt_len); | ||
348 | |||
349 | skb_pool[pool_index++] = remain_skb; | ||
350 | |||
351 | } else { | ||
352 | index = rx_remain_len; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | while (index < len) { | ||
357 | ptr = (u8 *) skb->data; | ||
358 | |||
359 | pkt_len = ptr[index] + (ptr[index+1] << 8); | ||
360 | pkt_tag = ptr[index+2] + (ptr[index+3] << 8); | ||
361 | |||
362 | if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) { | ||
363 | u16 pad_len; | ||
364 | |||
365 | pad_len = 4 - (pkt_len & 0x3); | ||
366 | if (pad_len == 4) | ||
367 | pad_len = 0; | ||
368 | |||
369 | chk_idx = index; | ||
370 | index = index + 4 + pkt_len + pad_len; | ||
371 | |||
372 | if (index > MAX_RX_BUF_SIZE) { | ||
373 | hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE; | ||
374 | hif_dev->rx_transfer_len = | ||
375 | MAX_RX_BUF_SIZE - chk_idx - 4; | ||
376 | hif_dev->rx_pad_len = pad_len; | ||
377 | |||
378 | nskb = __dev_alloc_skb(pkt_len + 32, | ||
379 | GFP_ATOMIC); | ||
380 | if (!nskb) { | ||
381 | dev_err(&hif_dev->udev->dev, | ||
382 | "ath9k_htc: RX memory allocation" | ||
383 | " error\n"); | ||
384 | goto err; | ||
385 | } | ||
386 | skb_reserve(nskb, 32); | ||
387 | RX_STAT_INC(skb_allocated); | ||
388 | |||
389 | memcpy(nskb->data, &(skb->data[chk_idx+4]), | ||
390 | hif_dev->rx_transfer_len); | ||
391 | |||
392 | /* Record the buffer pointer */ | ||
393 | hif_dev->remain_skb = nskb; | ||
394 | } else { | ||
395 | nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC); | ||
396 | if (!nskb) { | ||
397 | dev_err(&hif_dev->udev->dev, | ||
398 | "ath9k_htc: RX memory allocation" | ||
399 | " error\n"); | ||
400 | goto err; | ||
401 | } | ||
402 | skb_reserve(nskb, 32); | ||
403 | RX_STAT_INC(skb_allocated); | ||
404 | |||
405 | memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len); | ||
406 | skb_put(nskb, pkt_len); | ||
407 | skb_pool[pool_index++] = nskb; | ||
408 | } | ||
409 | } else { | ||
410 | RX_STAT_INC(skb_dropped); | ||
411 | dev_kfree_skb_any(skb); | ||
412 | return; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | err: | ||
417 | dev_kfree_skb_any(skb); | ||
418 | |||
419 | for (i = 0; i < pool_index; i++) { | ||
420 | ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i], | ||
421 | skb_pool[i]->len, USB_WLAN_RX_PIPE); | ||
422 | RX_STAT_INC(skb_completed); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | static void ath9k_hif_usb_rx_cb(struct urb *urb) | ||
427 | { | ||
428 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
429 | struct sk_buff *nskb; | ||
430 | struct hif_device_usb *hif_dev = (struct hif_device_usb *) | ||
431 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
432 | int ret; | ||
433 | |||
434 | if (!hif_dev) | ||
435 | goto free; | ||
436 | |||
437 | switch (urb->status) { | ||
438 | case 0: | ||
439 | break; | ||
440 | case -ENOENT: | ||
441 | case -ECONNRESET: | ||
442 | case -ENODEV: | ||
443 | case -ESHUTDOWN: | ||
444 | goto free; | ||
445 | default: | ||
446 | goto resubmit; | ||
447 | } | ||
448 | |||
449 | if (likely(urb->actual_length != 0)) { | ||
450 | skb_put(skb, urb->actual_length); | ||
451 | |||
452 | nskb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_ATOMIC); | ||
453 | if (!nskb) | ||
454 | goto resubmit; | ||
455 | |||
456 | usb_fill_bulk_urb(urb, hif_dev->udev, | ||
457 | usb_rcvbulkpipe(hif_dev->udev, | ||
458 | USB_WLAN_RX_PIPE), | ||
459 | nskb->data, MAX_RX_BUF_SIZE, | ||
460 | ath9k_hif_usb_rx_cb, nskb); | ||
461 | |||
462 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
463 | if (ret) { | ||
464 | dev_kfree_skb_any(nskb); | ||
465 | goto free; | ||
466 | } | ||
467 | |||
468 | ath9k_hif_usb_rx_stream(hif_dev, skb); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | resubmit: | ||
473 | skb_reset_tail_pointer(skb); | ||
474 | skb_trim(skb, 0); | ||
475 | |||
476 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
477 | if (ret) | ||
478 | goto free; | ||
479 | |||
480 | return; | ||
481 | free: | ||
482 | dev_kfree_skb_any(skb); | ||
483 | } | ||
484 | |||
485 | static void ath9k_hif_usb_reg_in_cb(struct urb *urb) | ||
486 | { | ||
487 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
488 | struct sk_buff *nskb; | ||
489 | struct hif_device_usb *hif_dev = (struct hif_device_usb *) | ||
490 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
491 | int ret; | ||
492 | |||
493 | if (!hif_dev) | ||
494 | goto free; | ||
495 | |||
496 | switch (urb->status) { | ||
497 | case 0: | ||
498 | break; | ||
499 | case -ENOENT: | ||
500 | case -ECONNRESET: | ||
501 | case -ENODEV: | ||
502 | case -ESHUTDOWN: | ||
503 | goto free; | ||
504 | default: | ||
505 | goto resubmit; | ||
506 | } | ||
507 | |||
508 | if (likely(urb->actual_length != 0)) { | ||
509 | skb_put(skb, urb->actual_length); | ||
510 | |||
511 | nskb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC); | ||
512 | if (!nskb) | ||
513 | goto resubmit; | ||
514 | |||
515 | usb_fill_int_urb(urb, hif_dev->udev, | ||
516 | usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), | ||
517 | nskb->data, MAX_REG_IN_BUF_SIZE, | ||
518 | ath9k_hif_usb_reg_in_cb, nskb, 1); | ||
519 | |||
520 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
521 | if (ret) { | ||
522 | dev_kfree_skb_any(nskb); | ||
523 | goto free; | ||
524 | } | ||
525 | |||
526 | ath9k_htc_rx_msg(hif_dev->htc_handle, skb, | ||
527 | skb->len, USB_REG_IN_PIPE); | ||
528 | |||
529 | return; | ||
530 | } | ||
531 | |||
532 | resubmit: | ||
533 | skb_reset_tail_pointer(skb); | ||
534 | skb_trim(skb, 0); | ||
535 | |||
536 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
537 | if (ret) | ||
538 | goto free; | ||
539 | |||
540 | return; | ||
541 | free: | ||
542 | dev_kfree_skb_any(skb); | ||
543 | } | ||
544 | |||
545 | static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) | ||
546 | { | ||
547 | unsigned long flags; | ||
548 | struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; | ||
549 | |||
550 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) { | ||
551 | list_del(&tx_buf->list); | ||
552 | usb_free_urb(tx_buf->urb); | ||
553 | kfree(tx_buf->buf); | ||
554 | kfree(tx_buf); | ||
555 | } | ||
556 | |||
557 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
558 | hif_dev->tx.flags |= HIF_USB_TX_FLUSH; | ||
559 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
560 | |||
561 | list_for_each_entry_safe(tx_buf, tx_buf_tmp, | ||
562 | &hif_dev->tx.tx_pending, list) { | ||
563 | usb_kill_urb(tx_buf->urb); | ||
564 | list_del(&tx_buf->list); | ||
565 | usb_free_urb(tx_buf->urb); | ||
566 | kfree(tx_buf->buf); | ||
567 | kfree(tx_buf); | ||
568 | } | ||
569 | |||
570 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
571 | hif_dev->tx.flags &= ~HIF_USB_TX_FLUSH; | ||
572 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
573 | } | ||
574 | |||
575 | static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) | ||
576 | { | ||
577 | struct tx_buf *tx_buf; | ||
578 | int i; | ||
579 | |||
580 | INIT_LIST_HEAD(&hif_dev->tx.tx_buf); | ||
581 | INIT_LIST_HEAD(&hif_dev->tx.tx_pending); | ||
582 | spin_lock_init(&hif_dev->tx.tx_lock); | ||
583 | __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); | ||
584 | |||
585 | for (i = 0; i < MAX_TX_URB_NUM; i++) { | ||
586 | tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); | ||
587 | if (!tx_buf) | ||
588 | goto err; | ||
589 | |||
590 | tx_buf->buf = kzalloc(MAX_TX_BUF_SIZE, GFP_KERNEL); | ||
591 | if (!tx_buf->buf) | ||
592 | goto err; | ||
593 | |||
594 | tx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
595 | if (!tx_buf->urb) | ||
596 | goto err; | ||
597 | |||
598 | tx_buf->hif_dev = hif_dev; | ||
599 | __skb_queue_head_init(&tx_buf->skb_queue); | ||
600 | |||
601 | list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | ||
602 | } | ||
603 | |||
604 | hif_dev->tx.tx_buf_cnt = MAX_TX_URB_NUM; | ||
605 | |||
606 | return 0; | ||
607 | err: | ||
608 | ath9k_hif_usb_dealloc_tx_urbs(hif_dev); | ||
609 | return -ENOMEM; | ||
610 | } | ||
611 | |||
612 | static void ath9k_hif_usb_dealloc_rx_skbs(struct hif_device_usb *hif_dev) | ||
613 | { | ||
614 | int i; | ||
615 | |||
616 | for (i = 0; i < MAX_RX_URB_NUM; i++) { | ||
617 | if (hif_dev->wlan_rx_data_urb[i]) { | ||
618 | if (hif_dev->wlan_rx_data_urb[i]->transfer_buffer) | ||
619 | dev_kfree_skb_any((void *) | ||
620 | hif_dev->wlan_rx_data_urb[i]->context); | ||
621 | } | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev) | ||
626 | { | ||
627 | int i; | ||
628 | |||
629 | for (i = 0; i < MAX_RX_URB_NUM; i++) { | ||
630 | if (hif_dev->wlan_rx_data_urb[i]) { | ||
631 | usb_kill_urb(hif_dev->wlan_rx_data_urb[i]); | ||
632 | usb_free_urb(hif_dev->wlan_rx_data_urb[i]); | ||
633 | hif_dev->wlan_rx_data_urb[i] = NULL; | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | |||
638 | static int ath9k_hif_usb_prep_rx_urb(struct hif_device_usb *hif_dev, | ||
639 | struct urb *urb) | ||
640 | { | ||
641 | struct sk_buff *skb; | ||
642 | |||
643 | skb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL); | ||
644 | if (!skb) | ||
645 | return -ENOMEM; | ||
646 | |||
647 | usb_fill_bulk_urb(urb, hif_dev->udev, | ||
648 | usb_rcvbulkpipe(hif_dev->udev, USB_WLAN_RX_PIPE), | ||
649 | skb->data, MAX_RX_BUF_SIZE, | ||
650 | ath9k_hif_usb_rx_cb, skb); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev) | ||
655 | { | ||
656 | int i, ret; | ||
657 | |||
658 | for (i = 0; i < MAX_RX_URB_NUM; i++) { | ||
659 | |||
660 | /* Allocate URB */ | ||
661 | hif_dev->wlan_rx_data_urb[i] = usb_alloc_urb(0, GFP_KERNEL); | ||
662 | if (hif_dev->wlan_rx_data_urb[i] == NULL) { | ||
663 | ret = -ENOMEM; | ||
664 | goto err_rx_urb; | ||
665 | } | ||
666 | |||
667 | /* Allocate buffer */ | ||
668 | ret = ath9k_hif_usb_prep_rx_urb(hif_dev, | ||
669 | hif_dev->wlan_rx_data_urb[i]); | ||
670 | if (ret) | ||
671 | goto err_rx_urb; | ||
672 | |||
673 | /* Submit URB */ | ||
674 | ret = usb_submit_urb(hif_dev->wlan_rx_data_urb[i], GFP_KERNEL); | ||
675 | if (ret) | ||
676 | goto err_rx_urb; | ||
677 | |||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | |||
682 | err_rx_urb: | ||
683 | ath9k_hif_usb_dealloc_rx_skbs(hif_dev); | ||
684 | ath9k_hif_usb_dealloc_rx_urbs(hif_dev); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev) | ||
689 | { | ||
690 | if (hif_dev->reg_in_urb) { | ||
691 | usb_kill_urb(hif_dev->reg_in_urb); | ||
692 | usb_free_urb(hif_dev->reg_in_urb); | ||
693 | hif_dev->reg_in_urb = NULL; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev) | ||
698 | { | ||
699 | struct sk_buff *skb; | ||
700 | |||
701 | hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
702 | if (hif_dev->reg_in_urb == NULL) | ||
703 | return -ENOMEM; | ||
704 | |||
705 | skb = __dev_alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL); | ||
706 | if (!skb) | ||
707 | goto err; | ||
708 | |||
709 | usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev, | ||
710 | usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE), | ||
711 | skb->data, MAX_REG_IN_BUF_SIZE, | ||
712 | ath9k_hif_usb_reg_in_cb, skb, 1); | ||
713 | |||
714 | if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0) | ||
715 | goto err_skb; | ||
716 | |||
717 | return 0; | ||
718 | |||
719 | err_skb: | ||
720 | dev_kfree_skb_any(skb); | ||
721 | err: | ||
722 | ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | |||
726 | static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev) | ||
727 | { | ||
728 | /* TX */ | ||
729 | if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0) | ||
730 | goto err; | ||
731 | |||
732 | /* RX */ | ||
733 | if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0) | ||
734 | goto err; | ||
735 | |||
736 | /* Register Read/Write */ | ||
737 | if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0) | ||
738 | goto err; | ||
739 | |||
740 | return 0; | ||
741 | err: | ||
742 | return -ENOMEM; | ||
743 | } | ||
744 | |||
745 | static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev) | ||
746 | { | ||
747 | int transfer, err; | ||
748 | const void *data = hif_dev->firmware->data; | ||
749 | size_t len = hif_dev->firmware->size; | ||
750 | u32 addr = AR9271_FIRMWARE; | ||
751 | u8 *buf = kzalloc(4096, GFP_KERNEL); | ||
752 | |||
753 | if (!buf) | ||
754 | return -ENOMEM; | ||
755 | |||
756 | while (len) { | ||
757 | transfer = min_t(int, len, 4096); | ||
758 | memcpy(buf, data, transfer); | ||
759 | |||
760 | err = usb_control_msg(hif_dev->udev, | ||
761 | usb_sndctrlpipe(hif_dev->udev, 0), | ||
762 | FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT, | ||
763 | addr >> 8, 0, buf, transfer, HZ); | ||
764 | if (err < 0) { | ||
765 | kfree(buf); | ||
766 | return err; | ||
767 | } | ||
768 | |||
769 | len -= transfer; | ||
770 | data += transfer; | ||
771 | addr += transfer; | ||
772 | } | ||
773 | kfree(buf); | ||
774 | |||
775 | /* | ||
776 | * Issue FW download complete command to firmware. | ||
777 | */ | ||
778 | err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0), | ||
779 | FIRMWARE_DOWNLOAD_COMP, | ||
780 | 0x40 | USB_DIR_OUT, | ||
781 | AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ); | ||
782 | if (err) | ||
783 | return -EIO; | ||
784 | |||
785 | dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n", | ||
786 | "ar9271.fw", (unsigned long) hif_dev->firmware->size); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev, | ||
792 | const char *fw_name) | ||
793 | { | ||
794 | int ret; | ||
795 | |||
796 | /* Request firmware */ | ||
797 | ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev); | ||
798 | if (ret) { | ||
799 | dev_err(&hif_dev->udev->dev, | ||
800 | "ath9k_htc: Firmware - %s not found\n", fw_name); | ||
801 | goto err_fw_req; | ||
802 | } | ||
803 | |||
804 | /* Download firmware */ | ||
805 | ret = ath9k_hif_usb_download_fw(hif_dev); | ||
806 | if (ret) { | ||
807 | dev_err(&hif_dev->udev->dev, | ||
808 | "ath9k_htc: Firmware - %s download failed\n", fw_name); | ||
809 | goto err_fw_download; | ||
810 | } | ||
811 | |||
812 | /* Alloc URBs */ | ||
813 | ret = ath9k_hif_usb_alloc_urbs(hif_dev); | ||
814 | if (ret) { | ||
815 | dev_err(&hif_dev->udev->dev, | ||
816 | "ath9k_htc: Unable to allocate URBs\n"); | ||
817 | goto err_urb; | ||
818 | } | ||
819 | |||
820 | return 0; | ||
821 | |||
822 | err_urb: | ||
823 | /* Nothing */ | ||
824 | err_fw_download: | ||
825 | release_firmware(hif_dev->firmware); | ||
826 | err_fw_req: | ||
827 | hif_dev->firmware = NULL; | ||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev) | ||
832 | { | ||
833 | ath9k_hif_usb_dealloc_reg_in_urb(hif_dev); | ||
834 | ath9k_hif_usb_dealloc_tx_urbs(hif_dev); | ||
835 | ath9k_hif_usb_dealloc_rx_urbs(hif_dev); | ||
836 | } | ||
837 | |||
838 | static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev) | ||
839 | { | ||
840 | ath9k_hif_usb_dealloc_urbs(hif_dev); | ||
841 | if (hif_dev->firmware) | ||
842 | release_firmware(hif_dev->firmware); | ||
843 | } | ||
844 | |||
845 | static int ath9k_hif_usb_probe(struct usb_interface *interface, | ||
846 | const struct usb_device_id *id) | ||
847 | { | ||
848 | struct usb_device *udev = interface_to_usbdev(interface); | ||
849 | struct hif_device_usb *hif_dev; | ||
850 | const char *fw_name = (const char *) id->driver_info; | ||
851 | int ret = 0; | ||
852 | |||
853 | hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL); | ||
854 | if (!hif_dev) { | ||
855 | ret = -ENOMEM; | ||
856 | goto err_alloc; | ||
857 | } | ||
858 | |||
859 | usb_get_dev(udev); | ||
860 | hif_dev->udev = udev; | ||
861 | hif_dev->interface = interface; | ||
862 | hif_dev->device_id = id->idProduct; | ||
863 | #ifdef CONFIG_PM | ||
864 | udev->reset_resume = 1; | ||
865 | #endif | ||
866 | usb_set_intfdata(interface, hif_dev); | ||
867 | |||
868 | ret = ath9k_hif_usb_dev_init(hif_dev, fw_name); | ||
869 | if (ret) { | ||
870 | ret = -EINVAL; | ||
871 | goto err_hif_init_usb; | ||
872 | } | ||
873 | |||
874 | hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev); | ||
875 | if (hif_dev->htc_handle == NULL) { | ||
876 | ret = -ENOMEM; | ||
877 | goto err_htc_hw_alloc; | ||
878 | } | ||
879 | |||
880 | ret = ath9k_htc_hw_init(&hif_usb, hif_dev->htc_handle, hif_dev, | ||
881 | &hif_dev->udev->dev, hif_dev->device_id, | ||
882 | ATH9K_HIF_USB); | ||
883 | if (ret) { | ||
884 | ret = -EINVAL; | ||
885 | goto err_htc_hw_init; | ||
886 | } | ||
887 | |||
888 | dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n"); | ||
889 | |||
890 | return 0; | ||
891 | |||
892 | err_htc_hw_init: | ||
893 | ath9k_htc_hw_free(hif_dev->htc_handle); | ||
894 | err_htc_hw_alloc: | ||
895 | ath9k_hif_usb_dev_deinit(hif_dev); | ||
896 | err_hif_init_usb: | ||
897 | usb_set_intfdata(interface, NULL); | ||
898 | kfree(hif_dev); | ||
899 | usb_put_dev(udev); | ||
900 | err_alloc: | ||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | static void ath9k_hif_usb_disconnect(struct usb_interface *interface) | ||
905 | { | ||
906 | struct usb_device *udev = interface_to_usbdev(interface); | ||
907 | struct hif_device_usb *hif_dev = | ||
908 | (struct hif_device_usb *) usb_get_intfdata(interface); | ||
909 | |||
910 | if (hif_dev) { | ||
911 | ath9k_htc_hw_deinit(hif_dev->htc_handle, true); | ||
912 | ath9k_htc_hw_free(hif_dev->htc_handle); | ||
913 | ath9k_hif_usb_dev_deinit(hif_dev); | ||
914 | usb_set_intfdata(interface, NULL); | ||
915 | } | ||
916 | |||
917 | if (hif_dev->flags & HIF_USB_START) | ||
918 | usb_reset_device(udev); | ||
919 | |||
920 | kfree(hif_dev); | ||
921 | dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n"); | ||
922 | usb_put_dev(udev); | ||
923 | } | ||
924 | |||
925 | #ifdef CONFIG_PM | ||
926 | static int ath9k_hif_usb_suspend(struct usb_interface *interface, | ||
927 | pm_message_t message) | ||
928 | { | ||
929 | struct hif_device_usb *hif_dev = | ||
930 | (struct hif_device_usb *) usb_get_intfdata(interface); | ||
931 | |||
932 | ath9k_hif_usb_dealloc_urbs(hif_dev); | ||
933 | |||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int ath9k_hif_usb_resume(struct usb_interface *interface) | ||
938 | { | ||
939 | struct hif_device_usb *hif_dev = | ||
940 | (struct hif_device_usb *) usb_get_intfdata(interface); | ||
941 | int ret; | ||
942 | |||
943 | ret = ath9k_hif_usb_alloc_urbs(hif_dev); | ||
944 | if (ret) | ||
945 | return ret; | ||
946 | |||
947 | if (hif_dev->firmware) { | ||
948 | ret = ath9k_hif_usb_download_fw(hif_dev); | ||
949 | if (ret) | ||
950 | goto fail_resume; | ||
951 | } else { | ||
952 | ath9k_hif_usb_dealloc_urbs(hif_dev); | ||
953 | return -EIO; | ||
954 | } | ||
955 | |||
956 | mdelay(100); | ||
957 | |||
958 | ret = ath9k_htc_resume(hif_dev->htc_handle); | ||
959 | |||
960 | if (ret) | ||
961 | goto fail_resume; | ||
962 | |||
963 | return 0; | ||
964 | |||
965 | fail_resume: | ||
966 | ath9k_hif_usb_dealloc_urbs(hif_dev); | ||
967 | |||
968 | return ret; | ||
969 | } | ||
970 | #endif | ||
971 | |||
972 | static struct usb_driver ath9k_hif_usb_driver = { | ||
973 | .name = "ath9k_hif_usb", | ||
974 | .probe = ath9k_hif_usb_probe, | ||
975 | .disconnect = ath9k_hif_usb_disconnect, | ||
976 | #ifdef CONFIG_PM | ||
977 | .suspend = ath9k_hif_usb_suspend, | ||
978 | .resume = ath9k_hif_usb_resume, | ||
979 | .reset_resume = ath9k_hif_usb_resume, | ||
980 | #endif | ||
981 | .id_table = ath9k_hif_usb_ids, | ||
982 | .soft_unbind = 1, | ||
983 | }; | ||
984 | |||
985 | int ath9k_hif_usb_init(void) | ||
986 | { | ||
987 | return usb_register(&ath9k_hif_usb_driver); | ||
988 | } | ||
989 | |||
990 | void ath9k_hif_usb_exit(void) | ||
991 | { | ||
992 | usb_deregister(&ath9k_hif_usb_driver); | ||
993 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h new file mode 100644 index 000000000000..7cc3762a6789 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef HTC_USB_H | ||
18 | #define HTC_USB_H | ||
19 | |||
20 | #define AR9271_FIRMWARE 0x501000 | ||
21 | #define AR9271_FIRMWARE_TEXT 0x903000 | ||
22 | |||
23 | #define FIRMWARE_DOWNLOAD 0x30 | ||
24 | #define FIRMWARE_DOWNLOAD_COMP 0x31 | ||
25 | |||
26 | #define ATH_USB_RX_STREAM_MODE_TAG 0x4e00 | ||
27 | #define ATH_USB_TX_STREAM_MODE_TAG 0x697e | ||
28 | |||
29 | /* FIXME: Verify these numbers (with Windows) */ | ||
30 | #define MAX_TX_URB_NUM 8 | ||
31 | #define MAX_TX_BUF_NUM 1024 | ||
32 | #define MAX_TX_BUF_SIZE 32768 | ||
33 | #define MAX_TX_AGGR_NUM 20 | ||
34 | |||
35 | #define MAX_RX_URB_NUM 8 | ||
36 | #define MAX_RX_BUF_SIZE 16384 | ||
37 | |||
38 | #define MAX_REG_OUT_URB_NUM 1 | ||
39 | #define MAX_REG_OUT_BUF_NUM 8 | ||
40 | |||
41 | #define MAX_REG_IN_BUF_SIZE 64 | ||
42 | |||
43 | /* USB Endpoint definition */ | ||
44 | #define USB_WLAN_TX_PIPE 1 | ||
45 | #define USB_WLAN_RX_PIPE 2 | ||
46 | #define USB_REG_IN_PIPE 3 | ||
47 | #define USB_REG_OUT_PIPE 4 | ||
48 | |||
49 | #define HIF_USB_MAX_RXPIPES 2 | ||
50 | #define HIF_USB_MAX_TXPIPES 4 | ||
51 | |||
52 | struct tx_buf { | ||
53 | u8 *buf; | ||
54 | u16 len; | ||
55 | u16 offset; | ||
56 | struct urb *urb; | ||
57 | struct sk_buff_head skb_queue; | ||
58 | struct hif_device_usb *hif_dev; | ||
59 | struct list_head list; | ||
60 | }; | ||
61 | |||
62 | #define HIF_USB_TX_STOP BIT(0) | ||
63 | #define HIF_USB_TX_FLUSH BIT(1) | ||
64 | |||
65 | struct hif_usb_tx { | ||
66 | u8 flags; | ||
67 | u8 tx_buf_cnt; | ||
68 | u16 tx_skb_cnt; | ||
69 | struct sk_buff_head tx_skb_queue; | ||
70 | struct list_head tx_buf; | ||
71 | struct list_head tx_pending; | ||
72 | spinlock_t tx_lock; | ||
73 | }; | ||
74 | |||
75 | struct cmd_buf { | ||
76 | struct sk_buff *skb; | ||
77 | struct hif_device_usb *hif_dev; | ||
78 | }; | ||
79 | |||
80 | #define HIF_USB_START BIT(0) | ||
81 | |||
82 | struct hif_device_usb { | ||
83 | u16 device_id; | ||
84 | struct usb_device *udev; | ||
85 | struct usb_interface *interface; | ||
86 | const struct firmware *firmware; | ||
87 | struct htc_target *htc_handle; | ||
88 | u8 flags; | ||
89 | |||
90 | struct hif_usb_tx tx; | ||
91 | |||
92 | struct urb *wlan_rx_data_urb[MAX_RX_URB_NUM]; | ||
93 | struct urb *reg_in_urb; | ||
94 | |||
95 | struct sk_buff *remain_skb; | ||
96 | int rx_remain_len; | ||
97 | int rx_pkt_len; | ||
98 | int rx_transfer_len; | ||
99 | int rx_pad_len; | ||
100 | }; | ||
101 | |||
102 | int ath9k_hif_usb_init(void); | ||
103 | void ath9k_hif_usb_exit(void); | ||
104 | |||
105 | #endif /* HTC_USB_H */ | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h new file mode 100644 index 000000000000..777064945fca --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef HTC_H | ||
18 | #define HTC_H | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/usb.h> | ||
22 | #include <linux/firmware.h> | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/leds.h> | ||
26 | #include <net/mac80211.h> | ||
27 | |||
28 | #include "common.h" | ||
29 | #include "htc_hst.h" | ||
30 | #include "hif_usb.h" | ||
31 | #include "wmi.h" | ||
32 | |||
33 | #define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ | ||
34 | #define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ | ||
35 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ | ||
36 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ | ||
37 | |||
38 | #define ATH_DEFAULT_BMISS_LIMIT 10 | ||
39 | #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) | ||
40 | #define TSF_TO_TU(_h, _l) \ | ||
41 | ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) | ||
42 | |||
43 | extern struct ieee80211_ops ath9k_htc_ops; | ||
44 | extern int htc_modparam_nohwcrypt; | ||
45 | |||
46 | enum htc_phymode { | ||
47 | HTC_MODE_AUTO = 0, | ||
48 | HTC_MODE_11A = 1, | ||
49 | HTC_MODE_11B = 2, | ||
50 | HTC_MODE_11G = 3, | ||
51 | HTC_MODE_FH = 4, | ||
52 | HTC_MODE_TURBO_A = 5, | ||
53 | HTC_MODE_TURBO_G = 6, | ||
54 | HTC_MODE_11NA = 7, | ||
55 | HTC_MODE_11NG = 8 | ||
56 | }; | ||
57 | |||
58 | enum htc_opmode { | ||
59 | HTC_M_STA = 1, | ||
60 | HTC_M_IBSS = 0, | ||
61 | HTC_M_AHDEMO = 3, | ||
62 | HTC_M_HOSTAP = 6, | ||
63 | HTC_M_MONITOR = 8, | ||
64 | HTC_M_WDS = 2 | ||
65 | }; | ||
66 | |||
67 | #define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) | ||
68 | #define ATH9K_HTC_AMPDU 1 | ||
69 | #define ATH9K_HTC_NORMAL 2 | ||
70 | |||
71 | #define ATH9K_HTC_TX_CTSONLY 0x1 | ||
72 | #define ATH9K_HTC_TX_RTSCTS 0x2 | ||
73 | #define ATH9K_HTC_TX_USE_MIN_RATE 0x100 | ||
74 | |||
75 | struct tx_frame_hdr { | ||
76 | u8 data_type; | ||
77 | u8 node_idx; | ||
78 | u8 vif_idx; | ||
79 | u8 tidno; | ||
80 | u32 flags; /* ATH9K_HTC_TX_* */ | ||
81 | u8 key_type; | ||
82 | u8 keyix; | ||
83 | u8 reserved[26]; | ||
84 | } __packed; | ||
85 | |||
86 | struct tx_mgmt_hdr { | ||
87 | u8 node_idx; | ||
88 | u8 vif_idx; | ||
89 | u8 tidno; | ||
90 | u8 flags; | ||
91 | u8 key_type; | ||
92 | u8 keyix; | ||
93 | u16 reserved; | ||
94 | } __packed; | ||
95 | |||
96 | struct tx_beacon_header { | ||
97 | u8 len_changed; | ||
98 | u8 vif_index; | ||
99 | u16 rev; | ||
100 | } __packed; | ||
101 | |||
102 | struct ath9k_htc_target_hw { | ||
103 | u32 flags; | ||
104 | u32 flags_ext; | ||
105 | u32 ampdu_limit; | ||
106 | u8 ampdu_subframes; | ||
107 | u8 tx_chainmask; | ||
108 | u8 tx_chainmask_legacy; | ||
109 | u8 rtscts_ratecode; | ||
110 | u8 protmode; | ||
111 | } __packed; | ||
112 | |||
113 | struct ath9k_htc_cap_target { | ||
114 | u32 flags; | ||
115 | u32 flags_ext; | ||
116 | u32 ampdu_limit; | ||
117 | u8 ampdu_subframes; | ||
118 | u8 tx_chainmask; | ||
119 | u8 tx_chainmask_legacy; | ||
120 | u8 rtscts_ratecode; | ||
121 | u8 protmode; | ||
122 | } __packed; | ||
123 | |||
124 | struct ath9k_htc_target_vif { | ||
125 | u8 index; | ||
126 | u8 des_bssid[ETH_ALEN]; | ||
127 | enum htc_opmode opmode; | ||
128 | u8 myaddr[ETH_ALEN]; | ||
129 | u8 bssid[ETH_ALEN]; | ||
130 | u32 flags; | ||
131 | u32 flags_ext; | ||
132 | u16 ps_sta; | ||
133 | u16 rtsthreshold; | ||
134 | u8 ath_cap; | ||
135 | u8 node; | ||
136 | s8 mcast_rate; | ||
137 | } __packed; | ||
138 | |||
139 | #define ATH_HTC_STA_AUTH 0x0001 | ||
140 | #define ATH_HTC_STA_QOS 0x0002 | ||
141 | #define ATH_HTC_STA_ERP 0x0004 | ||
142 | #define ATH_HTC_STA_HT 0x0008 | ||
143 | |||
144 | /* FIXME: UAPSD variables */ | ||
145 | struct ath9k_htc_target_sta { | ||
146 | u16 associd; | ||
147 | u16 txpower; | ||
148 | u32 ucastkey; | ||
149 | u8 macaddr[ETH_ALEN]; | ||
150 | u8 bssid[ETH_ALEN]; | ||
151 | u8 sta_index; | ||
152 | u8 vif_index; | ||
153 | u8 vif_sta; | ||
154 | u16 flags; /* ATH_HTC_STA_* */ | ||
155 | u16 htcap; | ||
156 | u8 valid; | ||
157 | u16 capinfo; | ||
158 | struct ath9k_htc_target_hw *hw; | ||
159 | struct ath9k_htc_target_vif *vif; | ||
160 | u16 txseqmgmt; | ||
161 | u8 is_vif_sta; | ||
162 | u16 maxampdu; | ||
163 | u16 iv16; | ||
164 | u32 iv32; | ||
165 | } __packed; | ||
166 | |||
167 | struct ath9k_htc_target_aggr { | ||
168 | u8 sta_index; | ||
169 | u8 tidno; | ||
170 | u8 aggr_enable; | ||
171 | u8 padding; | ||
172 | } __packed; | ||
173 | |||
174 | #define ATH_HTC_RATE_MAX 30 | ||
175 | |||
176 | #define WLAN_RC_DS_FLAG 0x01 | ||
177 | #define WLAN_RC_40_FLAG 0x02 | ||
178 | #define WLAN_RC_SGI_FLAG 0x04 | ||
179 | #define WLAN_RC_HT_FLAG 0x08 | ||
180 | |||
181 | struct ath9k_htc_rateset { | ||
182 | u8 rs_nrates; | ||
183 | u8 rs_rates[ATH_HTC_RATE_MAX]; | ||
184 | }; | ||
185 | |||
186 | struct ath9k_htc_rate { | ||
187 | struct ath9k_htc_rateset legacy_rates; | ||
188 | struct ath9k_htc_rateset ht_rates; | ||
189 | } __packed; | ||
190 | |||
191 | struct ath9k_htc_target_rate { | ||
192 | u8 sta_index; | ||
193 | u8 isnew; | ||
194 | u32 capflags; | ||
195 | struct ath9k_htc_rate rates; | ||
196 | }; | ||
197 | |||
198 | struct ath9k_htc_target_stats { | ||
199 | u32 tx_shortretry; | ||
200 | u32 tx_longretry; | ||
201 | u32 tx_xretries; | ||
202 | u32 ht_txunaggr_xretry; | ||
203 | u32 ht_tx_xretries; | ||
204 | } __packed; | ||
205 | |||
206 | struct ath9k_htc_vif { | ||
207 | u8 index; | ||
208 | }; | ||
209 | |||
210 | #define ATH9K_HTC_MAX_STA 8 | ||
211 | #define ATH9K_HTC_MAX_TID 8 | ||
212 | |||
213 | enum tid_aggr_state { | ||
214 | AGGR_STOP = 0, | ||
215 | AGGR_PROGRESS, | ||
216 | AGGR_START, | ||
217 | AGGR_OPERATIONAL | ||
218 | }; | ||
219 | |||
220 | struct ath9k_htc_sta { | ||
221 | u8 index; | ||
222 | enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID]; | ||
223 | }; | ||
224 | |||
225 | struct ath9k_htc_aggr_work { | ||
226 | u16 tid; | ||
227 | u8 sta_addr[ETH_ALEN]; | ||
228 | struct ieee80211_hw *hw; | ||
229 | struct ieee80211_vif *vif; | ||
230 | enum ieee80211_ampdu_mlme_action action; | ||
231 | struct mutex mutex; | ||
232 | }; | ||
233 | |||
234 | #define ATH9K_HTC_RXBUF 256 | ||
235 | #define HTC_RX_FRAME_HEADER_SIZE 40 | ||
236 | |||
237 | struct ath9k_htc_rxbuf { | ||
238 | bool in_process; | ||
239 | struct sk_buff *skb; | ||
240 | struct ath_htc_rx_status rxstatus; | ||
241 | struct list_head list; | ||
242 | }; | ||
243 | |||
244 | struct ath9k_htc_rx { | ||
245 | int last_rssi; /* FIXME: per-STA */ | ||
246 | struct list_head rxbuf; | ||
247 | spinlock_t rxbuflock; | ||
248 | }; | ||
249 | |||
250 | struct ath9k_htc_tx_ctl { | ||
251 | u8 type; /* ATH9K_HTC_* */ | ||
252 | }; | ||
253 | |||
254 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
255 | |||
256 | #define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++) | ||
257 | #define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++) | ||
258 | |||
259 | struct ath_tx_stats { | ||
260 | u32 buf_queued; | ||
261 | u32 buf_completed; | ||
262 | u32 skb_queued; | ||
263 | u32 skb_completed; | ||
264 | }; | ||
265 | |||
266 | struct ath_rx_stats { | ||
267 | u32 skb_allocated; | ||
268 | u32 skb_completed; | ||
269 | u32 skb_dropped; | ||
270 | }; | ||
271 | |||
272 | struct ath9k_debug { | ||
273 | struct dentry *debugfs_phy; | ||
274 | struct dentry *debugfs_tgt_stats; | ||
275 | struct dentry *debugfs_xmit; | ||
276 | struct dentry *debugfs_recv; | ||
277 | struct ath_tx_stats tx_stats; | ||
278 | struct ath_rx_stats rx_stats; | ||
279 | u32 txrate; | ||
280 | }; | ||
281 | |||
282 | #else | ||
283 | |||
284 | #define TX_STAT_INC(c) do { } while (0) | ||
285 | #define RX_STAT_INC(c) do { } while (0) | ||
286 | |||
287 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ | ||
288 | |||
289 | #define ATH_LED_PIN_DEF 1 | ||
290 | #define ATH_LED_PIN_9287 8 | ||
291 | #define ATH_LED_PIN_9271 15 | ||
292 | #define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ | ||
293 | #define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ | ||
294 | |||
295 | enum ath_led_type { | ||
296 | ATH_LED_RADIO, | ||
297 | ATH_LED_ASSOC, | ||
298 | ATH_LED_TX, | ||
299 | ATH_LED_RX | ||
300 | }; | ||
301 | |||
302 | struct ath_led { | ||
303 | struct ath9k_htc_priv *priv; | ||
304 | struct led_classdev led_cdev; | ||
305 | enum ath_led_type led_type; | ||
306 | struct delayed_work brightness_work; | ||
307 | char name[32]; | ||
308 | bool registered; | ||
309 | int brightness; | ||
310 | }; | ||
311 | |||
312 | #define OP_INVALID BIT(0) | ||
313 | #define OP_SCANNING BIT(1) | ||
314 | #define OP_FULL_RESET BIT(2) | ||
315 | #define OP_LED_ASSOCIATED BIT(3) | ||
316 | #define OP_LED_ON BIT(4) | ||
317 | #define OP_PREAMBLE_SHORT BIT(5) | ||
318 | #define OP_PROTECT_ENABLE BIT(6) | ||
319 | #define OP_TXAGGR BIT(7) | ||
320 | #define OP_ASSOCIATED BIT(8) | ||
321 | #define OP_ENABLE_BEACON BIT(9) | ||
322 | #define OP_LED_DEINIT BIT(10) | ||
323 | |||
324 | struct ath9k_htc_priv { | ||
325 | struct device *dev; | ||
326 | struct ieee80211_hw *hw; | ||
327 | struct ath_hw *ah; | ||
328 | struct htc_target *htc; | ||
329 | struct wmi *wmi; | ||
330 | |||
331 | enum htc_endpoint_id wmi_cmd_ep; | ||
332 | enum htc_endpoint_id beacon_ep; | ||
333 | enum htc_endpoint_id cab_ep; | ||
334 | enum htc_endpoint_id uapsd_ep; | ||
335 | enum htc_endpoint_id mgmt_ep; | ||
336 | enum htc_endpoint_id data_be_ep; | ||
337 | enum htc_endpoint_id data_bk_ep; | ||
338 | enum htc_endpoint_id data_vi_ep; | ||
339 | enum htc_endpoint_id data_vo_ep; | ||
340 | |||
341 | u16 op_flags; | ||
342 | u16 curtxpow; | ||
343 | u16 txpowlimit; | ||
344 | u16 nvifs; | ||
345 | u16 nstations; | ||
346 | u16 seq_no; | ||
347 | u32 bmiss_cnt; | ||
348 | |||
349 | struct sk_buff *beacon; | ||
350 | spinlock_t beacon_lock; | ||
351 | |||
352 | struct ieee80211_vif *vif; | ||
353 | unsigned int rxfilter; | ||
354 | struct tasklet_struct wmi_tasklet; | ||
355 | struct tasklet_struct rx_tasklet; | ||
356 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | ||
357 | struct ath9k_htc_rx rx; | ||
358 | struct tasklet_struct tx_tasklet; | ||
359 | struct sk_buff_head tx_queue; | ||
360 | struct ath9k_htc_aggr_work aggr_work; | ||
361 | struct delayed_work ath9k_aggr_work; | ||
362 | struct delayed_work ath9k_ani_work; | ||
363 | |||
364 | struct ath_led radio_led; | ||
365 | struct ath_led assoc_led; | ||
366 | struct ath_led tx_led; | ||
367 | struct ath_led rx_led; | ||
368 | struct delayed_work ath9k_led_blink_work; | ||
369 | int led_on_duration; | ||
370 | int led_off_duration; | ||
371 | int led_on_cnt; | ||
372 | int led_off_cnt; | ||
373 | int hwq_map[ATH9K_WME_AC_VO+1]; | ||
374 | |||
375 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
376 | struct ath9k_debug debug; | ||
377 | #endif | ||
378 | struct ath9k_htc_target_rate tgt_rate; | ||
379 | |||
380 | struct mutex mutex; | ||
381 | }; | ||
382 | |||
383 | static inline void ath_read_cachesize(struct ath_common *common, int *csz) | ||
384 | { | ||
385 | common->bus_ops->read_cachesize(common, csz); | ||
386 | } | ||
387 | |||
388 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | ||
389 | struct ieee80211_vif *vif, | ||
390 | struct ieee80211_bss_conf *bss_conf); | ||
391 | void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending); | ||
392 | void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv, | ||
393 | struct ieee80211_vif *vif); | ||
394 | |||
395 | void ath9k_htc_rxep(void *priv, struct sk_buff *skb, | ||
396 | enum htc_endpoint_id ep_id); | ||
397 | void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, | ||
398 | bool txok); | ||
399 | |||
400 | void ath9k_htc_station_work(struct work_struct *work); | ||
401 | void ath9k_htc_aggr_work(struct work_struct *work); | ||
402 | void ath9k_ani_work(struct work_struct *work);; | ||
403 | |||
404 | int ath9k_tx_init(struct ath9k_htc_priv *priv); | ||
405 | void ath9k_tx_tasklet(unsigned long data); | ||
406 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb); | ||
407 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv); | ||
408 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, | ||
409 | enum ath9k_tx_queue_subtype qtype); | ||
410 | int get_hw_qnum(u16 queue, int *hwq_map); | ||
411 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | ||
412 | struct ath9k_tx_queue_info *qinfo); | ||
413 | |||
414 | int ath9k_rx_init(struct ath9k_htc_priv *priv); | ||
415 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); | ||
416 | void ath9k_host_rx_init(struct ath9k_htc_priv *priv); | ||
417 | void ath9k_rx_tasklet(unsigned long data); | ||
418 | |||
419 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); | ||
420 | void ath9k_init_leds(struct ath9k_htc_priv *priv); | ||
421 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv); | ||
422 | |||
423 | int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, | ||
424 | u16 devid); | ||
425 | void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug); | ||
426 | #ifdef CONFIG_PM | ||
427 | int ath9k_htc_resume(struct htc_target *htc_handle); | ||
428 | #endif | ||
429 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
430 | int ath9k_htc_debug_create_root(void); | ||
431 | void ath9k_htc_debug_remove_root(void); | ||
432 | int ath9k_htc_init_debug(struct ath_hw *ah); | ||
433 | void ath9k_htc_exit_debug(struct ath_hw *ah); | ||
434 | #else | ||
435 | static inline int ath9k_htc_debug_create_root(void) { return 0; }; | ||
436 | static inline void ath9k_htc_debug_remove_root(void) {}; | ||
437 | static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; | ||
438 | static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {}; | ||
439 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ | ||
440 | |||
441 | #endif /* HTC_H */ | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c new file mode 100644 index 000000000000..25f5b5377bac --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | #define FUDGE 2 | ||
20 | |||
21 | static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, | ||
22 | struct ieee80211_bss_conf *bss_conf) | ||
23 | { | ||
24 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
25 | struct ath9k_beacon_state bs; | ||
26 | enum ath9k_int imask = 0; | ||
27 | int dtimperiod, dtimcount, sleepduration; | ||
28 | int cfpperiod, cfpcount, bmiss_timeout; | ||
29 | u32 nexttbtt = 0, intval, tsftu, htc_imask = 0; | ||
30 | u64 tsf; | ||
31 | int num_beacons, offset, dtim_dec_count, cfp_dec_count; | ||
32 | int ret; | ||
33 | u8 cmd_rsp; | ||
34 | |||
35 | memset(&bs, 0, sizeof(bs)); | ||
36 | |||
37 | intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD; | ||
38 | bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_int); | ||
39 | |||
40 | /* | ||
41 | * Setup dtim and cfp parameters according to | ||
42 | * last beacon we received (which may be none). | ||
43 | */ | ||
44 | dtimperiod = bss_conf->dtim_period; | ||
45 | if (dtimperiod <= 0) /* NB: 0 if not known */ | ||
46 | dtimperiod = 1; | ||
47 | dtimcount = 1; | ||
48 | if (dtimcount >= dtimperiod) /* NB: sanity check */ | ||
49 | dtimcount = 0; | ||
50 | cfpperiod = 1; /* NB: no PCF support yet */ | ||
51 | cfpcount = 0; | ||
52 | |||
53 | sleepduration = intval; | ||
54 | if (sleepduration <= 0) | ||
55 | sleepduration = intval; | ||
56 | |||
57 | /* | ||
58 | * Pull nexttbtt forward to reflect the current | ||
59 | * TSF and calculate dtim+cfp state for the result. | ||
60 | */ | ||
61 | tsf = ath9k_hw_gettsf64(priv->ah); | ||
62 | tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; | ||
63 | |||
64 | num_beacons = tsftu / intval + 1; | ||
65 | offset = tsftu % intval; | ||
66 | nexttbtt = tsftu - offset; | ||
67 | if (offset) | ||
68 | nexttbtt += intval; | ||
69 | |||
70 | /* DTIM Beacon every dtimperiod Beacon */ | ||
71 | dtim_dec_count = num_beacons % dtimperiod; | ||
72 | /* CFP every cfpperiod DTIM Beacon */ | ||
73 | cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod; | ||
74 | if (dtim_dec_count) | ||
75 | cfp_dec_count++; | ||
76 | |||
77 | dtimcount -= dtim_dec_count; | ||
78 | if (dtimcount < 0) | ||
79 | dtimcount += dtimperiod; | ||
80 | |||
81 | cfpcount -= cfp_dec_count; | ||
82 | if (cfpcount < 0) | ||
83 | cfpcount += cfpperiod; | ||
84 | |||
85 | bs.bs_intval = intval; | ||
86 | bs.bs_nexttbtt = nexttbtt; | ||
87 | bs.bs_dtimperiod = dtimperiod*intval; | ||
88 | bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval; | ||
89 | bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod; | ||
90 | bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod; | ||
91 | bs.bs_cfpmaxduration = 0; | ||
92 | |||
93 | /* | ||
94 | * Calculate the number of consecutive beacons to miss* before taking | ||
95 | * a BMISS interrupt. The configuration is specified in TU so we only | ||
96 | * need calculate based on the beacon interval. Note that we clamp the | ||
97 | * result to at most 15 beacons. | ||
98 | */ | ||
99 | if (sleepduration > intval) { | ||
100 | bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2; | ||
101 | } else { | ||
102 | bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval); | ||
103 | if (bs.bs_bmissthreshold > 15) | ||
104 | bs.bs_bmissthreshold = 15; | ||
105 | else if (bs.bs_bmissthreshold <= 0) | ||
106 | bs.bs_bmissthreshold = 1; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Calculate sleep duration. The configuration is given in ms. | ||
111 | * We ensure a multiple of the beacon period is used. Also, if the sleep | ||
112 | * duration is greater than the DTIM period then it makes senses | ||
113 | * to make it a multiple of that. | ||
114 | * | ||
115 | * XXX fixed at 100ms | ||
116 | */ | ||
117 | |||
118 | bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration); | ||
119 | if (bs.bs_sleepduration > bs.bs_dtimperiod) | ||
120 | bs.bs_sleepduration = bs.bs_dtimperiod; | ||
121 | |||
122 | /* TSF out of range threshold fixed at 1 second */ | ||
123 | bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; | ||
124 | |||
125 | ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); | ||
126 | ath_print(common, ATH_DBG_BEACON, | ||
127 | "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", | ||
128 | bs.bs_bmissthreshold, bs.bs_sleepduration, | ||
129 | bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); | ||
130 | |||
131 | /* Set the computed STA beacon timers */ | ||
132 | |||
133 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
134 | ath9k_hw_set_sta_beacon_timers(priv->ah, &bs); | ||
135 | imask |= ATH9K_INT_BMISS; | ||
136 | htc_imask = cpu_to_be32(imask); | ||
137 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | ||
138 | } | ||
139 | |||
140 | static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, | ||
141 | struct ieee80211_bss_conf *bss_conf) | ||
142 | { | ||
143 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
144 | enum ath9k_int imask = 0; | ||
145 | u32 nexttbtt, intval, htc_imask = 0; | ||
146 | int ret; | ||
147 | u8 cmd_rsp; | ||
148 | |||
149 | intval = bss_conf->beacon_int & ATH9K_BEACON_PERIOD; | ||
150 | nexttbtt = intval; | ||
151 | intval |= ATH9K_BEACON_ENA; | ||
152 | if (priv->op_flags & OP_ENABLE_BEACON) | ||
153 | imask |= ATH9K_INT_SWBA; | ||
154 | |||
155 | ath_print(common, ATH_DBG_BEACON, | ||
156 | "IBSS Beacon config, intval: %d, imask: 0x%x\n", | ||
157 | bss_conf->beacon_int, imask); | ||
158 | |||
159 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
160 | ath9k_hw_beaconinit(priv->ah, nexttbtt, intval); | ||
161 | priv->bmiss_cnt = 0; | ||
162 | htc_imask = cpu_to_be32(imask); | ||
163 | WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask); | ||
164 | } | ||
165 | |||
166 | void ath9k_htc_beacon_update(struct ath9k_htc_priv *priv, | ||
167 | struct ieee80211_vif *vif) | ||
168 | { | ||
169 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
170 | |||
171 | spin_lock_bh(&priv->beacon_lock); | ||
172 | |||
173 | if (priv->beacon) | ||
174 | dev_kfree_skb_any(priv->beacon); | ||
175 | |||
176 | priv->beacon = ieee80211_beacon_get(priv->hw, vif); | ||
177 | if (!priv->beacon) | ||
178 | ath_print(common, ATH_DBG_BEACON, | ||
179 | "Unable to allocate beacon\n"); | ||
180 | |||
181 | spin_unlock_bh(&priv->beacon_lock); | ||
182 | } | ||
183 | |||
184 | void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending) | ||
185 | { | ||
186 | struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv; | ||
187 | struct tx_beacon_header beacon_hdr; | ||
188 | struct ath9k_htc_tx_ctl tx_ctl; | ||
189 | struct ieee80211_tx_info *info; | ||
190 | u8 *tx_fhdr; | ||
191 | |||
192 | memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header)); | ||
193 | memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); | ||
194 | |||
195 | /* FIXME: Handle BMISS */ | ||
196 | if (beacon_pending != 0) { | ||
197 | priv->bmiss_cnt++; | ||
198 | return; | ||
199 | } | ||
200 | |||
201 | spin_lock_bh(&priv->beacon_lock); | ||
202 | |||
203 | if (unlikely(priv->op_flags & OP_SCANNING)) { | ||
204 | spin_unlock_bh(&priv->beacon_lock); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | if (unlikely(priv->beacon == NULL)) { | ||
209 | spin_unlock_bh(&priv->beacon_lock); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | /* Free the old SKB first */ | ||
214 | dev_kfree_skb_any(priv->beacon); | ||
215 | |||
216 | /* Get a new beacon */ | ||
217 | priv->beacon = ieee80211_beacon_get(priv->hw, priv->vif); | ||
218 | if (!priv->beacon) { | ||
219 | spin_unlock_bh(&priv->beacon_lock); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | info = IEEE80211_SKB_CB(priv->beacon); | ||
224 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | ||
225 | struct ieee80211_hdr *hdr = | ||
226 | (struct ieee80211_hdr *) priv->beacon->data; | ||
227 | priv->seq_no += 0x10; | ||
228 | hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); | ||
229 | hdr->seq_ctrl |= cpu_to_le16(priv->seq_no); | ||
230 | } | ||
231 | |||
232 | tx_ctl.type = ATH9K_HTC_NORMAL; | ||
233 | beacon_hdr.vif_index = avp->index; | ||
234 | tx_fhdr = skb_push(priv->beacon, sizeof(beacon_hdr)); | ||
235 | memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr)); | ||
236 | |||
237 | htc_send(priv->htc, priv->beacon, priv->beacon_ep, &tx_ctl); | ||
238 | |||
239 | spin_unlock_bh(&priv->beacon_lock); | ||
240 | } | ||
241 | |||
242 | void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | ||
243 | struct ieee80211_vif *vif, | ||
244 | struct ieee80211_bss_conf *bss_conf) | ||
245 | { | ||
246 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
247 | |||
248 | switch (vif->type) { | ||
249 | case NL80211_IFTYPE_STATION: | ||
250 | ath9k_htc_beacon_config_sta(priv, bss_conf); | ||
251 | break; | ||
252 | case NL80211_IFTYPE_ADHOC: | ||
253 | ath9k_htc_beacon_config_adhoc(priv, bss_conf); | ||
254 | break; | ||
255 | default: | ||
256 | ath_print(common, ATH_DBG_CONFIG, | ||
257 | "Unsupported beaconing mode\n"); | ||
258 | return; | ||
259 | } | ||
260 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c new file mode 100644 index 000000000000..10c87605d2c4 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -0,0 +1,713 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | MODULE_AUTHOR("Atheros Communications"); | ||
20 | MODULE_LICENSE("Dual BSD/GPL"); | ||
21 | MODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices"); | ||
22 | |||
23 | static unsigned int ath9k_debug = ATH_DBG_DEFAULT; | ||
24 | module_param_named(debug, ath9k_debug, uint, 0); | ||
25 | MODULE_PARM_DESC(debug, "Debugging mask"); | ||
26 | |||
27 | int htc_modparam_nohwcrypt; | ||
28 | module_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444); | ||
29 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | ||
30 | |||
31 | #define CHAN2G(_freq, _idx) { \ | ||
32 | .center_freq = (_freq), \ | ||
33 | .hw_value = (_idx), \ | ||
34 | .max_power = 20, \ | ||
35 | } | ||
36 | |||
37 | static struct ieee80211_channel ath9k_2ghz_channels[] = { | ||
38 | CHAN2G(2412, 0), /* Channel 1 */ | ||
39 | CHAN2G(2417, 1), /* Channel 2 */ | ||
40 | CHAN2G(2422, 2), /* Channel 3 */ | ||
41 | CHAN2G(2427, 3), /* Channel 4 */ | ||
42 | CHAN2G(2432, 4), /* Channel 5 */ | ||
43 | CHAN2G(2437, 5), /* Channel 6 */ | ||
44 | CHAN2G(2442, 6), /* Channel 7 */ | ||
45 | CHAN2G(2447, 7), /* Channel 8 */ | ||
46 | CHAN2G(2452, 8), /* Channel 9 */ | ||
47 | CHAN2G(2457, 9), /* Channel 10 */ | ||
48 | CHAN2G(2462, 10), /* Channel 11 */ | ||
49 | CHAN2G(2467, 11), /* Channel 12 */ | ||
50 | CHAN2G(2472, 12), /* Channel 13 */ | ||
51 | CHAN2G(2484, 13), /* Channel 14 */ | ||
52 | }; | ||
53 | |||
54 | /* Atheros hardware rate code addition for short premble */ | ||
55 | #define SHPCHECK(__hw_rate, __flags) \ | ||
56 | ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0) | ||
57 | |||
58 | #define RATE(_bitrate, _hw_rate, _flags) { \ | ||
59 | .bitrate = (_bitrate), \ | ||
60 | .flags = (_flags), \ | ||
61 | .hw_value = (_hw_rate), \ | ||
62 | .hw_value_short = (SHPCHECK(_hw_rate, _flags)) \ | ||
63 | } | ||
64 | |||
65 | static struct ieee80211_rate ath9k_legacy_rates[] = { | ||
66 | RATE(10, 0x1b, 0), | ||
67 | RATE(20, 0x1a, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp : 0x1e */ | ||
68 | RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */ | ||
69 | RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */ | ||
70 | RATE(60, 0x0b, 0), | ||
71 | RATE(90, 0x0f, 0), | ||
72 | RATE(120, 0x0a, 0), | ||
73 | RATE(180, 0x0e, 0), | ||
74 | RATE(240, 0x09, 0), | ||
75 | RATE(360, 0x0d, 0), | ||
76 | RATE(480, 0x08, 0), | ||
77 | RATE(540, 0x0c, 0), | ||
78 | }; | ||
79 | |||
80 | static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) | ||
81 | { | ||
82 | int time_left; | ||
83 | |||
84 | /* Firmware can take up to 50ms to get ready, to be safe use 1 second */ | ||
85 | time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ); | ||
86 | if (!time_left) { | ||
87 | dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n"); | ||
88 | return -ETIMEDOUT; | ||
89 | } | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static void ath9k_deinit_priv(struct ath9k_htc_priv *priv) | ||
95 | { | ||
96 | ath9k_htc_exit_debug(priv->ah); | ||
97 | ath9k_hw_deinit(priv->ah); | ||
98 | tasklet_kill(&priv->wmi_tasklet); | ||
99 | tasklet_kill(&priv->rx_tasklet); | ||
100 | tasklet_kill(&priv->tx_tasklet); | ||
101 | kfree(priv->ah); | ||
102 | priv->ah = NULL; | ||
103 | } | ||
104 | |||
105 | static void ath9k_deinit_device(struct ath9k_htc_priv *priv) | ||
106 | { | ||
107 | struct ieee80211_hw *hw = priv->hw; | ||
108 | |||
109 | wiphy_rfkill_stop_polling(hw->wiphy); | ||
110 | ath9k_deinit_leds(priv); | ||
111 | ieee80211_unregister_hw(hw); | ||
112 | ath9k_rx_cleanup(priv); | ||
113 | ath9k_tx_cleanup(priv); | ||
114 | ath9k_deinit_priv(priv); | ||
115 | } | ||
116 | |||
117 | static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv, | ||
118 | u16 service_id, | ||
119 | void (*tx) (void *, | ||
120 | struct sk_buff *, | ||
121 | enum htc_endpoint_id, | ||
122 | bool txok), | ||
123 | enum htc_endpoint_id *ep_id) | ||
124 | { | ||
125 | struct htc_service_connreq req; | ||
126 | |||
127 | memset(&req, 0, sizeof(struct htc_service_connreq)); | ||
128 | |||
129 | req.service_id = service_id; | ||
130 | req.ep_callbacks.priv = priv; | ||
131 | req.ep_callbacks.rx = ath9k_htc_rxep; | ||
132 | req.ep_callbacks.tx = tx; | ||
133 | |||
134 | return htc_connect_service(priv->htc, &req, ep_id); | ||
135 | } | ||
136 | |||
137 | static int ath9k_init_htc_services(struct ath9k_htc_priv *priv) | ||
138 | { | ||
139 | int ret; | ||
140 | |||
141 | /* WMI CMD*/ | ||
142 | ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep); | ||
143 | if (ret) | ||
144 | goto err; | ||
145 | |||
146 | /* Beacon */ | ||
147 | ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, NULL, | ||
148 | &priv->beacon_ep); | ||
149 | if (ret) | ||
150 | goto err; | ||
151 | |||
152 | /* CAB */ | ||
153 | ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep, | ||
154 | &priv->cab_ep); | ||
155 | if (ret) | ||
156 | goto err; | ||
157 | |||
158 | |||
159 | /* UAPSD */ | ||
160 | ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep, | ||
161 | &priv->uapsd_ep); | ||
162 | if (ret) | ||
163 | goto err; | ||
164 | |||
165 | /* MGMT */ | ||
166 | ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep, | ||
167 | &priv->mgmt_ep); | ||
168 | if (ret) | ||
169 | goto err; | ||
170 | |||
171 | /* DATA BE */ | ||
172 | ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep, | ||
173 | &priv->data_be_ep); | ||
174 | if (ret) | ||
175 | goto err; | ||
176 | |||
177 | /* DATA BK */ | ||
178 | ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep, | ||
179 | &priv->data_bk_ep); | ||
180 | if (ret) | ||
181 | goto err; | ||
182 | |||
183 | /* DATA VI */ | ||
184 | ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep, | ||
185 | &priv->data_vi_ep); | ||
186 | if (ret) | ||
187 | goto err; | ||
188 | |||
189 | /* DATA VO */ | ||
190 | ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep, | ||
191 | &priv->data_vo_ep); | ||
192 | if (ret) | ||
193 | goto err; | ||
194 | |||
195 | ret = htc_init(priv->htc); | ||
196 | if (ret) | ||
197 | goto err; | ||
198 | |||
199 | return 0; | ||
200 | |||
201 | err: | ||
202 | dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n"); | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | static int ath9k_reg_notifier(struct wiphy *wiphy, | ||
207 | struct regulatory_request *request) | ||
208 | { | ||
209 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
210 | struct ath9k_htc_priv *priv = hw->priv; | ||
211 | |||
212 | return ath_reg_notifier_apply(wiphy, request, | ||
213 | ath9k_hw_regulatory(priv->ah)); | ||
214 | } | ||
215 | |||
216 | static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) | ||
217 | { | ||
218 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
219 | struct ath_common *common = ath9k_hw_common(ah); | ||
220 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; | ||
221 | __be32 val, reg = cpu_to_be32(reg_offset); | ||
222 | int r; | ||
223 | |||
224 | r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID, | ||
225 | (u8 *) ®, sizeof(reg), | ||
226 | (u8 *) &val, sizeof(val), | ||
227 | 100); | ||
228 | if (unlikely(r)) { | ||
229 | ath_print(common, ATH_DBG_WMI, | ||
230 | "REGISTER READ FAILED: (0x%04x, %d)\n", | ||
231 | reg_offset, r); | ||
232 | return -EIO; | ||
233 | } | ||
234 | |||
235 | return be32_to_cpu(val); | ||
236 | } | ||
237 | |||
238 | static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) | ||
239 | { | ||
240 | struct ath_hw *ah = (struct ath_hw *) hw_priv; | ||
241 | struct ath_common *common = ath9k_hw_common(ah); | ||
242 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; | ||
243 | __be32 buf[2] = { | ||
244 | cpu_to_be32(reg_offset), | ||
245 | cpu_to_be32(val), | ||
246 | }; | ||
247 | int r; | ||
248 | |||
249 | r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID, | ||
250 | (u8 *) &buf, sizeof(buf), | ||
251 | (u8 *) &val, sizeof(val), | ||
252 | 100); | ||
253 | if (unlikely(r)) { | ||
254 | ath_print(common, ATH_DBG_WMI, | ||
255 | "REGISTER WRITE FAILED:(0x%04x, %d)\n", | ||
256 | reg_offset, r); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static const struct ath_ops ath9k_common_ops = { | ||
261 | .read = ath9k_ioread32, | ||
262 | .write = ath9k_iowrite32, | ||
263 | }; | ||
264 | |||
265 | static void ath_usb_read_cachesize(struct ath_common *common, int *csz) | ||
266 | { | ||
267 | *csz = L1_CACHE_BYTES >> 2; | ||
268 | } | ||
269 | |||
270 | static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data) | ||
271 | { | ||
272 | struct ath_hw *ah = (struct ath_hw *) common->ah; | ||
273 | |||
274 | (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); | ||
275 | |||
276 | if (!ath9k_hw_wait(ah, | ||
277 | AR_EEPROM_STATUS_DATA, | ||
278 | AR_EEPROM_STATUS_DATA_BUSY | | ||
279 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, | ||
280 | AH_WAIT_TIMEOUT)) | ||
281 | return false; | ||
282 | |||
283 | *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), | ||
284 | AR_EEPROM_STATUS_DATA_VAL); | ||
285 | |||
286 | return true; | ||
287 | } | ||
288 | |||
289 | static const struct ath_bus_ops ath9k_usb_bus_ops = { | ||
290 | .read_cachesize = ath_usb_read_cachesize, | ||
291 | .eeprom_read = ath_usb_eeprom_read, | ||
292 | }; | ||
293 | |||
294 | static void setup_ht_cap(struct ath9k_htc_priv *priv, | ||
295 | struct ieee80211_sta_ht_cap *ht_info) | ||
296 | { | ||
297 | ht_info->ht_supported = true; | ||
298 | ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | ||
299 | IEEE80211_HT_CAP_SM_PS | | ||
300 | IEEE80211_HT_CAP_SGI_40 | | ||
301 | IEEE80211_HT_CAP_DSSSCCK40; | ||
302 | |||
303 | ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; | ||
304 | ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; | ||
305 | |||
306 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | ||
307 | ht_info->mcs.rx_mask[0] = 0xff; | ||
308 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; | ||
309 | } | ||
310 | |||
311 | static int ath9k_init_queues(struct ath9k_htc_priv *priv) | ||
312 | { | ||
313 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
314 | int i; | ||
315 | |||
316 | for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++) | ||
317 | priv->hwq_map[i] = -1; | ||
318 | |||
319 | if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) { | ||
320 | ath_print(common, ATH_DBG_FATAL, | ||
321 | "Unable to setup xmit queue for BE traffic\n"); | ||
322 | goto err; | ||
323 | } | ||
324 | |||
325 | if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BK)) { | ||
326 | ath_print(common, ATH_DBG_FATAL, | ||
327 | "Unable to setup xmit queue for BK traffic\n"); | ||
328 | goto err; | ||
329 | } | ||
330 | if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VI)) { | ||
331 | ath_print(common, ATH_DBG_FATAL, | ||
332 | "Unable to setup xmit queue for VI traffic\n"); | ||
333 | goto err; | ||
334 | } | ||
335 | if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VO)) { | ||
336 | ath_print(common, ATH_DBG_FATAL, | ||
337 | "Unable to setup xmit queue for VO traffic\n"); | ||
338 | goto err; | ||
339 | } | ||
340 | |||
341 | return 0; | ||
342 | |||
343 | err: | ||
344 | return -EINVAL; | ||
345 | } | ||
346 | |||
347 | static void ath9k_init_crypto(struct ath9k_htc_priv *priv) | ||
348 | { | ||
349 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
350 | int i = 0; | ||
351 | |||
352 | /* Get the hardware key cache size. */ | ||
353 | common->keymax = priv->ah->caps.keycache_size; | ||
354 | if (common->keymax > ATH_KEYMAX) { | ||
355 | ath_print(common, ATH_DBG_ANY, | ||
356 | "Warning, using only %u entries in %u key cache\n", | ||
357 | ATH_KEYMAX, common->keymax); | ||
358 | common->keymax = ATH_KEYMAX; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * Reset the key cache since some parts do not | ||
363 | * reset the contents on initial power up. | ||
364 | */ | ||
365 | for (i = 0; i < common->keymax; i++) | ||
366 | ath9k_hw_keyreset(priv->ah, (u16) i); | ||
367 | |||
368 | if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, | ||
369 | ATH9K_CIPHER_TKIP, NULL)) { | ||
370 | /* | ||
371 | * Whether we should enable h/w TKIP MIC. | ||
372 | * XXX: if we don't support WME TKIP MIC, then we wouldn't | ||
373 | * report WMM capable, so it's always safe to turn on | ||
374 | * TKIP MIC in this case. | ||
375 | */ | ||
376 | ath9k_hw_setcapability(priv->ah, ATH9K_CAP_TKIP_MIC, 0, 1, NULL); | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Check whether the separate key cache entries | ||
381 | * are required to handle both tx+rx MIC keys. | ||
382 | * With split mic keys the number of stations is limited | ||
383 | * to 27 otherwise 59. | ||
384 | */ | ||
385 | if (ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, | ||
386 | ATH9K_CIPHER_TKIP, NULL) | ||
387 | && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER, | ||
388 | ATH9K_CIPHER_MIC, NULL) | ||
389 | && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_TKIP_SPLIT, | ||
390 | 0, NULL)) | ||
391 | common->splitmic = 1; | ||
392 | |||
393 | /* turn on mcast key search if possible */ | ||
394 | if (!ath9k_hw_getcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) | ||
395 | (void)ath9k_hw_setcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, | ||
396 | 1, 1, NULL); | ||
397 | } | ||
398 | |||
399 | static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) | ||
400 | { | ||
401 | if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) { | ||
402 | priv->sbands[IEEE80211_BAND_2GHZ].channels = | ||
403 | ath9k_2ghz_channels; | ||
404 | priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; | ||
405 | priv->sbands[IEEE80211_BAND_2GHZ].n_channels = | ||
406 | ARRAY_SIZE(ath9k_2ghz_channels); | ||
407 | priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates; | ||
408 | priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates = | ||
409 | ARRAY_SIZE(ath9k_legacy_rates); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static void ath9k_init_misc(struct ath9k_htc_priv *priv) | ||
414 | { | ||
415 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
416 | |||
417 | common->tx_chainmask = priv->ah->caps.tx_chainmask; | ||
418 | common->rx_chainmask = priv->ah->caps.rx_chainmask; | ||
419 | |||
420 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | ||
421 | memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); | ||
422 | |||
423 | priv->op_flags |= OP_TXAGGR; | ||
424 | } | ||
425 | |||
426 | static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid) | ||
427 | { | ||
428 | struct ath_hw *ah = NULL; | ||
429 | struct ath_common *common; | ||
430 | int ret = 0, csz = 0; | ||
431 | |||
432 | priv->op_flags |= OP_INVALID; | ||
433 | |||
434 | ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); | ||
435 | if (!ah) | ||
436 | return -ENOMEM; | ||
437 | |||
438 | ah->hw_version.devid = devid; | ||
439 | ah->hw_version.subsysid = 0; /* FIXME */ | ||
440 | priv->ah = ah; | ||
441 | |||
442 | common = ath9k_hw_common(ah); | ||
443 | common->ops = &ath9k_common_ops; | ||
444 | common->bus_ops = &ath9k_usb_bus_ops; | ||
445 | common->ah = ah; | ||
446 | common->hw = priv->hw; | ||
447 | common->priv = priv; | ||
448 | common->debug_mask = ath9k_debug; | ||
449 | |||
450 | spin_lock_init(&priv->wmi->wmi_lock); | ||
451 | spin_lock_init(&priv->beacon_lock); | ||
452 | mutex_init(&priv->mutex); | ||
453 | mutex_init(&priv->aggr_work.mutex); | ||
454 | tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet, | ||
455 | (unsigned long)priv); | ||
456 | tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet, | ||
457 | (unsigned long)priv); | ||
458 | tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv); | ||
459 | INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work); | ||
460 | INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work); | ||
461 | |||
462 | /* | ||
463 | * Cache line size is used to size and align various | ||
464 | * structures used to communicate with the hardware. | ||
465 | */ | ||
466 | ath_read_cachesize(common, &csz); | ||
467 | common->cachelsz = csz << 2; /* convert to bytes */ | ||
468 | |||
469 | ret = ath9k_hw_init(ah); | ||
470 | if (ret) { | ||
471 | ath_print(common, ATH_DBG_FATAL, | ||
472 | "Unable to initialize hardware; " | ||
473 | "initialization status: %d\n", ret); | ||
474 | goto err_hw; | ||
475 | } | ||
476 | |||
477 | ret = ath9k_htc_init_debug(ah); | ||
478 | if (ret) { | ||
479 | ath_print(common, ATH_DBG_FATAL, | ||
480 | "Unable to create debugfs files\n"); | ||
481 | goto err_debug; | ||
482 | } | ||
483 | |||
484 | ret = ath9k_init_queues(priv); | ||
485 | if (ret) | ||
486 | goto err_queues; | ||
487 | |||
488 | ath9k_init_crypto(priv); | ||
489 | ath9k_init_channels_rates(priv); | ||
490 | ath9k_init_misc(priv); | ||
491 | |||
492 | return 0; | ||
493 | |||
494 | err_queues: | ||
495 | ath9k_htc_exit_debug(ah); | ||
496 | err_debug: | ||
497 | ath9k_hw_deinit(ah); | ||
498 | err_hw: | ||
499 | |||
500 | kfree(ah); | ||
501 | priv->ah = NULL; | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, | ||
507 | struct ieee80211_hw *hw) | ||
508 | { | ||
509 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
510 | |||
511 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
512 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
513 | IEEE80211_HW_SPECTRUM_MGMT | | ||
514 | IEEE80211_HW_HAS_RATE_CONTROL; | ||
515 | |||
516 | hw->wiphy->interface_modes = | ||
517 | BIT(NL80211_IFTYPE_STATION) | | ||
518 | BIT(NL80211_IFTYPE_ADHOC); | ||
519 | |||
520 | hw->queues = 4; | ||
521 | hw->channel_change_time = 5000; | ||
522 | hw->max_listen_interval = 10; | ||
523 | hw->vif_data_size = sizeof(struct ath9k_htc_vif); | ||
524 | hw->sta_data_size = sizeof(struct ath9k_htc_sta); | ||
525 | |||
526 | /* tx_frame_hdr is larger than tx_mgmt_hdr anyway */ | ||
527 | hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) + | ||
528 | sizeof(struct htc_frame_hdr) + 4; | ||
529 | |||
530 | if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) | ||
531 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = | ||
532 | &priv->sbands[IEEE80211_BAND_2GHZ]; | ||
533 | |||
534 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) { | ||
535 | if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) | ||
536 | setup_ht_cap(priv, | ||
537 | &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap); | ||
538 | } | ||
539 | |||
540 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); | ||
541 | } | ||
542 | |||
543 | static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid) | ||
544 | { | ||
545 | struct ieee80211_hw *hw = priv->hw; | ||
546 | struct ath_common *common; | ||
547 | struct ath_hw *ah; | ||
548 | int error = 0; | ||
549 | struct ath_regulatory *reg; | ||
550 | |||
551 | /* Bring up device */ | ||
552 | error = ath9k_init_priv(priv, devid); | ||
553 | if (error != 0) | ||
554 | goto err_init; | ||
555 | |||
556 | ah = priv->ah; | ||
557 | common = ath9k_hw_common(ah); | ||
558 | ath9k_set_hw_capab(priv, hw); | ||
559 | |||
560 | /* Initialize regulatory */ | ||
561 | error = ath_regd_init(&common->regulatory, priv->hw->wiphy, | ||
562 | ath9k_reg_notifier); | ||
563 | if (error) | ||
564 | goto err_regd; | ||
565 | |||
566 | reg = &common->regulatory; | ||
567 | |||
568 | /* Setup TX */ | ||
569 | error = ath9k_tx_init(priv); | ||
570 | if (error != 0) | ||
571 | goto err_tx; | ||
572 | |||
573 | /* Setup RX */ | ||
574 | error = ath9k_rx_init(priv); | ||
575 | if (error != 0) | ||
576 | goto err_rx; | ||
577 | |||
578 | /* Register with mac80211 */ | ||
579 | error = ieee80211_register_hw(hw); | ||
580 | if (error) | ||
581 | goto err_register; | ||
582 | |||
583 | /* Handle world regulatory */ | ||
584 | if (!ath_is_world_regd(reg)) { | ||
585 | error = regulatory_hint(hw->wiphy, reg->alpha2); | ||
586 | if (error) | ||
587 | goto err_world; | ||
588 | } | ||
589 | |||
590 | ath9k_init_leds(priv); | ||
591 | ath9k_start_rfkill_poll(priv); | ||
592 | |||
593 | return 0; | ||
594 | |||
595 | err_world: | ||
596 | ieee80211_unregister_hw(hw); | ||
597 | err_register: | ||
598 | ath9k_rx_cleanup(priv); | ||
599 | err_rx: | ||
600 | ath9k_tx_cleanup(priv); | ||
601 | err_tx: | ||
602 | /* Nothing */ | ||
603 | err_regd: | ||
604 | ath9k_deinit_priv(priv); | ||
605 | err_init: | ||
606 | return error; | ||
607 | } | ||
608 | |||
609 | int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, | ||
610 | u16 devid) | ||
611 | { | ||
612 | struct ieee80211_hw *hw; | ||
613 | struct ath9k_htc_priv *priv; | ||
614 | int ret; | ||
615 | |||
616 | hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops); | ||
617 | if (!hw) | ||
618 | return -ENOMEM; | ||
619 | |||
620 | priv = hw->priv; | ||
621 | priv->hw = hw; | ||
622 | priv->htc = htc_handle; | ||
623 | priv->dev = dev; | ||
624 | htc_handle->drv_priv = priv; | ||
625 | SET_IEEE80211_DEV(hw, priv->dev); | ||
626 | |||
627 | ret = ath9k_htc_wait_for_target(priv); | ||
628 | if (ret) | ||
629 | goto err_free; | ||
630 | |||
631 | priv->wmi = ath9k_init_wmi(priv); | ||
632 | if (!priv->wmi) { | ||
633 | ret = -EINVAL; | ||
634 | goto err_free; | ||
635 | } | ||
636 | |||
637 | ret = ath9k_init_htc_services(priv); | ||
638 | if (ret) | ||
639 | goto err_init; | ||
640 | |||
641 | ret = ath9k_init_device(priv, devid); | ||
642 | if (ret) | ||
643 | goto err_init; | ||
644 | |||
645 | return 0; | ||
646 | |||
647 | err_init: | ||
648 | ath9k_deinit_wmi(priv); | ||
649 | err_free: | ||
650 | ieee80211_free_hw(hw); | ||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug) | ||
655 | { | ||
656 | if (htc_handle->drv_priv) { | ||
657 | ath9k_deinit_device(htc_handle->drv_priv); | ||
658 | ath9k_deinit_wmi(htc_handle->drv_priv); | ||
659 | ieee80211_free_hw(htc_handle->drv_priv->hw); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | #ifdef CONFIG_PM | ||
664 | int ath9k_htc_resume(struct htc_target *htc_handle) | ||
665 | { | ||
666 | int ret; | ||
667 | |||
668 | ret = ath9k_htc_wait_for_target(htc_handle->drv_priv); | ||
669 | if (ret) | ||
670 | return ret; | ||
671 | |||
672 | ret = ath9k_init_htc_services(htc_handle->drv_priv); | ||
673 | return ret; | ||
674 | } | ||
675 | #endif | ||
676 | |||
677 | static int __init ath9k_htc_init(void) | ||
678 | { | ||
679 | int error; | ||
680 | |||
681 | error = ath9k_htc_debug_create_root(); | ||
682 | if (error < 0) { | ||
683 | printk(KERN_ERR | ||
684 | "ath9k_htc: Unable to create debugfs root: %d\n", | ||
685 | error); | ||
686 | goto err_dbg; | ||
687 | } | ||
688 | |||
689 | error = ath9k_hif_usb_init(); | ||
690 | if (error < 0) { | ||
691 | printk(KERN_ERR | ||
692 | "ath9k_htc: No USB devices found," | ||
693 | " driver not installed.\n"); | ||
694 | error = -ENODEV; | ||
695 | goto err_usb; | ||
696 | } | ||
697 | |||
698 | return 0; | ||
699 | |||
700 | err_usb: | ||
701 | ath9k_htc_debug_remove_root(); | ||
702 | err_dbg: | ||
703 | return error; | ||
704 | } | ||
705 | module_init(ath9k_htc_init); | ||
706 | |||
707 | static void __exit ath9k_htc_exit(void) | ||
708 | { | ||
709 | ath9k_hif_usb_exit(); | ||
710 | ath9k_htc_debug_remove_root(); | ||
711 | printk(KERN_INFO "ath9k_htc: Driver unloaded\n"); | ||
712 | } | ||
713 | module_exit(ath9k_htc_exit); | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c new file mode 100644 index 000000000000..20a2c1341e20 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -0,0 +1,1626 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
20 | static struct dentry *ath9k_debugfs_root; | ||
21 | #endif | ||
22 | |||
23 | /*************/ | ||
24 | /* Utilities */ | ||
25 | /*************/ | ||
26 | |||
27 | static void ath_update_txpow(struct ath9k_htc_priv *priv) | ||
28 | { | ||
29 | struct ath_hw *ah = priv->ah; | ||
30 | u32 txpow; | ||
31 | |||
32 | if (priv->curtxpow != priv->txpowlimit) { | ||
33 | ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit); | ||
34 | /* read back in case value is clamped */ | ||
35 | ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); | ||
36 | priv->curtxpow = txpow; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | /* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */ | ||
41 | static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv, | ||
42 | struct ath9k_channel *ichan) | ||
43 | { | ||
44 | enum htc_phymode mode; | ||
45 | |||
46 | mode = HTC_MODE_AUTO; | ||
47 | |||
48 | switch (ichan->chanmode) { | ||
49 | case CHANNEL_G: | ||
50 | case CHANNEL_G_HT20: | ||
51 | case CHANNEL_G_HT40PLUS: | ||
52 | case CHANNEL_G_HT40MINUS: | ||
53 | mode = HTC_MODE_11NG; | ||
54 | break; | ||
55 | case CHANNEL_A: | ||
56 | case CHANNEL_A_HT20: | ||
57 | case CHANNEL_A_HT40PLUS: | ||
58 | case CHANNEL_A_HT40MINUS: | ||
59 | mode = HTC_MODE_11NA; | ||
60 | break; | ||
61 | default: | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | return mode; | ||
66 | } | ||
67 | |||
68 | static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | ||
69 | struct ieee80211_hw *hw, | ||
70 | struct ath9k_channel *hchan) | ||
71 | { | ||
72 | struct ath_hw *ah = priv->ah; | ||
73 | struct ath_common *common = ath9k_hw_common(ah); | ||
74 | struct ieee80211_conf *conf = &common->hw->conf; | ||
75 | bool fastcc = true; | ||
76 | struct ieee80211_channel *channel = hw->conf.channel; | ||
77 | enum htc_phymode mode; | ||
78 | u16 htc_mode; | ||
79 | u8 cmd_rsp; | ||
80 | int ret; | ||
81 | |||
82 | if (priv->op_flags & OP_INVALID) | ||
83 | return -EIO; | ||
84 | |||
85 | if (priv->op_flags & OP_FULL_RESET) | ||
86 | fastcc = false; | ||
87 | |||
88 | /* Fiddle around with fastcc later on, for now just use full reset */ | ||
89 | fastcc = false; | ||
90 | |||
91 | htc_stop(priv->htc); | ||
92 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
93 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
94 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
95 | |||
96 | ath_print(common, ATH_DBG_CONFIG, | ||
97 | "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n", | ||
98 | priv->ah->curchan->channel, | ||
99 | channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf)); | ||
100 | |||
101 | ret = ath9k_hw_reset(ah, hchan, fastcc); | ||
102 | if (ret) { | ||
103 | ath_print(common, ATH_DBG_FATAL, | ||
104 | "Unable to reset channel (%u Mhz) " | ||
105 | "reset status %d\n", channel->center_freq, ret); | ||
106 | goto err; | ||
107 | } | ||
108 | |||
109 | ath_update_txpow(priv); | ||
110 | |||
111 | WMI_CMD(WMI_START_RECV_CMDID); | ||
112 | if (ret) | ||
113 | goto err; | ||
114 | |||
115 | ath9k_host_rx_init(priv); | ||
116 | |||
117 | mode = ath9k_htc_get_curmode(priv, hchan); | ||
118 | htc_mode = cpu_to_be16(mode); | ||
119 | WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); | ||
120 | if (ret) | ||
121 | goto err; | ||
122 | |||
123 | WMI_CMD(WMI_ENABLE_INTR_CMDID); | ||
124 | if (ret) | ||
125 | goto err; | ||
126 | |||
127 | htc_start(priv->htc); | ||
128 | |||
129 | priv->op_flags &= ~OP_FULL_RESET; | ||
130 | err: | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) | ||
135 | { | ||
136 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
137 | struct ath9k_htc_target_vif hvif; | ||
138 | int ret = 0; | ||
139 | u8 cmd_rsp; | ||
140 | |||
141 | if (priv->nvifs > 0) | ||
142 | return -ENOBUFS; | ||
143 | |||
144 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
145 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
146 | |||
147 | hvif.opmode = cpu_to_be32(HTC_M_MONITOR); | ||
148 | priv->ah->opmode = NL80211_IFTYPE_MONITOR; | ||
149 | hvif.index = priv->nvifs; | ||
150 | |||
151 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | ||
152 | if (ret) | ||
153 | return ret; | ||
154 | |||
155 | priv->nvifs++; | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) | ||
160 | { | ||
161 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
162 | struct ath9k_htc_target_vif hvif; | ||
163 | int ret = 0; | ||
164 | u8 cmd_rsp; | ||
165 | |||
166 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
167 | memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); | ||
168 | hvif.index = 0; /* Should do for now */ | ||
169 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
170 | priv->nvifs--; | ||
171 | |||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, | ||
176 | struct ieee80211_vif *vif, | ||
177 | struct ieee80211_sta *sta) | ||
178 | { | ||
179 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
180 | struct ath9k_htc_target_sta tsta; | ||
181 | struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv; | ||
182 | struct ath9k_htc_sta *ista; | ||
183 | int ret; | ||
184 | u8 cmd_rsp; | ||
185 | |||
186 | if (priv->nstations >= ATH9K_HTC_MAX_STA) | ||
187 | return -ENOBUFS; | ||
188 | |||
189 | memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta)); | ||
190 | |||
191 | if (sta) { | ||
192 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
193 | memcpy(&tsta.macaddr, sta->addr, ETH_ALEN); | ||
194 | memcpy(&tsta.bssid, common->curbssid, ETH_ALEN); | ||
195 | tsta.associd = common->curaid; | ||
196 | tsta.is_vif_sta = 0; | ||
197 | tsta.valid = true; | ||
198 | ista->index = priv->nstations; | ||
199 | } else { | ||
200 | memcpy(&tsta.macaddr, vif->addr, ETH_ALEN); | ||
201 | tsta.is_vif_sta = 1; | ||
202 | } | ||
203 | |||
204 | tsta.sta_index = priv->nstations; | ||
205 | tsta.vif_index = avp->index; | ||
206 | tsta.maxampdu = 0xffff; | ||
207 | if (sta && sta->ht_cap.ht_supported) | ||
208 | tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); | ||
209 | |||
210 | WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta); | ||
211 | if (ret) { | ||
212 | if (sta) | ||
213 | ath_print(common, ATH_DBG_FATAL, | ||
214 | "Unable to add station entry for: %pM\n", sta->addr); | ||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | if (sta) | ||
219 | ath_print(common, ATH_DBG_CONFIG, | ||
220 | "Added a station entry for: %pM (idx: %d)\n", | ||
221 | sta->addr, tsta.sta_index); | ||
222 | |||
223 | priv->nstations++; | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, | ||
228 | struct ieee80211_vif *vif, | ||
229 | struct ieee80211_sta *sta) | ||
230 | { | ||
231 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
232 | struct ath9k_htc_sta *ista; | ||
233 | int ret; | ||
234 | u8 cmd_rsp, sta_idx; | ||
235 | |||
236 | if (sta) { | ||
237 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
238 | sta_idx = ista->index; | ||
239 | } else { | ||
240 | sta_idx = 0; | ||
241 | } | ||
242 | |||
243 | WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx); | ||
244 | if (ret) { | ||
245 | if (sta) | ||
246 | ath_print(common, ATH_DBG_FATAL, | ||
247 | "Unable to remove station entry for: %pM\n", | ||
248 | sta->addr); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | if (sta) | ||
253 | ath_print(common, ATH_DBG_CONFIG, | ||
254 | "Removed a station entry for: %pM (idx: %d)\n", | ||
255 | sta->addr, sta_idx); | ||
256 | |||
257 | priv->nstations--; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) | ||
262 | { | ||
263 | struct ath9k_htc_cap_target tcap; | ||
264 | int ret; | ||
265 | u8 cmd_rsp; | ||
266 | |||
267 | memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); | ||
268 | |||
269 | /* FIXME: Values are hardcoded */ | ||
270 | tcap.flags = 0x240c40; | ||
271 | tcap.flags_ext = 0x80601000; | ||
272 | tcap.ampdu_limit = 0xffff0000; | ||
273 | tcap.ampdu_subframes = 20; | ||
274 | tcap.tx_chainmask_legacy = 1; | ||
275 | tcap.protmode = 1; | ||
276 | tcap.tx_chainmask = 1; | ||
277 | |||
278 | WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv, | ||
284 | struct ieee80211_vif *vif, | ||
285 | struct ieee80211_sta *sta) | ||
286 | { | ||
287 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
288 | struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
289 | struct ieee80211_supported_band *sband; | ||
290 | struct ath9k_htc_target_rate trate; | ||
291 | u32 caps = 0; | ||
292 | u8 cmd_rsp; | ||
293 | int i, j, ret; | ||
294 | |||
295 | memset(&trate, 0, sizeof(trate)); | ||
296 | |||
297 | /* Only 2GHz is supported */ | ||
298 | sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; | ||
299 | |||
300 | for (i = 0, j = 0; i < sband->n_bitrates; i++) { | ||
301 | if (sta->supp_rates[sband->band] & BIT(i)) { | ||
302 | priv->tgt_rate.rates.legacy_rates.rs_rates[j] | ||
303 | = (sband->bitrates[i].bitrate * 2) / 10; | ||
304 | j++; | ||
305 | } | ||
306 | } | ||
307 | priv->tgt_rate.rates.legacy_rates.rs_nrates = j; | ||
308 | |||
309 | if (sta->ht_cap.ht_supported) { | ||
310 | for (i = 0, j = 0; i < 77; i++) { | ||
311 | if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) | ||
312 | priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i; | ||
313 | if (j == ATH_HTC_RATE_MAX) | ||
314 | break; | ||
315 | } | ||
316 | priv->tgt_rate.rates.ht_rates.rs_nrates = j; | ||
317 | |||
318 | caps = WLAN_RC_HT_FLAG; | ||
319 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | ||
320 | caps |= WLAN_RC_40_FLAG; | ||
321 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | ||
322 | caps |= WLAN_RC_SGI_FLAG; | ||
323 | |||
324 | } | ||
325 | |||
326 | priv->tgt_rate.sta_index = ista->index; | ||
327 | priv->tgt_rate.isnew = 1; | ||
328 | trate = priv->tgt_rate; | ||
329 | priv->tgt_rate.capflags = caps; | ||
330 | trate.capflags = cpu_to_be32(caps); | ||
331 | |||
332 | WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); | ||
333 | if (ret) { | ||
334 | ath_print(common, ATH_DBG_FATAL, | ||
335 | "Unable to initialize Rate information on target\n"); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | ath_print(common, ATH_DBG_CONFIG, | ||
340 | "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40) | ||
345 | { | ||
346 | struct ath9k_htc_priv *priv = hw->priv; | ||
347 | struct ieee80211_conf *conf = &hw->conf; | ||
348 | |||
349 | if (!conf_is_ht(conf)) | ||
350 | return false; | ||
351 | |||
352 | if (!(priv->op_flags & OP_ASSOCIATED) || | ||
353 | (priv->op_flags & OP_SCANNING)) | ||
354 | return false; | ||
355 | |||
356 | if (conf_is_ht40(conf)) { | ||
357 | if (priv->ah->curchan->chanmode & | ||
358 | (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) { | ||
359 | return false; | ||
360 | } else { | ||
361 | *cw40 = true; | ||
362 | return true; | ||
363 | } | ||
364 | } else { /* ht20 */ | ||
365 | if (priv->ah->curchan->chanmode & CHANNEL_HT20) | ||
366 | return false; | ||
367 | else | ||
368 | return true; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40) | ||
373 | { | ||
374 | struct ath9k_htc_target_rate trate; | ||
375 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
376 | int ret; | ||
377 | u8 cmd_rsp; | ||
378 | |||
379 | memset(&trate, 0, sizeof(trate)); | ||
380 | |||
381 | trate = priv->tgt_rate; | ||
382 | |||
383 | if (is_cw40) | ||
384 | priv->tgt_rate.capflags |= WLAN_RC_40_FLAG; | ||
385 | else | ||
386 | priv->tgt_rate.capflags &= ~WLAN_RC_40_FLAG; | ||
387 | |||
388 | trate.capflags = cpu_to_be32(priv->tgt_rate.capflags); | ||
389 | |||
390 | WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate); | ||
391 | if (ret) { | ||
392 | ath_print(common, ATH_DBG_FATAL, | ||
393 | "Unable to update Rate information on target\n"); | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | ath_print(common, ATH_DBG_CONFIG, "Rate control updated with " | ||
398 | "caps:0x%x on target\n", priv->tgt_rate.capflags); | ||
399 | } | ||
400 | |||
401 | static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv, | ||
402 | struct ieee80211_vif *vif, | ||
403 | u8 *sta_addr, u8 tid, bool oper) | ||
404 | { | ||
405 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
406 | struct ath9k_htc_target_aggr aggr; | ||
407 | struct ieee80211_sta *sta = NULL; | ||
408 | struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
409 | int ret = 0; | ||
410 | u8 cmd_rsp; | ||
411 | |||
412 | if (tid > ATH9K_HTC_MAX_TID) | ||
413 | return -EINVAL; | ||
414 | |||
415 | rcu_read_lock(); | ||
416 | sta = ieee80211_find_sta(vif, sta_addr); | ||
417 | if (sta) { | ||
418 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
419 | } else { | ||
420 | rcu_read_unlock(); | ||
421 | return -EINVAL; | ||
422 | } | ||
423 | |||
424 | if (!ista) { | ||
425 | rcu_read_unlock(); | ||
426 | return -EINVAL; | ||
427 | } | ||
428 | |||
429 | memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr)); | ||
430 | |||
431 | aggr.sta_index = ista->index; | ||
432 | rcu_read_unlock(); | ||
433 | aggr.tidno = tid; | ||
434 | aggr.aggr_enable = oper; | ||
435 | |||
436 | if (oper) | ||
437 | ista->tid_state[tid] = AGGR_START; | ||
438 | else | ||
439 | ista->tid_state[tid] = AGGR_STOP; | ||
440 | |||
441 | WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr); | ||
442 | if (ret) | ||
443 | ath_print(common, ATH_DBG_CONFIG, | ||
444 | "Unable to %s TX aggregation for (%pM, %d)\n", | ||
445 | (oper) ? "start" : "stop", sta->addr, tid); | ||
446 | else | ||
447 | ath_print(common, ATH_DBG_CONFIG, | ||
448 | "%s aggregation for (%pM, %d)\n", | ||
449 | (oper) ? "Starting" : "Stopping", sta->addr, tid); | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | void ath9k_htc_aggr_work(struct work_struct *work) | ||
455 | { | ||
456 | int ret = 0; | ||
457 | struct ath9k_htc_priv *priv = | ||
458 | container_of(work, struct ath9k_htc_priv, | ||
459 | ath9k_aggr_work.work); | ||
460 | struct ath9k_htc_aggr_work *wk = &priv->aggr_work; | ||
461 | |||
462 | mutex_lock(&wk->mutex); | ||
463 | |||
464 | switch (wk->action) { | ||
465 | case IEEE80211_AMPDU_TX_START: | ||
466 | ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, | ||
467 | wk->tid, true); | ||
468 | if (!ret) | ||
469 | ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr, | ||
470 | wk->tid); | ||
471 | break; | ||
472 | case IEEE80211_AMPDU_TX_STOP: | ||
473 | ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr, | ||
474 | wk->tid, false); | ||
475 | ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid); | ||
476 | break; | ||
477 | default: | ||
478 | ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, | ||
479 | "Unknown AMPDU action\n"); | ||
480 | } | ||
481 | |||
482 | mutex_unlock(&wk->mutex); | ||
483 | } | ||
484 | |||
485 | /*********/ | ||
486 | /* DEBUG */ | ||
487 | /*********/ | ||
488 | |||
489 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
490 | |||
491 | static int ath9k_debugfs_open(struct inode *inode, struct file *file) | ||
492 | { | ||
493 | file->private_data = inode->i_private; | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, | ||
498 | size_t count, loff_t *ppos) | ||
499 | { | ||
500 | struct ath9k_htc_priv *priv = | ||
501 | (struct ath9k_htc_priv *) file->private_data; | ||
502 | struct ath9k_htc_target_stats cmd_rsp; | ||
503 | char buf[512]; | ||
504 | unsigned int len = 0; | ||
505 | int ret = 0; | ||
506 | |||
507 | memset(&cmd_rsp, 0, sizeof(cmd_rsp)); | ||
508 | |||
509 | WMI_CMD(WMI_TGT_STATS_CMDID); | ||
510 | if (ret) | ||
511 | return -EINVAL; | ||
512 | |||
513 | |||
514 | len += snprintf(buf + len, sizeof(buf) - len, | ||
515 | "%19s : %10u\n", "TX Short Retries", | ||
516 | be32_to_cpu(cmd_rsp.tx_shortretry)); | ||
517 | len += snprintf(buf + len, sizeof(buf) - len, | ||
518 | "%19s : %10u\n", "TX Long Retries", | ||
519 | be32_to_cpu(cmd_rsp.tx_longretry)); | ||
520 | len += snprintf(buf + len, sizeof(buf) - len, | ||
521 | "%19s : %10u\n", "TX Xretries", | ||
522 | be32_to_cpu(cmd_rsp.tx_xretries)); | ||
523 | len += snprintf(buf + len, sizeof(buf) - len, | ||
524 | "%19s : %10u\n", "TX Unaggr. Xretries", | ||
525 | be32_to_cpu(cmd_rsp.ht_txunaggr_xretry)); | ||
526 | len += snprintf(buf + len, sizeof(buf) - len, | ||
527 | "%19s : %10u\n", "TX Xretries (HT)", | ||
528 | be32_to_cpu(cmd_rsp.ht_tx_xretries)); | ||
529 | len += snprintf(buf + len, sizeof(buf) - len, | ||
530 | "%19s : %10u\n", "TX Rate", priv->debug.txrate); | ||
531 | |||
532 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
533 | } | ||
534 | |||
535 | static const struct file_operations fops_tgt_stats = { | ||
536 | .read = read_file_tgt_stats, | ||
537 | .open = ath9k_debugfs_open, | ||
538 | .owner = THIS_MODULE | ||
539 | }; | ||
540 | |||
541 | static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | ||
542 | size_t count, loff_t *ppos) | ||
543 | { | ||
544 | struct ath9k_htc_priv *priv = | ||
545 | (struct ath9k_htc_priv *) file->private_data; | ||
546 | char buf[512]; | ||
547 | unsigned int len = 0; | ||
548 | |||
549 | len += snprintf(buf + len, sizeof(buf) - len, | ||
550 | "%20s : %10u\n", "Buffers queued", | ||
551 | priv->debug.tx_stats.buf_queued); | ||
552 | len += snprintf(buf + len, sizeof(buf) - len, | ||
553 | "%20s : %10u\n", "Buffers completed", | ||
554 | priv->debug.tx_stats.buf_completed); | ||
555 | len += snprintf(buf + len, sizeof(buf) - len, | ||
556 | "%20s : %10u\n", "SKBs queued", | ||
557 | priv->debug.tx_stats.skb_queued); | ||
558 | len += snprintf(buf + len, sizeof(buf) - len, | ||
559 | "%20s : %10u\n", "SKBs completed", | ||
560 | priv->debug.tx_stats.skb_completed); | ||
561 | |||
562 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
563 | } | ||
564 | |||
565 | static const struct file_operations fops_xmit = { | ||
566 | .read = read_file_xmit, | ||
567 | .open = ath9k_debugfs_open, | ||
568 | .owner = THIS_MODULE | ||
569 | }; | ||
570 | |||
571 | static ssize_t read_file_recv(struct file *file, char __user *user_buf, | ||
572 | size_t count, loff_t *ppos) | ||
573 | { | ||
574 | struct ath9k_htc_priv *priv = | ||
575 | (struct ath9k_htc_priv *) file->private_data; | ||
576 | char buf[512]; | ||
577 | unsigned int len = 0; | ||
578 | |||
579 | len += snprintf(buf + len, sizeof(buf) - len, | ||
580 | "%20s : %10u\n", "SKBs allocated", | ||
581 | priv->debug.rx_stats.skb_allocated); | ||
582 | len += snprintf(buf + len, sizeof(buf) - len, | ||
583 | "%20s : %10u\n", "SKBs completed", | ||
584 | priv->debug.rx_stats.skb_completed); | ||
585 | len += snprintf(buf + len, sizeof(buf) - len, | ||
586 | "%20s : %10u\n", "SKBs Dropped", | ||
587 | priv->debug.rx_stats.skb_dropped); | ||
588 | |||
589 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
590 | } | ||
591 | |||
592 | static const struct file_operations fops_recv = { | ||
593 | .read = read_file_recv, | ||
594 | .open = ath9k_debugfs_open, | ||
595 | .owner = THIS_MODULE | ||
596 | }; | ||
597 | |||
598 | int ath9k_htc_init_debug(struct ath_hw *ah) | ||
599 | { | ||
600 | struct ath_common *common = ath9k_hw_common(ah); | ||
601 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; | ||
602 | |||
603 | if (!ath9k_debugfs_root) | ||
604 | return -ENOENT; | ||
605 | |||
606 | priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy), | ||
607 | ath9k_debugfs_root); | ||
608 | if (!priv->debug.debugfs_phy) | ||
609 | goto err; | ||
610 | |||
611 | priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR, | ||
612 | priv->debug.debugfs_phy, | ||
613 | priv, &fops_tgt_stats); | ||
614 | if (!priv->debug.debugfs_tgt_stats) | ||
615 | goto err; | ||
616 | |||
617 | |||
618 | priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR, | ||
619 | priv->debug.debugfs_phy, | ||
620 | priv, &fops_xmit); | ||
621 | if (!priv->debug.debugfs_xmit) | ||
622 | goto err; | ||
623 | |||
624 | priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR, | ||
625 | priv->debug.debugfs_phy, | ||
626 | priv, &fops_recv); | ||
627 | if (!priv->debug.debugfs_recv) | ||
628 | goto err; | ||
629 | |||
630 | return 0; | ||
631 | |||
632 | err: | ||
633 | ath9k_htc_exit_debug(ah); | ||
634 | return -ENOMEM; | ||
635 | } | ||
636 | |||
637 | void ath9k_htc_exit_debug(struct ath_hw *ah) | ||
638 | { | ||
639 | struct ath_common *common = ath9k_hw_common(ah); | ||
640 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv; | ||
641 | |||
642 | debugfs_remove(priv->debug.debugfs_recv); | ||
643 | debugfs_remove(priv->debug.debugfs_xmit); | ||
644 | debugfs_remove(priv->debug.debugfs_tgt_stats); | ||
645 | debugfs_remove(priv->debug.debugfs_phy); | ||
646 | } | ||
647 | |||
648 | int ath9k_htc_debug_create_root(void) | ||
649 | { | ||
650 | ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
651 | if (!ath9k_debugfs_root) | ||
652 | return -ENOENT; | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | void ath9k_htc_debug_remove_root(void) | ||
658 | { | ||
659 | debugfs_remove(ath9k_debugfs_root); | ||
660 | ath9k_debugfs_root = NULL; | ||
661 | } | ||
662 | |||
663 | #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ | ||
664 | |||
665 | /*******/ | ||
666 | /* ANI */ | ||
667 | /*******/ | ||
668 | |||
669 | static void ath_start_ani(struct ath9k_htc_priv *priv) | ||
670 | { | ||
671 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
672 | unsigned long timestamp = jiffies_to_msecs(jiffies); | ||
673 | |||
674 | common->ani.longcal_timer = timestamp; | ||
675 | common->ani.shortcal_timer = timestamp; | ||
676 | common->ani.checkani_timer = timestamp; | ||
677 | |||
678 | ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, | ||
679 | msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | ||
680 | } | ||
681 | |||
682 | void ath9k_ani_work(struct work_struct *work) | ||
683 | { | ||
684 | struct ath9k_htc_priv *priv = | ||
685 | container_of(work, struct ath9k_htc_priv, | ||
686 | ath9k_ani_work.work); | ||
687 | struct ath_hw *ah = priv->ah; | ||
688 | struct ath_common *common = ath9k_hw_common(ah); | ||
689 | bool longcal = false; | ||
690 | bool shortcal = false; | ||
691 | bool aniflag = false; | ||
692 | unsigned int timestamp = jiffies_to_msecs(jiffies); | ||
693 | u32 cal_interval, short_cal_interval; | ||
694 | |||
695 | short_cal_interval = ATH_STA_SHORT_CALINTERVAL; | ||
696 | |||
697 | /* Long calibration runs independently of short calibration. */ | ||
698 | if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { | ||
699 | longcal = true; | ||
700 | ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies); | ||
701 | common->ani.longcal_timer = timestamp; | ||
702 | } | ||
703 | |||
704 | /* Short calibration applies only while caldone is false */ | ||
705 | if (!common->ani.caldone) { | ||
706 | if ((timestamp - common->ani.shortcal_timer) >= | ||
707 | short_cal_interval) { | ||
708 | shortcal = true; | ||
709 | ath_print(common, ATH_DBG_ANI, | ||
710 | "shortcal @%lu\n", jiffies); | ||
711 | common->ani.shortcal_timer = timestamp; | ||
712 | common->ani.resetcal_timer = timestamp; | ||
713 | } | ||
714 | } else { | ||
715 | if ((timestamp - common->ani.resetcal_timer) >= | ||
716 | ATH_RESTART_CALINTERVAL) { | ||
717 | common->ani.caldone = ath9k_hw_reset_calvalid(ah); | ||
718 | if (common->ani.caldone) | ||
719 | common->ani.resetcal_timer = timestamp; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | /* Verify whether we must check ANI */ | ||
724 | if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { | ||
725 | aniflag = true; | ||
726 | common->ani.checkani_timer = timestamp; | ||
727 | } | ||
728 | |||
729 | /* Skip all processing if there's nothing to do. */ | ||
730 | if (longcal || shortcal || aniflag) { | ||
731 | /* Call ANI routine if necessary */ | ||
732 | if (aniflag) | ||
733 | ath9k_hw_ani_monitor(ah, ah->curchan); | ||
734 | |||
735 | /* Perform calibration if necessary */ | ||
736 | if (longcal || shortcal) { | ||
737 | common->ani.caldone = | ||
738 | ath9k_hw_calibrate(ah, ah->curchan, | ||
739 | common->rx_chainmask, | ||
740 | longcal); | ||
741 | |||
742 | if (longcal) | ||
743 | common->ani.noise_floor = | ||
744 | ath9k_hw_getchan_noise(ah, ah->curchan); | ||
745 | |||
746 | ath_print(common, ATH_DBG_ANI, | ||
747 | " calibrate chan %u/%x nf: %d\n", | ||
748 | ah->curchan->channel, | ||
749 | ah->curchan->channelFlags, | ||
750 | common->ani.noise_floor); | ||
751 | } | ||
752 | } | ||
753 | |||
754 | /* | ||
755 | * Set timer interval based on previous results. | ||
756 | * The interval must be the shortest necessary to satisfy ANI, | ||
757 | * short calibration and long calibration. | ||
758 | */ | ||
759 | cal_interval = ATH_LONG_CALINTERVAL; | ||
760 | if (priv->ah->config.enable_ani) | ||
761 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | ||
762 | if (!common->ani.caldone) | ||
763 | cal_interval = min(cal_interval, (u32)short_cal_interval); | ||
764 | |||
765 | ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work, | ||
766 | msecs_to_jiffies(cal_interval)); | ||
767 | } | ||
768 | |||
769 | /*******/ | ||
770 | /* LED */ | ||
771 | /*******/ | ||
772 | |||
773 | static void ath9k_led_blink_work(struct work_struct *work) | ||
774 | { | ||
775 | struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, | ||
776 | ath9k_led_blink_work.work); | ||
777 | |||
778 | if (!(priv->op_flags & OP_LED_ASSOCIATED)) | ||
779 | return; | ||
780 | |||
781 | if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || | ||
782 | (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
783 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
784 | else | ||
785 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
786 | (priv->op_flags & OP_LED_ON) ? 1 : 0); | ||
787 | |||
788 | ieee80211_queue_delayed_work(priv->hw, | ||
789 | &priv->ath9k_led_blink_work, | ||
790 | (priv->op_flags & OP_LED_ON) ? | ||
791 | msecs_to_jiffies(priv->led_off_duration) : | ||
792 | msecs_to_jiffies(priv->led_on_duration)); | ||
793 | |||
794 | priv->led_on_duration = priv->led_on_cnt ? | ||
795 | max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : | ||
796 | ATH_LED_ON_DURATION_IDLE; | ||
797 | priv->led_off_duration = priv->led_off_cnt ? | ||
798 | max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : | ||
799 | ATH_LED_OFF_DURATION_IDLE; | ||
800 | priv->led_on_cnt = priv->led_off_cnt = 0; | ||
801 | |||
802 | if (priv->op_flags & OP_LED_ON) | ||
803 | priv->op_flags &= ~OP_LED_ON; | ||
804 | else | ||
805 | priv->op_flags |= OP_LED_ON; | ||
806 | } | ||
807 | |||
808 | static void ath9k_led_brightness_work(struct work_struct *work) | ||
809 | { | ||
810 | struct ath_led *led = container_of(work, struct ath_led, | ||
811 | brightness_work.work); | ||
812 | struct ath9k_htc_priv *priv = led->priv; | ||
813 | |||
814 | switch (led->brightness) { | ||
815 | case LED_OFF: | ||
816 | if (led->led_type == ATH_LED_ASSOC || | ||
817 | led->led_type == ATH_LED_RADIO) { | ||
818 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, | ||
819 | (led->led_type == ATH_LED_RADIO)); | ||
820 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
821 | if (led->led_type == ATH_LED_RADIO) | ||
822 | priv->op_flags &= ~OP_LED_ON; | ||
823 | } else { | ||
824 | priv->led_off_cnt++; | ||
825 | } | ||
826 | break; | ||
827 | case LED_FULL: | ||
828 | if (led->led_type == ATH_LED_ASSOC) { | ||
829 | priv->op_flags |= OP_LED_ASSOCIATED; | ||
830 | ieee80211_queue_delayed_work(priv->hw, | ||
831 | &priv->ath9k_led_blink_work, 0); | ||
832 | } else if (led->led_type == ATH_LED_RADIO) { | ||
833 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); | ||
834 | priv->op_flags |= OP_LED_ON; | ||
835 | } else { | ||
836 | priv->led_on_cnt++; | ||
837 | } | ||
838 | break; | ||
839 | default: | ||
840 | break; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | static void ath9k_led_brightness(struct led_classdev *led_cdev, | ||
845 | enum led_brightness brightness) | ||
846 | { | ||
847 | struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); | ||
848 | struct ath9k_htc_priv *priv = led->priv; | ||
849 | |||
850 | led->brightness = brightness; | ||
851 | if (!(priv->op_flags & OP_LED_DEINIT)) | ||
852 | ieee80211_queue_delayed_work(priv->hw, | ||
853 | &led->brightness_work, 0); | ||
854 | } | ||
855 | |||
856 | static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) | ||
857 | { | ||
858 | cancel_delayed_work_sync(&priv->radio_led.brightness_work); | ||
859 | cancel_delayed_work_sync(&priv->assoc_led.brightness_work); | ||
860 | cancel_delayed_work_sync(&priv->tx_led.brightness_work); | ||
861 | cancel_delayed_work_sync(&priv->rx_led.brightness_work); | ||
862 | } | ||
863 | |||
864 | static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, | ||
865 | char *trigger) | ||
866 | { | ||
867 | int ret; | ||
868 | |||
869 | led->priv = priv; | ||
870 | led->led_cdev.name = led->name; | ||
871 | led->led_cdev.default_trigger = trigger; | ||
872 | led->led_cdev.brightness_set = ath9k_led_brightness; | ||
873 | |||
874 | ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); | ||
875 | if (ret) | ||
876 | ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, | ||
877 | "Failed to register led:%s", led->name); | ||
878 | else | ||
879 | led->registered = 1; | ||
880 | |||
881 | INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); | ||
882 | |||
883 | return ret; | ||
884 | } | ||
885 | |||
886 | static void ath9k_unregister_led(struct ath_led *led) | ||
887 | { | ||
888 | if (led->registered) { | ||
889 | led_classdev_unregister(&led->led_cdev); | ||
890 | led->registered = 0; | ||
891 | } | ||
892 | } | ||
893 | |||
894 | void ath9k_deinit_leds(struct ath9k_htc_priv *priv) | ||
895 | { | ||
896 | priv->op_flags |= OP_LED_DEINIT; | ||
897 | ath9k_unregister_led(&priv->assoc_led); | ||
898 | priv->op_flags &= ~OP_LED_ASSOCIATED; | ||
899 | ath9k_unregister_led(&priv->tx_led); | ||
900 | ath9k_unregister_led(&priv->rx_led); | ||
901 | ath9k_unregister_led(&priv->radio_led); | ||
902 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); | ||
903 | } | ||
904 | |||
905 | void ath9k_init_leds(struct ath9k_htc_priv *priv) | ||
906 | { | ||
907 | char *trigger; | ||
908 | int ret; | ||
909 | |||
910 | if (AR_SREV_9287(priv->ah)) | ||
911 | priv->ah->led_pin = ATH_LED_PIN_9287; | ||
912 | else if (AR_SREV_9271(priv->ah)) | ||
913 | priv->ah->led_pin = ATH_LED_PIN_9271; | ||
914 | else | ||
915 | priv->ah->led_pin = ATH_LED_PIN_DEF; | ||
916 | |||
917 | /* Configure gpio 1 for output */ | ||
918 | ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin, | ||
919 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | ||
920 | /* LED off, active low */ | ||
921 | ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); | ||
922 | |||
923 | INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); | ||
924 | |||
925 | trigger = ieee80211_get_radio_led_name(priv->hw); | ||
926 | snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), | ||
927 | "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); | ||
928 | ret = ath9k_register_led(priv, &priv->radio_led, trigger); | ||
929 | priv->radio_led.led_type = ATH_LED_RADIO; | ||
930 | if (ret) | ||
931 | goto fail; | ||
932 | |||
933 | trigger = ieee80211_get_assoc_led_name(priv->hw); | ||
934 | snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), | ||
935 | "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); | ||
936 | ret = ath9k_register_led(priv, &priv->assoc_led, trigger); | ||
937 | priv->assoc_led.led_type = ATH_LED_ASSOC; | ||
938 | if (ret) | ||
939 | goto fail; | ||
940 | |||
941 | trigger = ieee80211_get_tx_led_name(priv->hw); | ||
942 | snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), | ||
943 | "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); | ||
944 | ret = ath9k_register_led(priv, &priv->tx_led, trigger); | ||
945 | priv->tx_led.led_type = ATH_LED_TX; | ||
946 | if (ret) | ||
947 | goto fail; | ||
948 | |||
949 | trigger = ieee80211_get_rx_led_name(priv->hw); | ||
950 | snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), | ||
951 | "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); | ||
952 | ret = ath9k_register_led(priv, &priv->rx_led, trigger); | ||
953 | priv->rx_led.led_type = ATH_LED_RX; | ||
954 | if (ret) | ||
955 | goto fail; | ||
956 | |||
957 | priv->op_flags &= ~OP_LED_DEINIT; | ||
958 | |||
959 | return; | ||
960 | |||
961 | fail: | ||
962 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
963 | ath9k_deinit_leds(priv); | ||
964 | } | ||
965 | |||
966 | /*******************/ | ||
967 | /* Rfkill */ | ||
968 | /*******************/ | ||
969 | |||
970 | static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) | ||
971 | { | ||
972 | return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == | ||
973 | priv->ah->rfkill_polarity; | ||
974 | } | ||
975 | |||
976 | static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) | ||
977 | { | ||
978 | struct ath9k_htc_priv *priv = hw->priv; | ||
979 | bool blocked = !!ath_is_rfkill_set(priv); | ||
980 | |||
981 | wiphy_rfkill_set_hw_state(hw->wiphy, blocked); | ||
982 | } | ||
983 | |||
984 | void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) | ||
985 | { | ||
986 | if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) | ||
987 | wiphy_rfkill_start_polling(priv->hw->wiphy); | ||
988 | } | ||
989 | |||
990 | /**********************/ | ||
991 | /* mac80211 Callbacks */ | ||
992 | /**********************/ | ||
993 | |||
994 | static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
995 | { | ||
996 | struct ieee80211_hdr *hdr; | ||
997 | struct ath9k_htc_priv *priv = hw->priv; | ||
998 | int padpos, padsize; | ||
999 | |||
1000 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1001 | |||
1002 | /* Add the padding after the header if this is not already done */ | ||
1003 | padpos = ath9k_cmn_padpos(hdr->frame_control); | ||
1004 | padsize = padpos & 3; | ||
1005 | if (padsize && skb->len > padpos) { | ||
1006 | if (skb_headroom(skb) < padsize) | ||
1007 | return -1; | ||
1008 | skb_push(skb, padsize); | ||
1009 | memmove(skb->data, skb->data + padsize, padpos); | ||
1010 | } | ||
1011 | |||
1012 | if (ath9k_htc_tx_start(priv, skb) != 0) { | ||
1013 | ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, "Tx failed"); | ||
1014 | goto fail_tx; | ||
1015 | } | ||
1016 | |||
1017 | return 0; | ||
1018 | |||
1019 | fail_tx: | ||
1020 | dev_kfree_skb_any(skb); | ||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | static int ath9k_htc_start(struct ieee80211_hw *hw) | ||
1025 | { | ||
1026 | struct ath9k_htc_priv *priv = hw->priv; | ||
1027 | struct ath_hw *ah = priv->ah; | ||
1028 | struct ath_common *common = ath9k_hw_common(ah); | ||
1029 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
1030 | struct ath9k_channel *init_channel; | ||
1031 | int ret = 0; | ||
1032 | enum htc_phymode mode; | ||
1033 | u16 htc_mode; | ||
1034 | u8 cmd_rsp; | ||
1035 | |||
1036 | ath_print(common, ATH_DBG_CONFIG, | ||
1037 | "Starting driver with initial channel: %d MHz\n", | ||
1038 | curchan->center_freq); | ||
1039 | |||
1040 | mutex_lock(&priv->mutex); | ||
1041 | |||
1042 | /* setup initial channel */ | ||
1043 | init_channel = ath9k_cmn_get_curchannel(hw, ah); | ||
1044 | |||
1045 | /* Reset SERDES registers */ | ||
1046 | ath9k_hw_configpcipowersave(ah, 0, 0); | ||
1047 | |||
1048 | ath9k_hw_htc_resetinit(ah); | ||
1049 | ret = ath9k_hw_reset(ah, init_channel, false); | ||
1050 | if (ret) { | ||
1051 | ath_print(common, ATH_DBG_FATAL, | ||
1052 | "Unable to reset hardware; reset status %d " | ||
1053 | "(freq %u MHz)\n", ret, curchan->center_freq); | ||
1054 | goto mutex_unlock; | ||
1055 | } | ||
1056 | |||
1057 | ath_update_txpow(priv); | ||
1058 | |||
1059 | mode = ath9k_htc_get_curmode(priv, init_channel); | ||
1060 | htc_mode = cpu_to_be16(mode); | ||
1061 | WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode); | ||
1062 | if (ret) | ||
1063 | goto mutex_unlock; | ||
1064 | |||
1065 | WMI_CMD(WMI_ATH_INIT_CMDID); | ||
1066 | if (ret) | ||
1067 | goto mutex_unlock; | ||
1068 | |||
1069 | WMI_CMD(WMI_START_RECV_CMDID); | ||
1070 | if (ret) | ||
1071 | goto mutex_unlock; | ||
1072 | |||
1073 | ath9k_host_rx_init(priv); | ||
1074 | |||
1075 | priv->op_flags &= ~OP_INVALID; | ||
1076 | htc_start(priv->htc); | ||
1077 | |||
1078 | mutex_unlock: | ||
1079 | mutex_unlock(&priv->mutex); | ||
1080 | return ret; | ||
1081 | } | ||
1082 | |||
1083 | static void ath9k_htc_stop(struct ieee80211_hw *hw) | ||
1084 | { | ||
1085 | struct ath9k_htc_priv *priv = hw->priv; | ||
1086 | struct ath_hw *ah = priv->ah; | ||
1087 | struct ath_common *common = ath9k_hw_common(ah); | ||
1088 | int ret = 0; | ||
1089 | u8 cmd_rsp; | ||
1090 | |||
1091 | mutex_lock(&priv->mutex); | ||
1092 | |||
1093 | if (priv->op_flags & OP_INVALID) { | ||
1094 | ath_print(common, ATH_DBG_ANY, "Device not present\n"); | ||
1095 | mutex_unlock(&priv->mutex); | ||
1096 | return; | ||
1097 | } | ||
1098 | |||
1099 | htc_stop(priv->htc); | ||
1100 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | ||
1101 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | ||
1102 | WMI_CMD(WMI_STOP_RECV_CMDID); | ||
1103 | ath9k_hw_phy_disable(ah); | ||
1104 | ath9k_hw_disable(ah); | ||
1105 | ath9k_hw_configpcipowersave(ah, 1, 1); | ||
1106 | ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); | ||
1107 | |||
1108 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
1109 | cancel_delayed_work_sync(&priv->ath9k_aggr_work); | ||
1110 | cancel_delayed_work_sync(&priv->ath9k_led_blink_work); | ||
1111 | ath9k_led_stop_brightness(priv); | ||
1112 | skb_queue_purge(&priv->tx_queue); | ||
1113 | |||
1114 | /* Remove monitor interface here */ | ||
1115 | if (ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
1116 | if (ath9k_htc_remove_monitor_interface(priv)) | ||
1117 | ath_print(common, ATH_DBG_FATAL, | ||
1118 | "Unable to remove monitor interface\n"); | ||
1119 | else | ||
1120 | ath_print(common, ATH_DBG_CONFIG, | ||
1121 | "Monitor interface removed\n"); | ||
1122 | } | ||
1123 | |||
1124 | priv->op_flags |= OP_INVALID; | ||
1125 | mutex_unlock(&priv->mutex); | ||
1126 | |||
1127 | ath_print(common, ATH_DBG_CONFIG, "Driver halt\n"); | ||
1128 | } | ||
1129 | |||
1130 | static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | ||
1131 | struct ieee80211_vif *vif) | ||
1132 | { | ||
1133 | struct ath9k_htc_priv *priv = hw->priv; | ||
1134 | struct ath9k_htc_vif *avp = (void *)vif->drv_priv; | ||
1135 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
1136 | struct ath9k_htc_target_vif hvif; | ||
1137 | int ret = 0; | ||
1138 | u8 cmd_rsp; | ||
1139 | |||
1140 | mutex_lock(&priv->mutex); | ||
1141 | |||
1142 | /* Only one interface for now */ | ||
1143 | if (priv->nvifs > 0) { | ||
1144 | ret = -ENOBUFS; | ||
1145 | goto out; | ||
1146 | } | ||
1147 | |||
1148 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
1149 | memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); | ||
1150 | |||
1151 | switch (vif->type) { | ||
1152 | case NL80211_IFTYPE_STATION: | ||
1153 | hvif.opmode = cpu_to_be32(HTC_M_STA); | ||
1154 | break; | ||
1155 | case NL80211_IFTYPE_ADHOC: | ||
1156 | hvif.opmode = cpu_to_be32(HTC_M_IBSS); | ||
1157 | break; | ||
1158 | default: | ||
1159 | ath_print(common, ATH_DBG_FATAL, | ||
1160 | "Interface type %d not yet supported\n", vif->type); | ||
1161 | ret = -EOPNOTSUPP; | ||
1162 | goto out; | ||
1163 | } | ||
1164 | |||
1165 | ath_print(common, ATH_DBG_CONFIG, | ||
1166 | "Attach a VIF of type: %d\n", vif->type); | ||
1167 | |||
1168 | priv->ah->opmode = vif->type; | ||
1169 | |||
1170 | /* Index starts from zero on the target */ | ||
1171 | avp->index = hvif.index = priv->nvifs; | ||
1172 | hvif.rtsthreshold = cpu_to_be16(2304); | ||
1173 | WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); | ||
1174 | if (ret) | ||
1175 | goto out; | ||
1176 | |||
1177 | priv->nvifs++; | ||
1178 | |||
1179 | /* | ||
1180 | * We need a node in target to tx mgmt frames | ||
1181 | * before association. | ||
1182 | */ | ||
1183 | ret = ath9k_htc_add_station(priv, vif, NULL); | ||
1184 | if (ret) | ||
1185 | goto out; | ||
1186 | |||
1187 | ret = ath9k_htc_update_cap_target(priv); | ||
1188 | if (ret) | ||
1189 | ath_print(common, ATH_DBG_CONFIG, "Failed to update" | ||
1190 | " capability in target \n"); | ||
1191 | |||
1192 | priv->vif = vif; | ||
1193 | out: | ||
1194 | mutex_unlock(&priv->mutex); | ||
1195 | return ret; | ||
1196 | } | ||
1197 | |||
1198 | static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | ||
1199 | struct ieee80211_vif *vif) | ||
1200 | { | ||
1201 | struct ath9k_htc_priv *priv = hw->priv; | ||
1202 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
1203 | struct ath9k_htc_vif *avp = (void *)vif->drv_priv; | ||
1204 | struct ath9k_htc_target_vif hvif; | ||
1205 | int ret = 0; | ||
1206 | u8 cmd_rsp; | ||
1207 | |||
1208 | ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); | ||
1209 | |||
1210 | mutex_lock(&priv->mutex); | ||
1211 | |||
1212 | memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); | ||
1213 | memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); | ||
1214 | hvif.index = avp->index; | ||
1215 | WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); | ||
1216 | priv->nvifs--; | ||
1217 | |||
1218 | ath9k_htc_remove_station(priv, vif, NULL); | ||
1219 | |||
1220 | if (vif->type == NL80211_IFTYPE_ADHOC) { | ||
1221 | spin_lock_bh(&priv->beacon_lock); | ||
1222 | if (priv->beacon) | ||
1223 | dev_kfree_skb_any(priv->beacon); | ||
1224 | priv->beacon = NULL; | ||
1225 | spin_unlock_bh(&priv->beacon_lock); | ||
1226 | } | ||
1227 | |||
1228 | priv->vif = NULL; | ||
1229 | |||
1230 | mutex_unlock(&priv->mutex); | ||
1231 | } | ||
1232 | |||
1233 | static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) | ||
1234 | { | ||
1235 | struct ath9k_htc_priv *priv = hw->priv; | ||
1236 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
1237 | struct ieee80211_conf *conf = &hw->conf; | ||
1238 | |||
1239 | mutex_lock(&priv->mutex); | ||
1240 | |||
1241 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
1242 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
1243 | int pos = curchan->hw_value; | ||
1244 | bool is_cw40 = false; | ||
1245 | |||
1246 | ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", | ||
1247 | curchan->center_freq); | ||
1248 | |||
1249 | if (check_rc_update(hw, &is_cw40)) | ||
1250 | ath9k_htc_rc_update(priv, is_cw40); | ||
1251 | |||
1252 | ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); | ||
1253 | |||
1254 | if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { | ||
1255 | ath_print(common, ATH_DBG_FATAL, | ||
1256 | "Unable to set channel\n"); | ||
1257 | mutex_unlock(&priv->mutex); | ||
1258 | return -EINVAL; | ||
1259 | } | ||
1260 | |||
1261 | } | ||
1262 | |||
1263 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | ||
1264 | if (conf->flags & IEEE80211_CONF_MONITOR) { | ||
1265 | if (ath9k_htc_add_monitor_interface(priv)) | ||
1266 | ath_print(common, ATH_DBG_FATAL, | ||
1267 | "Failed to set monitor mode\n"); | ||
1268 | else | ||
1269 | ath_print(common, ATH_DBG_CONFIG, | ||
1270 | "HW opmode set to Monitor mode\n"); | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1274 | mutex_unlock(&priv->mutex); | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1279 | #define SUPPORTED_FILTERS \ | ||
1280 | (FIF_PROMISC_IN_BSS | \ | ||
1281 | FIF_ALLMULTI | \ | ||
1282 | FIF_CONTROL | \ | ||
1283 | FIF_PSPOLL | \ | ||
1284 | FIF_OTHER_BSS | \ | ||
1285 | FIF_BCN_PRBRESP_PROMISC | \ | ||
1286 | FIF_FCSFAIL) | ||
1287 | |||
1288 | static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, | ||
1289 | unsigned int changed_flags, | ||
1290 | unsigned int *total_flags, | ||
1291 | u64 multicast) | ||
1292 | { | ||
1293 | struct ath9k_htc_priv *priv = hw->priv; | ||
1294 | u32 rfilt; | ||
1295 | |||
1296 | mutex_lock(&priv->mutex); | ||
1297 | |||
1298 | changed_flags &= SUPPORTED_FILTERS; | ||
1299 | *total_flags &= SUPPORTED_FILTERS; | ||
1300 | |||
1301 | priv->rxfilter = *total_flags; | ||
1302 | rfilt = ath9k_cmn_calcrxfilter(hw, priv->ah, priv->rxfilter); | ||
1303 | ath9k_hw_setrxfilter(priv->ah, rfilt); | ||
1304 | |||
1305 | ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG, | ||
1306 | "Set HW RX filter: 0x%x\n", rfilt); | ||
1307 | |||
1308 | mutex_unlock(&priv->mutex); | ||
1309 | } | ||
1310 | |||
1311 | static void ath9k_htc_sta_notify(struct ieee80211_hw *hw, | ||
1312 | struct ieee80211_vif *vif, | ||
1313 | enum sta_notify_cmd cmd, | ||
1314 | struct ieee80211_sta *sta) | ||
1315 | { | ||
1316 | struct ath9k_htc_priv *priv = hw->priv; | ||
1317 | int ret; | ||
1318 | |||
1319 | switch (cmd) { | ||
1320 | case STA_NOTIFY_ADD: | ||
1321 | ret = ath9k_htc_add_station(priv, vif, sta); | ||
1322 | if (!ret) | ||
1323 | ath9k_htc_init_rate(priv, vif, sta); | ||
1324 | break; | ||
1325 | case STA_NOTIFY_REMOVE: | ||
1326 | ath9k_htc_remove_station(priv, vif, sta); | ||
1327 | break; | ||
1328 | default: | ||
1329 | break; | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1333 | static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
1334 | const struct ieee80211_tx_queue_params *params) | ||
1335 | { | ||
1336 | struct ath9k_htc_priv *priv = hw->priv; | ||
1337 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
1338 | struct ath9k_tx_queue_info qi; | ||
1339 | int ret = 0, qnum; | ||
1340 | |||
1341 | if (queue >= WME_NUM_AC) | ||
1342 | return 0; | ||
1343 | |||
1344 | mutex_lock(&priv->mutex); | ||
1345 | |||
1346 | memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); | ||
1347 | |||
1348 | qi.tqi_aifs = params->aifs; | ||
1349 | qi.tqi_cwmin = params->cw_min; | ||
1350 | qi.tqi_cwmax = params->cw_max; | ||
1351 | qi.tqi_burstTime = params->txop; | ||
1352 | |||
1353 | qnum = get_hw_qnum(queue, priv->hwq_map); | ||
1354 | |||
1355 | ath_print(common, ATH_DBG_CONFIG, | ||
1356 | "Configure tx [queue/hwq] [%d/%d], " | ||
1357 | "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | ||
1358 | queue, qnum, params->aifs, params->cw_min, | ||
1359 | params->cw_max, params->txop); | ||
1360 | |||
1361 | ret = ath_htc_txq_update(priv, qnum, &qi); | ||
1362 | if (ret) | ||
1363 | ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); | ||
1364 | |||
1365 | mutex_unlock(&priv->mutex); | ||
1366 | |||
1367 | return ret; | ||
1368 | } | ||
1369 | |||
1370 | static int ath9k_htc_set_key(struct ieee80211_hw *hw, | ||
1371 | enum set_key_cmd cmd, | ||
1372 | struct ieee80211_vif *vif, | ||
1373 | struct ieee80211_sta *sta, | ||
1374 | struct ieee80211_key_conf *key) | ||
1375 | { | ||
1376 | struct ath9k_htc_priv *priv = hw->priv; | ||
1377 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
1378 | int ret = 0; | ||
1379 | |||
1380 | if (htc_modparam_nohwcrypt) | ||
1381 | return -ENOSPC; | ||
1382 | |||
1383 | mutex_lock(&priv->mutex); | ||
1384 | ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n"); | ||
1385 | |||
1386 | switch (cmd) { | ||
1387 | case SET_KEY: | ||
1388 | ret = ath9k_cmn_key_config(common, vif, sta, key); | ||
1389 | if (ret >= 0) { | ||
1390 | key->hw_key_idx = ret; | ||
1391 | /* push IV and Michael MIC generation to stack */ | ||
1392 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
1393 | if (key->alg == ALG_TKIP) | ||
1394 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
1395 | if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP) | ||
1396 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT; | ||
1397 | ret = 0; | ||
1398 | } | ||
1399 | break; | ||
1400 | case DISABLE_KEY: | ||
1401 | ath9k_cmn_key_delete(common, key); | ||
1402 | break; | ||
1403 | default: | ||
1404 | ret = -EINVAL; | ||
1405 | } | ||
1406 | |||
1407 | mutex_unlock(&priv->mutex); | ||
1408 | |||
1409 | return ret; | ||
1410 | } | ||
1411 | |||
1412 | static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | ||
1413 | struct ieee80211_vif *vif, | ||
1414 | struct ieee80211_bss_conf *bss_conf, | ||
1415 | u32 changed) | ||
1416 | { | ||
1417 | struct ath9k_htc_priv *priv = hw->priv; | ||
1418 | struct ath_hw *ah = priv->ah; | ||
1419 | struct ath_common *common = ath9k_hw_common(ah); | ||
1420 | |||
1421 | mutex_lock(&priv->mutex); | ||
1422 | |||
1423 | if (changed & BSS_CHANGED_ASSOC) { | ||
1424 | common->curaid = bss_conf->assoc ? | ||
1425 | bss_conf->aid : 0; | ||
1426 | ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", | ||
1427 | bss_conf->assoc); | ||
1428 | |||
1429 | if (bss_conf->assoc) { | ||
1430 | priv->op_flags |= OP_ASSOCIATED; | ||
1431 | ath_start_ani(priv); | ||
1432 | } else { | ||
1433 | priv->op_flags &= ~OP_ASSOCIATED; | ||
1434 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | if (changed & BSS_CHANGED_BSSID) { | ||
1439 | /* Set BSSID */ | ||
1440 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1441 | ath9k_hw_write_associd(ah); | ||
1442 | |||
1443 | ath_print(common, ATH_DBG_CONFIG, | ||
1444 | "BSSID: %pM aid: 0x%x\n", | ||
1445 | common->curbssid, common->curaid); | ||
1446 | } | ||
1447 | |||
1448 | if ((changed & BSS_CHANGED_BEACON_INT) || | ||
1449 | (changed & BSS_CHANGED_BEACON) || | ||
1450 | ((changed & BSS_CHANGED_BEACON_ENABLED) && | ||
1451 | bss_conf->enable_beacon)) { | ||
1452 | priv->op_flags |= OP_ENABLE_BEACON; | ||
1453 | ath9k_htc_beacon_config(priv, vif, bss_conf); | ||
1454 | } | ||
1455 | |||
1456 | if (changed & BSS_CHANGED_BEACON) | ||
1457 | ath9k_htc_beacon_update(priv, vif); | ||
1458 | |||
1459 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && | ||
1460 | !bss_conf->enable_beacon) { | ||
1461 | priv->op_flags &= ~OP_ENABLE_BEACON; | ||
1462 | ath9k_htc_beacon_config(priv, vif, bss_conf); | ||
1463 | } | ||
1464 | |||
1465 | if (changed & BSS_CHANGED_ERP_PREAMBLE) { | ||
1466 | ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", | ||
1467 | bss_conf->use_short_preamble); | ||
1468 | if (bss_conf->use_short_preamble) | ||
1469 | priv->op_flags |= OP_PREAMBLE_SHORT; | ||
1470 | else | ||
1471 | priv->op_flags &= ~OP_PREAMBLE_SHORT; | ||
1472 | } | ||
1473 | |||
1474 | if (changed & BSS_CHANGED_ERP_CTS_PROT) { | ||
1475 | ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", | ||
1476 | bss_conf->use_cts_prot); | ||
1477 | if (bss_conf->use_cts_prot && | ||
1478 | hw->conf.channel->band != IEEE80211_BAND_5GHZ) | ||
1479 | priv->op_flags |= OP_PROTECT_ENABLE; | ||
1480 | else | ||
1481 | priv->op_flags &= ~OP_PROTECT_ENABLE; | ||
1482 | } | ||
1483 | |||
1484 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
1485 | if (bss_conf->use_short_slot) | ||
1486 | ah->slottime = 9; | ||
1487 | else | ||
1488 | ah->slottime = 20; | ||
1489 | |||
1490 | ath9k_hw_init_global_settings(ah); | ||
1491 | } | ||
1492 | |||
1493 | mutex_unlock(&priv->mutex); | ||
1494 | } | ||
1495 | |||
1496 | static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) | ||
1497 | { | ||
1498 | struct ath9k_htc_priv *priv = hw->priv; | ||
1499 | u64 tsf; | ||
1500 | |||
1501 | mutex_lock(&priv->mutex); | ||
1502 | tsf = ath9k_hw_gettsf64(priv->ah); | ||
1503 | mutex_unlock(&priv->mutex); | ||
1504 | |||
1505 | return tsf; | ||
1506 | } | ||
1507 | |||
1508 | static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) | ||
1509 | { | ||
1510 | struct ath9k_htc_priv *priv = hw->priv; | ||
1511 | |||
1512 | mutex_lock(&priv->mutex); | ||
1513 | ath9k_hw_settsf64(priv->ah, tsf); | ||
1514 | mutex_unlock(&priv->mutex); | ||
1515 | } | ||
1516 | |||
1517 | static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) | ||
1518 | { | ||
1519 | struct ath9k_htc_priv *priv = hw->priv; | ||
1520 | |||
1521 | mutex_lock(&priv->mutex); | ||
1522 | ath9k_hw_reset_tsf(priv->ah); | ||
1523 | mutex_unlock(&priv->mutex); | ||
1524 | } | ||
1525 | |||
1526 | static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, | ||
1527 | struct ieee80211_vif *vif, | ||
1528 | enum ieee80211_ampdu_mlme_action action, | ||
1529 | struct ieee80211_sta *sta, | ||
1530 | u16 tid, u16 *ssn) | ||
1531 | { | ||
1532 | struct ath9k_htc_priv *priv = hw->priv; | ||
1533 | struct ath9k_htc_aggr_work *work = &priv->aggr_work; | ||
1534 | struct ath9k_htc_sta *ista; | ||
1535 | |||
1536 | switch (action) { | ||
1537 | case IEEE80211_AMPDU_RX_START: | ||
1538 | break; | ||
1539 | case IEEE80211_AMPDU_RX_STOP: | ||
1540 | break; | ||
1541 | case IEEE80211_AMPDU_TX_START: | ||
1542 | case IEEE80211_AMPDU_TX_STOP: | ||
1543 | if (!(priv->op_flags & OP_TXAGGR)) | ||
1544 | return -ENOTSUPP; | ||
1545 | memcpy(work->sta_addr, sta->addr, ETH_ALEN); | ||
1546 | work->hw = hw; | ||
1547 | work->vif = vif; | ||
1548 | work->action = action; | ||
1549 | work->tid = tid; | ||
1550 | ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0); | ||
1551 | break; | ||
1552 | case IEEE80211_AMPDU_TX_OPERATIONAL: | ||
1553 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
1554 | ista->tid_state[tid] = AGGR_OPERATIONAL; | ||
1555 | break; | ||
1556 | default: | ||
1557 | ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL, | ||
1558 | "Unknown AMPDU action\n"); | ||
1559 | } | ||
1560 | |||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) | ||
1565 | { | ||
1566 | struct ath9k_htc_priv *priv = hw->priv; | ||
1567 | |||
1568 | mutex_lock(&priv->mutex); | ||
1569 | spin_lock_bh(&priv->beacon_lock); | ||
1570 | priv->op_flags |= OP_SCANNING; | ||
1571 | spin_unlock_bh(&priv->beacon_lock); | ||
1572 | cancel_delayed_work_sync(&priv->ath9k_ani_work); | ||
1573 | mutex_unlock(&priv->mutex); | ||
1574 | } | ||
1575 | |||
1576 | static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) | ||
1577 | { | ||
1578 | struct ath9k_htc_priv *priv = hw->priv; | ||
1579 | |||
1580 | mutex_lock(&priv->mutex); | ||
1581 | spin_lock_bh(&priv->beacon_lock); | ||
1582 | priv->op_flags &= ~OP_SCANNING; | ||
1583 | spin_unlock_bh(&priv->beacon_lock); | ||
1584 | priv->op_flags |= OP_FULL_RESET; | ||
1585 | ath_start_ani(priv); | ||
1586 | mutex_unlock(&priv->mutex); | ||
1587 | } | ||
1588 | |||
1589 | static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
1590 | { | ||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, | ||
1595 | u8 coverage_class) | ||
1596 | { | ||
1597 | struct ath9k_htc_priv *priv = hw->priv; | ||
1598 | |||
1599 | mutex_lock(&priv->mutex); | ||
1600 | priv->ah->coverage_class = coverage_class; | ||
1601 | ath9k_hw_init_global_settings(priv->ah); | ||
1602 | mutex_unlock(&priv->mutex); | ||
1603 | } | ||
1604 | |||
1605 | struct ieee80211_ops ath9k_htc_ops = { | ||
1606 | .tx = ath9k_htc_tx, | ||
1607 | .start = ath9k_htc_start, | ||
1608 | .stop = ath9k_htc_stop, | ||
1609 | .add_interface = ath9k_htc_add_interface, | ||
1610 | .remove_interface = ath9k_htc_remove_interface, | ||
1611 | .config = ath9k_htc_config, | ||
1612 | .configure_filter = ath9k_htc_configure_filter, | ||
1613 | .sta_notify = ath9k_htc_sta_notify, | ||
1614 | .conf_tx = ath9k_htc_conf_tx, | ||
1615 | .bss_info_changed = ath9k_htc_bss_info_changed, | ||
1616 | .set_key = ath9k_htc_set_key, | ||
1617 | .get_tsf = ath9k_htc_get_tsf, | ||
1618 | .set_tsf = ath9k_htc_set_tsf, | ||
1619 | .reset_tsf = ath9k_htc_reset_tsf, | ||
1620 | .ampdu_action = ath9k_htc_ampdu_action, | ||
1621 | .sw_scan_start = ath9k_htc_sw_scan_start, | ||
1622 | .sw_scan_complete = ath9k_htc_sw_scan_complete, | ||
1623 | .set_rts_threshold = ath9k_htc_set_rts_threshold, | ||
1624 | .rfkill_poll = ath9k_htc_rfkill_poll_state, | ||
1625 | .set_coverage_class = ath9k_htc_set_coverage_class, | ||
1626 | }; | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c new file mode 100644 index 000000000000..ac66cf0b2d53 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -0,0 +1,604 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | /******/ | ||
20 | /* TX */ | ||
21 | /******/ | ||
22 | |||
23 | int get_hw_qnum(u16 queue, int *hwq_map) | ||
24 | { | ||
25 | switch (queue) { | ||
26 | case 0: | ||
27 | return hwq_map[ATH9K_WME_AC_VO]; | ||
28 | case 1: | ||
29 | return hwq_map[ATH9K_WME_AC_VI]; | ||
30 | case 2: | ||
31 | return hwq_map[ATH9K_WME_AC_BE]; | ||
32 | case 3: | ||
33 | return hwq_map[ATH9K_WME_AC_BK]; | ||
34 | default: | ||
35 | return hwq_map[ATH9K_WME_AC_BE]; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, | ||
40 | struct ath9k_tx_queue_info *qinfo) | ||
41 | { | ||
42 | struct ath_hw *ah = priv->ah; | ||
43 | int error = 0; | ||
44 | struct ath9k_tx_queue_info qi; | ||
45 | |||
46 | ath9k_hw_get_txq_props(ah, qnum, &qi); | ||
47 | |||
48 | qi.tqi_aifs = qinfo->tqi_aifs; | ||
49 | qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ | ||
50 | qi.tqi_cwmax = qinfo->tqi_cwmax; | ||
51 | qi.tqi_burstTime = qinfo->tqi_burstTime; | ||
52 | qi.tqi_readyTime = qinfo->tqi_readyTime; | ||
53 | |||
54 | if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { | ||
55 | ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, | ||
56 | "Unable to update hardware queue %u!\n", qnum); | ||
57 | error = -EIO; | ||
58 | } else { | ||
59 | ath9k_hw_resettxqueue(ah, qnum); | ||
60 | } | ||
61 | |||
62 | return error; | ||
63 | } | ||
64 | |||
65 | int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) | ||
66 | { | ||
67 | struct ieee80211_hdr *hdr; | ||
68 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
69 | struct ieee80211_sta *sta = tx_info->control.sta; | ||
70 | struct ath9k_htc_sta *ista; | ||
71 | struct ath9k_htc_vif *avp; | ||
72 | struct ath9k_htc_tx_ctl tx_ctl; | ||
73 | enum htc_endpoint_id epid; | ||
74 | u16 qnum, hw_qnum; | ||
75 | __le16 fc; | ||
76 | u8 *tx_fhdr; | ||
77 | u8 sta_idx; | ||
78 | |||
79 | hdr = (struct ieee80211_hdr *) skb->data; | ||
80 | fc = hdr->frame_control; | ||
81 | |||
82 | avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv; | ||
83 | if (sta) { | ||
84 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
85 | sta_idx = ista->index; | ||
86 | } else { | ||
87 | sta_idx = 0; | ||
88 | } | ||
89 | |||
90 | memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); | ||
91 | |||
92 | if (ieee80211_is_data(fc)) { | ||
93 | struct tx_frame_hdr tx_hdr; | ||
94 | u8 *qc; | ||
95 | |||
96 | memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); | ||
97 | |||
98 | tx_hdr.node_idx = sta_idx; | ||
99 | tx_hdr.vif_idx = avp->index; | ||
100 | |||
101 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | ||
102 | tx_ctl.type = ATH9K_HTC_AMPDU; | ||
103 | tx_hdr.data_type = ATH9K_HTC_AMPDU; | ||
104 | } else { | ||
105 | tx_ctl.type = ATH9K_HTC_NORMAL; | ||
106 | tx_hdr.data_type = ATH9K_HTC_NORMAL; | ||
107 | } | ||
108 | |||
109 | if (ieee80211_is_data(fc)) { | ||
110 | qc = ieee80211_get_qos_ctl(hdr); | ||
111 | tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
112 | } | ||
113 | |||
114 | /* Check for RTS protection */ | ||
115 | if (priv->hw->wiphy->rts_threshold != (u32) -1) | ||
116 | if (skb->len > priv->hw->wiphy->rts_threshold) | ||
117 | tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS; | ||
118 | |||
119 | /* CTS-to-self */ | ||
120 | if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) && | ||
121 | (priv->op_flags & OP_PROTECT_ENABLE)) | ||
122 | tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY; | ||
123 | |||
124 | tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); | ||
125 | if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) | ||
126 | tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; | ||
127 | else | ||
128 | tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; | ||
129 | |||
130 | tx_fhdr = skb_push(skb, sizeof(tx_hdr)); | ||
131 | memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); | ||
132 | |||
133 | qnum = skb_get_queue_mapping(skb); | ||
134 | hw_qnum = get_hw_qnum(qnum, priv->hwq_map); | ||
135 | |||
136 | switch (hw_qnum) { | ||
137 | case 0: | ||
138 | epid = priv->data_be_ep; | ||
139 | break; | ||
140 | case 2: | ||
141 | epid = priv->data_vi_ep; | ||
142 | break; | ||
143 | case 3: | ||
144 | epid = priv->data_vo_ep; | ||
145 | break; | ||
146 | case 1: | ||
147 | default: | ||
148 | epid = priv->data_bk_ep; | ||
149 | break; | ||
150 | } | ||
151 | } else { | ||
152 | struct tx_mgmt_hdr mgmt_hdr; | ||
153 | |||
154 | memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); | ||
155 | |||
156 | tx_ctl.type = ATH9K_HTC_NORMAL; | ||
157 | |||
158 | mgmt_hdr.node_idx = sta_idx; | ||
159 | mgmt_hdr.vif_idx = avp->index; | ||
160 | mgmt_hdr.tidno = 0; | ||
161 | mgmt_hdr.flags = 0; | ||
162 | |||
163 | mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); | ||
164 | if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) | ||
165 | mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; | ||
166 | else | ||
167 | mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; | ||
168 | |||
169 | tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); | ||
170 | memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); | ||
171 | epid = priv->mgmt_ep; | ||
172 | } | ||
173 | |||
174 | return htc_send(priv->htc, skb, epid, &tx_ctl); | ||
175 | } | ||
176 | |||
177 | void ath9k_tx_tasklet(unsigned long data) | ||
178 | { | ||
179 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | ||
180 | struct ieee80211_sta *sta; | ||
181 | struct ieee80211_hdr *hdr; | ||
182 | struct ieee80211_tx_info *tx_info; | ||
183 | struct sk_buff *skb = NULL; | ||
184 | __le16 fc; | ||
185 | |||
186 | while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { | ||
187 | |||
188 | hdr = (struct ieee80211_hdr *) skb->data; | ||
189 | fc = hdr->frame_control; | ||
190 | tx_info = IEEE80211_SKB_CB(skb); | ||
191 | sta = tx_info->control.sta; | ||
192 | |||
193 | rcu_read_lock(); | ||
194 | |||
195 | if (sta && conf_is_ht(&priv->hw->conf) && | ||
196 | (priv->op_flags & OP_TXAGGR) | ||
197 | && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | ||
198 | if (ieee80211_is_data_qos(fc)) { | ||
199 | u8 *qc, tid; | ||
200 | struct ath9k_htc_sta *ista; | ||
201 | |||
202 | qc = ieee80211_get_qos_ctl(hdr); | ||
203 | tid = qc[0] & 0xf; | ||
204 | ista = (struct ath9k_htc_sta *)sta->drv_priv; | ||
205 | |||
206 | if ((tid < ATH9K_HTC_MAX_TID) && | ||
207 | ista->tid_state[tid] == AGGR_STOP) { | ||
208 | ieee80211_start_tx_ba_session(sta, tid); | ||
209 | ista->tid_state[tid] = AGGR_PROGRESS; | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | rcu_read_unlock(); | ||
215 | |||
216 | memset(&tx_info->status, 0, sizeof(tx_info->status)); | ||
217 | ieee80211_tx_status(priv->hw, skb); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | ||
222 | enum htc_endpoint_id ep_id, bool txok) | ||
223 | { | ||
224 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; | ||
225 | struct ieee80211_tx_info *tx_info; | ||
226 | |||
227 | if (!skb) | ||
228 | return; | ||
229 | |||
230 | if (ep_id == priv->mgmt_ep) | ||
231 | skb_pull(skb, sizeof(struct tx_mgmt_hdr)); | ||
232 | else | ||
233 | /* TODO: Check for cab/uapsd/data */ | ||
234 | skb_pull(skb, sizeof(struct tx_frame_hdr)); | ||
235 | |||
236 | tx_info = IEEE80211_SKB_CB(skb); | ||
237 | |||
238 | if (txok) | ||
239 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | ||
240 | |||
241 | skb_queue_tail(&priv->tx_queue, skb); | ||
242 | tasklet_schedule(&priv->tx_tasklet); | ||
243 | } | ||
244 | |||
245 | int ath9k_tx_init(struct ath9k_htc_priv *priv) | ||
246 | { | ||
247 | skb_queue_head_init(&priv->tx_queue); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | void ath9k_tx_cleanup(struct ath9k_htc_priv *priv) | ||
252 | { | ||
253 | |||
254 | } | ||
255 | |||
256 | bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, | ||
257 | enum ath9k_tx_queue_subtype subtype) | ||
258 | { | ||
259 | struct ath_hw *ah = priv->ah; | ||
260 | struct ath_common *common = ath9k_hw_common(ah); | ||
261 | struct ath9k_tx_queue_info qi; | ||
262 | int qnum; | ||
263 | |||
264 | memset(&qi, 0, sizeof(qi)); | ||
265 | |||
266 | qi.tqi_subtype = subtype; | ||
267 | qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; | ||
268 | qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; | ||
269 | qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; | ||
270 | qi.tqi_physCompBuf = 0; | ||
271 | qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; | ||
272 | |||
273 | qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); | ||
274 | if (qnum == -1) | ||
275 | return false; | ||
276 | |||
277 | if (qnum >= ARRAY_SIZE(priv->hwq_map)) { | ||
278 | ath_print(common, ATH_DBG_FATAL, | ||
279 | "qnum %u out of range, max %u!\n", | ||
280 | qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); | ||
281 | ath9k_hw_releasetxqueue(ah, qnum); | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | priv->hwq_map[subtype] = qnum; | ||
286 | return true; | ||
287 | } | ||
288 | |||
289 | /******/ | ||
290 | /* RX */ | ||
291 | /******/ | ||
292 | |||
293 | void ath9k_host_rx_init(struct ath9k_htc_priv *priv) | ||
294 | { | ||
295 | ath9k_hw_rxena(priv->ah); | ||
296 | ath9k_cmn_opmode_init(priv->hw, priv->ah, priv->rxfilter); | ||
297 | ath9k_hw_startpcureceive(priv->ah); | ||
298 | priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
299 | } | ||
300 | |||
301 | static void ath9k_process_rate(struct ieee80211_hw *hw, | ||
302 | struct ieee80211_rx_status *rxs, | ||
303 | u8 rx_rate, u8 rs_flags) | ||
304 | { | ||
305 | struct ieee80211_supported_band *sband; | ||
306 | enum ieee80211_band band; | ||
307 | unsigned int i = 0; | ||
308 | |||
309 | if (rx_rate & 0x80) { | ||
310 | /* HT rate */ | ||
311 | rxs->flag |= RX_FLAG_HT; | ||
312 | if (rs_flags & ATH9K_RX_2040) | ||
313 | rxs->flag |= RX_FLAG_40MHZ; | ||
314 | if (rs_flags & ATH9K_RX_GI) | ||
315 | rxs->flag |= RX_FLAG_SHORT_GI; | ||
316 | rxs->rate_idx = rx_rate & 0x7f; | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | band = hw->conf.channel->band; | ||
321 | sband = hw->wiphy->bands[band]; | ||
322 | |||
323 | for (i = 0; i < sband->n_bitrates; i++) { | ||
324 | if (sband->bitrates[i].hw_value == rx_rate) { | ||
325 | rxs->rate_idx = i; | ||
326 | return; | ||
327 | } | ||
328 | if (sband->bitrates[i].hw_value_short == rx_rate) { | ||
329 | rxs->rate_idx = i; | ||
330 | rxs->flag |= RX_FLAG_SHORTPRE; | ||
331 | return; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | } | ||
336 | |||
337 | static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, | ||
338 | struct ath9k_htc_rxbuf *rxbuf, | ||
339 | struct ieee80211_rx_status *rx_status) | ||
340 | |||
341 | { | ||
342 | struct ieee80211_hdr *hdr; | ||
343 | struct ieee80211_hw *hw = priv->hw; | ||
344 | struct sk_buff *skb = rxbuf->skb; | ||
345 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
346 | int hdrlen, padpos, padsize; | ||
347 | int last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
348 | __le16 fc; | ||
349 | |||
350 | hdr = (struct ieee80211_hdr *)skb->data; | ||
351 | fc = hdr->frame_control; | ||
352 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | ||
353 | |||
354 | padpos = ath9k_cmn_padpos(fc); | ||
355 | |||
356 | padsize = padpos & 3; | ||
357 | if (padsize && skb->len >= padpos+padsize) { | ||
358 | memmove(skb->data + padsize, skb->data, padpos); | ||
359 | skb_pull(skb, padsize); | ||
360 | } | ||
361 | |||
362 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); | ||
363 | |||
364 | if (rxbuf->rxstatus.rs_status != 0) { | ||
365 | if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) | ||
366 | rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; | ||
367 | if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) | ||
368 | goto rx_next; | ||
369 | |||
370 | if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { | ||
371 | /* FIXME */ | ||
372 | } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { | ||
373 | if (ieee80211_is_ctl(fc)) | ||
374 | /* | ||
375 | * Sometimes, we get invalid | ||
376 | * MIC failures on valid control frames. | ||
377 | * Remove these mic errors. | ||
378 | */ | ||
379 | rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; | ||
380 | else | ||
381 | rx_status->flag |= RX_FLAG_MMIC_ERROR; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * Reject error frames with the exception of | ||
386 | * decryption and MIC failures. For monitor mode, | ||
387 | * we also ignore the CRC error. | ||
388 | */ | ||
389 | if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { | ||
390 | if (rxbuf->rxstatus.rs_status & | ||
391 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | | ||
392 | ATH9K_RXERR_CRC)) | ||
393 | goto rx_next; | ||
394 | } else { | ||
395 | if (rxbuf->rxstatus.rs_status & | ||
396 | ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { | ||
397 | goto rx_next; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { | ||
403 | u8 keyix; | ||
404 | keyix = rxbuf->rxstatus.rs_keyix; | ||
405 | if (keyix != ATH9K_RXKEYIX_INVALID) { | ||
406 | rx_status->flag |= RX_FLAG_DECRYPTED; | ||
407 | } else if (ieee80211_has_protected(fc) && | ||
408 | skb->len >= hdrlen + 4) { | ||
409 | keyix = skb->data[hdrlen + 3] >> 6; | ||
410 | if (test_bit(keyix, common->keymap)) | ||
411 | rx_status->flag |= RX_FLAG_DECRYPTED; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, | ||
416 | rxbuf->rxstatus.rs_flags); | ||
417 | |||
418 | if (priv->op_flags & OP_ASSOCIATED) { | ||
419 | if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && | ||
420 | !rxbuf->rxstatus.rs_moreaggr) | ||
421 | ATH_RSSI_LPF(priv->rx.last_rssi, | ||
422 | rxbuf->rxstatus.rs_rssi); | ||
423 | |||
424 | last_rssi = priv->rx.last_rssi; | ||
425 | |||
426 | if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) | ||
427 | rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, | ||
428 | ATH_RSSI_EP_MULTIPLIER); | ||
429 | |||
430 | if (rxbuf->rxstatus.rs_rssi < 0) | ||
431 | rxbuf->rxstatus.rs_rssi = 0; | ||
432 | |||
433 | if (ieee80211_is_beacon(fc)) | ||
434 | priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; | ||
435 | } | ||
436 | |||
437 | rx_status->mactime = rxbuf->rxstatus.rs_tstamp; | ||
438 | rx_status->band = hw->conf.channel->band; | ||
439 | rx_status->freq = hw->conf.channel->center_freq; | ||
440 | rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; | ||
441 | rx_status->antenna = rxbuf->rxstatus.rs_antenna; | ||
442 | rx_status->flag |= RX_FLAG_TSFT; | ||
443 | |||
444 | return true; | ||
445 | |||
446 | rx_next: | ||
447 | return false; | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * FIXME: Handle FLUSH later on. | ||
452 | */ | ||
453 | void ath9k_rx_tasklet(unsigned long data) | ||
454 | { | ||
455 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | ||
456 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; | ||
457 | struct ieee80211_rx_status rx_status; | ||
458 | struct sk_buff *skb; | ||
459 | unsigned long flags; | ||
460 | |||
461 | |||
462 | do { | ||
463 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); | ||
464 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { | ||
465 | if (tmp_buf->in_process) { | ||
466 | rxbuf = tmp_buf; | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if (rxbuf == NULL) { | ||
472 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | if (!rxbuf->skb) | ||
477 | goto requeue; | ||
478 | |||
479 | if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { | ||
480 | dev_kfree_skb_any(rxbuf->skb); | ||
481 | goto requeue; | ||
482 | } | ||
483 | |||
484 | memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, | ||
485 | sizeof(struct ieee80211_rx_status)); | ||
486 | skb = rxbuf->skb; | ||
487 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); | ||
488 | |||
489 | ieee80211_rx(priv->hw, skb); | ||
490 | |||
491 | spin_lock_irqsave(&priv->rx.rxbuflock, flags); | ||
492 | requeue: | ||
493 | rxbuf->in_process = false; | ||
494 | rxbuf->skb = NULL; | ||
495 | list_move_tail(&rxbuf->list, &priv->rx.rxbuf); | ||
496 | rxbuf = NULL; | ||
497 | spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); | ||
498 | } while (1); | ||
499 | |||
500 | } | ||
501 | |||
502 | void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, | ||
503 | enum htc_endpoint_id ep_id) | ||
504 | { | ||
505 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; | ||
506 | struct ath_hw *ah = priv->ah; | ||
507 | struct ath_common *common = ath9k_hw_common(ah); | ||
508 | struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; | ||
509 | struct ath_htc_rx_status *rxstatus; | ||
510 | u32 len = 0; | ||
511 | |||
512 | spin_lock(&priv->rx.rxbuflock); | ||
513 | list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { | ||
514 | if (!tmp_buf->in_process) { | ||
515 | rxbuf = tmp_buf; | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | spin_unlock(&priv->rx.rxbuflock); | ||
520 | |||
521 | if (rxbuf == NULL) { | ||
522 | ath_print(common, ATH_DBG_ANY, | ||
523 | "No free RX buffer\n"); | ||
524 | goto err; | ||
525 | } | ||
526 | |||
527 | len = skb->len; | ||
528 | if (len <= HTC_RX_FRAME_HEADER_SIZE) { | ||
529 | ath_print(common, ATH_DBG_FATAL, | ||
530 | "Corrupted RX frame, dropping\n"); | ||
531 | goto err; | ||
532 | } | ||
533 | |||
534 | rxstatus = (struct ath_htc_rx_status *)skb->data; | ||
535 | |||
536 | rxstatus->rs_tstamp = be64_to_cpu(rxstatus->rs_tstamp); | ||
537 | rxstatus->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); | ||
538 | rxstatus->evm0 = be32_to_cpu(rxstatus->evm0); | ||
539 | rxstatus->evm1 = be32_to_cpu(rxstatus->evm1); | ||
540 | rxstatus->evm2 = be32_to_cpu(rxstatus->evm2); | ||
541 | |||
542 | if (rxstatus->rs_datalen - (len - HTC_RX_FRAME_HEADER_SIZE) != 0) { | ||
543 | ath_print(common, ATH_DBG_FATAL, | ||
544 | "Corrupted RX data len, dropping " | ||
545 | "(epid: %d, dlen: %d, skblen: %d)\n", | ||
546 | ep_id, rxstatus->rs_datalen, len); | ||
547 | goto err; | ||
548 | } | ||
549 | |||
550 | spin_lock(&priv->rx.rxbuflock); | ||
551 | memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); | ||
552 | skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); | ||
553 | skb->len = rxstatus->rs_datalen; | ||
554 | rxbuf->skb = skb; | ||
555 | rxbuf->in_process = true; | ||
556 | spin_unlock(&priv->rx.rxbuflock); | ||
557 | |||
558 | tasklet_schedule(&priv->rx_tasklet); | ||
559 | return; | ||
560 | err: | ||
561 | dev_kfree_skb_any(skb); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | /* FIXME: Locking for cleanup/init */ | ||
566 | |||
567 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv) | ||
568 | { | ||
569 | struct ath9k_htc_rxbuf *rxbuf, *tbuf; | ||
570 | |||
571 | list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { | ||
572 | list_del(&rxbuf->list); | ||
573 | if (rxbuf->skb) | ||
574 | dev_kfree_skb_any(rxbuf->skb); | ||
575 | kfree(rxbuf); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | int ath9k_rx_init(struct ath9k_htc_priv *priv) | ||
580 | { | ||
581 | struct ath_hw *ah = priv->ah; | ||
582 | struct ath_common *common = ath9k_hw_common(ah); | ||
583 | struct ath9k_htc_rxbuf *rxbuf; | ||
584 | int i = 0; | ||
585 | |||
586 | INIT_LIST_HEAD(&priv->rx.rxbuf); | ||
587 | spin_lock_init(&priv->rx.rxbuflock); | ||
588 | |||
589 | for (i = 0; i < ATH9K_HTC_RXBUF; i++) { | ||
590 | rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); | ||
591 | if (rxbuf == NULL) { | ||
592 | ath_print(common, ATH_DBG_FATAL, | ||
593 | "Unable to allocate RX buffers\n"); | ||
594 | goto err; | ||
595 | } | ||
596 | list_add_tail(&rxbuf->list, &priv->rx.rxbuf); | ||
597 | } | ||
598 | |||
599 | return 0; | ||
600 | |||
601 | err: | ||
602 | ath9k_rx_cleanup(priv); | ||
603 | return -ENOMEM; | ||
604 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c new file mode 100644 index 000000000000..9a48999d0979 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | static int htc_issue_send(struct htc_target *target, struct sk_buff* skb, | ||
20 | u16 len, u8 flags, u8 epid, | ||
21 | struct ath9k_htc_tx_ctl *tx_ctl) | ||
22 | { | ||
23 | struct htc_frame_hdr *hdr; | ||
24 | struct htc_endpoint *endpoint = &target->endpoint[epid]; | ||
25 | int status; | ||
26 | |||
27 | hdr = (struct htc_frame_hdr *) | ||
28 | skb_push(skb, sizeof(struct htc_frame_hdr)); | ||
29 | hdr->endpoint_id = epid; | ||
30 | hdr->flags = flags; | ||
31 | hdr->payload_len = cpu_to_be16(len); | ||
32 | |||
33 | status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb, | ||
34 | tx_ctl); | ||
35 | return status; | ||
36 | } | ||
37 | |||
38 | static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint) | ||
39 | { | ||
40 | enum htc_endpoint_id avail_epid; | ||
41 | |||
42 | for (avail_epid = ENDPOINT_MAX; avail_epid > ENDPOINT0; avail_epid--) | ||
43 | if (endpoint[avail_epid].service_id == 0) | ||
44 | return &endpoint[avail_epid]; | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | static u8 service_to_ulpipe(u16 service_id) | ||
49 | { | ||
50 | switch (service_id) { | ||
51 | case WMI_CONTROL_SVC: | ||
52 | return 4; | ||
53 | case WMI_BEACON_SVC: | ||
54 | case WMI_CAB_SVC: | ||
55 | case WMI_UAPSD_SVC: | ||
56 | case WMI_MGMT_SVC: | ||
57 | case WMI_DATA_VO_SVC: | ||
58 | case WMI_DATA_VI_SVC: | ||
59 | case WMI_DATA_BE_SVC: | ||
60 | case WMI_DATA_BK_SVC: | ||
61 | return 1; | ||
62 | default: | ||
63 | return 0; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static u8 service_to_dlpipe(u16 service_id) | ||
68 | { | ||
69 | switch (service_id) { | ||
70 | case WMI_CONTROL_SVC: | ||
71 | return 3; | ||
72 | case WMI_BEACON_SVC: | ||
73 | case WMI_CAB_SVC: | ||
74 | case WMI_UAPSD_SVC: | ||
75 | case WMI_MGMT_SVC: | ||
76 | case WMI_DATA_VO_SVC: | ||
77 | case WMI_DATA_VI_SVC: | ||
78 | case WMI_DATA_BE_SVC: | ||
79 | case WMI_DATA_BK_SVC: | ||
80 | return 2; | ||
81 | default: | ||
82 | return 0; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static void htc_process_target_rdy(struct htc_target *target, | ||
87 | void *buf) | ||
88 | { | ||
89 | struct htc_endpoint *endpoint; | ||
90 | struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf; | ||
91 | |||
92 | target->credits = be16_to_cpu(htc_ready_msg->credits); | ||
93 | target->credit_size = be16_to_cpu(htc_ready_msg->credit_size); | ||
94 | |||
95 | endpoint = &target->endpoint[ENDPOINT0]; | ||
96 | endpoint->service_id = HTC_CTRL_RSVD_SVC; | ||
97 | endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH; | ||
98 | complete(&target->target_wait); | ||
99 | } | ||
100 | |||
101 | static void htc_process_conn_rsp(struct htc_target *target, | ||
102 | struct htc_frame_hdr *htc_hdr) | ||
103 | { | ||
104 | struct htc_conn_svc_rspmsg *svc_rspmsg; | ||
105 | struct htc_endpoint *endpoint, *tmp_endpoint = NULL; | ||
106 | u16 service_id; | ||
107 | u16 max_msglen; | ||
108 | enum htc_endpoint_id epid, tepid; | ||
109 | |||
110 | svc_rspmsg = (struct htc_conn_svc_rspmsg *) | ||
111 | ((void *) htc_hdr + sizeof(struct htc_frame_hdr)); | ||
112 | |||
113 | if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) { | ||
114 | epid = svc_rspmsg->endpoint_id; | ||
115 | service_id = be16_to_cpu(svc_rspmsg->service_id); | ||
116 | max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len); | ||
117 | endpoint = &target->endpoint[epid]; | ||
118 | |||
119 | for (tepid = ENDPOINT_MAX; tepid > ENDPOINT0; tepid--) { | ||
120 | tmp_endpoint = &target->endpoint[tepid]; | ||
121 | if (tmp_endpoint->service_id == service_id) { | ||
122 | tmp_endpoint->service_id = 0; | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (!tmp_endpoint) | ||
128 | return; | ||
129 | |||
130 | endpoint->service_id = service_id; | ||
131 | endpoint->max_txqdepth = tmp_endpoint->max_txqdepth; | ||
132 | endpoint->ep_callbacks = tmp_endpoint->ep_callbacks; | ||
133 | endpoint->ul_pipeid = tmp_endpoint->ul_pipeid; | ||
134 | endpoint->dl_pipeid = tmp_endpoint->dl_pipeid; | ||
135 | endpoint->max_msglen = max_msglen; | ||
136 | target->conn_rsp_epid = epid; | ||
137 | complete(&target->cmd_wait); | ||
138 | } else { | ||
139 | target->conn_rsp_epid = ENDPOINT_UNUSED; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | static int htc_config_pipe_credits(struct htc_target *target) | ||
144 | { | ||
145 | struct sk_buff *skb; | ||
146 | struct htc_config_pipe_msg *cp_msg; | ||
147 | int ret, time_left; | ||
148 | |||
149 | skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr)); | ||
150 | if (!skb) { | ||
151 | dev_err(target->dev, "failed to allocate send buffer\n"); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | skb_reserve(skb, sizeof(struct htc_frame_hdr)); | ||
155 | |||
156 | cp_msg = (struct htc_config_pipe_msg *) | ||
157 | skb_put(skb, sizeof(struct htc_config_pipe_msg)); | ||
158 | |||
159 | cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID); | ||
160 | cp_msg->pipe_id = USB_WLAN_TX_PIPE; | ||
161 | cp_msg->credits = 28; | ||
162 | |||
163 | target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS; | ||
164 | |||
165 | ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); | ||
166 | if (ret) | ||
167 | goto err; | ||
168 | |||
169 | time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); | ||
170 | if (!time_left) { | ||
171 | dev_err(target->dev, "HTC credit config timeout\n"); | ||
172 | return -ETIMEDOUT; | ||
173 | } | ||
174 | |||
175 | return 0; | ||
176 | err: | ||
177 | dev_kfree_skb(skb); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | static int htc_setup_complete(struct htc_target *target) | ||
182 | { | ||
183 | struct sk_buff *skb; | ||
184 | struct htc_comp_msg *comp_msg; | ||
185 | int ret = 0, time_left; | ||
186 | |||
187 | skb = dev_alloc_skb(50 + sizeof(struct htc_frame_hdr)); | ||
188 | if (!skb) { | ||
189 | dev_err(target->dev, "failed to allocate send buffer\n"); | ||
190 | return -ENOMEM; | ||
191 | } | ||
192 | skb_reserve(skb, sizeof(struct htc_frame_hdr)); | ||
193 | |||
194 | comp_msg = (struct htc_comp_msg *) | ||
195 | skb_put(skb, sizeof(struct htc_comp_msg)); | ||
196 | comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID); | ||
197 | |||
198 | target->htc_flags |= HTC_OP_START_WAIT; | ||
199 | |||
200 | ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); | ||
201 | if (ret) | ||
202 | goto err; | ||
203 | |||
204 | time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); | ||
205 | if (!time_left) { | ||
206 | dev_err(target->dev, "HTC start timeout\n"); | ||
207 | return -ETIMEDOUT; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | |||
212 | err: | ||
213 | dev_kfree_skb(skb); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | /* HTC APIs */ | ||
218 | |||
219 | int htc_init(struct htc_target *target) | ||
220 | { | ||
221 | int ret; | ||
222 | |||
223 | ret = htc_config_pipe_credits(target); | ||
224 | if (ret) | ||
225 | return ret; | ||
226 | |||
227 | return htc_setup_complete(target); | ||
228 | } | ||
229 | |||
230 | int htc_connect_service(struct htc_target *target, | ||
231 | struct htc_service_connreq *service_connreq, | ||
232 | enum htc_endpoint_id *conn_rsp_epid) | ||
233 | { | ||
234 | struct sk_buff *skb; | ||
235 | struct htc_endpoint *endpoint; | ||
236 | struct htc_conn_svc_msg *conn_msg; | ||
237 | int ret, time_left; | ||
238 | |||
239 | /* Find an available endpoint */ | ||
240 | endpoint = get_next_avail_ep(target->endpoint); | ||
241 | if (!endpoint) { | ||
242 | dev_err(target->dev, "Endpoint is not available for" | ||
243 | "service %d\n", service_connreq->service_id); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | endpoint->service_id = service_connreq->service_id; | ||
248 | endpoint->max_txqdepth = service_connreq->max_send_qdepth; | ||
249 | endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id); | ||
250 | endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id); | ||
251 | endpoint->ep_callbacks = service_connreq->ep_callbacks; | ||
252 | |||
253 | skb = dev_alloc_skb(sizeof(struct htc_conn_svc_msg) + | ||
254 | sizeof(struct htc_frame_hdr)); | ||
255 | if (!skb) { | ||
256 | dev_err(target->dev, "Failed to allocate buf to send" | ||
257 | "service connect req\n"); | ||
258 | return -ENOMEM; | ||
259 | } | ||
260 | |||
261 | skb_reserve(skb, sizeof(struct htc_frame_hdr)); | ||
262 | |||
263 | conn_msg = (struct htc_conn_svc_msg *) | ||
264 | skb_put(skb, sizeof(struct htc_conn_svc_msg)); | ||
265 | conn_msg->service_id = cpu_to_be16(service_connreq->service_id); | ||
266 | conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID); | ||
267 | conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags); | ||
268 | conn_msg->dl_pipeid = endpoint->dl_pipeid; | ||
269 | conn_msg->ul_pipeid = endpoint->ul_pipeid; | ||
270 | |||
271 | ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL); | ||
272 | if (ret) | ||
273 | goto err; | ||
274 | |||
275 | time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); | ||
276 | if (!time_left) { | ||
277 | dev_err(target->dev, "Service connection timeout for: %d\n", | ||
278 | service_connreq->service_id); | ||
279 | return -ETIMEDOUT; | ||
280 | } | ||
281 | |||
282 | *conn_rsp_epid = target->conn_rsp_epid; | ||
283 | return 0; | ||
284 | err: | ||
285 | dev_kfree_skb(skb); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int htc_send(struct htc_target *target, struct sk_buff *skb, | ||
290 | enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl) | ||
291 | { | ||
292 | return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl); | ||
293 | } | ||
294 | |||
295 | void htc_stop(struct htc_target *target) | ||
296 | { | ||
297 | enum htc_endpoint_id epid; | ||
298 | struct htc_endpoint *endpoint; | ||
299 | |||
300 | for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) { | ||
301 | endpoint = &target->endpoint[epid]; | ||
302 | if (endpoint->service_id != 0) | ||
303 | target->hif->stop(target->hif_dev, endpoint->ul_pipeid); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | void htc_start(struct htc_target *target) | ||
308 | { | ||
309 | enum htc_endpoint_id epid; | ||
310 | struct htc_endpoint *endpoint; | ||
311 | |||
312 | for (epid = ENDPOINT0; epid <= ENDPOINT_MAX; epid++) { | ||
313 | endpoint = &target->endpoint[epid]; | ||
314 | if (endpoint->service_id != 0) | ||
315 | target->hif->start(target->hif_dev, | ||
316 | endpoint->ul_pipeid); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, | ||
321 | struct sk_buff *skb, bool txok) | ||
322 | { | ||
323 | struct htc_endpoint *endpoint; | ||
324 | struct htc_frame_hdr *htc_hdr; | ||
325 | |||
326 | if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) { | ||
327 | complete(&htc_handle->cmd_wait); | ||
328 | htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS; | ||
329 | } | ||
330 | |||
331 | if (htc_handle->htc_flags & HTC_OP_START_WAIT) { | ||
332 | complete(&htc_handle->cmd_wait); | ||
333 | htc_handle->htc_flags &= ~HTC_OP_START_WAIT; | ||
334 | } | ||
335 | |||
336 | if (skb) { | ||
337 | htc_hdr = (struct htc_frame_hdr *) skb->data; | ||
338 | endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id]; | ||
339 | skb_pull(skb, sizeof(struct htc_frame_hdr)); | ||
340 | |||
341 | if (endpoint->ep_callbacks.tx) { | ||
342 | endpoint->ep_callbacks.tx(htc_handle->drv_priv, skb, | ||
343 | htc_hdr->endpoint_id, txok); | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * HTC Messages are handled directly here and the obtained SKB | ||
350 | * is freed. | ||
351 | * | ||
352 | * Sevice messages (Data, WMI) passed to the corresponding | ||
353 | * endpoint RX handlers, which have to free the SKB. | ||
354 | */ | ||
355 | void ath9k_htc_rx_msg(struct htc_target *htc_handle, | ||
356 | struct sk_buff *skb, u32 len, u8 pipe_id) | ||
357 | { | ||
358 | struct htc_frame_hdr *htc_hdr; | ||
359 | enum htc_endpoint_id epid; | ||
360 | struct htc_endpoint *endpoint; | ||
361 | u16 *msg_id; | ||
362 | |||
363 | if (!htc_handle || !skb) | ||
364 | return; | ||
365 | |||
366 | htc_hdr = (struct htc_frame_hdr *) skb->data; | ||
367 | epid = htc_hdr->endpoint_id; | ||
368 | |||
369 | if (epid >= ENDPOINT_MAX) { | ||
370 | dev_kfree_skb_any(skb); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | if (epid == ENDPOINT0) { | ||
375 | |||
376 | /* Handle trailer */ | ||
377 | if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) { | ||
378 | if (be32_to_cpu(*(u32 *) skb->data) == 0x00C60000) | ||
379 | /* Move past the Watchdog pattern */ | ||
380 | htc_hdr = (struct htc_frame_hdr *) skb->data + 4; | ||
381 | } | ||
382 | |||
383 | /* Get the message ID */ | ||
384 | msg_id = (u16 *) ((void *) htc_hdr + | ||
385 | sizeof(struct htc_frame_hdr)); | ||
386 | |||
387 | /* Now process HTC messages */ | ||
388 | switch (be16_to_cpu(*msg_id)) { | ||
389 | case HTC_MSG_READY_ID: | ||
390 | htc_process_target_rdy(htc_handle, htc_hdr); | ||
391 | break; | ||
392 | case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID: | ||
393 | htc_process_conn_rsp(htc_handle, htc_hdr); | ||
394 | break; | ||
395 | default: | ||
396 | break; | ||
397 | } | ||
398 | |||
399 | dev_kfree_skb_any(skb); | ||
400 | |||
401 | } else { | ||
402 | if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) | ||
403 | skb_trim(skb, len - htc_hdr->control[0]); | ||
404 | |||
405 | skb_pull(skb, sizeof(struct htc_frame_hdr)); | ||
406 | |||
407 | endpoint = &htc_handle->endpoint[epid]; | ||
408 | if (endpoint->ep_callbacks.rx) | ||
409 | endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv, | ||
410 | skb, epid); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | struct htc_target *ath9k_htc_hw_alloc(void *hif_handle) | ||
415 | { | ||
416 | struct htc_target *target; | ||
417 | |||
418 | target = kzalloc(sizeof(struct htc_target), GFP_KERNEL); | ||
419 | if (!target) | ||
420 | printk(KERN_ERR "Unable to allocate memory for" | ||
421 | "target device\n"); | ||
422 | |||
423 | return target; | ||
424 | } | ||
425 | |||
426 | void ath9k_htc_hw_free(struct htc_target *htc) | ||
427 | { | ||
428 | kfree(htc); | ||
429 | } | ||
430 | |||
431 | int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target, | ||
432 | void *hif_handle, struct device *dev, u16 devid, | ||
433 | enum ath9k_hif_transports transport) | ||
434 | { | ||
435 | struct htc_endpoint *endpoint; | ||
436 | int err = 0; | ||
437 | |||
438 | init_completion(&target->target_wait); | ||
439 | init_completion(&target->cmd_wait); | ||
440 | |||
441 | target->hif = hif; | ||
442 | target->hif_dev = hif_handle; | ||
443 | target->dev = dev; | ||
444 | |||
445 | /* Assign control endpoint pipe IDs */ | ||
446 | endpoint = &target->endpoint[ENDPOINT0]; | ||
447 | endpoint->ul_pipeid = hif->control_ul_pipe; | ||
448 | endpoint->dl_pipeid = hif->control_dl_pipe; | ||
449 | |||
450 | err = ath9k_htc_probe_device(target, dev, devid); | ||
451 | if (err) { | ||
452 | printk(KERN_ERR "Failed to initialize the device\n"); | ||
453 | return -ENODEV; | ||
454 | } | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug) | ||
460 | { | ||
461 | if (target) | ||
462 | ath9k_htc_disconnect_device(target, hot_unplug); | ||
463 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h new file mode 100644 index 000000000000..cd7048ffd239 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef HTC_HST_H | ||
18 | #define HTC_HST_H | ||
19 | |||
20 | struct ath9k_htc_priv; | ||
21 | struct htc_target; | ||
22 | struct ath9k_htc_tx_ctl; | ||
23 | |||
24 | enum ath9k_hif_transports { | ||
25 | ATH9K_HIF_USB, | ||
26 | }; | ||
27 | |||
28 | struct ath9k_htc_hif { | ||
29 | struct list_head list; | ||
30 | const enum ath9k_hif_transports transport; | ||
31 | const char *name; | ||
32 | |||
33 | u8 control_dl_pipe; | ||
34 | u8 control_ul_pipe; | ||
35 | |||
36 | void (*start) (void *hif_handle, u8 pipe); | ||
37 | void (*stop) (void *hif_handle, u8 pipe); | ||
38 | int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf, | ||
39 | struct ath9k_htc_tx_ctl *tx_ctl); | ||
40 | }; | ||
41 | |||
42 | enum htc_endpoint_id { | ||
43 | ENDPOINT_UNUSED = -1, | ||
44 | ENDPOINT0 = 0, | ||
45 | ENDPOINT1 = 1, | ||
46 | ENDPOINT2 = 2, | ||
47 | ENDPOINT3 = 3, | ||
48 | ENDPOINT4 = 4, | ||
49 | ENDPOINT5 = 5, | ||
50 | ENDPOINT6 = 6, | ||
51 | ENDPOINT7 = 7, | ||
52 | ENDPOINT8 = 8, | ||
53 | ENDPOINT_MAX = 22 | ||
54 | }; | ||
55 | |||
56 | /* Htc frame hdr flags */ | ||
57 | #define HTC_FLAGS_RECV_TRAILER (1 << 1) | ||
58 | |||
59 | struct htc_frame_hdr { | ||
60 | u8 endpoint_id; | ||
61 | u8 flags; | ||
62 | u16 payload_len; | ||
63 | u8 control[4]; | ||
64 | } __packed; | ||
65 | |||
66 | struct htc_ready_msg { | ||
67 | u16 message_id; | ||
68 | u16 credits; | ||
69 | u16 credit_size; | ||
70 | u8 max_endpoints; | ||
71 | u8 pad; | ||
72 | } __packed; | ||
73 | |||
74 | struct htc_config_pipe_msg { | ||
75 | u16 message_id; | ||
76 | u8 pipe_id; | ||
77 | u8 credits; | ||
78 | } __packed; | ||
79 | |||
80 | struct htc_packet { | ||
81 | void *pktcontext; | ||
82 | u8 *buf; | ||
83 | u8 *buf_payload; | ||
84 | u32 buflen; | ||
85 | u32 payload_len; | ||
86 | |||
87 | int endpoint; | ||
88 | int status; | ||
89 | |||
90 | void *context; | ||
91 | u32 reserved; | ||
92 | }; | ||
93 | |||
94 | struct htc_ep_callbacks { | ||
95 | void *priv; | ||
96 | void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok); | ||
97 | void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); | ||
98 | }; | ||
99 | |||
100 | #define HTC_TX_QUEUE_SIZE 256 | ||
101 | |||
102 | struct htc_txq { | ||
103 | struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; | ||
104 | u32 txqdepth; | ||
105 | u16 txbuf_cnt; | ||
106 | u16 txq_head; | ||
107 | u16 txq_tail; | ||
108 | }; | ||
109 | |||
110 | struct htc_endpoint { | ||
111 | u16 service_id; | ||
112 | |||
113 | struct htc_ep_callbacks ep_callbacks; | ||
114 | struct htc_txq htc_txq; | ||
115 | u32 max_txqdepth; | ||
116 | int max_msglen; | ||
117 | |||
118 | u8 ul_pipeid; | ||
119 | u8 dl_pipeid; | ||
120 | }; | ||
121 | |||
122 | #define HTC_MAX_CONTROL_MESSAGE_LENGTH 255 | ||
123 | #define HTC_CONTROL_BUFFER_SIZE \ | ||
124 | (HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr)) | ||
125 | |||
126 | #define NUM_CONTROL_BUFFERS 8 | ||
127 | #define HST_ENDPOINT_MAX 8 | ||
128 | |||
129 | struct htc_control_buf { | ||
130 | struct htc_packet htc_pkt; | ||
131 | u8 buf[HTC_CONTROL_BUFFER_SIZE]; | ||
132 | }; | ||
133 | |||
134 | #define HTC_OP_START_WAIT BIT(0) | ||
135 | #define HTC_OP_CONFIG_PIPE_CREDITS BIT(1) | ||
136 | |||
137 | struct htc_target { | ||
138 | void *hif_dev; | ||
139 | struct ath9k_htc_priv *drv_priv; | ||
140 | struct device *dev; | ||
141 | struct ath9k_htc_hif *hif; | ||
142 | struct htc_endpoint endpoint[HST_ENDPOINT_MAX]; | ||
143 | struct completion target_wait; | ||
144 | struct completion cmd_wait; | ||
145 | struct list_head list; | ||
146 | enum htc_endpoint_id conn_rsp_epid; | ||
147 | u16 credits; | ||
148 | u16 credit_size; | ||
149 | u8 htc_flags; | ||
150 | }; | ||
151 | |||
152 | enum htc_msg_id { | ||
153 | HTC_MSG_READY_ID = 1, | ||
154 | HTC_MSG_CONNECT_SERVICE_ID, | ||
155 | HTC_MSG_CONNECT_SERVICE_RESPONSE_ID, | ||
156 | HTC_MSG_SETUP_COMPLETE_ID, | ||
157 | HTC_MSG_CONFIG_PIPE_ID, | ||
158 | HTC_MSG_CONFIG_PIPE_RESPONSE_ID, | ||
159 | }; | ||
160 | |||
161 | struct htc_service_connreq { | ||
162 | u16 service_id; | ||
163 | u16 con_flags; | ||
164 | u32 max_send_qdepth; | ||
165 | struct htc_ep_callbacks ep_callbacks; | ||
166 | }; | ||
167 | |||
168 | /* Current service IDs */ | ||
169 | |||
170 | enum htc_service_group_ids{ | ||
171 | RSVD_SERVICE_GROUP = 0, | ||
172 | WMI_SERVICE_GROUP = 1, | ||
173 | |||
174 | HTC_SERVICE_GROUP_LAST = 255 | ||
175 | }; | ||
176 | |||
177 | #define MAKE_SERVICE_ID(group, index) \ | ||
178 | (int)(((int)group << 8) | (int)(index)) | ||
179 | |||
180 | /* NOTE: service ID of 0x0000 is reserved and should never be used */ | ||
181 | #define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1) | ||
182 | #define HTC_LOOPBACK_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 2) | ||
183 | |||
184 | #define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0) | ||
185 | #define WMI_BEACON_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1) | ||
186 | #define WMI_CAB_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2) | ||
187 | #define WMI_UAPSD_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3) | ||
188 | #define WMI_MGMT_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) | ||
189 | #define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 5) | ||
190 | #define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 6) | ||
191 | #define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 7) | ||
192 | #define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 8) | ||
193 | |||
194 | struct htc_conn_svc_msg { | ||
195 | u16 msg_id; | ||
196 | u16 service_id; | ||
197 | u16 con_flags; | ||
198 | u8 dl_pipeid; | ||
199 | u8 ul_pipeid; | ||
200 | u8 svc_meta_len; | ||
201 | u8 pad; | ||
202 | } __packed; | ||
203 | |||
204 | /* connect response status codes */ | ||
205 | #define HTC_SERVICE_SUCCESS 0 | ||
206 | #define HTC_SERVICE_NOT_FOUND 1 | ||
207 | #define HTC_SERVICE_FAILED 2 | ||
208 | #define HTC_SERVICE_NO_RESOURCES 3 | ||
209 | #define HTC_SERVICE_NO_MORE_EP 4 | ||
210 | |||
211 | struct htc_conn_svc_rspmsg { | ||
212 | u16 msg_id; | ||
213 | u16 service_id; | ||
214 | u8 status; | ||
215 | u8 endpoint_id; | ||
216 | u16 max_msg_len; | ||
217 | u8 svc_meta_len; | ||
218 | u8 pad; | ||
219 | } __packed; | ||
220 | |||
221 | struct htc_comp_msg { | ||
222 | u16 msg_id; | ||
223 | } __packed; | ||
224 | |||
225 | int htc_init(struct htc_target *target); | ||
226 | int htc_connect_service(struct htc_target *target, | ||
227 | struct htc_service_connreq *service_connreq, | ||
228 | enum htc_endpoint_id *conn_rsp_eid); | ||
229 | int htc_send(struct htc_target *target, struct sk_buff *skb, | ||
230 | enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl); | ||
231 | void htc_stop(struct htc_target *target); | ||
232 | void htc_start(struct htc_target *target); | ||
233 | |||
234 | void ath9k_htc_rx_msg(struct htc_target *htc_handle, | ||
235 | struct sk_buff *skb, u32 len, u8 pipe_id); | ||
236 | void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, | ||
237 | struct sk_buff *skb, bool txok); | ||
238 | |||
239 | struct htc_target *ath9k_htc_hw_alloc(void *hif_handle); | ||
240 | void ath9k_htc_hw_free(struct htc_target *htc); | ||
241 | int ath9k_htc_hw_init(struct ath9k_htc_hif *hif, struct htc_target *target, | ||
242 | void *hif_handle, struct device *dev, u16 devid, | ||
243 | enum ath9k_hif_transports transport); | ||
244 | void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug); | ||
245 | |||
246 | #endif /* HTC_HST_H */ | ||
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1fb14edfcb2a..77db932c3137 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -499,8 +499,10 @@ static int ath9k_hw_post_init(struct ath_hw *ah) | |||
499 | { | 499 | { |
500 | int ecode; | 500 | int ecode; |
501 | 501 | ||
502 | if (!ath9k_hw_chip_test(ah)) | 502 | if (!AR_SREV_9271(ah)) { |
503 | return -ENODEV; | 503 | if (!ath9k_hw_chip_test(ah)) |
504 | return -ENODEV; | ||
505 | } | ||
504 | 506 | ||
505 | ecode = ath9k_hw_rf_claim(ah); | 507 | ecode = ath9k_hw_rf_claim(ah); |
506 | if (ecode != 0) | 508 | if (ecode != 0) |
@@ -603,9 +605,23 @@ static void ath9k_hw_init_mode_regs(struct ath_hw *ah) | |||
603 | ARRAY_SIZE(ar9271Modes_9271), 6); | 605 | ARRAY_SIZE(ar9271Modes_9271), 6); |
604 | INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, | 606 | INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, |
605 | ARRAY_SIZE(ar9271Common_9271), 2); | 607 | ARRAY_SIZE(ar9271Common_9271), 2); |
608 | INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271, | ||
609 | ar9271Common_normal_cck_fir_coeff_9271, | ||
610 | ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2); | ||
611 | INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271, | ||
612 | ar9271Common_japan_2484_cck_fir_coeff_9271, | ||
613 | ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2); | ||
606 | INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, | 614 | INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, |
607 | ar9271Modes_9271_1_0_only, | 615 | ar9271Modes_9271_1_0_only, |
608 | ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); | 616 | ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); |
617 | INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, | ||
618 | ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6); | ||
619 | INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271, | ||
620 | ar9271Modes_high_power_tx_gain_9271, | ||
621 | ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6); | ||
622 | INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, | ||
623 | ar9271Modes_normal_power_tx_gain_9271, | ||
624 | ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6); | ||
609 | return; | 625 | return; |
610 | } | 626 | } |
611 | 627 | ||
@@ -990,22 +1006,6 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) | |||
990 | REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); | 1006 | REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); |
991 | } | 1007 | } |
992 | 1008 | ||
993 | static void ath9k_hw_change_target_baud(struct ath_hw *ah, u32 freq, u32 baud) | ||
994 | { | ||
995 | u32 lcr; | ||
996 | u32 baud_divider = freq * 1000 * 1000 / 16 / baud; | ||
997 | |||
998 | lcr = REG_READ(ah , 0x5100c); | ||
999 | lcr |= 0x80; | ||
1000 | |||
1001 | REG_WRITE(ah, 0x5100c, lcr); | ||
1002 | REG_WRITE(ah, 0x51004, (baud_divider >> 8)); | ||
1003 | REG_WRITE(ah, 0x51000, (baud_divider & 0xff)); | ||
1004 | |||
1005 | lcr &= ~0x80; | ||
1006 | REG_WRITE(ah, 0x5100c, lcr); | ||
1007 | } | ||
1008 | |||
1009 | static void ath9k_hw_init_pll(struct ath_hw *ah, | 1009 | static void ath9k_hw_init_pll(struct ath_hw *ah, |
1010 | struct ath9k_channel *chan) | 1010 | struct ath9k_channel *chan) |
1011 | { | 1011 | { |
@@ -1071,22 +1071,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, | |||
1071 | 1071 | ||
1072 | /* Switch the core clock for ar9271 to 117Mhz */ | 1072 | /* Switch the core clock for ar9271 to 117Mhz */ |
1073 | if (AR_SREV_9271(ah)) { | 1073 | if (AR_SREV_9271(ah)) { |
1074 | if ((pll == 0x142c) || (pll == 0x2850) ) { | 1074 | udelay(500); |
1075 | udelay(500); | 1075 | REG_WRITE(ah, 0x50040, 0x304); |
1076 | /* set CLKOBS to output AHB clock */ | ||
1077 | REG_WRITE(ah, 0x7020, 0xe); | ||
1078 | /* | ||
1079 | * 0x304: 117Mhz, ahb_ratio: 1x1 | ||
1080 | * 0x306: 40Mhz, ahb_ratio: 1x1 | ||
1081 | */ | ||
1082 | REG_WRITE(ah, 0x50040, 0x304); | ||
1083 | /* | ||
1084 | * makes adjustments for the baud dividor to keep the | ||
1085 | * targetted baud rate based on the used core clock. | ||
1086 | */ | ||
1087 | ath9k_hw_change_target_baud(ah, AR9271_CORE_CLOCK, | ||
1088 | AR9271_TARGET_BAUD_RATE); | ||
1089 | } | ||
1090 | } | 1076 | } |
1091 | 1077 | ||
1092 | udelay(RTC_PLL_SETTLE_DELAY); | 1078 | udelay(RTC_PLL_SETTLE_DELAY); |
@@ -1241,7 +1227,7 @@ void ath9k_hw_deinit(struct ath_hw *ah) | |||
1241 | { | 1227 | { |
1242 | struct ath_common *common = ath9k_hw_common(ah); | 1228 | struct ath_common *common = ath9k_hw_common(ah); |
1243 | 1229 | ||
1244 | if (common->state <= ATH_HW_INITIALIZED) | 1230 | if (common->state < ATH_HW_INITIALIZED) |
1245 | goto free_hw; | 1231 | goto free_hw; |
1246 | 1232 | ||
1247 | if (!AR_SREV_9100(ah)) | 1233 | if (!AR_SREV_9100(ah)) |
@@ -1252,8 +1238,6 @@ void ath9k_hw_deinit(struct ath_hw *ah) | |||
1252 | free_hw: | 1238 | free_hw: |
1253 | if (!AR_SREV_9280_10_OR_LATER(ah)) | 1239 | if (!AR_SREV_9280_10_OR_LATER(ah)) |
1254 | ath9k_hw_rf_free_ext_banks(ah); | 1240 | ath9k_hw_rf_free_ext_banks(ah); |
1255 | kfree(ah); | ||
1256 | ah = NULL; | ||
1257 | } | 1241 | } |
1258 | EXPORT_SYMBOL(ath9k_hw_deinit); | 1242 | EXPORT_SYMBOL(ath9k_hw_deinit); |
1259 | 1243 | ||
@@ -1266,26 +1250,6 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, | |||
1266 | { | 1250 | { |
1267 | u32 val; | 1251 | u32 val; |
1268 | 1252 | ||
1269 | if (AR_SREV_9271(ah)) { | ||
1270 | /* | ||
1271 | * Enable spectral scan to solution for issues with stuck | ||
1272 | * beacons on AR9271 1.0. The beacon stuck issue is not seeon on | ||
1273 | * AR9271 1.1 | ||
1274 | */ | ||
1275 | if (AR_SREV_9271_10(ah)) { | ||
1276 | val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | | ||
1277 | AR_PHY_SPECTRAL_SCAN_ENABLE; | ||
1278 | REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val); | ||
1279 | } | ||
1280 | else if (AR_SREV_9271_11(ah)) | ||
1281 | /* | ||
1282 | * change AR_PHY_RF_CTL3 setting to fix MAC issue | ||
1283 | * present on AR9271 1.1 | ||
1284 | */ | ||
1285 | REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001); | ||
1286 | return; | ||
1287 | } | ||
1288 | |||
1289 | /* | 1253 | /* |
1290 | * Set the RX_ABORT and RX_DIS and clear if off only after | 1254 | * Set the RX_ABORT and RX_DIS and clear if off only after |
1291 | * RXE is set for MAC. This prevents frames with corrupted | 1255 | * RXE is set for MAC. This prevents frames with corrupted |
@@ -1294,8 +1258,10 @@ static void ath9k_hw_override_ini(struct ath_hw *ah, | |||
1294 | REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); | 1258 | REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); |
1295 | 1259 | ||
1296 | if (AR_SREV_9280_10_OR_LATER(ah)) { | 1260 | if (AR_SREV_9280_10_OR_LATER(ah)) { |
1297 | val = REG_READ(ah, AR_PCU_MISC_MODE2) & | 1261 | val = REG_READ(ah, AR_PCU_MISC_MODE2); |
1298 | (~AR_PCU_MISC_MODE2_HWWAR1); | 1262 | |
1263 | if (!AR_SREV_9271(ah)) | ||
1264 | val &= ~AR_PCU_MISC_MODE2_HWWAR1; | ||
1299 | 1265 | ||
1300 | if (AR_SREV_9287_10_OR_LATER(ah)) | 1266 | if (AR_SREV_9287_10_OR_LATER(ah)) |
1301 | val = val & (~AR_PCU_MISC_MODE2_HWWAR2); | 1267 | val = val & (~AR_PCU_MISC_MODE2_HWWAR2); |
@@ -1439,7 +1405,10 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1439 | return -EINVAL; | 1405 | return -EINVAL; |
1440 | } | 1406 | } |
1441 | 1407 | ||
1408 | /* Set correct baseband to analog shift setting to access analog chips */ | ||
1442 | REG_WRITE(ah, AR_PHY(0), 0x00000007); | 1409 | REG_WRITE(ah, AR_PHY(0), 0x00000007); |
1410 | |||
1411 | /* Write ADDAC shifts */ | ||
1443 | REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); | 1412 | REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); |
1444 | ah->eep_ops->set_addac(ah, chan); | 1413 | ah->eep_ops->set_addac(ah, chan); |
1445 | 1414 | ||
@@ -1451,9 +1420,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1451 | sizeof(u32) * ah->iniAddac.ia_rows * | 1420 | sizeof(u32) * ah->iniAddac.ia_rows * |
1452 | ah->iniAddac.ia_columns; | 1421 | ah->iniAddac.ia_columns; |
1453 | 1422 | ||
1423 | /* For AR5416 2.0/2.1 */ | ||
1454 | memcpy(ah->addac5416_21, | 1424 | memcpy(ah->addac5416_21, |
1455 | ah->iniAddac.ia_array, addacSize); | 1425 | ah->iniAddac.ia_array, addacSize); |
1456 | 1426 | ||
1427 | /* override CLKDRV value at [row, column] = [31, 1] */ | ||
1457 | (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; | 1428 | (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; |
1458 | 1429 | ||
1459 | temp.ia_array = ah->addac5416_21; | 1430 | temp.ia_array = ah->addac5416_21; |
@@ -1485,6 +1456,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1485 | AR_SREV_9287_10_OR_LATER(ah)) | 1456 | AR_SREV_9287_10_OR_LATER(ah)) |
1486 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); | 1457 | REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); |
1487 | 1458 | ||
1459 | if (AR_SREV_9271_10(ah)) | ||
1460 | REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, | ||
1461 | modesIndex, regWrites); | ||
1462 | |||
1463 | /* Write common array parameters */ | ||
1488 | for (i = 0; i < ah->iniCommon.ia_rows; i++) { | 1464 | for (i = 0; i < ah->iniCommon.ia_rows; i++) { |
1489 | u32 reg = INI_RA(&ah->iniCommon, i, 0); | 1465 | u32 reg = INI_RA(&ah->iniCommon, i, 0); |
1490 | u32 val = INI_RA(&ah->iniCommon, i, 1); | 1466 | u32 val = INI_RA(&ah->iniCommon, i, 1); |
@@ -1499,11 +1475,16 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1499 | DO_DELAY(regWrites); | 1475 | DO_DELAY(regWrites); |
1500 | } | 1476 | } |
1501 | 1477 | ||
1502 | ath9k_hw_write_regs(ah, freqIndex, regWrites); | 1478 | if (AR_SREV_9271(ah)) { |
1479 | if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1) | ||
1480 | REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271, | ||
1481 | modesIndex, regWrites); | ||
1482 | else | ||
1483 | REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, | ||
1484 | modesIndex, regWrites); | ||
1485 | } | ||
1503 | 1486 | ||
1504 | if (AR_SREV_9271_10(ah)) | 1487 | ath9k_hw_write_regs(ah, freqIndex, regWrites); |
1505 | REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only, | ||
1506 | modesIndex, regWrites); | ||
1507 | 1488 | ||
1508 | if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { | 1489 | if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) { |
1509 | REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, | 1490 | REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, |
@@ -1517,6 +1498,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1517 | if (OLC_FOR_AR9280_20_LATER) | 1498 | if (OLC_FOR_AR9280_20_LATER) |
1518 | ath9k_olc_init(ah); | 1499 | ath9k_olc_init(ah); |
1519 | 1500 | ||
1501 | /* Set TX power */ | ||
1520 | ah->eep_ops->set_txpower(ah, chan, | 1502 | ah->eep_ops->set_txpower(ah, chan, |
1521 | ath9k_regd_get_ctl(regulatory, chan), | 1503 | ath9k_regd_get_ctl(regulatory, chan), |
1522 | channel->max_antenna_gain * 2, | 1504 | channel->max_antenna_gain * 2, |
@@ -1524,6 +1506,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1524 | min((u32) MAX_RATE_POWER, | 1506 | min((u32) MAX_RATE_POWER, |
1525 | (u32) regulatory->power_limit)); | 1507 | (u32) regulatory->power_limit)); |
1526 | 1508 | ||
1509 | /* Write analog registers */ | ||
1527 | if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { | 1510 | if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { |
1528 | ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, | 1511 | ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, |
1529 | "ar5416SetRfRegs failed\n"); | 1512 | "ar5416SetRfRegs failed\n"); |
@@ -1966,6 +1949,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1966 | 1949 | ||
1967 | ath9k_hw_mark_phy_inactive(ah); | 1950 | ath9k_hw_mark_phy_inactive(ah); |
1968 | 1951 | ||
1952 | /* Only required on the first reset */ | ||
1969 | if (AR_SREV_9271(ah) && ah->htc_reset_init) { | 1953 | if (AR_SREV_9271(ah) && ah->htc_reset_init) { |
1970 | REG_WRITE(ah, | 1954 | REG_WRITE(ah, |
1971 | AR9271_RESET_POWER_DOWN_CONTROL, | 1955 | AR9271_RESET_POWER_DOWN_CONTROL, |
@@ -1978,6 +1962,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1978 | return -EINVAL; | 1962 | return -EINVAL; |
1979 | } | 1963 | } |
1980 | 1964 | ||
1965 | /* Only required on the first reset */ | ||
1981 | if (AR_SREV_9271(ah) && ah->htc_reset_init) { | 1966 | if (AR_SREV_9271(ah) && ah->htc_reset_init) { |
1982 | ah->htc_reset_init = false; | 1967 | ah->htc_reset_init = false; |
1983 | REG_WRITE(ah, | 1968 | REG_WRITE(ah, |
@@ -2438,7 +2423,7 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) | |||
2438 | if (!AR_SREV_9100(ah)) | 2423 | if (!AR_SREV_9100(ah)) |
2439 | REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); | 2424 | REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); |
2440 | 2425 | ||
2441 | if(!AR_SREV_5416(ah)) | 2426 | if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) |
2442 | REG_CLR_BIT(ah, (AR_RTC_RESET), | 2427 | REG_CLR_BIT(ah, (AR_RTC_RESET), |
2443 | AR_RTC_RESET_EN); | 2428 | AR_RTC_RESET_EN); |
2444 | } | 2429 | } |
@@ -3216,7 +3201,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
3216 | else | 3201 | else |
3217 | pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; | 3202 | pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; |
3218 | 3203 | ||
3219 | if (AR_SREV_9285_10_OR_LATER(ah)) | 3204 | if (AR_SREV_9271(ah)) |
3205 | pCap->num_gpio_pins = AR9271_NUM_GPIO; | ||
3206 | else if (AR_SREV_9285_10_OR_LATER(ah)) | ||
3220 | pCap->num_gpio_pins = AR9285_NUM_GPIO; | 3207 | pCap->num_gpio_pins = AR9285_NUM_GPIO; |
3221 | else if (AR_SREV_9280_10_OR_LATER(ah)) | 3208 | else if (AR_SREV_9280_10_OR_LATER(ah)) |
3222 | pCap->num_gpio_pins = AR928X_NUM_GPIO; | 3209 | pCap->num_gpio_pins = AR928X_NUM_GPIO; |
@@ -3452,7 +3439,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio) | |||
3452 | if (gpio >= ah->caps.num_gpio_pins) | 3439 | if (gpio >= ah->caps.num_gpio_pins) |
3453 | return 0xffffffff; | 3440 | return 0xffffffff; |
3454 | 3441 | ||
3455 | if (AR_SREV_9287_10_OR_LATER(ah)) | 3442 | if (AR_SREV_9271(ah)) |
3443 | return MS_REG_READ(AR9271, gpio) != 0; | ||
3444 | else if (AR_SREV_9287_10_OR_LATER(ah)) | ||
3456 | return MS_REG_READ(AR9287, gpio) != 0; | 3445 | return MS_REG_READ(AR9287, gpio) != 0; |
3457 | else if (AR_SREV_9285_10_OR_LATER(ah)) | 3446 | else if (AR_SREV_9285_10_OR_LATER(ah)) |
3458 | return MS_REG_READ(AR9285, gpio) != 0; | 3447 | return MS_REG_READ(AR9285, gpio) != 0; |
@@ -3481,6 +3470,9 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output); | |||
3481 | 3470 | ||
3482 | void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) | 3471 | void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val) |
3483 | { | 3472 | { |
3473 | if (AR_SREV_9271(ah)) | ||
3474 | val = ~val; | ||
3475 | |||
3484 | REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), | 3476 | REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), |
3485 | AR_GPIO_BIT(gpio)); | 3477 | AR_GPIO_BIT(gpio)); |
3486 | } | 3478 | } |
@@ -3865,6 +3857,16 @@ void ath_gen_timer_isr(struct ath_hw *ah) | |||
3865 | } | 3857 | } |
3866 | EXPORT_SYMBOL(ath_gen_timer_isr); | 3858 | EXPORT_SYMBOL(ath_gen_timer_isr); |
3867 | 3859 | ||
3860 | /********/ | ||
3861 | /* HTC */ | ||
3862 | /********/ | ||
3863 | |||
3864 | void ath9k_hw_htc_resetinit(struct ath_hw *ah) | ||
3865 | { | ||
3866 | ah->htc_reset_init = true; | ||
3867 | } | ||
3868 | EXPORT_SYMBOL(ath9k_hw_htc_resetinit); | ||
3869 | |||
3868 | static struct { | 3870 | static struct { |
3869 | u32 version; | 3871 | u32 version; |
3870 | const char * name; | 3872 | const char * name; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 20d90268ce31..6b03e1688b22 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -599,6 +599,11 @@ struct ath_hw { | |||
599 | struct ar5416IniArray iniModes_9271_1_0_only; | 599 | struct ar5416IniArray iniModes_9271_1_0_only; |
600 | struct ar5416IniArray iniCckfirNormal; | 600 | struct ar5416IniArray iniCckfirNormal; |
601 | struct ar5416IniArray iniCckfirJapan2484; | 601 | struct ar5416IniArray iniCckfirJapan2484; |
602 | struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271; | ||
603 | struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271; | ||
604 | struct ar5416IniArray iniModes_9271_ANI_reg; | ||
605 | struct ar5416IniArray iniModes_high_power_tx_gain_9271; | ||
606 | struct ar5416IniArray iniModes_normal_power_tx_gain_9271; | ||
602 | 607 | ||
603 | u32 intr_gen_timer_trigger; | 608 | u32 intr_gen_timer_trigger; |
604 | u32 intr_gen_timer_thresh; | 609 | u32 intr_gen_timer_thresh; |
@@ -702,6 +707,9 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); | |||
702 | 707 | ||
703 | void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); | 708 | void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); |
704 | 709 | ||
710 | /* HTC */ | ||
711 | void ath9k_hw_htc_resetinit(struct ath_hw *ah); | ||
712 | |||
705 | #define ATH_PCIE_CAP_LINK_CTRL 0x70 | 713 | #define ATH_PCIE_CAP_LINK_CTRL 0x70 |
706 | #define ATH_PCIE_CAP_LINK_L0S 1 | 714 | #define ATH_PCIE_CAP_LINK_L0S 1 |
707 | #define ATH_PCIE_CAP_LINK_L1 2 | 715 | #define ATH_PCIE_CAP_LINK_L1 2 |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 623c2f884987..6063f5463708 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -758,6 +758,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc) | |||
758 | 758 | ||
759 | tasklet_kill(&sc->intr_tq); | 759 | tasklet_kill(&sc->intr_tq); |
760 | tasklet_kill(&sc->bcon_tasklet); | 760 | tasklet_kill(&sc->bcon_tasklet); |
761 | |||
762 | kfree(sc->sc_ah); | ||
763 | sc->sc_ah = NULL; | ||
761 | } | 764 | } |
762 | 765 | ||
763 | void ath9k_deinit_device(struct ath_softc *sc) | 766 | void ath9k_deinit_device(struct ath_softc *sc) |
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h index 8a3bf3ab998d..177bdeb84ad7 100644 --- a/drivers/net/wireless/ath/ath9k/initvals.h +++ b/drivers/net/wireless/ath/ath9k/initvals.h | |||
@@ -6441,7 +6441,7 @@ static const u_int32_t ar9271Modes_9271[][6] = { | |||
6441 | { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, | 6441 | { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, |
6442 | { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, | 6442 | { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, |
6443 | { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, | 6443 | { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, |
6444 | { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, | 6444 | { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, |
6445 | { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, | 6445 | { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, |
6446 | { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, | 6446 | { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, |
6447 | { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, | 6447 | { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, |
@@ -6455,8 +6455,8 @@ static const u_int32_t ar9271Modes_9271[][6] = { | |||
6455 | { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, | 6455 | { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, |
6456 | { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, | 6456 | { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, |
6457 | { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, | 6457 | { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, |
6458 | { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, | 6458 | { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, |
6459 | { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, | 6459 | { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, |
6460 | { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, | 6460 | { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, |
6461 | { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, | 6461 | { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, |
6462 | { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, | 6462 | { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, |
@@ -6569,7 +6569,7 @@ static const u_int32_t ar9271Modes_9271[][6] = { | |||
6569 | { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, | 6569 | { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 }, |
6570 | { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, | 6570 | { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 }, |
6571 | { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, | 6571 | { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 }, |
6572 | { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 }, | 6572 | { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 }, |
6573 | { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, | 6573 | { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 }, |
6574 | { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, | 6574 | { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 }, |
6575 | { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, | 6575 | { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 }, |
@@ -6583,8 +6583,8 @@ static const u_int32_t ar9271Modes_9271[][6] = { | |||
6583 | { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, | 6583 | { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, |
6584 | { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, | 6584 | { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, |
6585 | { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, | 6585 | { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, |
6586 | { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, | 6586 | { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 }, |
6587 | { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, | 6587 | { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 }, |
6588 | { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, | 6588 | { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 }, |
6589 | { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, | 6589 | { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 }, |
6590 | { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, | 6590 | { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 }, |
@@ -6683,25 +6683,6 @@ static const u_int32_t ar9271Modes_9271[][6] = { | |||
6683 | { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, | 6683 | { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, |
6684 | { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, | 6684 | { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, |
6685 | { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, | 6685 | { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, |
6686 | { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, | ||
6687 | { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, | ||
6688 | { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, | ||
6689 | { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, | ||
6690 | { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, | ||
6691 | { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, | ||
6692 | { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, | ||
6693 | { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, | ||
6694 | { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, | ||
6695 | { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, | ||
6696 | { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, | ||
6697 | { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, | ||
6698 | { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, | ||
6699 | { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, | ||
6700 | { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, | ||
6701 | { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, | ||
6702 | { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, | ||
6703 | { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
6704 | { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
6705 | { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, | 6686 | { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, |
6706 | }; | 6687 | }; |
6707 | 6688 | ||
@@ -6879,7 +6860,7 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
6879 | { 0x00008258, 0x00000000 }, | 6860 | { 0x00008258, 0x00000000 }, |
6880 | { 0x0000825c, 0x400000ff }, | 6861 | { 0x0000825c, 0x400000ff }, |
6881 | { 0x00008260, 0x00080922 }, | 6862 | { 0x00008260, 0x00080922 }, |
6882 | { 0x00008264, 0x88a00010 }, | 6863 | { 0x00008264, 0xa8a00010 }, |
6883 | { 0x00008270, 0x00000000 }, | 6864 | { 0x00008270, 0x00000000 }, |
6884 | { 0x00008274, 0x40000000 }, | 6865 | { 0x00008274, 0x40000000 }, |
6885 | { 0x00008278, 0x003e4180 }, | 6866 | { 0x00008278, 0x003e4180 }, |
@@ -6910,13 +6891,10 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
6910 | { 0x00007810, 0x71c0d388 }, | 6891 | { 0x00007810, 0x71c0d388 }, |
6911 | { 0x00007814, 0x924934a8 }, | 6892 | { 0x00007814, 0x924934a8 }, |
6912 | { 0x0000781c, 0x00000000 }, | 6893 | { 0x0000781c, 0x00000000 }, |
6913 | { 0x00007820, 0x00000c04 }, | ||
6914 | { 0x00007824, 0x00d8abff }, | ||
6915 | { 0x00007828, 0x66964300 }, | 6894 | { 0x00007828, 0x66964300 }, |
6916 | { 0x0000782c, 0x8db6d961 }, | 6895 | { 0x0000782c, 0x8db6d961 }, |
6917 | { 0x00007830, 0x8db6d96c }, | 6896 | { 0x00007830, 0x8db6d96c }, |
6918 | { 0x00007834, 0x6140008b }, | 6897 | { 0x00007834, 0x6140008b }, |
6919 | { 0x00007838, 0x00000029 }, | ||
6920 | { 0x0000783c, 0x72ee0a72 }, | 6898 | { 0x0000783c, 0x72ee0a72 }, |
6921 | { 0x00007840, 0xbbfffffc }, | 6899 | { 0x00007840, 0xbbfffffc }, |
6922 | { 0x00007844, 0x000c0db6 }, | 6900 | { 0x00007844, 0x000c0db6 }, |
@@ -6929,7 +6907,6 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
6929 | { 0x00007860, 0x21084210 }, | 6907 | { 0x00007860, 0x21084210 }, |
6930 | { 0x00007864, 0xf7d7ffde }, | 6908 | { 0x00007864, 0xf7d7ffde }, |
6931 | { 0x00007868, 0xc2034080 }, | 6909 | { 0x00007868, 0xc2034080 }, |
6932 | { 0x0000786c, 0x48609eb4 }, | ||
6933 | { 0x00007870, 0x10142c00 }, | 6910 | { 0x00007870, 0x10142c00 }, |
6934 | { 0x00009808, 0x00000000 }, | 6911 | { 0x00009808, 0x00000000 }, |
6935 | { 0x0000980c, 0xafe68e30 }, | 6912 | { 0x0000980c, 0xafe68e30 }, |
@@ -6982,9 +6959,6 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
6982 | { 0x000099e8, 0x3c466478 }, | 6959 | { 0x000099e8, 0x3c466478 }, |
6983 | { 0x000099ec, 0x0cc80caa }, | 6960 | { 0x000099ec, 0x0cc80caa }, |
6984 | { 0x000099f0, 0x00000000 }, | 6961 | { 0x000099f0, 0x00000000 }, |
6985 | { 0x0000a1f4, 0x00000000 }, | ||
6986 | { 0x0000a1f8, 0x71733d01 }, | ||
6987 | { 0x0000a1fc, 0xd0ad5c12 }, | ||
6988 | { 0x0000a208, 0x803e68c8 }, | 6962 | { 0x0000a208, 0x803e68c8 }, |
6989 | { 0x0000a210, 0x4080a333 }, | 6963 | { 0x0000a210, 0x4080a333 }, |
6990 | { 0x0000a214, 0x00206c10 }, | 6964 | { 0x0000a214, 0x00206c10 }, |
@@ -7004,13 +6978,9 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
7004 | { 0x0000a260, 0xdfa90f01 }, | 6978 | { 0x0000a260, 0xdfa90f01 }, |
7005 | { 0x0000a268, 0x00000000 }, | 6979 | { 0x0000a268, 0x00000000 }, |
7006 | { 0x0000a26c, 0x0ebae9e6 }, | 6980 | { 0x0000a26c, 0x0ebae9e6 }, |
7007 | { 0x0000a278, 0x3bdef7bd }, | ||
7008 | { 0x0000a27c, 0x050e83bd }, | ||
7009 | { 0x0000a388, 0x0c000000 }, | 6981 | { 0x0000a388, 0x0c000000 }, |
7010 | { 0x0000a38c, 0x20202020 }, | 6982 | { 0x0000a38c, 0x20202020 }, |
7011 | { 0x0000a390, 0x20202020 }, | 6983 | { 0x0000a390, 0x20202020 }, |
7012 | { 0x0000a394, 0x3bdef7bd }, | ||
7013 | { 0x0000a398, 0x000003bd }, | ||
7014 | { 0x0000a39c, 0x00000001 }, | 6984 | { 0x0000a39c, 0x00000001 }, |
7015 | { 0x0000a3a0, 0x00000000 }, | 6985 | { 0x0000a3a0, 0x00000000 }, |
7016 | { 0x0000a3a4, 0x00000000 }, | 6986 | { 0x0000a3a4, 0x00000000 }, |
@@ -7025,8 +6995,6 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
7025 | { 0x0000a3cc, 0x20202020 }, | 6995 | { 0x0000a3cc, 0x20202020 }, |
7026 | { 0x0000a3d0, 0x20202020 }, | 6996 | { 0x0000a3d0, 0x20202020 }, |
7027 | { 0x0000a3d4, 0x20202020 }, | 6997 | { 0x0000a3d4, 0x20202020 }, |
7028 | { 0x0000a3dc, 0x3bdef7bd }, | ||
7029 | { 0x0000a3e0, 0x000003bd }, | ||
7030 | { 0x0000a3e4, 0x00000000 }, | 6998 | { 0x0000a3e4, 0x00000000 }, |
7031 | { 0x0000a3e8, 0x18c43433 }, | 6999 | { 0x0000a3e8, 0x18c43433 }, |
7032 | { 0x0000a3ec, 0x00f70081 }, | 7000 | { 0x0000a3ec, 0x00f70081 }, |
@@ -7046,7 +7014,102 @@ static const u_int32_t ar9271Common_9271[][2] = { | |||
7046 | { 0x0000d384, 0xf3307ff0 }, | 7014 | { 0x0000d384, 0xf3307ff0 }, |
7047 | }; | 7015 | }; |
7048 | 7016 | ||
7017 | static const u_int32_t ar9271Common_normal_cck_fir_coeff_9271[][2] = { | ||
7018 | { 0x0000a1f4, 0x00fffeff }, | ||
7019 | { 0x0000a1f8, 0x00f5f9ff }, | ||
7020 | { 0x0000a1fc, 0xb79f6427 }, | ||
7021 | }; | ||
7022 | |||
7023 | static const u_int32_t ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = { | ||
7024 | { 0x0000a1f4, 0x00000000 }, | ||
7025 | { 0x0000a1f8, 0xefff0301 }, | ||
7026 | { 0x0000a1fc, 0xca9228ee }, | ||
7027 | }; | ||
7028 | |||
7049 | static const u_int32_t ar9271Modes_9271_1_0_only[][6] = { | 7029 | static const u_int32_t ar9271Modes_9271_1_0_only[][6] = { |
7050 | { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 }, | 7030 | { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 }, |
7051 | { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, | 7031 | { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, |
7052 | }; | 7032 | }; |
7033 | |||
7034 | static const u_int32_t ar9271Modes_9271_ANI_reg[][6] = { | ||
7035 | { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, | ||
7036 | { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e }, | ||
7037 | { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, | ||
7038 | { 0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881 }, | ||
7039 | { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, | ||
7040 | { 0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8 }, | ||
7041 | { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, | ||
7042 | { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, | ||
7043 | }; | ||
7044 | |||
7045 | static const u_int32_t ar9271Modes_normal_power_tx_gain_9271[][6] = { | ||
7046 | { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, | ||
7047 | { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 }, | ||
7048 | { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 }, | ||
7049 | { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 }, | ||
7050 | { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 }, | ||
7051 | { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 }, | ||
7052 | { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 }, | ||
7053 | { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 }, | ||
7054 | { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 }, | ||
7055 | { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 }, | ||
7056 | { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 }, | ||
7057 | { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 }, | ||
7058 | { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 }, | ||
7059 | { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, | ||
7060 | { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, | ||
7061 | { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, | ||
7062 | { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7063 | { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7064 | { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7065 | { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7066 | { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7067 | { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7068 | { 0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029 }, | ||
7069 | { 0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff }, | ||
7070 | { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 }, | ||
7071 | { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 }, | ||
7072 | { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 }, | ||
7073 | { 0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, | ||
7074 | { 0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd }, | ||
7075 | { 0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, | ||
7076 | { 0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd }, | ||
7077 | { 0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd }, | ||
7078 | { 0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd }, | ||
7079 | }; | ||
7080 | |||
7081 | static const u_int32_t ar9271Modes_high_power_tx_gain_9271[][6] = { | ||
7082 | { 0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000 }, | ||
7083 | { 0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000 }, | ||
7084 | { 0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000 }, | ||
7085 | { 0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000 }, | ||
7086 | { 0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000 }, | ||
7087 | { 0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000 }, | ||
7088 | { 0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000 }, | ||
7089 | { 0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000 }, | ||
7090 | { 0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000 }, | ||
7091 | { 0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000 }, | ||
7092 | { 0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000 }, | ||
7093 | { 0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000 }, | ||
7094 | { 0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000 }, | ||
7095 | { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 }, | ||
7096 | { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 }, | ||
7097 | { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 }, | ||
7098 | { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7099 | { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7100 | { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7101 | { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7102 | { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7103 | { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, | ||
7104 | { 0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b }, | ||
7105 | { 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff }, | ||
7106 | { 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 }, | ||
7107 | { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 }, | ||
7108 | { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 }, | ||
7109 | { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 }, | ||
7110 | { 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 }, | ||
7111 | { 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 }, | ||
7112 | { 0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 }, | ||
7113 | { 0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 }, | ||
7114 | { 0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 }, | ||
7115 | }; | ||
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 589490b69ddc..7af823a1527d 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -351,7 +351,7 @@ void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
351 | 351 | ||
352 | ads->ds_ctl6 = SM(keyType, AR_EncrType); | 352 | ads->ds_ctl6 = SM(keyType, AR_EncrType); |
353 | 353 | ||
354 | if (AR_SREV_9285(ah)) { | 354 | if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { |
355 | ads->ds_ctl8 = 0; | 355 | ads->ds_ctl8 = 0; |
356 | ads->ds_ctl9 = 0; | 356 | ads->ds_ctl9 = 0; |
357 | ads->ds_ctl10 = 0; | 357 | ads->ds_ctl10 = 0; |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 29851e6376a9..a5e543bd2271 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -150,6 +150,32 @@ struct ath_rx_status { | |||
150 | u32 evm2; | 150 | u32 evm2; |
151 | }; | 151 | }; |
152 | 152 | ||
153 | struct ath_htc_rx_status { | ||
154 | u64 rs_tstamp; | ||
155 | u16 rs_datalen; | ||
156 | u8 rs_status; | ||
157 | u8 rs_phyerr; | ||
158 | int8_t rs_rssi; | ||
159 | int8_t rs_rssi_ctl0; | ||
160 | int8_t rs_rssi_ctl1; | ||
161 | int8_t rs_rssi_ctl2; | ||
162 | int8_t rs_rssi_ext0; | ||
163 | int8_t rs_rssi_ext1; | ||
164 | int8_t rs_rssi_ext2; | ||
165 | u8 rs_keyix; | ||
166 | u8 rs_rate; | ||
167 | u8 rs_antenna; | ||
168 | u8 rs_more; | ||
169 | u8 rs_isaggr; | ||
170 | u8 rs_moreaggr; | ||
171 | u8 rs_num_delims; | ||
172 | u8 rs_flags; | ||
173 | u8 rs_dummy; | ||
174 | u32 evm0; | ||
175 | u32 evm1; | ||
176 | u32 evm2; | ||
177 | }; | ||
178 | |||
153 | #define ATH9K_RXERR_CRC 0x01 | 179 | #define ATH9K_RXERR_CRC 0x01 |
154 | #define ATH9K_RXERR_PHY 0x02 | 180 | #define ATH9K_RXERR_PHY 0x02 |
155 | #define ATH9K_RXERR_FIFO 0x04 | 181 | #define ATH9K_RXERR_FIFO 0x04 |
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index f4818e4fa4b0..36083dde863d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h | |||
@@ -110,8 +110,8 @@ struct ath_rate_table { | |||
110 | int rate_cnt; | 110 | int rate_cnt; |
111 | int mcs_start; | 111 | int mcs_start; |
112 | struct { | 112 | struct { |
113 | int valid; | 113 | u8 valid; |
114 | int valid_single_stream; | 114 | u8 valid_single_stream; |
115 | u8 phy; | 115 | u8 phy; |
116 | u32 ratekbps; | 116 | u32 ratekbps; |
117 | u32 user_ratekbps; | 117 | u32 user_ratekbps; |
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 72cfa8ebd9ae..198e41dd38a6 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h | |||
@@ -940,6 +940,7 @@ enum { | |||
940 | #define AR928X_NUM_GPIO 10 | 940 | #define AR928X_NUM_GPIO 10 |
941 | #define AR9285_NUM_GPIO 12 | 941 | #define AR9285_NUM_GPIO 12 |
942 | #define AR9287_NUM_GPIO 11 | 942 | #define AR9287_NUM_GPIO 11 |
943 | #define AR9271_NUM_GPIO 16 | ||
943 | 944 | ||
944 | #define AR_GPIO_IN_OUT 0x4048 | 945 | #define AR_GPIO_IN_OUT 0x4048 |
945 | #define AR_GPIO_IN_VAL 0x0FFFC000 | 946 | #define AR_GPIO_IN_VAL 0x0FFFC000 |
@@ -950,6 +951,8 @@ enum { | |||
950 | #define AR9285_GPIO_IN_VAL_S 12 | 951 | #define AR9285_GPIO_IN_VAL_S 12 |
951 | #define AR9287_GPIO_IN_VAL 0x003FF800 | 952 | #define AR9287_GPIO_IN_VAL 0x003FF800 |
952 | #define AR9287_GPIO_IN_VAL_S 11 | 953 | #define AR9287_GPIO_IN_VAL_S 11 |
954 | #define AR9271_GPIO_IN_VAL 0xFFFF0000 | ||
955 | #define AR9271_GPIO_IN_VAL_S 16 | ||
953 | 956 | ||
954 | #define AR_GPIO_OE_OUT 0x404c | 957 | #define AR_GPIO_OE_OUT 0x404c |
955 | #define AR_GPIO_OE_OUT_DRV 0x3 | 958 | #define AR_GPIO_OE_OUT_DRV 0x3 |
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c new file mode 100644 index 000000000000..818dea0164ec --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wmi.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include "htc.h" | ||
18 | |||
19 | static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) | ||
20 | { | ||
21 | switch (wmi_cmd) { | ||
22 | case WMI_ECHO_CMDID: | ||
23 | return "WMI_ECHO_CMDID"; | ||
24 | case WMI_ACCESS_MEMORY_CMDID: | ||
25 | return "WMI_ACCESS_MEMORY_CMDID"; | ||
26 | case WMI_DISABLE_INTR_CMDID: | ||
27 | return "WMI_DISABLE_INTR_CMDID"; | ||
28 | case WMI_ENABLE_INTR_CMDID: | ||
29 | return "WMI_ENABLE_INTR_CMDID"; | ||
30 | case WMI_RX_LINK_CMDID: | ||
31 | return "WMI_RX_LINK_CMDID"; | ||
32 | case WMI_ATH_INIT_CMDID: | ||
33 | return "WMI_ATH_INIT_CMDID"; | ||
34 | case WMI_ABORT_TXQ_CMDID: | ||
35 | return "WMI_ABORT_TXQ_CMDID"; | ||
36 | case WMI_STOP_TX_DMA_CMDID: | ||
37 | return "WMI_STOP_TX_DMA_CMDID"; | ||
38 | case WMI_STOP_DMA_RECV_CMDID: | ||
39 | return "WMI_STOP_DMA_RECV_CMDID"; | ||
40 | case WMI_ABORT_TX_DMA_CMDID: | ||
41 | return "WMI_ABORT_TX_DMA_CMDID"; | ||
42 | case WMI_DRAIN_TXQ_CMDID: | ||
43 | return "WMI_DRAIN_TXQ_CMDID"; | ||
44 | case WMI_DRAIN_TXQ_ALL_CMDID: | ||
45 | return "WMI_DRAIN_TXQ_ALL_CMDID"; | ||
46 | case WMI_START_RECV_CMDID: | ||
47 | return "WMI_START_RECV_CMDID"; | ||
48 | case WMI_STOP_RECV_CMDID: | ||
49 | return "WMI_STOP_RECV_CMDID"; | ||
50 | case WMI_FLUSH_RECV_CMDID: | ||
51 | return "WMI_FLUSH_RECV_CMDID"; | ||
52 | case WMI_SET_MODE_CMDID: | ||
53 | return "WMI_SET_MODE_CMDID"; | ||
54 | case WMI_RESET_CMDID: | ||
55 | return "WMI_RESET_CMDID"; | ||
56 | case WMI_NODE_CREATE_CMDID: | ||
57 | return "WMI_NODE_CREATE_CMDID"; | ||
58 | case WMI_NODE_REMOVE_CMDID: | ||
59 | return "WMI_NODE_REMOVE_CMDID"; | ||
60 | case WMI_VAP_REMOVE_CMDID: | ||
61 | return "WMI_VAP_REMOVE_CMDID"; | ||
62 | case WMI_VAP_CREATE_CMDID: | ||
63 | return "WMI_VAP_CREATE_CMDID"; | ||
64 | case WMI_BEACON_UPDATE_CMDID: | ||
65 | return "WMI_BEACON_UPDATE_CMDID"; | ||
66 | case WMI_REG_READ_CMDID: | ||
67 | return "WMI_REG_READ_CMDID"; | ||
68 | case WMI_REG_WRITE_CMDID: | ||
69 | return "WMI_REG_WRITE_CMDID"; | ||
70 | case WMI_RC_STATE_CHANGE_CMDID: | ||
71 | return "WMI_RC_STATE_CHANGE_CMDID"; | ||
72 | case WMI_RC_RATE_UPDATE_CMDID: | ||
73 | return "WMI_RC_RATE_UPDATE_CMDID"; | ||
74 | case WMI_DEBUG_INFO_CMDID: | ||
75 | return "WMI_DEBUG_INFO_CMDID"; | ||
76 | case WMI_HOST_ATTACH: | ||
77 | return "WMI_HOST_ATTACH"; | ||
78 | case WMI_TARGET_IC_UPDATE_CMDID: | ||
79 | return "WMI_TARGET_IC_UPDATE_CMDID"; | ||
80 | case WMI_TGT_STATS_CMDID: | ||
81 | return "WMI_TGT_STATS_CMDID"; | ||
82 | case WMI_TX_AGGR_ENABLE_CMDID: | ||
83 | return "WMI_TX_AGGR_ENABLE_CMDID"; | ||
84 | case WMI_TGT_DETACH_CMDID: | ||
85 | return "WMI_TGT_DETACH_CMDID"; | ||
86 | case WMI_TGT_TXQ_ENABLE_CMDID: | ||
87 | return "WMI_TGT_TXQ_ENABLE_CMDID"; | ||
88 | } | ||
89 | |||
90 | return "Bogus"; | ||
91 | } | ||
92 | |||
93 | struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv) | ||
94 | { | ||
95 | struct wmi *wmi; | ||
96 | |||
97 | wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL); | ||
98 | if (!wmi) | ||
99 | return NULL; | ||
100 | |||
101 | wmi->drv_priv = priv; | ||
102 | wmi->stopped = false; | ||
103 | mutex_init(&wmi->op_mutex); | ||
104 | init_completion(&wmi->cmd_wait); | ||
105 | |||
106 | return wmi; | ||
107 | } | ||
108 | |||
109 | void ath9k_deinit_wmi(struct ath9k_htc_priv *priv) | ||
110 | { | ||
111 | struct wmi *wmi = priv->wmi; | ||
112 | |||
113 | mutex_lock(&wmi->op_mutex); | ||
114 | wmi->stopped = true; | ||
115 | mutex_unlock(&wmi->op_mutex); | ||
116 | |||
117 | kfree(priv->wmi); | ||
118 | } | ||
119 | |||
120 | void ath9k_wmi_tasklet(unsigned long data) | ||
121 | { | ||
122 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | ||
123 | struct ath_common *common = ath9k_hw_common(priv->ah); | ||
124 | struct wmi_cmd_hdr *hdr; | ||
125 | struct wmi_swba *swba_hdr; | ||
126 | enum wmi_event_id event; | ||
127 | struct sk_buff *skb; | ||
128 | void *wmi_event; | ||
129 | unsigned long flags; | ||
130 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
131 | u32 txrate; | ||
132 | #endif | ||
133 | |||
134 | spin_lock_irqsave(&priv->wmi->wmi_lock, flags); | ||
135 | skb = priv->wmi->wmi_skb; | ||
136 | spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags); | ||
137 | |||
138 | hdr = (struct wmi_cmd_hdr *) skb->data; | ||
139 | event = be16_to_cpu(hdr->command_id); | ||
140 | wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr)); | ||
141 | |||
142 | ath_print(common, ATH_DBG_WMI, | ||
143 | "WMI Event: 0x%x\n", event); | ||
144 | |||
145 | switch (event) { | ||
146 | case WMI_TGT_RDY_EVENTID: | ||
147 | break; | ||
148 | case WMI_SWBA_EVENTID: | ||
149 | swba_hdr = (struct wmi_swba *) wmi_event; | ||
150 | ath9k_htc_swba(priv, swba_hdr->beacon_pending); | ||
151 | break; | ||
152 | case WMI_FATAL_EVENTID: | ||
153 | break; | ||
154 | case WMI_TXTO_EVENTID: | ||
155 | break; | ||
156 | case WMI_BMISS_EVENTID: | ||
157 | break; | ||
158 | case WMI_WLAN_TXCOMP_EVENTID: | ||
159 | break; | ||
160 | case WMI_DELBA_EVENTID: | ||
161 | break; | ||
162 | case WMI_TXRATE_EVENTID: | ||
163 | #ifdef CONFIG_ATH9K_HTC_DEBUGFS | ||
164 | txrate = ((struct wmi_event_txrate *)wmi_event)->txrate; | ||
165 | priv->debug.txrate = be32_to_cpu(txrate); | ||
166 | #endif | ||
167 | break; | ||
168 | default: | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | dev_kfree_skb_any(skb); | ||
173 | } | ||
174 | |||
175 | static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) | ||
176 | { | ||
177 | skb_pull(skb, sizeof(struct wmi_cmd_hdr)); | ||
178 | |||
179 | if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0) | ||
180 | memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len); | ||
181 | |||
182 | complete(&wmi->cmd_wait); | ||
183 | } | ||
184 | |||
185 | static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, | ||
186 | enum htc_endpoint_id epid) | ||
187 | { | ||
188 | struct wmi *wmi = (struct wmi *) priv; | ||
189 | struct wmi_cmd_hdr *hdr; | ||
190 | u16 cmd_id; | ||
191 | |||
192 | if (unlikely(wmi->stopped)) | ||
193 | goto free_skb; | ||
194 | |||
195 | hdr = (struct wmi_cmd_hdr *) skb->data; | ||
196 | cmd_id = be16_to_cpu(hdr->command_id); | ||
197 | |||
198 | if (cmd_id & 0x1000) { | ||
199 | spin_lock(&wmi->wmi_lock); | ||
200 | wmi->wmi_skb = skb; | ||
201 | spin_unlock(&wmi->wmi_lock); | ||
202 | tasklet_schedule(&wmi->drv_priv->wmi_tasklet); | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | /* WMI command response */ | ||
207 | ath9k_wmi_rsp_callback(wmi, skb); | ||
208 | |||
209 | free_skb: | ||
210 | dev_kfree_skb_any(skb); | ||
211 | } | ||
212 | |||
213 | static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb, | ||
214 | enum htc_endpoint_id epid, bool txok) | ||
215 | { | ||
216 | dev_kfree_skb_any(skb); | ||
217 | } | ||
218 | |||
219 | int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, | ||
220 | enum htc_endpoint_id *wmi_ctrl_epid) | ||
221 | { | ||
222 | struct htc_service_connreq connect; | ||
223 | int ret; | ||
224 | |||
225 | wmi->htc = htc; | ||
226 | |||
227 | memset(&connect, 0, sizeof(connect)); | ||
228 | |||
229 | connect.ep_callbacks.priv = wmi; | ||
230 | connect.ep_callbacks.tx = ath9k_wmi_ctrl_tx; | ||
231 | connect.ep_callbacks.rx = ath9k_wmi_ctrl_rx; | ||
232 | connect.service_id = WMI_CONTROL_SVC; | ||
233 | |||
234 | ret = htc_connect_service(htc, &connect, &wmi->ctrl_epid); | ||
235 | if (ret) | ||
236 | return ret; | ||
237 | |||
238 | *wmi_ctrl_epid = wmi->ctrl_epid; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int ath9k_wmi_cmd_issue(struct wmi *wmi, | ||
244 | struct sk_buff *skb, | ||
245 | enum wmi_cmd_id cmd, u16 len) | ||
246 | { | ||
247 | struct wmi_cmd_hdr *hdr; | ||
248 | |||
249 | hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr)); | ||
250 | hdr->command_id = cpu_to_be16(cmd); | ||
251 | hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id); | ||
252 | |||
253 | return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL); | ||
254 | } | ||
255 | |||
256 | int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, | ||
257 | u8 *cmd_buf, u32 cmd_len, | ||
258 | u8 *rsp_buf, u32 rsp_len, | ||
259 | u32 timeout) | ||
260 | { | ||
261 | struct ath_hw *ah = wmi->drv_priv->ah; | ||
262 | struct ath_common *common = ath9k_hw_common(ah); | ||
263 | u16 headroom = sizeof(struct htc_frame_hdr) + | ||
264 | sizeof(struct wmi_cmd_hdr); | ||
265 | struct sk_buff *skb; | ||
266 | u8 *data; | ||
267 | int time_left, ret = 0; | ||
268 | |||
269 | if (!wmi) | ||
270 | return -EINVAL; | ||
271 | |||
272 | skb = dev_alloc_skb(headroom + cmd_len); | ||
273 | if (!skb) | ||
274 | return -ENOMEM; | ||
275 | |||
276 | skb_reserve(skb, headroom); | ||
277 | |||
278 | if (cmd_len != 0 && cmd_buf != NULL) { | ||
279 | data = (u8 *) skb_put(skb, cmd_len); | ||
280 | memcpy(data, cmd_buf, cmd_len); | ||
281 | } | ||
282 | |||
283 | mutex_lock(&wmi->op_mutex); | ||
284 | |||
285 | /* check if wmi stopped flag is set */ | ||
286 | if (unlikely(wmi->stopped)) { | ||
287 | ret = -EPROTO; | ||
288 | goto out; | ||
289 | } | ||
290 | |||
291 | /* record the rsp buffer and length */ | ||
292 | wmi->cmd_rsp_buf = rsp_buf; | ||
293 | wmi->cmd_rsp_len = rsp_len; | ||
294 | |||
295 | ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len); | ||
296 | if (ret) | ||
297 | goto out; | ||
298 | |||
299 | time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout); | ||
300 | if (!time_left) { | ||
301 | ath_print(common, ATH_DBG_WMI, | ||
302 | "Timeout waiting for WMI command: %s\n", | ||
303 | wmi_cmd_to_name(cmd_id)); | ||
304 | mutex_unlock(&wmi->op_mutex); | ||
305 | return -ETIMEDOUT; | ||
306 | } | ||
307 | |||
308 | mutex_unlock(&wmi->op_mutex); | ||
309 | |||
310 | return 0; | ||
311 | |||
312 | out: | ||
313 | ath_print(common, ATH_DBG_WMI, | ||
314 | "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); | ||
315 | mutex_unlock(&wmi->op_mutex); | ||
316 | dev_kfree_skb_any(skb); | ||
317 | |||
318 | return ret; | ||
319 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h new file mode 100644 index 000000000000..39ef926f27c2 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wmi.h | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Atheros Communications Inc. | ||
3 | * | ||
4 | * Permission to use, copy, modify, and/or distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #ifndef WMI_H | ||
18 | #define WMI_H | ||
19 | |||
20 | |||
21 | struct wmi_event_txrate { | ||
22 | u32 txrate; | ||
23 | struct { | ||
24 | u8 rssi_thresh; | ||
25 | u8 per; | ||
26 | } rc_stats; | ||
27 | } __packed; | ||
28 | |||
29 | struct wmi_cmd_hdr { | ||
30 | u16 command_id; | ||
31 | u16 seq_no; | ||
32 | } __packed; | ||
33 | |||
34 | struct wmi_swba { | ||
35 | u8 beacon_pending; | ||
36 | } __packed; | ||
37 | |||
38 | enum wmi_cmd_id { | ||
39 | WMI_ECHO_CMDID = 0x0001, | ||
40 | WMI_ACCESS_MEMORY_CMDID, | ||
41 | |||
42 | /* Commands to Target */ | ||
43 | WMI_DISABLE_INTR_CMDID, | ||
44 | WMI_ENABLE_INTR_CMDID, | ||
45 | WMI_RX_LINK_CMDID, | ||
46 | WMI_ATH_INIT_CMDID, | ||
47 | WMI_ABORT_TXQ_CMDID, | ||
48 | WMI_STOP_TX_DMA_CMDID, | ||
49 | WMI_STOP_DMA_RECV_CMDID, | ||
50 | WMI_ABORT_TX_DMA_CMDID, | ||
51 | WMI_DRAIN_TXQ_CMDID, | ||
52 | WMI_DRAIN_TXQ_ALL_CMDID, | ||
53 | WMI_START_RECV_CMDID, | ||
54 | WMI_STOP_RECV_CMDID, | ||
55 | WMI_FLUSH_RECV_CMDID, | ||
56 | WMI_SET_MODE_CMDID, | ||
57 | WMI_RESET_CMDID, | ||
58 | WMI_NODE_CREATE_CMDID, | ||
59 | WMI_NODE_REMOVE_CMDID, | ||
60 | WMI_VAP_REMOVE_CMDID, | ||
61 | WMI_VAP_CREATE_CMDID, | ||
62 | WMI_BEACON_UPDATE_CMDID, | ||
63 | WMI_REG_READ_CMDID, | ||
64 | WMI_REG_WRITE_CMDID, | ||
65 | WMI_RC_STATE_CHANGE_CMDID, | ||
66 | WMI_RC_RATE_UPDATE_CMDID, | ||
67 | WMI_DEBUG_INFO_CMDID, | ||
68 | WMI_HOST_ATTACH, | ||
69 | WMI_TARGET_IC_UPDATE_CMDID, | ||
70 | WMI_TGT_STATS_CMDID, | ||
71 | WMI_TX_AGGR_ENABLE_CMDID, | ||
72 | WMI_TGT_DETACH_CMDID, | ||
73 | WMI_TGT_TXQ_ENABLE_CMDID, | ||
74 | }; | ||
75 | |||
76 | enum wmi_event_id { | ||
77 | WMI_TGT_RDY_EVENTID = 0x1001, | ||
78 | WMI_SWBA_EVENTID, | ||
79 | WMI_FATAL_EVENTID, | ||
80 | WMI_TXTO_EVENTID, | ||
81 | WMI_BMISS_EVENTID, | ||
82 | WMI_WLAN_TXCOMP_EVENTID, | ||
83 | WMI_DELBA_EVENTID, | ||
84 | WMI_TXRATE_EVENTID, | ||
85 | }; | ||
86 | |||
87 | struct wmi { | ||
88 | struct ath9k_htc_priv *drv_priv; | ||
89 | struct htc_target *htc; | ||
90 | enum htc_endpoint_id ctrl_epid; | ||
91 | struct mutex op_mutex; | ||
92 | struct completion cmd_wait; | ||
93 | u16 tx_seq_id; | ||
94 | u8 *cmd_rsp_buf; | ||
95 | u32 cmd_rsp_len; | ||
96 | bool stopped; | ||
97 | |||
98 | struct sk_buff *wmi_skb; | ||
99 | spinlock_t wmi_lock; | ||
100 | }; | ||
101 | |||
102 | struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv); | ||
103 | void ath9k_deinit_wmi(struct ath9k_htc_priv *priv); | ||
104 | int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi, | ||
105 | enum htc_endpoint_id *wmi_ctrl_epid); | ||
106 | int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, | ||
107 | u8 *cmd_buf, u32 cmd_len, | ||
108 | u8 *rsp_buf, u32 rsp_len, | ||
109 | u32 timeout); | ||
110 | void ath9k_wmi_tasklet(unsigned long data); | ||
111 | |||
112 | #define WMI_CMD(_wmi_cmd) \ | ||
113 | do { \ | ||
114 | ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, NULL, 0, \ | ||
115 | (u8 *) &cmd_rsp, \ | ||
116 | sizeof(cmd_rsp), HZ); \ | ||
117 | } while (0) | ||
118 | |||
119 | #define WMI_CMD_BUF(_wmi_cmd, _buf) \ | ||
120 | do { \ | ||
121 | ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, \ | ||
122 | (u8 *) _buf, sizeof(*_buf), \ | ||
123 | &cmd_rsp, sizeof(cmd_rsp), HZ); \ | ||
124 | } while (0) | ||
125 | |||
126 | #endif /* WMI_H */ | ||
diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index 8263633c003c..873bf526e11f 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h | |||
@@ -59,6 +59,7 @@ enum ATH_DEBUG { | |||
59 | ATH_DBG_PS = 0x00000800, | 59 | ATH_DBG_PS = 0x00000800, |
60 | ATH_DBG_HWTIMER = 0x00001000, | 60 | ATH_DBG_HWTIMER = 0x00001000, |
61 | ATH_DBG_BTCOEX = 0x00002000, | 61 | ATH_DBG_BTCOEX = 0x00002000, |
62 | ATH_DBG_WMI = 0x00004000, | ||
62 | ATH_DBG_ANY = 0xffffffff | 63 | ATH_DBG_ANY = 0xffffffff |
63 | }; | 64 | }; |
64 | 65 | ||
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1521b1e78d21..14cf3bd7ea51 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -4348,11 +4348,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
4348 | b43_set_phytxctl_defaults(dev); | 4348 | b43_set_phytxctl_defaults(dev); |
4349 | 4349 | ||
4350 | /* Minimum Contention Window */ | 4350 | /* Minimum Contention Window */ |
4351 | if (phy->type == B43_PHYTYPE_B) { | 4351 | if (phy->type == B43_PHYTYPE_B) |
4352 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F); | 4352 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F); |
4353 | } else { | 4353 | else |
4354 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF); | 4354 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF); |
4355 | } | ||
4356 | /* Maximum Contention Window */ | 4355 | /* Maximum Contention Window */ |
4357 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); | 4356 | b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); |
4358 | 4357 | ||
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 6dc0733df46b..cb3ba134865e 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -9995,49 +9995,48 @@ static int ipw_wx_sw_reset(struct net_device *dev, | |||
9995 | } | 9995 | } |
9996 | 9996 | ||
9997 | /* Rebase the WE IOCTLs to zero for the handler array */ | 9997 | /* Rebase the WE IOCTLs to zero for the handler array */ |
9998 | #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] | ||
9999 | static iw_handler ipw_wx_handlers[] = { | 9998 | static iw_handler ipw_wx_handlers[] = { |
10000 | IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname, | 9999 | IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname), |
10001 | IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, | 10000 | IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq), |
10002 | IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, | 10001 | IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq), |
10003 | IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, | 10002 | IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode), |
10004 | IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, | 10003 | IW_HANDLER(SIOCGIWMODE, ipw_wx_get_mode), |
10005 | IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens, | 10004 | IW_HANDLER(SIOCSIWSENS, ipw_wx_set_sens), |
10006 | IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens, | 10005 | IW_HANDLER(SIOCGIWSENS, ipw_wx_get_sens), |
10007 | IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, | 10006 | IW_HANDLER(SIOCGIWRANGE, ipw_wx_get_range), |
10008 | IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, | 10007 | IW_HANDLER(SIOCSIWAP, ipw_wx_set_wap), |
10009 | IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, | 10008 | IW_HANDLER(SIOCGIWAP, ipw_wx_get_wap), |
10010 | IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, | 10009 | IW_HANDLER(SIOCSIWSCAN, ipw_wx_set_scan), |
10011 | IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, | 10010 | IW_HANDLER(SIOCGIWSCAN, ipw_wx_get_scan), |
10012 | IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, | 10011 | IW_HANDLER(SIOCSIWESSID, ipw_wx_set_essid), |
10013 | IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, | 10012 | IW_HANDLER(SIOCGIWESSID, ipw_wx_get_essid), |
10014 | IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, | 10013 | IW_HANDLER(SIOCSIWNICKN, ipw_wx_set_nick), |
10015 | IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, | 10014 | IW_HANDLER(SIOCGIWNICKN, ipw_wx_get_nick), |
10016 | IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, | 10015 | IW_HANDLER(SIOCSIWRATE, ipw_wx_set_rate), |
10017 | IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, | 10016 | IW_HANDLER(SIOCGIWRATE, ipw_wx_get_rate), |
10018 | IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, | 10017 | IW_HANDLER(SIOCSIWRTS, ipw_wx_set_rts), |
10019 | IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, | 10018 | IW_HANDLER(SIOCGIWRTS, ipw_wx_get_rts), |
10020 | IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, | 10019 | IW_HANDLER(SIOCSIWFRAG, ipw_wx_set_frag), |
10021 | IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, | 10020 | IW_HANDLER(SIOCGIWFRAG, ipw_wx_get_frag), |
10022 | IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, | 10021 | IW_HANDLER(SIOCSIWTXPOW, ipw_wx_set_txpow), |
10023 | IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, | 10022 | IW_HANDLER(SIOCGIWTXPOW, ipw_wx_get_txpow), |
10024 | IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, | 10023 | IW_HANDLER(SIOCSIWRETRY, ipw_wx_set_retry), |
10025 | IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, | 10024 | IW_HANDLER(SIOCGIWRETRY, ipw_wx_get_retry), |
10026 | IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, | 10025 | IW_HANDLER(SIOCSIWENCODE, ipw_wx_set_encode), |
10027 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, | 10026 | IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode), |
10028 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, | 10027 | IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power), |
10029 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, | 10028 | IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power), |
10030 | IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy, | 10029 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), |
10031 | IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, | 10030 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), |
10032 | IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, | 10031 | IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), |
10033 | IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, | 10032 | IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), |
10034 | IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, | 10033 | IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie), |
10035 | IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, | 10034 | IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie), |
10036 | IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, | 10035 | IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme), |
10037 | IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth, | 10036 | IW_HANDLER(SIOCSIWAUTH, ipw_wx_set_auth), |
10038 | IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, | 10037 | IW_HANDLER(SIOCGIWAUTH, ipw_wx_get_auth), |
10039 | IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, | 10038 | IW_HANDLER(SIOCSIWENCODEEXT, ipw_wx_set_encodeext), |
10040 | IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, | 10039 | IW_HANDLER(SIOCGIWENCODEEXT, ipw_wx_get_encodeext), |
10041 | }; | 10040 | }; |
10042 | 10041 | ||
10043 | enum { | 10042 | enum { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 59b092eaa829..9e392896005d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -212,6 +212,9 @@ static struct iwl_lib_ops iwl1000_lib = { | |||
212 | .set_ct_kill = iwl1000_set_ct_threshold, | 212 | .set_ct_kill = iwl1000_set_ct_threshold, |
213 | }, | 213 | }, |
214 | .add_bcast_station = iwl_add_bcast_station, | 214 | .add_bcast_station = iwl_add_bcast_station, |
215 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
216 | .check_plcp_health = iwl_good_plcp_health, | ||
217 | .check_ack_health = iwl_good_ack_health, | ||
215 | }; | 218 | }; |
216 | 219 | ||
217 | static const struct iwl_ops iwl1000_ops = { | 220 | static const struct iwl_ops iwl1000_ops = { |
@@ -223,7 +226,7 @@ static const struct iwl_ops iwl1000_ops = { | |||
223 | }; | 226 | }; |
224 | 227 | ||
225 | struct iwl_cfg iwl1000_bgn_cfg = { | 228 | struct iwl_cfg iwl1000_bgn_cfg = { |
226 | .name = "1000 Series BGN", | 229 | .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN", |
227 | .fw_name_pre = IWL1000_FW_PRE, | 230 | .fw_name_pre = IWL1000_FW_PRE, |
228 | .ucode_api_max = IWL1000_UCODE_API_MAX, | 231 | .ucode_api_max = IWL1000_UCODE_API_MAX, |
229 | .ucode_api_min = IWL1000_UCODE_API_MIN, | 232 | .ucode_api_min = IWL1000_UCODE_API_MIN, |
@@ -249,10 +252,11 @@ struct iwl_cfg iwl1000_bgn_cfg = { | |||
249 | .support_ct_kill_exit = true, | 252 | .support_ct_kill_exit = true, |
250 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, | 253 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, |
251 | .chain_noise_scale = 1000, | 254 | .chain_noise_scale = 1000, |
255 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
252 | }; | 256 | }; |
253 | 257 | ||
254 | struct iwl_cfg iwl1000_bg_cfg = { | 258 | struct iwl_cfg iwl1000_bg_cfg = { |
255 | .name = "1000 Series BG", | 259 | .name = "Intel(R) Centrino(R) Wireless-N 1000 BG", |
256 | .fw_name_pre = IWL1000_FW_PRE, | 260 | .fw_name_pre = IWL1000_FW_PRE, |
257 | .ucode_api_max = IWL1000_UCODE_API_MAX, | 261 | .ucode_api_max = IWL1000_UCODE_API_MAX, |
258 | .ucode_api_min = IWL1000_UCODE_API_MIN, | 262 | .ucode_api_min = IWL1000_UCODE_API_MIN, |
@@ -277,6 +281,7 @@ struct iwl_cfg iwl1000_bg_cfg = { | |||
277 | .support_ct_kill_exit = true, | 281 | .support_ct_kill_exit = true, |
278 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, | 282 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, |
279 | .chain_noise_scale = 1000, | 283 | .chain_noise_scale = 1000, |
284 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
280 | }; | 285 | }; |
281 | 286 | ||
282 | MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); | 287 | MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index b588cb69536a..605aca4c78c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c | |||
@@ -329,16 +329,25 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, | |||
329 | 329 | ||
330 | } | 330 | } |
331 | 331 | ||
332 | static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | 332 | /* |
333 | struct ieee80211_sta *sta, void *priv_sta) | 333 | * Called after adding a new station to initialize rate scaling |
334 | */ | ||
335 | void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id) | ||
334 | { | 336 | { |
335 | struct iwl3945_rs_sta *rs_sta = priv_sta; | 337 | struct ieee80211_hw *hw = priv->hw; |
336 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; | 338 | struct ieee80211_conf *conf = &priv->hw->conf; |
339 | struct iwl3945_sta_priv *psta; | ||
340 | struct iwl3945_rs_sta *rs_sta; | ||
341 | struct ieee80211_supported_band *sband; | ||
337 | int i; | 342 | int i; |
338 | 343 | ||
339 | IWL_DEBUG_RATE(priv, "enter\n"); | 344 | IWL_DEBUG_INFO(priv, "enter \n"); |
345 | if (sta_id == priv->hw_params.bcast_sta_id) | ||
346 | goto out; | ||
340 | 347 | ||
341 | spin_lock_init(&rs_sta->lock); | 348 | psta = (struct iwl3945_sta_priv *) sta->drv_priv; |
349 | rs_sta = &psta->rs_sta; | ||
350 | sband = hw->wiphy->bands[conf->channel->band]; | ||
342 | 351 | ||
343 | rs_sta->priv = priv; | 352 | rs_sta->priv = priv; |
344 | 353 | ||
@@ -351,9 +360,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
351 | rs_sta->last_flush = jiffies; | 360 | rs_sta->last_flush = jiffies; |
352 | rs_sta->flush_time = IWL_RATE_FLUSH; | 361 | rs_sta->flush_time = IWL_RATE_FLUSH; |
353 | rs_sta->last_tx_packets = 0; | 362 | rs_sta->last_tx_packets = 0; |
354 | rs_sta->ibss_sta_added = 0; | ||
355 | 363 | ||
356 | init_timer(&rs_sta->rate_scale_flush); | ||
357 | rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; | 364 | rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; |
358 | rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush; | 365 | rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush; |
359 | 366 | ||
@@ -380,8 +387,10 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
380 | IWL_FIRST_OFDM_RATE; | 387 | IWL_FIRST_OFDM_RATE; |
381 | } | 388 | } |
382 | 389 | ||
390 | out: | ||
391 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
383 | 392 | ||
384 | IWL_DEBUG_RATE(priv, "leave\n"); | 393 | IWL_DEBUG_INFO(priv, "leave\n"); |
385 | } | 394 | } |
386 | 395 | ||
387 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 396 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
@@ -405,6 +414,9 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp) | |||
405 | 414 | ||
406 | rs_sta = &psta->rs_sta; | 415 | rs_sta = &psta->rs_sta; |
407 | 416 | ||
417 | spin_lock_init(&rs_sta->lock); | ||
418 | init_timer(&rs_sta->rate_scale_flush); | ||
419 | |||
408 | IWL_DEBUG_RATE(priv, "leave\n"); | 420 | IWL_DEBUG_RATE(priv, "leave\n"); |
409 | 421 | ||
410 | return rs_sta; | 422 | return rs_sta; |
@@ -413,13 +425,14 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp) | |||
413 | static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta, | 425 | static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta, |
414 | void *priv_sta) | 426 | void *priv_sta) |
415 | { | 427 | { |
416 | struct iwl3945_sta_priv *psta = (void *) sta->drv_priv; | 428 | struct iwl3945_rs_sta *rs_sta = priv_sta; |
417 | struct iwl3945_rs_sta *rs_sta = &psta->rs_sta; | ||
418 | struct iwl_priv *priv __maybe_unused = rs_sta->priv; | ||
419 | 429 | ||
420 | IWL_DEBUG_RATE(priv, "enter\n"); | 430 | /* |
431 | * Be careful not to use any members of iwl3945_rs_sta (like trying | ||
432 | * to use iwl_priv to print out debugging) since it may not be fully | ||
433 | * initialized at this point. | ||
434 | */ | ||
421 | del_timer_sync(&rs_sta->rate_scale_flush); | 435 | del_timer_sync(&rs_sta->rate_scale_flush); |
422 | IWL_DEBUG_RATE(priv, "leave\n"); | ||
423 | } | 436 | } |
424 | 437 | ||
425 | 438 | ||
@@ -458,6 +471,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband | |||
458 | return; | 471 | return; |
459 | } | 472 | } |
460 | 473 | ||
474 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
475 | if (!rs_sta->priv) { | ||
476 | IWL_DEBUG_RATE(priv, "leave: STA priv data uninitialized!\n"); | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | |||
461 | rs_sta->tx_packets++; | 481 | rs_sta->tx_packets++; |
462 | 482 | ||
463 | scale_rate_index = first_index; | 483 | scale_rate_index = first_index; |
@@ -625,7 +645,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
625 | u32 fail_count; | 645 | u32 fail_count; |
626 | s8 scale_action = 0; | 646 | s8 scale_action = 0; |
627 | unsigned long flags; | 647 | unsigned long flags; |
628 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
629 | u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; | 648 | u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0; |
630 | s8 max_rate_idx = -1; | 649 | s8 max_rate_idx = -1; |
631 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; | 650 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; |
@@ -633,6 +652,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
633 | 652 | ||
634 | IWL_DEBUG_RATE(priv, "enter\n"); | 653 | IWL_DEBUG_RATE(priv, "enter\n"); |
635 | 654 | ||
655 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
656 | if (rs_sta && !rs_sta->priv) { | ||
657 | IWL_DEBUG_RATE(priv, "Rate scaling information not initialized yet.\n"); | ||
658 | priv_sta = NULL; | ||
659 | } | ||
660 | |||
636 | if (rate_control_send_low(sta, priv_sta, txrc)) | 661 | if (rate_control_send_low(sta, priv_sta, txrc)) |
637 | return; | 662 | return; |
638 | 663 | ||
@@ -650,20 +675,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
650 | if (sband->band == IEEE80211_BAND_5GHZ) | 675 | if (sband->band == IEEE80211_BAND_5GHZ) |
651 | rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; | 676 | rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; |
652 | 677 | ||
653 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | ||
654 | !rs_sta->ibss_sta_added) { | ||
655 | u8 sta_id = iwl_find_station(priv, hdr->addr1); | ||
656 | |||
657 | if (sta_id == IWL_INVALID_STATION) { | ||
658 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", | ||
659 | hdr->addr1); | ||
660 | sta_id = iwl_add_station(priv, hdr->addr1, false, | ||
661 | CMD_ASYNC, NULL); | ||
662 | } | ||
663 | if (sta_id != IWL_INVALID_STATION) | ||
664 | rs_sta->ibss_sta_added = 1; | ||
665 | } | ||
666 | |||
667 | spin_lock_irqsave(&rs_sta->lock, flags); | 678 | spin_lock_irqsave(&rs_sta->lock, flags); |
668 | 679 | ||
669 | /* for recent assoc, choose best rate regarding | 680 | /* for recent assoc, choose best rate regarding |
@@ -883,12 +894,22 @@ static void iwl3945_remove_debugfs(void *priv, void *priv_sta) | |||
883 | } | 894 | } |
884 | #endif | 895 | #endif |
885 | 896 | ||
897 | /* | ||
898 | * Initialization of rate scaling information is done by driver after | ||
899 | * the station is added. Since mac80211 calls this function before a | ||
900 | * station is added we ignore it. | ||
901 | */ | ||
902 | static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband, | ||
903 | struct ieee80211_sta *sta, void *priv_sta) | ||
904 | { | ||
905 | } | ||
906 | |||
886 | static struct rate_control_ops rs_ops = { | 907 | static struct rate_control_ops rs_ops = { |
887 | .module = NULL, | 908 | .module = NULL, |
888 | .name = RS_NAME, | 909 | .name = RS_NAME, |
889 | .tx_status = rs_tx_status, | 910 | .tx_status = rs_tx_status, |
890 | .get_rate = rs_get_rate, | 911 | .get_rate = rs_get_rate, |
891 | .rate_init = rs_rate_init, | 912 | .rate_init = rs_rate_init_stub, |
892 | .alloc = rs_alloc, | 913 | .alloc = rs_alloc, |
893 | .free = rs_free, | 914 | .free = rs_free, |
894 | .alloc_sta = rs_alloc_sta, | 915 | .alloc_sta = rs_alloc_sta, |
@@ -899,7 +920,6 @@ static struct rate_control_ops rs_ops = { | |||
899 | #endif | 920 | #endif |
900 | 921 | ||
901 | }; | 922 | }; |
902 | |||
903 | void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | 923 | void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) |
904 | { | 924 | { |
905 | struct iwl_priv *priv = hw->priv; | 925 | struct iwl_priv *priv = hw->priv; |
@@ -916,6 +936,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) | |||
916 | sta = ieee80211_find_sta(priv->vif, | 936 | sta = ieee80211_find_sta(priv->vif, |
917 | priv->stations[sta_id].sta.sta.addr); | 937 | priv->stations[sta_id].sta.sta.addr); |
918 | if (!sta) { | 938 | if (!sta) { |
939 | IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n"); | ||
919 | rcu_read_unlock(); | 940 | rcu_read_unlock(); |
920 | return; | 941 | return; |
921 | } | 942 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 12a42fc743d7..3b5889d8d662 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -1911,6 +1911,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
1911 | "configuration (%d).\n", rc); | 1911 | "configuration (%d).\n", rc); |
1912 | return rc; | 1912 | return rc; |
1913 | } | 1913 | } |
1914 | iwl_clear_ucode_stations(priv, false); | ||
1915 | iwl_restore_stations(priv); | ||
1914 | } | 1916 | } |
1915 | 1917 | ||
1916 | IWL_DEBUG_INFO(priv, "Sending RXON\n" | 1918 | IWL_DEBUG_INFO(priv, "Sending RXON\n" |
@@ -1941,7 +1943,10 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
1941 | 1943 | ||
1942 | memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); | 1944 | memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); |
1943 | 1945 | ||
1944 | iwl_clear_stations_table(priv); | 1946 | if (!new_assoc) { |
1947 | iwl_clear_ucode_stations(priv, false); | ||
1948 | iwl_restore_stations(priv); | ||
1949 | } | ||
1945 | 1950 | ||
1946 | /* If we issue a new RXON command which required a tune then we must | 1951 | /* If we issue a new RXON command which required a tune then we must |
1947 | * send a new TXPOWER command or we won't be able to Tx any frames */ | 1952 | * send a new TXPOWER command or we won't be able to Tx any frames */ |
@@ -1951,19 +1956,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv) | |||
1951 | return rc; | 1956 | return rc; |
1952 | } | 1957 | } |
1953 | 1958 | ||
1954 | /* Add the broadcast address so we can send broadcast frames */ | ||
1955 | priv->cfg->ops->lib->add_bcast_station(priv); | ||
1956 | |||
1957 | /* If we have set the ASSOC_MSK and we are in BSS mode then | ||
1958 | * add the IWL_AP_ID to the station rate table */ | ||
1959 | if (iwl_is_associated(priv) && | ||
1960 | (priv->iw_mode == NL80211_IFTYPE_STATION)) | ||
1961 | if (iwl_add_station(priv, priv->active_rxon.bssid_addr, | ||
1962 | true, CMD_SYNC, NULL) == IWL_INVALID_STATION) { | ||
1963 | IWL_ERR(priv, "Error adding AP address for transmit\n"); | ||
1964 | return -EIO; | ||
1965 | } | ||
1966 | |||
1967 | /* Init the hardware's rate fallback order based on the band */ | 1959 | /* Init the hardware's rate fallback order based on the band */ |
1968 | rc = iwl3945_init_hw_rate_table(priv); | 1960 | rc = iwl3945_init_hw_rate_table(priv); |
1969 | if (rc) { | 1961 | if (rc) { |
@@ -2828,6 +2820,7 @@ static struct iwl_cfg iwl3945_bg_cfg = { | |||
2828 | .led_compensation = 64, | 2820 | .led_compensation = 64, |
2829 | .broken_powersave = true, | 2821 | .broken_powersave = true, |
2830 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 2822 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
2823 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
2831 | }; | 2824 | }; |
2832 | 2825 | ||
2833 | static struct iwl_cfg iwl3945_abg_cfg = { | 2826 | static struct iwl_cfg iwl3945_abg_cfg = { |
@@ -2846,6 +2839,7 @@ static struct iwl_cfg iwl3945_abg_cfg = { | |||
2846 | .led_compensation = 64, | 2839 | .led_compensation = 64, |
2847 | .broken_powersave = true, | 2840 | .broken_powersave = true, |
2848 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 2841 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
2842 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
2849 | }; | 2843 | }; |
2850 | 2844 | ||
2851 | DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { | 2845 | DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 452dfd5456c6..b89219573b91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h | |||
@@ -95,7 +95,6 @@ struct iwl3945_rs_sta { | |||
95 | u8 tgg; | 95 | u8 tgg; |
96 | u8 flush_pending; | 96 | u8 flush_pending; |
97 | u8 start_rate; | 97 | u8 start_rate; |
98 | u8 ibss_sta_added; | ||
99 | struct timer_list rate_scale_flush; | 98 | struct timer_list rate_scale_flush; |
100 | struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; | 99 | struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945]; |
101 | #ifdef CONFIG_MAC80211_DEBUGFS | 100 | #ifdef CONFIG_MAC80211_DEBUGFS |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 644aacfbd7df..3949133d9ee2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -2187,6 +2187,7 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2187 | .load_ucode = iwl4965_load_bsm, | 2187 | .load_ucode = iwl4965_load_bsm, |
2188 | .dump_nic_event_log = iwl_dump_nic_event_log, | 2188 | .dump_nic_event_log = iwl_dump_nic_event_log, |
2189 | .dump_nic_error_log = iwl_dump_nic_error_log, | 2189 | .dump_nic_error_log = iwl_dump_nic_error_log, |
2190 | .dump_fh = iwl_dump_fh, | ||
2190 | .set_channel_switch = iwl4965_hw_channel_switch, | 2191 | .set_channel_switch = iwl4965_hw_channel_switch, |
2191 | .apm_ops = { | 2192 | .apm_ops = { |
2192 | .init = iwl_apm_init, | 2193 | .init = iwl_apm_init, |
@@ -2220,6 +2221,7 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2220 | .set_ct_kill = iwl4965_set_ct_threshold, | 2221 | .set_ct_kill = iwl4965_set_ct_threshold, |
2221 | }, | 2222 | }, |
2222 | .add_bcast_station = iwl_add_bcast_station, | 2223 | .add_bcast_station = iwl_add_bcast_station, |
2224 | .check_plcp_health = iwl_good_plcp_health, | ||
2223 | }; | 2225 | }; |
2224 | 2226 | ||
2225 | static const struct iwl_ops iwl4965_ops = { | 2227 | static const struct iwl_ops iwl4965_ops = { |
@@ -2231,7 +2233,7 @@ static const struct iwl_ops iwl4965_ops = { | |||
2231 | }; | 2233 | }; |
2232 | 2234 | ||
2233 | struct iwl_cfg iwl4965_agn_cfg = { | 2235 | struct iwl_cfg iwl4965_agn_cfg = { |
2234 | .name = "4965AGN", | 2236 | .name = "Intel(R) Wireless WiFi Link 4965AGN", |
2235 | .fw_name_pre = IWL4965_FW_PRE, | 2237 | .fw_name_pre = IWL4965_FW_PRE, |
2236 | .ucode_api_max = IWL4965_UCODE_API_MAX, | 2238 | .ucode_api_max = IWL4965_UCODE_API_MAX, |
2237 | .ucode_api_min = IWL4965_UCODE_API_MIN, | 2239 | .ucode_api_min = IWL4965_UCODE_API_MIN, |
@@ -2254,6 +2256,7 @@ struct iwl_cfg iwl4965_agn_cfg = { | |||
2254 | .led_compensation = 61, | 2256 | .led_compensation = 61, |
2255 | .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, | 2257 | .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS, |
2256 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 2258 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
2259 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
2257 | }; | 2260 | }; |
2258 | 2261 | ||
2259 | /* Module firmware */ | 2262 | /* Module firmware */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 37e1e77f513d..2267cad49cbf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -544,7 +544,6 @@ void iwl5000_init_alive_start(struct iwl_priv *priv) | |||
544 | goto restart; | 544 | goto restart; |
545 | } | 545 | } |
546 | 546 | ||
547 | iwl_clear_stations_table(priv); | ||
548 | ret = priv->cfg->ops->lib->alive_notify(priv); | 547 | ret = priv->cfg->ops->lib->alive_notify(priv); |
549 | if (ret) { | 548 | if (ret) { |
550 | IWL_WARN(priv, | 549 | IWL_WARN(priv, |
@@ -1500,6 +1499,9 @@ struct iwl_lib_ops iwl5000_lib = { | |||
1500 | .set_ct_kill = iwl5000_set_ct_threshold, | 1499 | .set_ct_kill = iwl5000_set_ct_threshold, |
1501 | }, | 1500 | }, |
1502 | .add_bcast_station = iwl_add_bcast_station, | 1501 | .add_bcast_station = iwl_add_bcast_station, |
1502 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
1503 | .check_plcp_health = iwl_good_plcp_health, | ||
1504 | .check_ack_health = iwl_good_ack_health, | ||
1503 | }; | 1505 | }; |
1504 | 1506 | ||
1505 | static struct iwl_lib_ops iwl5150_lib = { | 1507 | static struct iwl_lib_ops iwl5150_lib = { |
@@ -1554,6 +1556,9 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
1554 | .set_ct_kill = iwl5150_set_ct_threshold, | 1556 | .set_ct_kill = iwl5150_set_ct_threshold, |
1555 | }, | 1557 | }, |
1556 | .add_bcast_station = iwl_add_bcast_station, | 1558 | .add_bcast_station = iwl_add_bcast_station, |
1559 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
1560 | .check_plcp_health = iwl_good_plcp_health, | ||
1561 | .check_ack_health = iwl_good_ack_health, | ||
1557 | }; | 1562 | }; |
1558 | 1563 | ||
1559 | static const struct iwl_ops iwl5000_ops = { | 1564 | static const struct iwl_ops iwl5000_ops = { |
@@ -1580,7 +1585,7 @@ struct iwl_mod_params iwl50_mod_params = { | |||
1580 | 1585 | ||
1581 | 1586 | ||
1582 | struct iwl_cfg iwl5300_agn_cfg = { | 1587 | struct iwl_cfg iwl5300_agn_cfg = { |
1583 | .name = "5300AGN", | 1588 | .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", |
1584 | .fw_name_pre = IWL5000_FW_PRE, | 1589 | .fw_name_pre = IWL5000_FW_PRE, |
1585 | .ucode_api_max = IWL5000_UCODE_API_MAX, | 1590 | .ucode_api_max = IWL5000_UCODE_API_MAX, |
1586 | .ucode_api_min = IWL5000_UCODE_API_MIN, | 1591 | .ucode_api_min = IWL5000_UCODE_API_MIN, |
@@ -1603,10 +1608,11 @@ struct iwl_cfg iwl5300_agn_cfg = { | |||
1603 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1608 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1604 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1609 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1605 | .chain_noise_scale = 1000, | 1610 | .chain_noise_scale = 1000, |
1611 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1606 | }; | 1612 | }; |
1607 | 1613 | ||
1608 | struct iwl_cfg iwl5100_bgn_cfg = { | 1614 | struct iwl_cfg iwl5100_bgn_cfg = { |
1609 | .name = "5100BGN", | 1615 | .name = "Intel(R) WiFi Link 5100 BGN", |
1610 | .fw_name_pre = IWL5000_FW_PRE, | 1616 | .fw_name_pre = IWL5000_FW_PRE, |
1611 | .ucode_api_max = IWL5000_UCODE_API_MAX, | 1617 | .ucode_api_max = IWL5000_UCODE_API_MAX, |
1612 | .ucode_api_min = IWL5000_UCODE_API_MIN, | 1618 | .ucode_api_min = IWL5000_UCODE_API_MIN, |
@@ -1629,10 +1635,11 @@ struct iwl_cfg iwl5100_bgn_cfg = { | |||
1629 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1635 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1630 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1636 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1631 | .chain_noise_scale = 1000, | 1637 | .chain_noise_scale = 1000, |
1638 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1632 | }; | 1639 | }; |
1633 | 1640 | ||
1634 | struct iwl_cfg iwl5100_abg_cfg = { | 1641 | struct iwl_cfg iwl5100_abg_cfg = { |
1635 | .name = "5100ABG", | 1642 | .name = "Intel(R) WiFi Link 5100 ABG", |
1636 | .fw_name_pre = IWL5000_FW_PRE, | 1643 | .fw_name_pre = IWL5000_FW_PRE, |
1637 | .ucode_api_max = IWL5000_UCODE_API_MAX, | 1644 | .ucode_api_max = IWL5000_UCODE_API_MAX, |
1638 | .ucode_api_min = IWL5000_UCODE_API_MIN, | 1645 | .ucode_api_min = IWL5000_UCODE_API_MIN, |
@@ -1653,10 +1660,11 @@ struct iwl_cfg iwl5100_abg_cfg = { | |||
1653 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1660 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1654 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1661 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1655 | .chain_noise_scale = 1000, | 1662 | .chain_noise_scale = 1000, |
1663 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1656 | }; | 1664 | }; |
1657 | 1665 | ||
1658 | struct iwl_cfg iwl5100_agn_cfg = { | 1666 | struct iwl_cfg iwl5100_agn_cfg = { |
1659 | .name = "5100AGN", | 1667 | .name = "Intel(R) WiFi Link 5100 AGN", |
1660 | .fw_name_pre = IWL5000_FW_PRE, | 1668 | .fw_name_pre = IWL5000_FW_PRE, |
1661 | .ucode_api_max = IWL5000_UCODE_API_MAX, | 1669 | .ucode_api_max = IWL5000_UCODE_API_MAX, |
1662 | .ucode_api_min = IWL5000_UCODE_API_MIN, | 1670 | .ucode_api_min = IWL5000_UCODE_API_MIN, |
@@ -1679,10 +1687,11 @@ struct iwl_cfg iwl5100_agn_cfg = { | |||
1679 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1687 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1680 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1688 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1681 | .chain_noise_scale = 1000, | 1689 | .chain_noise_scale = 1000, |
1690 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1682 | }; | 1691 | }; |
1683 | 1692 | ||
1684 | struct iwl_cfg iwl5350_agn_cfg = { | 1693 | struct iwl_cfg iwl5350_agn_cfg = { |
1685 | .name = "5350AGN", | 1694 | .name = "Intel(R) WiMAX/WiFi Link 5350 AGN", |
1686 | .fw_name_pre = IWL5000_FW_PRE, | 1695 | .fw_name_pre = IWL5000_FW_PRE, |
1687 | .ucode_api_max = IWL5000_UCODE_API_MAX, | 1696 | .ucode_api_max = IWL5000_UCODE_API_MAX, |
1688 | .ucode_api_min = IWL5000_UCODE_API_MIN, | 1697 | .ucode_api_min = IWL5000_UCODE_API_MIN, |
@@ -1705,10 +1714,11 @@ struct iwl_cfg iwl5350_agn_cfg = { | |||
1705 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1714 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1706 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1715 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1707 | .chain_noise_scale = 1000, | 1716 | .chain_noise_scale = 1000, |
1717 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1708 | }; | 1718 | }; |
1709 | 1719 | ||
1710 | struct iwl_cfg iwl5150_agn_cfg = { | 1720 | struct iwl_cfg iwl5150_agn_cfg = { |
1711 | .name = "5150AGN", | 1721 | .name = "Intel(R) WiMAX/WiFi Link 5150 AGN", |
1712 | .fw_name_pre = IWL5150_FW_PRE, | 1722 | .fw_name_pre = IWL5150_FW_PRE, |
1713 | .ucode_api_max = IWL5150_UCODE_API_MAX, | 1723 | .ucode_api_max = IWL5150_UCODE_API_MAX, |
1714 | .ucode_api_min = IWL5150_UCODE_API_MIN, | 1724 | .ucode_api_min = IWL5150_UCODE_API_MIN, |
@@ -1731,10 +1741,11 @@ struct iwl_cfg iwl5150_agn_cfg = { | |||
1731 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1741 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1732 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1742 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1733 | .chain_noise_scale = 1000, | 1743 | .chain_noise_scale = 1000, |
1744 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1734 | }; | 1745 | }; |
1735 | 1746 | ||
1736 | struct iwl_cfg iwl5150_abg_cfg = { | 1747 | struct iwl_cfg iwl5150_abg_cfg = { |
1737 | .name = "5150ABG", | 1748 | .name = "Intel(R) WiMAX/WiFi Link 5150 ABG", |
1738 | .fw_name_pre = IWL5150_FW_PRE, | 1749 | .fw_name_pre = IWL5150_FW_PRE, |
1739 | .ucode_api_max = IWL5150_UCODE_API_MAX, | 1750 | .ucode_api_max = IWL5150_UCODE_API_MAX, |
1740 | .ucode_api_min = IWL5150_UCODE_API_MIN, | 1751 | .ucode_api_min = IWL5150_UCODE_API_MIN, |
@@ -1755,6 +1766,7 @@ struct iwl_cfg iwl5150_abg_cfg = { | |||
1755 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, | 1766 | .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, |
1756 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | 1767 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, |
1757 | .chain_noise_scale = 1000, | 1768 | .chain_noise_scale = 1000, |
1769 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
1758 | }; | 1770 | }; |
1759 | 1771 | ||
1760 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); | 1772 | MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 4b7bc008220f..d75799946a7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -278,6 +278,9 @@ static struct iwl_lib_ops iwl6000_lib = { | |||
278 | .set_ct_kill = iwl6000_set_ct_threshold, | 278 | .set_ct_kill = iwl6000_set_ct_threshold, |
279 | }, | 279 | }, |
280 | .add_bcast_station = iwl_add_bcast_station, | 280 | .add_bcast_station = iwl_add_bcast_station, |
281 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
282 | .check_plcp_health = iwl_good_plcp_health, | ||
283 | .check_ack_health = iwl_good_ack_health, | ||
281 | }; | 284 | }; |
282 | 285 | ||
283 | static const struct iwl_ops iwl6000_ops = { | 286 | static const struct iwl_ops iwl6000_ops = { |
@@ -343,6 +346,9 @@ static struct iwl_lib_ops iwl6050_lib = { | |||
343 | .set_calib_version = iwl6050_set_calib_version, | 346 | .set_calib_version = iwl6050_set_calib_version, |
344 | }, | 347 | }, |
345 | .add_bcast_station = iwl_add_bcast_station, | 348 | .add_bcast_station = iwl_add_bcast_station, |
349 | .recover_from_tx_stall = iwl_bg_monitor_recover, | ||
350 | .check_plcp_health = iwl_good_plcp_health, | ||
351 | .check_ack_health = iwl_good_ack_health, | ||
346 | }; | 352 | }; |
347 | 353 | ||
348 | static const struct iwl_ops iwl6050_ops = { | 354 | static const struct iwl_ops iwl6050_ops = { |
@@ -357,7 +363,7 @@ static const struct iwl_ops iwl6050_ops = { | |||
357 | * "i": Internal configuration, use internal Power Amplifier | 363 | * "i": Internal configuration, use internal Power Amplifier |
358 | */ | 364 | */ |
359 | struct iwl_cfg iwl6000i_2agn_cfg = { | 365 | struct iwl_cfg iwl6000i_2agn_cfg = { |
360 | .name = "6000 Series 2x2 AGN", | 366 | .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN", |
361 | .fw_name_pre = IWL6000_FW_PRE, | 367 | .fw_name_pre = IWL6000_FW_PRE, |
362 | .ucode_api_max = IWL6000_UCODE_API_MAX, | 368 | .ucode_api_max = IWL6000_UCODE_API_MAX, |
363 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 369 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
@@ -386,10 +392,11 @@ struct iwl_cfg iwl6000i_2agn_cfg = { | |||
386 | .support_ct_kill_exit = true, | 392 | .support_ct_kill_exit = true, |
387 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 393 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
388 | .chain_noise_scale = 1000, | 394 | .chain_noise_scale = 1000, |
395 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
389 | }; | 396 | }; |
390 | 397 | ||
391 | struct iwl_cfg iwl6000i_2abg_cfg = { | 398 | struct iwl_cfg iwl6000i_2abg_cfg = { |
392 | .name = "6000 Series 2x2 ABG", | 399 | .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG", |
393 | .fw_name_pre = IWL6000_FW_PRE, | 400 | .fw_name_pre = IWL6000_FW_PRE, |
394 | .ucode_api_max = IWL6000_UCODE_API_MAX, | 401 | .ucode_api_max = IWL6000_UCODE_API_MAX, |
395 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 402 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
@@ -417,10 +424,11 @@ struct iwl_cfg iwl6000i_2abg_cfg = { | |||
417 | .support_ct_kill_exit = true, | 424 | .support_ct_kill_exit = true, |
418 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 425 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
419 | .chain_noise_scale = 1000, | 426 | .chain_noise_scale = 1000, |
427 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
420 | }; | 428 | }; |
421 | 429 | ||
422 | struct iwl_cfg iwl6000i_2bg_cfg = { | 430 | struct iwl_cfg iwl6000i_2bg_cfg = { |
423 | .name = "6000 Series 2x2 BG", | 431 | .name = "Intel(R) Centrino(R) Advanced-N 6200 BG", |
424 | .fw_name_pre = IWL6000_FW_PRE, | 432 | .fw_name_pre = IWL6000_FW_PRE, |
425 | .ucode_api_max = IWL6000_UCODE_API_MAX, | 433 | .ucode_api_max = IWL6000_UCODE_API_MAX, |
426 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 434 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
@@ -448,10 +456,11 @@ struct iwl_cfg iwl6000i_2bg_cfg = { | |||
448 | .support_ct_kill_exit = true, | 456 | .support_ct_kill_exit = true, |
449 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 457 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
450 | .chain_noise_scale = 1000, | 458 | .chain_noise_scale = 1000, |
459 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
451 | }; | 460 | }; |
452 | 461 | ||
453 | struct iwl_cfg iwl6050_2agn_cfg = { | 462 | struct iwl_cfg iwl6050_2agn_cfg = { |
454 | .name = "6050 Series 2x2 AGN", | 463 | .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN", |
455 | .fw_name_pre = IWL6050_FW_PRE, | 464 | .fw_name_pre = IWL6050_FW_PRE, |
456 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 465 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
457 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 466 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
@@ -480,10 +489,11 @@ struct iwl_cfg iwl6050_2agn_cfg = { | |||
480 | .support_ct_kill_exit = true, | 489 | .support_ct_kill_exit = true, |
481 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 490 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
482 | .chain_noise_scale = 1500, | 491 | .chain_noise_scale = 1500, |
492 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
483 | }; | 493 | }; |
484 | 494 | ||
485 | struct iwl_cfg iwl6050_2abg_cfg = { | 495 | struct iwl_cfg iwl6050_2abg_cfg = { |
486 | .name = "6050 Series 2x2 ABG", | 496 | .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG", |
487 | .fw_name_pre = IWL6050_FW_PRE, | 497 | .fw_name_pre = IWL6050_FW_PRE, |
488 | .ucode_api_max = IWL6050_UCODE_API_MAX, | 498 | .ucode_api_max = IWL6050_UCODE_API_MAX, |
489 | .ucode_api_min = IWL6050_UCODE_API_MIN, | 499 | .ucode_api_min = IWL6050_UCODE_API_MIN, |
@@ -511,10 +521,11 @@ struct iwl_cfg iwl6050_2abg_cfg = { | |||
511 | .support_ct_kill_exit = true, | 521 | .support_ct_kill_exit = true, |
512 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 522 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
513 | .chain_noise_scale = 1500, | 523 | .chain_noise_scale = 1500, |
524 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
514 | }; | 525 | }; |
515 | 526 | ||
516 | struct iwl_cfg iwl6000_3agn_cfg = { | 527 | struct iwl_cfg iwl6000_3agn_cfg = { |
517 | .name = "6000 Series 3x3 AGN", | 528 | .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN", |
518 | .fw_name_pre = IWL6000_FW_PRE, | 529 | .fw_name_pre = IWL6000_FW_PRE, |
519 | .ucode_api_max = IWL6000_UCODE_API_MAX, | 530 | .ucode_api_max = IWL6000_UCODE_API_MAX, |
520 | .ucode_api_min = IWL6000_UCODE_API_MIN, | 531 | .ucode_api_min = IWL6000_UCODE_API_MIN, |
@@ -543,6 +554,7 @@ struct iwl_cfg iwl6000_3agn_cfg = { | |||
543 | .support_ct_kill_exit = true, | 554 | .support_ct_kill_exit = true, |
544 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | 555 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, |
545 | .chain_noise_scale = 1000, | 556 | .chain_noise_scale = 1000, |
557 | .monitor_recover_period = IWL_MONITORING_PERIOD, | ||
546 | }; | 558 | }; |
547 | 559 | ||
548 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); | 560 | MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 84271cc62afa..5155b1a027eb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c | |||
@@ -769,6 +769,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, | |||
769 | 769 | ||
770 | IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); | 770 | IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); |
771 | 771 | ||
772 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
773 | if (!lq_sta) { | ||
774 | IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n"); | ||
775 | return; | ||
776 | } else if (!lq_sta->drv) { | ||
777 | IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n"); | ||
778 | return; | ||
779 | } | ||
780 | |||
772 | if (!ieee80211_is_data(hdr->frame_control) || | 781 | if (!ieee80211_is_data(hdr->frame_control) || |
773 | info->flags & IEEE80211_TX_CTL_NO_ACK) | 782 | info->flags & IEEE80211_TX_CTL_NO_ACK) |
774 | return; | 783 | return; |
@@ -778,10 +787,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, | |||
778 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) | 787 | !(info->flags & IEEE80211_TX_STAT_AMPDU)) |
779 | return; | 788 | return; |
780 | 789 | ||
781 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | ||
782 | !lq_sta->ibss_sta_added) | ||
783 | return; | ||
784 | |||
785 | /* | 790 | /* |
786 | * Ignore this Tx frame response if its initial rate doesn't match | 791 | * Ignore this Tx frame response if its initial rate doesn't match |
787 | * that of latest Link Quality command. There may be stragglers | 792 | * that of latest Link Quality command. There may be stragglers |
@@ -827,7 +832,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, | |||
827 | lq_sta->missed_rate_counter++; | 832 | lq_sta->missed_rate_counter++; |
828 | if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { | 833 | if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) { |
829 | lq_sta->missed_rate_counter = 0; | 834 | lq_sta->missed_rate_counter = 0; |
830 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); | 835 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false); |
831 | } | 836 | } |
832 | /* Regardless, ignore this status info for outdated rate */ | 837 | /* Regardless, ignore this status info for outdated rate */ |
833 | return; | 838 | return; |
@@ -1915,7 +1920,7 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv, | |||
1915 | /* Update uCode's rate table. */ | 1920 | /* Update uCode's rate table. */ |
1916 | rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); | 1921 | rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); |
1917 | rs_fill_link_cmd(priv, lq_sta, rate); | 1922 | rs_fill_link_cmd(priv, lq_sta, rate); |
1918 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); | 1923 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false); |
1919 | 1924 | ||
1920 | return rate; | 1925 | return rate; |
1921 | } | 1926 | } |
@@ -2291,7 +2296,7 @@ lq_update: | |||
2291 | IWL_DEBUG_RATE(priv, "Switch current mcs: %X index: %d\n", | 2296 | IWL_DEBUG_RATE(priv, "Switch current mcs: %X index: %d\n", |
2292 | tbl->current_rate, index); | 2297 | tbl->current_rate, index); |
2293 | rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); | 2298 | rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); |
2294 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); | 2299 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false); |
2295 | } else | 2300 | } else |
2296 | done_search = 1; | 2301 | done_search = 1; |
2297 | } | 2302 | } |
@@ -2340,7 +2345,20 @@ out: | |||
2340 | return; | 2345 | return; |
2341 | } | 2346 | } |
2342 | 2347 | ||
2343 | 2348 | /** | |
2349 | * rs_initialize_lq - Initialize a station's hardware rate table | ||
2350 | * | ||
2351 | * The uCode's station table contains a table of fallback rates | ||
2352 | * for automatic fallback during transmission. | ||
2353 | * | ||
2354 | * NOTE: This sets up a default set of values. These will be replaced later | ||
2355 | * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of | ||
2356 | * rc80211_simple. | ||
2357 | * | ||
2358 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
2359 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
2360 | * which requires station table entry to exist). | ||
2361 | */ | ||
2344 | static void rs_initialize_lq(struct iwl_priv *priv, | 2362 | static void rs_initialize_lq(struct iwl_priv *priv, |
2345 | struct ieee80211_conf *conf, | 2363 | struct ieee80211_conf *conf, |
2346 | struct ieee80211_sta *sta, | 2364 | struct ieee80211_sta *sta, |
@@ -2359,10 +2377,6 @@ static void rs_initialize_lq(struct iwl_priv *priv, | |||
2359 | 2377 | ||
2360 | i = lq_sta->last_txrate_idx; | 2378 | i = lq_sta->last_txrate_idx; |
2361 | 2379 | ||
2362 | if ((lq_sta->lq.sta_id == 0xff) && | ||
2363 | (priv->iw_mode == NL80211_IFTYPE_ADHOC)) | ||
2364 | goto out; | ||
2365 | |||
2366 | valid_tx_ant = priv->hw_params.valid_tx_ant; | 2380 | valid_tx_ant = priv->hw_params.valid_tx_ant; |
2367 | 2381 | ||
2368 | if (!lq_sta->search_better_tbl) | 2382 | if (!lq_sta->search_better_tbl) |
@@ -2390,7 +2404,8 @@ static void rs_initialize_lq(struct iwl_priv *priv, | |||
2390 | tbl->current_rate = rate; | 2404 | tbl->current_rate = rate; |
2391 | rs_set_expected_tpt_table(lq_sta, tbl); | 2405 | rs_set_expected_tpt_table(lq_sta, tbl); |
2392 | rs_fill_link_cmd(NULL, lq_sta, rate); | 2406 | rs_fill_link_cmd(NULL, lq_sta, rate); |
2393 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); | 2407 | priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq; |
2408 | iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_SYNC, true); | ||
2394 | out: | 2409 | out: |
2395 | return; | 2410 | return; |
2396 | } | 2411 | } |
@@ -2402,9 +2417,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2402 | struct sk_buff *skb = txrc->skb; | 2417 | struct sk_buff *skb = txrc->skb; |
2403 | struct ieee80211_supported_band *sband = txrc->sband; | 2418 | struct ieee80211_supported_band *sband = txrc->sband; |
2404 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; | 2419 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; |
2405 | struct ieee80211_conf *conf = &priv->hw->conf; | ||
2406 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
2407 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
2408 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 2420 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
2409 | struct iwl_lq_sta *lq_sta = priv_sta; | 2421 | struct iwl_lq_sta *lq_sta = priv_sta; |
2410 | int rate_idx; | 2422 | int rate_idx; |
@@ -2422,30 +2434,18 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, | |||
2422 | lq_sta->max_rate_idx = -1; | 2434 | lq_sta->max_rate_idx = -1; |
2423 | } | 2435 | } |
2424 | 2436 | ||
2437 | /* Treat uninitialized rate scaling data same as non-existing. */ | ||
2438 | if (lq_sta && !lq_sta->drv) { | ||
2439 | IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n"); | ||
2440 | priv_sta = NULL; | ||
2441 | } | ||
2442 | |||
2425 | /* Send management frames and NO_ACK data using lowest rate. */ | 2443 | /* Send management frames and NO_ACK data using lowest rate. */ |
2426 | if (rate_control_send_low(sta, priv_sta, txrc)) | 2444 | if (rate_control_send_low(sta, priv_sta, txrc)) |
2427 | return; | 2445 | return; |
2428 | 2446 | ||
2429 | rate_idx = lq_sta->last_txrate_idx; | 2447 | rate_idx = lq_sta->last_txrate_idx; |
2430 | 2448 | ||
2431 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && | ||
2432 | !lq_sta->ibss_sta_added) { | ||
2433 | u8 sta_id = iwl_find_station(priv, hdr->addr1); | ||
2434 | |||
2435 | if (sta_id == IWL_INVALID_STATION) { | ||
2436 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", | ||
2437 | hdr->addr1); | ||
2438 | sta_id = iwl_add_station(priv, hdr->addr1, | ||
2439 | false, CMD_ASYNC, ht_cap); | ||
2440 | } | ||
2441 | if ((sta_id != IWL_INVALID_STATION)) { | ||
2442 | lq_sta->lq.sta_id = sta_id; | ||
2443 | lq_sta->lq.rs_table[0].rate_n_flags = 0; | ||
2444 | lq_sta->ibss_sta_added = 1; | ||
2445 | rs_initialize_lq(priv, conf, sta, lq_sta); | ||
2446 | } | ||
2447 | } | ||
2448 | |||
2449 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { | 2449 | if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) { |
2450 | rate_idx -= IWL_FIRST_OFDM_RATE; | 2450 | rate_idx -= IWL_FIRST_OFDM_RATE; |
2451 | /* 6M and 9M shared same MCS index */ | 2451 | /* 6M and 9M shared same MCS index */ |
@@ -2495,16 +2495,25 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, | |||
2495 | return lq_sta; | 2495 | return lq_sta; |
2496 | } | 2496 | } |
2497 | 2497 | ||
2498 | static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | 2498 | /* |
2499 | struct ieee80211_sta *sta, void *priv_sta) | 2499 | * Called after adding a new station to initialize rate scaling |
2500 | */ | ||
2501 | void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id) | ||
2500 | { | 2502 | { |
2501 | int i, j; | 2503 | int i, j; |
2502 | struct iwl_priv *priv = (struct iwl_priv *)priv_r; | 2504 | struct ieee80211_hw *hw = priv->hw; |
2503 | struct ieee80211_conf *conf = &priv->hw->conf; | 2505 | struct ieee80211_conf *conf = &priv->hw->conf; |
2504 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | 2506 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; |
2505 | struct iwl_lq_sta *lq_sta = priv_sta; | 2507 | struct iwl_station_priv *sta_priv; |
2508 | struct iwl_lq_sta *lq_sta; | ||
2509 | struct ieee80211_supported_band *sband; | ||
2510 | |||
2511 | sta_priv = (struct iwl_station_priv *) sta->drv_priv; | ||
2512 | lq_sta = &sta_priv->lq_sta; | ||
2513 | sband = hw->wiphy->bands[conf->channel->band]; | ||
2514 | |||
2506 | 2515 | ||
2507 | lq_sta->lq.sta_id = 0xff; | 2516 | lq_sta->lq.sta_id = sta_id; |
2508 | 2517 | ||
2509 | for (j = 0; j < LQ_SIZE; j++) | 2518 | for (j = 0; j < LQ_SIZE; j++) |
2510 | for (i = 0; i < IWL_RATE_COUNT; i++) | 2519 | for (i = 0; i < IWL_RATE_COUNT; i++) |
@@ -2516,33 +2525,13 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, | |||
2516 | for (i = 0; i < IWL_RATE_COUNT; i++) | 2525 | for (i = 0; i < IWL_RATE_COUNT; i++) |
2517 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); | 2526 | rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]); |
2518 | 2527 | ||
2519 | IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init ***\n"); | 2528 | IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n", |
2529 | sta_id); | ||
2520 | /* TODO: what is a good starting rate for STA? About middle? Maybe not | 2530 | /* TODO: what is a good starting rate for STA? About middle? Maybe not |
2521 | * the lowest or the highest rate.. Could consider using RSSI from | 2531 | * the lowest or the highest rate.. Could consider using RSSI from |
2522 | * previous packets? Need to have IEEE 802.1X auth succeed immediately | 2532 | * previous packets? Need to have IEEE 802.1X auth succeed immediately |
2523 | * after assoc.. */ | 2533 | * after assoc.. */ |
2524 | 2534 | ||
2525 | lq_sta->ibss_sta_added = 0; | ||
2526 | if (priv->iw_mode == NL80211_IFTYPE_AP) { | ||
2527 | u8 sta_id = iwl_find_station(priv, | ||
2528 | sta->addr); | ||
2529 | |||
2530 | /* for IBSS the call are from tasklet */ | ||
2531 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); | ||
2532 | |||
2533 | if (sta_id == IWL_INVALID_STATION) { | ||
2534 | IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr); | ||
2535 | sta_id = iwl_add_station(priv, sta->addr, false, | ||
2536 | CMD_ASYNC, ht_cap); | ||
2537 | } | ||
2538 | if ((sta_id != IWL_INVALID_STATION)) { | ||
2539 | lq_sta->lq.sta_id = sta_id; | ||
2540 | lq_sta->lq.rs_table[0].rate_n_flags = 0; | ||
2541 | } | ||
2542 | /* FIXME: this is w/a remove it later */ | ||
2543 | priv->assoc_station_added = 1; | ||
2544 | } | ||
2545 | |||
2546 | lq_sta->is_dup = 0; | 2535 | lq_sta->is_dup = 0; |
2547 | lq_sta->max_rate_idx = -1; | 2536 | lq_sta->max_rate_idx = -1; |
2548 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; | 2537 | lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX; |
@@ -2795,7 +2784,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, | |||
2795 | 2784 | ||
2796 | if (lq_sta->dbg_fixed_rate) { | 2785 | if (lq_sta->dbg_fixed_rate) { |
2797 | rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); | 2786 | rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate); |
2798 | iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); | 2787 | iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false); |
2799 | } | 2788 | } |
2800 | 2789 | ||
2801 | return count; | 2790 | return count; |
@@ -2992,12 +2981,21 @@ static void rs_remove_debugfs(void *priv, void *priv_sta) | |||
2992 | } | 2981 | } |
2993 | #endif | 2982 | #endif |
2994 | 2983 | ||
2984 | /* | ||
2985 | * Initialization of rate scaling information is done by driver after | ||
2986 | * the station is added. Since mac80211 calls this function before a | ||
2987 | * station is added we ignore it. | ||
2988 | */ | ||
2989 | static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband, | ||
2990 | struct ieee80211_sta *sta, void *priv_sta) | ||
2991 | { | ||
2992 | } | ||
2995 | static struct rate_control_ops rs_ops = { | 2993 | static struct rate_control_ops rs_ops = { |
2996 | .module = NULL, | 2994 | .module = NULL, |
2997 | .name = RS_NAME, | 2995 | .name = RS_NAME, |
2998 | .tx_status = rs_tx_status, | 2996 | .tx_status = rs_tx_status, |
2999 | .get_rate = rs_get_rate, | 2997 | .get_rate = rs_get_rate, |
3000 | .rate_init = rs_rate_init, | 2998 | .rate_init = rs_rate_init_stub, |
3001 | .alloc = rs_alloc, | 2999 | .alloc = rs_alloc, |
3002 | .free = rs_free, | 3000 | .free = rs_free, |
3003 | .alloc_sta = rs_alloc_sta, | 3001 | .alloc_sta = rs_alloc_sta, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index e182f5a0f736..8292f6d48ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h | |||
@@ -403,7 +403,6 @@ struct iwl_lq_sta { | |||
403 | u8 is_green; | 403 | u8 is_green; |
404 | u8 is_dup; | 404 | u8 is_dup; |
405 | enum ieee80211_band band; | 405 | enum ieee80211_band band; |
406 | u8 ibss_sta_added; | ||
407 | 406 | ||
408 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ | 407 | /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ |
409 | u32 supp_rates; | 408 | u32 supp_rates; |
@@ -478,6 +477,12 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) | |||
478 | */ | 477 | */ |
479 | extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); | 478 | extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); |
480 | 479 | ||
480 | /* Initialize station's rate scaling information after adding station */ | ||
481 | extern void iwl_rs_rate_init(struct iwl_priv *priv, | ||
482 | struct ieee80211_sta *sta, u8 sta_id); | ||
483 | extern void iwl3945_rs_rate_init(struct iwl_priv *priv, | ||
484 | struct ieee80211_sta *sta, u8 sta_id); | ||
485 | |||
481 | /** | 486 | /** |
482 | * iwl_rate_control_register - Register the rate control algorithm callbacks | 487 | * iwl_rate_control_register - Register the rate control algorithm callbacks |
483 | * | 488 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index efee4e39d282..0a376f720d78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -144,9 +144,6 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | 146 | ||
147 | /* station table will be cleared */ | ||
148 | priv->assoc_station_added = 0; | ||
149 | |||
150 | /* If we are currently associated and the new config requires | 147 | /* If we are currently associated and the new config requires |
151 | * an RXON_ASSOC and the new config wants the associated mask enabled, | 148 | * an RXON_ASSOC and the new config wants the associated mask enabled, |
152 | * we must clear the associated from the active configuration | 149 | * we must clear the associated from the active configuration |
@@ -166,6 +163,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
166 | IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); | 163 | IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); |
167 | return ret; | 164 | return ret; |
168 | } | 165 | } |
166 | iwl_clear_ucode_stations(priv, false); | ||
167 | iwl_restore_stations(priv); | ||
169 | } | 168 | } |
170 | 169 | ||
171 | IWL_DEBUG_INFO(priv, "Sending RXON\n" | 170 | IWL_DEBUG_INFO(priv, "Sending RXON\n" |
@@ -179,9 +178,8 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
179 | iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); | 178 | iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto); |
180 | 179 | ||
181 | /* Apply the new configuration | 180 | /* Apply the new configuration |
182 | * RXON unassoc clears the station table in uCode, send it before | 181 | * RXON unassoc clears the station table in uCode so restoration of |
183 | * we add the bcast station. If assoc bit is set, we will send RXON | 182 | * stations is needed after it (the RXON command) completes |
184 | * after having added the bcast and bssid station. | ||
185 | */ | 183 | */ |
186 | if (!new_assoc) { | 184 | if (!new_assoc) { |
187 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, | 185 | ret = iwl_send_cmd_pdu(priv, REPLY_RXON, |
@@ -190,35 +188,14 @@ int iwl_commit_rxon(struct iwl_priv *priv) | |||
190 | IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); | 188 | IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); |
191 | return ret; | 189 | return ret; |
192 | } | 190 | } |
191 | IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON. \n"); | ||
193 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); | 192 | memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); |
193 | iwl_clear_ucode_stations(priv, false); | ||
194 | iwl_restore_stations(priv); | ||
194 | } | 195 | } |
195 | 196 | ||
196 | iwl_clear_stations_table(priv); | ||
197 | |||
198 | priv->start_calib = 0; | 197 | priv->start_calib = 0; |
199 | |||
200 | /* Add the broadcast address so we can send broadcast frames */ | ||
201 | priv->cfg->ops->lib->add_bcast_station(priv); | ||
202 | |||
203 | |||
204 | /* If we have set the ASSOC_MSK and we are in BSS mode then | ||
205 | * add the IWL_AP_ID to the station rate table */ | ||
206 | if (new_assoc) { | 198 | if (new_assoc) { |
207 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { | ||
208 | ret = iwl_rxon_add_station(priv, | ||
209 | priv->active_rxon.bssid_addr, 1); | ||
210 | if (ret == IWL_INVALID_STATION) { | ||
211 | IWL_ERR(priv, | ||
212 | "Error adding AP address for TX.\n"); | ||
213 | return -EIO; | ||
214 | } | ||
215 | priv->assoc_station_added = 1; | ||
216 | if (priv->default_wep_key && | ||
217 | iwl_send_static_wepkey_cmd(priv, 0)) | ||
218 | IWL_ERR(priv, | ||
219 | "Could not send WEP static key.\n"); | ||
220 | } | ||
221 | |||
222 | /* | 199 | /* |
223 | * allow CTS-to-self if possible for new association. | 200 | * allow CTS-to-self if possible for new association. |
224 | * this is relevant only for 5000 series and up, | 201 | * this is relevant only for 5000 series and up, |
@@ -2087,7 +2064,6 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
2087 | goto restart; | 2064 | goto restart; |
2088 | } | 2065 | } |
2089 | 2066 | ||
2090 | iwl_clear_stations_table(priv); | ||
2091 | ret = priv->cfg->ops->lib->alive_notify(priv); | 2067 | ret = priv->cfg->ops->lib->alive_notify(priv); |
2092 | if (ret) { | 2068 | if (ret) { |
2093 | IWL_WARN(priv, | 2069 | IWL_WARN(priv, |
@@ -2098,6 +2074,13 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
2098 | /* After the ALIVE response, we can send host commands to the uCode */ | 2074 | /* After the ALIVE response, we can send host commands to the uCode */ |
2099 | set_bit(STATUS_ALIVE, &priv->status); | 2075 | set_bit(STATUS_ALIVE, &priv->status); |
2100 | 2076 | ||
2077 | if (priv->cfg->ops->lib->recover_from_tx_stall) { | ||
2078 | /* Enable timer to monitor the driver queues */ | ||
2079 | mod_timer(&priv->monitor_recover, | ||
2080 | jiffies + | ||
2081 | msecs_to_jiffies(priv->cfg->monitor_recover_period)); | ||
2082 | } | ||
2083 | |||
2101 | if (iwl_is_rfkill(priv)) | 2084 | if (iwl_is_rfkill(priv)) |
2102 | return; | 2085 | return; |
2103 | 2086 | ||
@@ -2143,6 +2126,8 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
2143 | wake_up_interruptible(&priv->wait_command_queue); | 2126 | wake_up_interruptible(&priv->wait_command_queue); |
2144 | 2127 | ||
2145 | iwl_power_update_mode(priv, true); | 2128 | iwl_power_update_mode(priv, true); |
2129 | IWL_DEBUG_INFO(priv, "Updated power mode\n"); | ||
2130 | |||
2146 | 2131 | ||
2147 | return; | 2132 | return; |
2148 | 2133 | ||
@@ -2162,7 +2147,7 @@ static void __iwl_down(struct iwl_priv *priv) | |||
2162 | if (!exit_pending) | 2147 | if (!exit_pending) |
2163 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 2148 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
2164 | 2149 | ||
2165 | iwl_clear_stations_table(priv); | 2150 | iwl_clear_ucode_stations(priv, true); |
2166 | 2151 | ||
2167 | /* Unblock any waiting calls */ | 2152 | /* Unblock any waiting calls */ |
2168 | wake_up_interruptible_all(&priv->wait_command_queue); | 2153 | wake_up_interruptible_all(&priv->wait_command_queue); |
@@ -2359,8 +2344,6 @@ static int __iwl_up(struct iwl_priv *priv) | |||
2359 | 2344 | ||
2360 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 2345 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
2361 | 2346 | ||
2362 | iwl_clear_stations_table(priv); | ||
2363 | |||
2364 | /* load bootstrap state machine, | 2347 | /* load bootstrap state machine, |
2365 | * load bootstrap program into processor's memory, | 2348 | * load bootstrap program into processor's memory, |
2366 | * prepare to load the "initialize" uCode */ | 2349 | * prepare to load the "initialize" uCode */ |
@@ -2501,10 +2484,6 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2501 | return; | 2484 | return; |
2502 | } | 2485 | } |
2503 | 2486 | ||
2504 | IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", | ||
2505 | priv->assoc_id, priv->active_rxon.bssid_addr); | ||
2506 | |||
2507 | |||
2508 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2487 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2509 | return; | 2488 | return; |
2510 | 2489 | ||
@@ -2556,6 +2535,9 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2556 | 2535 | ||
2557 | iwlcore_commit_rxon(priv); | 2536 | iwlcore_commit_rxon(priv); |
2558 | 2537 | ||
2538 | IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", | ||
2539 | priv->assoc_id, priv->active_rxon.bssid_addr); | ||
2540 | |||
2559 | switch (priv->iw_mode) { | 2541 | switch (priv->iw_mode) { |
2560 | case NL80211_IFTYPE_STATION: | 2542 | case NL80211_IFTYPE_STATION: |
2561 | break; | 2543 | break; |
@@ -2565,7 +2547,7 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2565 | /* assume default assoc id */ | 2547 | /* assume default assoc id */ |
2566 | priv->assoc_id = 1; | 2548 | priv->assoc_id = 1; |
2567 | 2549 | ||
2568 | iwl_rxon_add_station(priv, priv->bssid, 0); | 2550 | iwl_add_local_station(priv, priv->bssid, true); |
2569 | iwl_send_beacon_cmd(priv); | 2551 | iwl_send_beacon_cmd(priv); |
2570 | 2552 | ||
2571 | break; | 2553 | break; |
@@ -2576,9 +2558,6 @@ void iwl_post_associate(struct iwl_priv *priv) | |||
2576 | break; | 2558 | break; |
2577 | } | 2559 | } |
2578 | 2560 | ||
2579 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) | ||
2580 | priv->assoc_station_added = 1; | ||
2581 | |||
2582 | spin_lock_irqsave(&priv->lock, flags); | 2561 | spin_lock_irqsave(&priv->lock, flags); |
2583 | iwl_activate_qos(priv, 0); | 2562 | iwl_activate_qos(priv, 0); |
2584 | spin_unlock_irqrestore(&priv->lock, flags); | 2563 | spin_unlock_irqrestore(&priv->lock, flags); |
@@ -2937,10 +2916,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
2937 | return ret; | 2916 | return ret; |
2938 | case IEEE80211_AMPDU_TX_START: | 2917 | case IEEE80211_AMPDU_TX_START: |
2939 | IWL_DEBUG_HT(priv, "start Tx\n"); | 2918 | IWL_DEBUG_HT(priv, "start Tx\n"); |
2940 | return iwl_tx_agg_start(priv, sta->addr, tid, ssn); | 2919 | ret = iwl_tx_agg_start(priv, sta->addr, tid, ssn); |
2920 | if (ret == 0) { | ||
2921 | priv->_agn.agg_tids_count++; | ||
2922 | IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", | ||
2923 | priv->_agn.agg_tids_count); | ||
2924 | } | ||
2925 | return ret; | ||
2941 | case IEEE80211_AMPDU_TX_STOP: | 2926 | case IEEE80211_AMPDU_TX_STOP: |
2942 | IWL_DEBUG_HT(priv, "stop Tx\n"); | 2927 | IWL_DEBUG_HT(priv, "stop Tx\n"); |
2943 | ret = iwl_tx_agg_stop(priv, sta->addr, tid); | 2928 | ret = iwl_tx_agg_stop(priv, sta->addr, tid); |
2929 | if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) { | ||
2930 | priv->_agn.agg_tids_count--; | ||
2931 | IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n", | ||
2932 | priv->_agn.agg_tids_count); | ||
2933 | } | ||
2944 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 2934 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
2945 | return 0; | 2935 | return 0; |
2946 | else | 2936 | else |
@@ -2977,18 +2967,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, | |||
2977 | struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; | 2967 | struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; |
2978 | int sta_id; | 2968 | int sta_id; |
2979 | 2969 | ||
2980 | /* | ||
2981 | * TODO: We really should use this callback to | ||
2982 | * actually maintain the station table in | ||
2983 | * the device. | ||
2984 | */ | ||
2985 | |||
2986 | switch (cmd) { | 2970 | switch (cmd) { |
2987 | case STA_NOTIFY_ADD: | ||
2988 | atomic_set(&sta_priv->pending_frames, 0); | ||
2989 | if (vif->type == NL80211_IFTYPE_AP) | ||
2990 | sta_priv->client = true; | ||
2991 | break; | ||
2992 | case STA_NOTIFY_SLEEP: | 2971 | case STA_NOTIFY_SLEEP: |
2993 | WARN_ON(!sta_priv->client); | 2972 | WARN_ON(!sta_priv->client); |
2994 | sta_priv->asleep = true; | 2973 | sta_priv->asleep = true; |
@@ -3009,6 +2988,55 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, | |||
3009 | } | 2988 | } |
3010 | } | 2989 | } |
3011 | 2990 | ||
2991 | /** | ||
2992 | * iwl_restore_wepkeys - Restore WEP keys to device | ||
2993 | */ | ||
2994 | static void iwl_restore_wepkeys(struct iwl_priv *priv) | ||
2995 | { | ||
2996 | mutex_lock(&priv->mutex); | ||
2997 | if (priv->iw_mode == NL80211_IFTYPE_STATION && | ||
2998 | priv->default_wep_key && | ||
2999 | iwl_send_static_wepkey_cmd(priv, 0)) | ||
3000 | IWL_ERR(priv, "Could not send WEP static key\n"); | ||
3001 | mutex_unlock(&priv->mutex); | ||
3002 | } | ||
3003 | |||
3004 | static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, | ||
3005 | struct ieee80211_vif *vif, | ||
3006 | struct ieee80211_sta *sta) | ||
3007 | { | ||
3008 | struct iwl_priv *priv = hw->priv; | ||
3009 | struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; | ||
3010 | bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION; | ||
3011 | int ret; | ||
3012 | u8 sta_id; | ||
3013 | |||
3014 | IWL_DEBUG_INFO(priv, "received request to add station %pM\n", | ||
3015 | sta->addr); | ||
3016 | |||
3017 | atomic_set(&sta_priv->pending_frames, 0); | ||
3018 | if (vif->type == NL80211_IFTYPE_AP) | ||
3019 | sta_priv->client = true; | ||
3020 | |||
3021 | ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap, | ||
3022 | &sta_id); | ||
3023 | if (ret) { | ||
3024 | IWL_ERR(priv, "Unable to add station %pM (%d)\n", | ||
3025 | sta->addr, ret); | ||
3026 | /* Should we return success if return code is EEXIST ? */ | ||
3027 | return ret; | ||
3028 | } | ||
3029 | |||
3030 | iwl_restore_wepkeys(priv); | ||
3031 | |||
3032 | /* Initialize rate scaling */ | ||
3033 | IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n", | ||
3034 | sta->addr); | ||
3035 | iwl_rs_rate_init(priv, sta, sta_id); | ||
3036 | |||
3037 | return ret; | ||
3038 | } | ||
3039 | |||
3012 | /***************************************************************************** | 3040 | /***************************************************************************** |
3013 | * | 3041 | * |
3014 | * sysfs attributes | 3042 | * sysfs attributes |
@@ -3214,6 +3242,13 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
3214 | priv->ucode_trace.data = (unsigned long)priv; | 3242 | priv->ucode_trace.data = (unsigned long)priv; |
3215 | priv->ucode_trace.function = iwl_bg_ucode_trace; | 3243 | priv->ucode_trace.function = iwl_bg_ucode_trace; |
3216 | 3244 | ||
3245 | if (priv->cfg->ops->lib->recover_from_tx_stall) { | ||
3246 | init_timer(&priv->monitor_recover); | ||
3247 | priv->monitor_recover.data = (unsigned long)priv; | ||
3248 | priv->monitor_recover.function = | ||
3249 | priv->cfg->ops->lib->recover_from_tx_stall; | ||
3250 | } | ||
3251 | |||
3217 | if (!priv->cfg->use_isr_legacy) | 3252 | if (!priv->cfg->use_isr_legacy) |
3218 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 3253 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
3219 | iwl_irq_tasklet, (unsigned long)priv); | 3254 | iwl_irq_tasklet, (unsigned long)priv); |
@@ -3233,6 +3268,8 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) | |||
3233 | cancel_work_sync(&priv->beacon_update); | 3268 | cancel_work_sync(&priv->beacon_update); |
3234 | del_timer_sync(&priv->statistics_periodic); | 3269 | del_timer_sync(&priv->statistics_periodic); |
3235 | del_timer_sync(&priv->ucode_trace); | 3270 | del_timer_sync(&priv->ucode_trace); |
3271 | if (priv->cfg->ops->lib->recover_from_tx_stall) | ||
3272 | del_timer_sync(&priv->monitor_recover); | ||
3236 | } | 3273 | } |
3237 | 3274 | ||
3238 | static void iwl_init_hw_rates(struct iwl_priv *priv, | 3275 | static void iwl_init_hw_rates(struct iwl_priv *priv, |
@@ -3270,9 +3307,6 @@ static int iwl_init_drv(struct iwl_priv *priv) | |||
3270 | mutex_init(&priv->mutex); | 3307 | mutex_init(&priv->mutex); |
3271 | mutex_init(&priv->sync_cmd_mutex); | 3308 | mutex_init(&priv->sync_cmd_mutex); |
3272 | 3309 | ||
3273 | /* Clear the driver's (not device's) station table */ | ||
3274 | iwl_clear_stations_table(priv); | ||
3275 | |||
3276 | priv->ieee_channels = NULL; | 3310 | priv->ieee_channels = NULL; |
3277 | priv->ieee_rates = NULL; | 3311 | priv->ieee_rates = NULL; |
3278 | priv->band = IEEE80211_BAND_2GHZ; | 3312 | priv->band = IEEE80211_BAND_2GHZ; |
@@ -3280,6 +3314,7 @@ static int iwl_init_drv(struct iwl_priv *priv) | |||
3280 | priv->iw_mode = NL80211_IFTYPE_STATION; | 3314 | priv->iw_mode = NL80211_IFTYPE_STATION; |
3281 | priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; | 3315 | priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; |
3282 | priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; | 3316 | priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; |
3317 | priv->_agn.agg_tids_count = 0; | ||
3283 | 3318 | ||
3284 | /* initialize force reset */ | 3319 | /* initialize force reset */ |
3285 | priv->force_reset[IWL_RF_RESET].reset_duration = | 3320 | priv->force_reset[IWL_RF_RESET].reset_duration = |
@@ -3365,6 +3400,8 @@ static struct ieee80211_ops iwl_hw_ops = { | |||
3365 | .ampdu_action = iwl_mac_ampdu_action, | 3400 | .ampdu_action = iwl_mac_ampdu_action, |
3366 | .hw_scan = iwl_mac_hw_scan, | 3401 | .hw_scan = iwl_mac_hw_scan, |
3367 | .sta_notify = iwl_mac_sta_notify, | 3402 | .sta_notify = iwl_mac_sta_notify, |
3403 | .sta_add = iwlagn_mac_sta_add, | ||
3404 | .sta_remove = iwl_mac_sta_remove, | ||
3368 | }; | 3405 | }; |
3369 | 3406 | ||
3370 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 3407 | static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
@@ -3468,7 +3505,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3468 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); | 3505 | iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); |
3469 | 3506 | ||
3470 | iwl_hw_detect(priv); | 3507 | iwl_hw_detect(priv); |
3471 | IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n", | 3508 | IWL_INFO(priv, "Detected %s, REV=0x%X\n", |
3472 | priv->cfg->name, priv->hw_rev); | 3509 | priv->cfg->name, priv->hw_rev); |
3473 | 3510 | ||
3474 | /* We disable the RETRY_TIMEOUT register (0x41) to keep | 3511 | /* We disable the RETRY_TIMEOUT register (0x41) to keep |
@@ -3649,7 +3686,6 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) | |||
3649 | iwl_rx_queue_free(priv, &priv->rxq); | 3686 | iwl_rx_queue_free(priv, &priv->rxq); |
3650 | iwl_hw_txq_ctx_free(priv); | 3687 | iwl_hw_txq_ctx_free(priv); |
3651 | 3688 | ||
3652 | iwl_clear_stations_table(priv); | ||
3653 | iwl_eeprom_free(priv); | 3689 | iwl_eeprom_free(priv); |
3654 | 3690 | ||
3655 | 3691 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ec435e5491d9..5180fb24cd38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -2283,8 +2283,6 @@ static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
2283 | 2283 | ||
2284 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 2284 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
2285 | 2285 | ||
2286 | iwl_clear_stations_table(priv); | ||
2287 | |||
2288 | return iwlcore_commit_rxon(priv); | 2286 | return iwlcore_commit_rxon(priv); |
2289 | } | 2287 | } |
2290 | 2288 | ||
@@ -2317,6 +2315,10 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | |||
2317 | err = iwl_set_mode(priv, vif); | 2315 | err = iwl_set_mode(priv, vif); |
2318 | if (err) | 2316 | if (err) |
2319 | goto out_err; | 2317 | goto out_err; |
2318 | |||
2319 | /* Add the broadcast address so we can send broadcast frames */ | ||
2320 | priv->cfg->ops->lib->add_bcast_station(priv); | ||
2321 | |||
2320 | goto out; | 2322 | goto out; |
2321 | 2323 | ||
2322 | out_err: | 2324 | out_err: |
@@ -2339,6 +2341,8 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, | |||
2339 | 2341 | ||
2340 | mutex_lock(&priv->mutex); | 2342 | mutex_lock(&priv->mutex); |
2341 | 2343 | ||
2344 | iwl_clear_ucode_stations(priv, true); | ||
2345 | |||
2342 | if (iwl_is_ready_rf(priv)) { | 2346 | if (iwl_is_ready_rf(priv)) { |
2343 | iwl_scan_cancel_timeout(priv, 100); | 2347 | iwl_scan_cancel_timeout(priv, 100); |
2344 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 2348 | priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
@@ -2526,7 +2530,6 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw) | |||
2526 | spin_lock_irqsave(&priv->lock, flags); | 2530 | spin_lock_irqsave(&priv->lock, flags); |
2527 | priv->assoc_id = 0; | 2531 | priv->assoc_id = 0; |
2528 | priv->assoc_capability = 0; | 2532 | priv->assoc_capability = 0; |
2529 | priv->assoc_station_added = 0; | ||
2530 | 2533 | ||
2531 | /* new association get rid of ibss beacon skb */ | 2534 | /* new association get rid of ibss beacon skb */ |
2532 | if (priv->ibss_beacon) | 2535 | if (priv->ibss_beacon) |
@@ -3048,6 +3051,99 @@ int iwl_force_reset(struct iwl_priv *priv, int mode) | |||
3048 | } | 3051 | } |
3049 | return 0; | 3052 | return 0; |
3050 | } | 3053 | } |
3054 | EXPORT_SYMBOL(iwl_force_reset); | ||
3055 | |||
3056 | /** | ||
3057 | * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover | ||
3058 | * | ||
3059 | * During normal condition (no queue is stuck), the timer is continually set to | ||
3060 | * execute every monitor_recover_period milliseconds after the last timer | ||
3061 | * expired. When the queue read_ptr is at the same place, the timer is | ||
3062 | * shorten to 100mSecs. This is | ||
3063 | * 1) to reduce the chance that the read_ptr may wrap around (not stuck) | ||
3064 | * 2) to detect the stuck queues quicker before the station and AP can | ||
3065 | * disassociate each other. | ||
3066 | * | ||
3067 | * This function monitors all the tx queues and recover from it if any | ||
3068 | * of the queues are stuck. | ||
3069 | * 1. It first check the cmd queue for stuck conditions. If it is stuck, | ||
3070 | * it will recover by resetting the firmware and return. | ||
3071 | * 2. Then, it checks for station association. If it associates it will check | ||
3072 | * other queues. If any queue is stuck, it will recover by resetting | ||
3073 | * the firmware. | ||
3074 | * Note: It the number of times the queue read_ptr to be at the same place to | ||
3075 | * be MAX_REPEAT+1 in order to consider to be stuck. | ||
3076 | */ | ||
3077 | /* | ||
3078 | * The maximum number of times the read pointer of the tx queue at the | ||
3079 | * same place without considering to be stuck. | ||
3080 | */ | ||
3081 | #define MAX_REPEAT (2) | ||
3082 | static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) | ||
3083 | { | ||
3084 | struct iwl_tx_queue *txq; | ||
3085 | struct iwl_queue *q; | ||
3086 | |||
3087 | txq = &priv->txq[cnt]; | ||
3088 | q = &txq->q; | ||
3089 | /* queue is empty, skip */ | ||
3090 | if (q->read_ptr != q->write_ptr) { | ||
3091 | if (q->read_ptr == q->last_read_ptr) { | ||
3092 | /* a queue has not been read from last time */ | ||
3093 | if (q->repeat_same_read_ptr > MAX_REPEAT) { | ||
3094 | IWL_ERR(priv, | ||
3095 | "queue %d stuck %d time. Fw reload.\n", | ||
3096 | q->id, q->repeat_same_read_ptr); | ||
3097 | q->repeat_same_read_ptr = 0; | ||
3098 | iwl_force_reset(priv, IWL_FW_RESET); | ||
3099 | } else { | ||
3100 | q->repeat_same_read_ptr++; | ||
3101 | IWL_DEBUG_RADIO(priv, | ||
3102 | "queue %d, not read %d time\n", | ||
3103 | q->id, | ||
3104 | q->repeat_same_read_ptr); | ||
3105 | mod_timer(&priv->monitor_recover, jiffies + | ||
3106 | msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS)); | ||
3107 | } | ||
3108 | return 1; | ||
3109 | } else { | ||
3110 | q->last_read_ptr = q->read_ptr; | ||
3111 | q->repeat_same_read_ptr = 0; | ||
3112 | } | ||
3113 | } | ||
3114 | return 0; | ||
3115 | } | ||
3116 | |||
3117 | void iwl_bg_monitor_recover(unsigned long data) | ||
3118 | { | ||
3119 | struct iwl_priv *priv = (struct iwl_priv *)data; | ||
3120 | int cnt; | ||
3121 | |||
3122 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
3123 | return; | ||
3124 | |||
3125 | /* monitor and check for stuck cmd queue */ | ||
3126 | if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM)) | ||
3127 | return; | ||
3128 | |||
3129 | /* monitor and check for other stuck queues */ | ||
3130 | if (iwl_is_associated(priv)) { | ||
3131 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { | ||
3132 | /* skip as we already checked the command queue */ | ||
3133 | if (cnt == IWL_CMD_QUEUE_NUM) | ||
3134 | continue; | ||
3135 | if (iwl_check_stuck_queue(priv, cnt)) | ||
3136 | return; | ||
3137 | } | ||
3138 | } | ||
3139 | /* | ||
3140 | * Reschedule the timer to occur in | ||
3141 | * priv->cfg->monitor_recover_period | ||
3142 | */ | ||
3143 | mod_timer(&priv->monitor_recover, | ||
3144 | jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period)); | ||
3145 | } | ||
3146 | EXPORT_SYMBOL(iwl_bg_monitor_recover); | ||
3051 | 3147 | ||
3052 | #ifdef CONFIG_PM | 3148 | #ifdef CONFIG_PM |
3053 | 3149 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index aced12f1611e..b3e698b576e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -191,6 +191,14 @@ struct iwl_lib_ops { | |||
191 | struct iwl_temp_ops temp_ops; | 191 | struct iwl_temp_ops temp_ops; |
192 | /* station management */ | 192 | /* station management */ |
193 | void (*add_bcast_station)(struct iwl_priv *priv); | 193 | void (*add_bcast_station)(struct iwl_priv *priv); |
194 | /* recover from tx queue stall */ | ||
195 | void (*recover_from_tx_stall)(unsigned long data); | ||
196 | /* check for plcp health */ | ||
197 | bool (*check_plcp_health)(struct iwl_priv *priv, | ||
198 | struct iwl_rx_packet *pkt); | ||
199 | /* check for ack health */ | ||
200 | bool (*check_ack_health)(struct iwl_priv *priv, | ||
201 | struct iwl_rx_packet *pkt); | ||
194 | }; | 202 | }; |
195 | 203 | ||
196 | struct iwl_led_ops { | 204 | struct iwl_led_ops { |
@@ -295,6 +303,8 @@ struct iwl_cfg { | |||
295 | const bool support_wimax_coexist; | 303 | const bool support_wimax_coexist; |
296 | u8 plcp_delta_threshold; | 304 | u8 plcp_delta_threshold; |
297 | s32 chain_noise_scale; | 305 | s32 chain_noise_scale; |
306 | /* timer period for monitor the driver queues */ | ||
307 | u32 monitor_recover_period; | ||
298 | }; | 308 | }; |
299 | 309 | ||
300 | /*************************** | 310 | /*************************** |
@@ -430,6 +440,10 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | |||
430 | struct iwl_rx_mem_buffer *rxb); | 440 | struct iwl_rx_mem_buffer *rxb); |
431 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | 441 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, |
432 | struct iwl_rx_mem_buffer *rxb); | 442 | struct iwl_rx_mem_buffer *rxb); |
443 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
444 | struct iwl_rx_packet *pkt); | ||
445 | bool iwl_good_ack_health(struct iwl_priv *priv, | ||
446 | struct iwl_rx_packet *pkt); | ||
433 | void iwl_rx_statistics(struct iwl_priv *priv, | 447 | void iwl_rx_statistics(struct iwl_priv *priv, |
434 | struct iwl_rx_mem_buffer *rxb); | 448 | struct iwl_rx_mem_buffer *rxb); |
435 | void iwl_reply_statistics(struct iwl_priv *priv, | 449 | void iwl_reply_statistics(struct iwl_priv *priv, |
@@ -568,6 +582,9 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) | |||
568 | pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); | 582 | pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl); |
569 | return pci_lnk_ctl; | 583 | return pci_lnk_ctl; |
570 | } | 584 | } |
585 | |||
586 | void iwl_bg_monitor_recover(unsigned long data); | ||
587 | |||
571 | #ifdef CONFIG_PM | 588 | #ifdef CONFIG_PM |
572 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); | 589 | int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); |
573 | int iwl_pci_resume(struct pci_dev *pdev); | 590 | int iwl_pci_resume(struct pci_dev *pdev); |
@@ -667,7 +684,7 @@ extern int iwl_send_statistics_request(struct iwl_priv *priv, | |||
667 | u8 flags, bool clear); | 684 | u8 flags, bool clear); |
668 | extern int iwl_verify_ucode(struct iwl_priv *priv); | 685 | extern int iwl_verify_ucode(struct iwl_priv *priv); |
669 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, | 686 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, |
670 | struct iwl_link_quality_cmd *lq, u8 flags); | 687 | struct iwl_link_quality_cmd *lq, u8 flags, bool init); |
671 | extern void iwl_rx_reply_rx(struct iwl_priv *priv, | 688 | extern void iwl_rx_reply_rx(struct iwl_priv *priv, |
672 | struct iwl_rx_mem_buffer *rxb); | 689 | struct iwl_rx_mem_buffer *rxb); |
673 | extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | 690 | extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 2e4d47c7139b..e847e6197a3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -183,6 +183,10 @@ struct iwl_queue { | |||
183 | int n_bd; /* number of BDs in this queue */ | 183 | int n_bd; /* number of BDs in this queue */ |
184 | int write_ptr; /* 1-st empty entry (index) host_w*/ | 184 | int write_ptr; /* 1-st empty entry (index) host_w*/ |
185 | int read_ptr; /* last used entry (index) host_r*/ | 185 | int read_ptr; /* last used entry (index) host_r*/ |
186 | /* use for monitoring and recovering the stuck queue */ | ||
187 | int last_read_ptr; /* storing the last read_ptr */ | ||
188 | /* number of time read_ptr and last_read_ptr are the same */ | ||
189 | u8 repeat_same_read_ptr; | ||
186 | dma_addr_t dma_addr; /* physical addr for BD's */ | 190 | dma_addr_t dma_addr; /* physical addr for BD's */ |
187 | int n_window; /* safe queue window */ | 191 | int n_window; /* safe queue window */ |
188 | u32 id; | 192 | u32 id; |
@@ -544,11 +548,18 @@ struct iwl_qos_info { | |||
544 | struct iwl_qosparam_cmd def_qos_parm; | 548 | struct iwl_qosparam_cmd def_qos_parm; |
545 | }; | 549 | }; |
546 | 550 | ||
551 | /* | ||
552 | * Structure should be accessed with sta_lock held. When station addition | ||
553 | * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only | ||
554 | * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock | ||
555 | * held. | ||
556 | */ | ||
547 | struct iwl_station_entry { | 557 | struct iwl_station_entry { |
548 | struct iwl_addsta_cmd sta; | 558 | struct iwl_addsta_cmd sta; |
549 | struct iwl_tid_data tid[MAX_TID_COUNT]; | 559 | struct iwl_tid_data tid[MAX_TID_COUNT]; |
550 | u8 used; | 560 | u8 used; |
551 | struct iwl_hw_key keyinfo; | 561 | struct iwl_hw_key keyinfo; |
562 | struct iwl_link_quality_cmd *lq; | ||
552 | }; | 563 | }; |
553 | 564 | ||
554 | /* | 565 | /* |
@@ -1037,6 +1048,11 @@ struct iwl_event_log { | |||
1037 | #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) | 1048 | #define IWL_DELAY_NEXT_FORCE_RF_RESET (HZ*3) |
1038 | #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) | 1049 | #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5) |
1039 | 1050 | ||
1051 | /* timer constants use to monitor and recover stuck tx queues in mSecs */ | ||
1052 | #define IWL_MONITORING_PERIOD (1000) | ||
1053 | #define IWL_ONE_HUNDRED_MSECS (100) | ||
1054 | #define IWL_SIXTY_SECS (60000) | ||
1055 | |||
1040 | enum iwl_reset { | 1056 | enum iwl_reset { |
1041 | IWL_RF_RESET = 0, | 1057 | IWL_RF_RESET = 0, |
1042 | IWL_FW_RESET, | 1058 | IWL_FW_RESET, |
@@ -1163,7 +1179,6 @@ struct iwl_priv { | |||
1163 | 1179 | ||
1164 | u16 active_rate; | 1180 | u16 active_rate; |
1165 | 1181 | ||
1166 | u8 assoc_station_added; | ||
1167 | u8 start_calib; | 1182 | u8 start_calib; |
1168 | struct iwl_sensitivity_data sensitivity_data; | 1183 | struct iwl_sensitivity_data sensitivity_data; |
1169 | struct iwl_chain_noise_data chain_noise_data; | 1184 | struct iwl_chain_noise_data chain_noise_data; |
@@ -1285,6 +1300,11 @@ struct iwl_priv { | |||
1285 | int ict_index; | 1300 | int ict_index; |
1286 | u32 inta; | 1301 | u32 inta; |
1287 | bool use_ict; | 1302 | bool use_ict; |
1303 | /* | ||
1304 | * reporting the number of tids has AGG on. 0 means | ||
1305 | * no AGGREGATION | ||
1306 | */ | ||
1307 | u8 agg_tids_count; | ||
1288 | } _agn; | 1308 | } _agn; |
1289 | #endif | 1309 | #endif |
1290 | }; | 1310 | }; |
@@ -1348,6 +1368,7 @@ struct iwl_priv { | |||
1348 | struct work_struct run_time_calib_work; | 1368 | struct work_struct run_time_calib_work; |
1349 | struct timer_list statistics_periodic; | 1369 | struct timer_list statistics_periodic; |
1350 | struct timer_list ucode_trace; | 1370 | struct timer_list ucode_trace; |
1371 | struct timer_list monitor_recover; | ||
1351 | bool hw_ready; | 1372 | bool hw_ready; |
1352 | 1373 | ||
1353 | struct iwl_event_log event_log; | 1374 | struct iwl_event_log event_log; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 8116aa0d7678..2fa30dfb7c59 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -616,29 +616,77 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, | |||
616 | 616 | ||
617 | #define REG_RECALIB_PERIOD (60) | 617 | #define REG_RECALIB_PERIOD (60) |
618 | 618 | ||
619 | #define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n" | 619 | /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ |
620 | void iwl_rx_statistics(struct iwl_priv *priv, | 620 | #define ACK_CNT_RATIO (50) |
621 | struct iwl_rx_mem_buffer *rxb) | 621 | #define BA_TIMEOUT_CNT (5) |
622 | #define BA_TIMEOUT_MAX (16) | ||
623 | |||
624 | #if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE) | ||
625 | /** | ||
626 | * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries. | ||
627 | * | ||
628 | * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding | ||
629 | * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal | ||
630 | * operation state. | ||
631 | */ | ||
632 | bool iwl_good_ack_health(struct iwl_priv *priv, | ||
633 | struct iwl_rx_packet *pkt) | ||
622 | { | 634 | { |
623 | int change; | 635 | bool rc = true; |
624 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 636 | int actual_ack_cnt_delta, expected_ack_cnt_delta; |
637 | int ba_timeout_delta; | ||
638 | |||
639 | actual_ack_cnt_delta = | ||
640 | le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) - | ||
641 | le32_to_cpu(priv->statistics.tx.actual_ack_cnt); | ||
642 | expected_ack_cnt_delta = | ||
643 | le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) - | ||
644 | le32_to_cpu(priv->statistics.tx.expected_ack_cnt); | ||
645 | ba_timeout_delta = | ||
646 | le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) - | ||
647 | le32_to_cpu(priv->statistics.tx.agg.ba_timeout); | ||
648 | if ((priv->_agn.agg_tids_count > 0) && | ||
649 | (expected_ack_cnt_delta > 0) && | ||
650 | (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta) | ||
651 | < ACK_CNT_RATIO) && | ||
652 | (ba_timeout_delta > BA_TIMEOUT_CNT)) { | ||
653 | IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d," | ||
654 | " expected_ack_cnt = %d\n", | ||
655 | actual_ack_cnt_delta, expected_ack_cnt_delta); | ||
656 | |||
657 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
658 | IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n", | ||
659 | priv->delta_statistics.tx.rx_detected_cnt); | ||
660 | IWL_DEBUG_RADIO(priv, | ||
661 | "ack_or_ba_timeout_collision delta = %d\n", | ||
662 | priv->delta_statistics.tx. | ||
663 | ack_or_ba_timeout_collision); | ||
664 | #endif | ||
665 | IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n", | ||
666 | ba_timeout_delta); | ||
667 | if (!actual_ack_cnt_delta && | ||
668 | (ba_timeout_delta >= BA_TIMEOUT_MAX)) | ||
669 | rc = false; | ||
670 | } | ||
671 | return rc; | ||
672 | } | ||
673 | EXPORT_SYMBOL(iwl_good_ack_health); | ||
674 | #endif | ||
675 | |||
676 | /** | ||
677 | * iwl_good_plcp_health - checks for plcp error. | ||
678 | * | ||
679 | * When the plcp error is exceeding the thresholds, reset the radio | ||
680 | * to improve the throughput. | ||
681 | */ | ||
682 | bool iwl_good_plcp_health(struct iwl_priv *priv, | ||
683 | struct iwl_rx_packet *pkt) | ||
684 | { | ||
685 | bool rc = true; | ||
625 | int combined_plcp_delta; | 686 | int combined_plcp_delta; |
626 | unsigned int plcp_msec; | 687 | unsigned int plcp_msec; |
627 | unsigned long plcp_received_jiffies; | 688 | unsigned long plcp_received_jiffies; |
628 | 689 | ||
629 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", | ||
630 | (int)sizeof(priv->statistics), | ||
631 | le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); | ||
632 | |||
633 | change = ((priv->statistics.general.temperature != | ||
634 | pkt->u.stats.general.temperature) || | ||
635 | ((priv->statistics.flag & | ||
636 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | ||
637 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | ||
638 | |||
639 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
640 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
641 | #endif | ||
642 | /* | 690 | /* |
643 | * check for plcp_err and trigger radio reset if it exceeds | 691 | * check for plcp_err and trigger radio reset if it exceeds |
644 | * the plcp error threshold plcp_delta. | 692 | * the plcp error threshold plcp_delta. |
@@ -659,11 +707,11 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
659 | le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); | 707 | le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err)); |
660 | 708 | ||
661 | if ((combined_plcp_delta > 0) && | 709 | if ((combined_plcp_delta > 0) && |
662 | ((combined_plcp_delta * 100) / plcp_msec) > | 710 | ((combined_plcp_delta * 100) / plcp_msec) > |
663 | priv->cfg->plcp_delta_threshold) { | 711 | priv->cfg->plcp_delta_threshold) { |
664 | /* | 712 | /* |
665 | * if plcp_err exceed the threshold, the following | 713 | * if plcp_err exceed the threshold, |
666 | * data is printed in csv format: | 714 | * the following data is printed in csv format: |
667 | * Text: plcp_err exceeded %d, | 715 | * Text: plcp_err exceeded %d, |
668 | * Received ofdm.plcp_err, | 716 | * Received ofdm.plcp_err, |
669 | * Current ofdm.plcp_err, | 717 | * Current ofdm.plcp_err, |
@@ -672,22 +720,73 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
672 | * combined_plcp_delta, | 720 | * combined_plcp_delta, |
673 | * plcp_msec | 721 | * plcp_msec |
674 | */ | 722 | */ |
675 | IWL_DEBUG_RADIO(priv, PLCP_MSG, | 723 | IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " |
724 | "%u, %u, %u, %u, %d, %u mSecs\n", | ||
676 | priv->cfg->plcp_delta_threshold, | 725 | priv->cfg->plcp_delta_threshold, |
677 | le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), | 726 | le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err), |
678 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), | 727 | le32_to_cpu(priv->statistics.rx.ofdm.plcp_err), |
679 | le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), | 728 | le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err), |
680 | le32_to_cpu( | 729 | le32_to_cpu( |
681 | priv->statistics.rx.ofdm_ht.plcp_err), | 730 | priv->statistics.rx.ofdm_ht.plcp_err), |
682 | combined_plcp_delta, plcp_msec); | 731 | combined_plcp_delta, plcp_msec); |
732 | rc = false; | ||
733 | } | ||
734 | } | ||
735 | return rc; | ||
736 | } | ||
737 | EXPORT_SYMBOL(iwl_good_plcp_health); | ||
683 | 738 | ||
684 | /* | 739 | static void iwl_recover_from_statistics(struct iwl_priv *priv, |
685 | * Reset the RF radio due to the high plcp | 740 | struct iwl_rx_packet *pkt) |
686 | * error rate | 741 | { |
687 | */ | 742 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
688 | iwl_force_reset(priv, IWL_RF_RESET); | 743 | return; |
744 | if (iwl_is_associated(priv)) { | ||
745 | if (priv->cfg->ops->lib->check_ack_health) { | ||
746 | if (!priv->cfg->ops->lib->check_ack_health( | ||
747 | priv, pkt)) { | ||
748 | /* | ||
749 | * low ack count detected | ||
750 | * restart Firmware | ||
751 | */ | ||
752 | IWL_ERR(priv, "low ack count detected, " | ||
753 | "restart firmware\n"); | ||
754 | iwl_force_reset(priv, IWL_FW_RESET); | ||
755 | } | ||
756 | } else if (priv->cfg->ops->lib->check_plcp_health) { | ||
757 | if (!priv->cfg->ops->lib->check_plcp_health( | ||
758 | priv, pkt)) { | ||
759 | /* | ||
760 | * high plcp error detected | ||
761 | * reset Radio | ||
762 | */ | ||
763 | iwl_force_reset(priv, IWL_RF_RESET); | ||
764 | } | ||
689 | } | 765 | } |
690 | } | 766 | } |
767 | } | ||
768 | |||
769 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
770 | struct iwl_rx_mem_buffer *rxb) | ||
771 | { | ||
772 | int change; | ||
773 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
774 | |||
775 | |||
776 | IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n", | ||
777 | (int)sizeof(priv->statistics), | ||
778 | le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK); | ||
779 | |||
780 | change = ((priv->statistics.general.temperature != | ||
781 | pkt->u.stats.general.temperature) || | ||
782 | ((priv->statistics.flag & | ||
783 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | ||
784 | (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | ||
785 | |||
786 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
787 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
788 | #endif | ||
789 | iwl_recover_from_statistics(priv, pkt); | ||
691 | 790 | ||
692 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); | 791 | memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics)); |
693 | 792 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index b1aad306efa9..d401b6f226f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -29,14 +29,12 @@ | |||
29 | 29 | ||
30 | #include <net/mac80211.h> | 30 | #include <net/mac80211.h> |
31 | #include <linux/etherdevice.h> | 31 | #include <linux/etherdevice.h> |
32 | #include <linux/sched.h> | ||
32 | 33 | ||
33 | #include "iwl-dev.h" | 34 | #include "iwl-dev.h" |
34 | #include "iwl-core.h" | 35 | #include "iwl-core.h" |
35 | #include "iwl-sta.h" | 36 | #include "iwl-sta.h" |
36 | 37 | ||
37 | #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ | ||
38 | #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ | ||
39 | |||
40 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | 38 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) |
41 | { | 39 | { |
42 | int i; | 40 | int i; |
@@ -64,6 +62,19 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | |||
64 | addr, priv->num_stations); | 62 | addr, priv->num_stations); |
65 | 63 | ||
66 | out: | 64 | out: |
65 | /* | ||
66 | * It may be possible that more commands interacting with stations | ||
67 | * arrive before we completed processing the adding of | ||
68 | * station | ||
69 | */ | ||
70 | if (ret != IWL_INVALID_STATION && | ||
71 | (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) || | ||
72 | ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) && | ||
73 | (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) { | ||
74 | IWL_ERR(priv, "Requested station info for sta %d before ready. \n", | ||
75 | ret); | ||
76 | ret = IWL_INVALID_STATION; | ||
77 | } | ||
67 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 78 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
68 | return ret; | 79 | return ret; |
69 | } | 80 | } |
@@ -158,13 +169,6 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
158 | priv->stations[sta_id].sta.mode == | 169 | priv->stations[sta_id].sta.mode == |
159 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 170 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
160 | addsta->sta.addr); | 171 | addsta->sta.addr); |
161 | |||
162 | /* | ||
163 | * Determine if we wanted to modify or add a station, | ||
164 | * if adding a station succeeded we have some more initialization | ||
165 | * to do when using station notification. TODO | ||
166 | */ | ||
167 | |||
168 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 172 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
169 | } | 173 | } |
170 | 174 | ||
@@ -190,6 +194,10 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
190 | .flags = flags, | 194 | .flags = flags, |
191 | .data = data, | 195 | .data = data, |
192 | }; | 196 | }; |
197 | u8 sta_id = sta->sta.sta_id; | ||
198 | |||
199 | IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", | ||
200 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); | ||
193 | 201 | ||
194 | if (flags & CMD_ASYNC) | 202 | if (flags & CMD_ASYNC) |
195 | cmd.callback = iwl_add_sta_callback; | 203 | cmd.callback = iwl_add_sta_callback; |
@@ -263,18 +271,19 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | |||
263 | } | 271 | } |
264 | 272 | ||
265 | /** | 273 | /** |
266 | * iwl_add_station - Add station to tables in driver and device | 274 | * iwl_prep_station - Prepare station information for addition |
275 | * | ||
276 | * should be called with sta_lock held | ||
267 | */ | 277 | */ |
268 | u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | 278 | static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr, |
269 | struct ieee80211_sta_ht_cap *ht_info) | 279 | bool is_ap, |
280 | struct ieee80211_sta_ht_cap *ht_info) | ||
270 | { | 281 | { |
271 | struct iwl_station_entry *station; | 282 | struct iwl_station_entry *station; |
272 | unsigned long flags_spin; | ||
273 | int i; | 283 | int i; |
274 | int sta_id = IWL_INVALID_STATION; | 284 | u8 sta_id = IWL_INVALID_STATION; |
275 | u16 rate; | 285 | u16 rate; |
276 | 286 | ||
277 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
278 | if (is_ap) | 287 | if (is_ap) |
279 | sta_id = IWL_AP_ID; | 288 | sta_id = IWL_AP_ID; |
280 | else if (is_broadcast_ether_addr(addr)) | 289 | else if (is_broadcast_ether_addr(addr)) |
@@ -292,20 +301,32 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | |||
292 | sta_id = i; | 301 | sta_id = i; |
293 | } | 302 | } |
294 | 303 | ||
295 | /* These two conditions have the same outcome, but keep them separate | 304 | /* |
296 | since they have different meanings */ | 305 | * These two conditions have the same outcome, but keep them |
297 | if (unlikely(sta_id == IWL_INVALID_STATION)) { | 306 | * separate |
298 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 307 | */ |
308 | if (unlikely(sta_id == IWL_INVALID_STATION)) | ||
309 | return sta_id; | ||
310 | |||
311 | /* | ||
312 | * uCode is not able to deal with multiple requests to add a | ||
313 | * station. Keep track if one is in progress so that we do not send | ||
314 | * another. | ||
315 | */ | ||
316 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
317 | IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", | ||
318 | sta_id); | ||
299 | return sta_id; | 319 | return sta_id; |
300 | } | 320 | } |
301 | 321 | ||
302 | if (priv->stations[sta_id].used && | 322 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && |
323 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && | ||
303 | !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { | 324 | !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { |
304 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 325 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", |
326 | sta_id, addr); | ||
305 | return sta_id; | 327 | return sta_id; |
306 | } | 328 | } |
307 | 329 | ||
308 | |||
309 | station = &priv->stations[sta_id]; | 330 | station = &priv->stations[sta_id]; |
310 | station->used = IWL_STA_DRIVER_ACTIVE; | 331 | station->used = IWL_STA_DRIVER_ACTIVE; |
311 | IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", | 332 | IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", |
@@ -330,86 +351,185 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | |||
330 | /* Turn on both antennas for the station... */ | 351 | /* Turn on both antennas for the station... */ |
331 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); | 352 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); |
332 | 353 | ||
354 | return sta_id; | ||
355 | |||
356 | } | ||
357 | |||
358 | #define STA_WAIT_TIMEOUT (HZ/2) | ||
359 | |||
360 | /** | ||
361 | * iwl_add_station_common - | ||
362 | */ | ||
363 | int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr, | ||
364 | bool is_ap, | ||
365 | struct ieee80211_sta_ht_cap *ht_info, | ||
366 | u8 *sta_id_r) | ||
367 | { | ||
368 | struct iwl_station_entry *station; | ||
369 | unsigned long flags_spin; | ||
370 | int ret = 0; | ||
371 | u8 sta_id; | ||
372 | |||
373 | *sta_id_r = 0; | ||
374 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
375 | sta_id = iwl_prep_station(priv, addr, is_ap, ht_info); | ||
376 | if (sta_id == IWL_INVALID_STATION) { | ||
377 | IWL_ERR(priv, "Unable to prepare station %pM for addition\n", | ||
378 | addr); | ||
379 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * uCode is not able to deal with multiple requests to add a | ||
385 | * station. Keep track if one is in progress so that we do not send | ||
386 | * another. | ||
387 | */ | ||
388 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
389 | IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", | ||
390 | sta_id); | ||
391 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
392 | return -EEXIST; | ||
393 | } | ||
394 | |||
395 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && | ||
396 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | ||
397 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", | ||
398 | sta_id, addr); | ||
399 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
400 | return -EEXIST; | ||
401 | } | ||
402 | |||
403 | priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; | ||
404 | station = &priv->stations[sta_id]; | ||
333 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 405 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
334 | 406 | ||
335 | /* Add station to device's station table */ | 407 | /* Add station to device's station table */ |
336 | iwl_send_add_sta(priv, &station->sta, flags); | 408 | ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC); |
337 | return sta_id; | 409 | if (ret) { |
338 | 410 | IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr); | |
411 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
412 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
413 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
414 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
415 | } | ||
416 | *sta_id_r = sta_id; | ||
417 | return ret; | ||
339 | } | 418 | } |
340 | EXPORT_SYMBOL(iwl_add_station); | 419 | EXPORT_SYMBOL(iwl_add_station_common); |
341 | 420 | ||
342 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const u8 *addr) | 421 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) |
343 | { | 422 | { |
344 | unsigned long flags; | 423 | int i, r; |
345 | u8 sta_id = iwl_find_station(priv, addr); | 424 | struct iwl_link_quality_cmd link_cmd = { |
425 | .reserved1 = 0, | ||
426 | }; | ||
427 | u32 rate_flags; | ||
346 | 428 | ||
347 | BUG_ON(sta_id == IWL_INVALID_STATION); | 429 | /* Set up the rate scaling to start at selected rate, fall back |
430 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
431 | if (is_ap) | ||
432 | r = IWL_RATE_54M_INDEX; | ||
433 | else if (priv->band == IEEE80211_BAND_5GHZ) | ||
434 | r = IWL_RATE_6M_INDEX; | ||
435 | else | ||
436 | r = IWL_RATE_1M_INDEX; | ||
437 | |||
438 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
439 | rate_flags = 0; | ||
440 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
441 | rate_flags |= RATE_MCS_CCK_MSK; | ||
348 | 442 | ||
349 | IWL_DEBUG_ASSOC(priv, "Removed STA from Ucode: %pM\n", addr); | 443 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << |
444 | RATE_MCS_ANT_POS; | ||
350 | 445 | ||
351 | spin_lock_irqsave(&priv->sta_lock, flags); | 446 | link_cmd.rs_table[i].rate_n_flags = |
447 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
448 | r = iwl_get_prev_ieee_rate(r); | ||
449 | } | ||
352 | 450 | ||
353 | /* Ucode must be active and driver must be non active */ | 451 | link_cmd.general_params.single_stream_ant_msk = |
354 | if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) | 452 | first_antenna(priv->hw_params.valid_tx_ant); |
355 | IWL_ERR(priv, "removed non active STA %d\n", sta_id); | 453 | link_cmd.general_params.dual_stream_ant_msk = 3; |
454 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
455 | link_cmd.agg_params.agg_time_limit = | ||
456 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
356 | 457 | ||
357 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | 458 | /* Update the rate scaling for control frame Tx to AP */ |
459 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | ||
358 | 460 | ||
359 | memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); | 461 | iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, |
360 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 462 | sizeof(link_cmd), &link_cmd); |
361 | } | 463 | } |
362 | 464 | ||
363 | static void iwl_remove_sta_callback(struct iwl_priv *priv, | 465 | /* |
364 | struct iwl_device_cmd *cmd, | 466 | * iwl_add_local_stations - Add stations not requested by mac80211 |
365 | struct iwl_rx_packet *pkt) | 467 | * |
468 | * This will be either the broadcast station or the bssid station needed by | ||
469 | * ad-hoc. | ||
470 | * | ||
471 | * Function sleeps. | ||
472 | */ | ||
473 | int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs) | ||
366 | { | 474 | { |
367 | struct iwl_rem_sta_cmd *rm_sta = | 475 | int ret; |
368 | (struct iwl_rem_sta_cmd *)cmd->cmd.payload; | 476 | u8 sta_id; |
369 | const u8 *addr = rm_sta->addr; | ||
370 | 477 | ||
371 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | 478 | ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id); |
372 | IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", | 479 | if (ret) { |
373 | pkt->hdr.flags); | 480 | IWL_ERR(priv, "Unable to add station %pM\n", addr); |
374 | return; | 481 | return ret; |
375 | } | 482 | } |
376 | 483 | ||
377 | switch (pkt->u.rem_sta.status) { | 484 | if (init_rs) |
378 | case REM_STA_SUCCESS_MSK: | 485 | /* Set up default rate scaling table in device's station table */ |
379 | iwl_sta_ucode_deactivate(priv, addr); | 486 | iwl_sta_init_lq(priv, addr, false); |
380 | break; | 487 | return 0; |
381 | default: | 488 | } |
382 | IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); | 489 | EXPORT_SYMBOL(iwl_add_local_station); |
383 | break; | 490 | |
384 | } | 491 | /** |
492 | * iwl_sta_ucode_deactivate - deactivate ucode status for a station | ||
493 | * | ||
494 | * priv->sta_lock must be held | ||
495 | */ | ||
496 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) | ||
497 | { | ||
498 | /* Ucode must be active and driver must be non active */ | ||
499 | if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) | ||
500 | IWL_ERR(priv, "removed non active STA %u\n", sta_id); | ||
501 | |||
502 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | ||
503 | |||
504 | memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); | ||
505 | IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id); | ||
385 | } | 506 | } |
386 | 507 | ||
387 | static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | 508 | static int iwl_send_remove_station(struct iwl_priv *priv, |
388 | u8 flags) | 509 | struct iwl_station_entry *station) |
389 | { | 510 | { |
390 | struct iwl_rx_packet *pkt; | 511 | struct iwl_rx_packet *pkt; |
391 | int ret; | 512 | int ret; |
392 | 513 | ||
514 | unsigned long flags_spin; | ||
393 | struct iwl_rem_sta_cmd rm_sta_cmd; | 515 | struct iwl_rem_sta_cmd rm_sta_cmd; |
394 | 516 | ||
395 | struct iwl_host_cmd cmd = { | 517 | struct iwl_host_cmd cmd = { |
396 | .id = REPLY_REMOVE_STA, | 518 | .id = REPLY_REMOVE_STA, |
397 | .len = sizeof(struct iwl_rem_sta_cmd), | 519 | .len = sizeof(struct iwl_rem_sta_cmd), |
398 | .flags = flags, | 520 | .flags = CMD_SYNC, |
399 | .data = &rm_sta_cmd, | 521 | .data = &rm_sta_cmd, |
400 | }; | 522 | }; |
401 | 523 | ||
402 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); | 524 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); |
403 | rm_sta_cmd.num_sta = 1; | 525 | rm_sta_cmd.num_sta = 1; |
404 | memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); | 526 | memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN); |
527 | |||
528 | cmd.flags |= CMD_WANT_SKB; | ||
405 | 529 | ||
406 | if (flags & CMD_ASYNC) | ||
407 | cmd.callback = iwl_remove_sta_callback; | ||
408 | else | ||
409 | cmd.flags |= CMD_WANT_SKB; | ||
410 | ret = iwl_send_cmd(priv, &cmd); | 530 | ret = iwl_send_cmd(priv, &cmd); |
411 | 531 | ||
412 | if (ret || (flags & CMD_ASYNC)) | 532 | if (ret) |
413 | return ret; | 533 | return ret; |
414 | 534 | ||
415 | pkt = (struct iwl_rx_packet *)cmd.reply_page; | 535 | pkt = (struct iwl_rx_packet *)cmd.reply_page; |
@@ -422,7 +542,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | |||
422 | if (!ret) { | 542 | if (!ret) { |
423 | switch (pkt->u.rem_sta.status) { | 543 | switch (pkt->u.rem_sta.status) { |
424 | case REM_STA_SUCCESS_MSK: | 544 | case REM_STA_SUCCESS_MSK: |
425 | iwl_sta_ucode_deactivate(priv, addr); | 545 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
546 | iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id); | ||
547 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
426 | IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); | 548 | IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); |
427 | break; | 549 | break; |
428 | default: | 550 | default: |
@@ -439,23 +561,35 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | |||
439 | /** | 561 | /** |
440 | * iwl_remove_station - Remove driver's knowledge of station. | 562 | * iwl_remove_station - Remove driver's knowledge of station. |
441 | */ | 563 | */ |
442 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | 564 | static int iwl_remove_station(struct iwl_priv *priv, struct ieee80211_sta *sta) |
443 | { | 565 | { |
444 | int sta_id = IWL_INVALID_STATION; | 566 | int sta_id = IWL_INVALID_STATION; |
445 | int i, ret = -EINVAL; | 567 | int i, ret = -EINVAL; |
446 | unsigned long flags; | 568 | unsigned long flags; |
569 | bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION; | ||
570 | struct iwl_station_entry *station; | ||
571 | |||
572 | if (!iwl_is_ready(priv)) { | ||
573 | IWL_DEBUG_INFO(priv, | ||
574 | "Unable to remove station %pM, device not ready. \n", | ||
575 | sta->addr); | ||
576 | /* | ||
577 | * It is typical for stations to be removed when we are | ||
578 | * going down. Return success since device will be down | ||
579 | * soon anyway | ||
580 | */ | ||
581 | return 0; | ||
582 | } | ||
447 | 583 | ||
448 | spin_lock_irqsave(&priv->sta_lock, flags); | 584 | spin_lock_irqsave(&priv->sta_lock, flags); |
449 | 585 | ||
450 | if (is_ap) | 586 | if (is_ap) |
451 | sta_id = IWL_AP_ID; | 587 | sta_id = IWL_AP_ID; |
452 | else if (is_broadcast_ether_addr(addr)) | ||
453 | sta_id = priv->hw_params.bcast_sta_id; | ||
454 | else | 588 | else |
455 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) | 589 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) |
456 | if (priv->stations[i].used && | 590 | if (priv->stations[i].used && |
457 | !compare_ether_addr(priv->stations[i].sta.sta.addr, | 591 | !compare_ether_addr(priv->stations[i].sta.sta.addr, |
458 | addr)) { | 592 | sta->addr)) { |
459 | sta_id = i; | 593 | sta_id = i; |
460 | break; | 594 | break; |
461 | } | 595 | } |
@@ -464,17 +598,17 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | |||
464 | goto out; | 598 | goto out; |
465 | 599 | ||
466 | IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", | 600 | IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", |
467 | sta_id, addr); | 601 | sta_id, sta->addr); |
468 | 602 | ||
469 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { | 603 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { |
470 | IWL_ERR(priv, "Removing %pM but non DRIVER active\n", | 604 | IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", |
471 | addr); | 605 | sta->addr); |
472 | goto out; | 606 | goto out; |
473 | } | 607 | } |
474 | 608 | ||
475 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | 609 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { |
476 | IWL_ERR(priv, "Removing %pM but non UCODE active\n", | 610 | IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", |
477 | addr); | 611 | sta->addr); |
478 | goto out; | 612 | goto out; |
479 | } | 613 | } |
480 | 614 | ||
@@ -485,9 +619,10 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | |||
485 | 619 | ||
486 | BUG_ON(priv->num_stations < 0); | 620 | BUG_ON(priv->num_stations < 0); |
487 | 621 | ||
622 | station = &priv->stations[sta_id]; | ||
488 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 623 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
489 | 624 | ||
490 | ret = iwl_send_remove_station(priv, addr, CMD_ASYNC); | 625 | ret = iwl_send_remove_station(priv, station); |
491 | return ret; | 626 | return ret; |
492 | out: | 627 | out: |
493 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 628 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
@@ -495,37 +630,122 @@ out: | |||
495 | } | 630 | } |
496 | 631 | ||
497 | /** | 632 | /** |
498 | * iwl_clear_stations_table - Clear the driver's station table | 633 | * iwl_clear_ucode_stations() - clear entire station table driver and/or ucode |
499 | * | 634 | * @priv: |
500 | * NOTE: This does not clear or otherwise alter the device's station table. | 635 | * @force: If set then the uCode station table needs to be cleared here. If |
636 | * not set then the uCode station table has already been cleared, | ||
637 | * for example after sending it a RXON command without ASSOC bit | ||
638 | * set, and we just need to change driver state here. | ||
501 | */ | 639 | */ |
502 | void iwl_clear_stations_table(struct iwl_priv *priv) | 640 | void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force) |
503 | { | 641 | { |
504 | unsigned long flags; | ||
505 | int i; | 642 | int i; |
643 | unsigned long flags_spin; | ||
644 | bool cleared = false; | ||
645 | |||
646 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver%s\n", | ||
647 | force ? " and ucode" : ""); | ||
648 | |||
649 | if (force) { | ||
650 | if (!iwl_is_ready(priv)) { | ||
651 | /* | ||
652 | * If device is not ready at this point the station | ||
653 | * table is likely already empty (uCode not ready | ||
654 | * to receive station requests) or will soon be | ||
655 | * due to interface going down. | ||
656 | */ | ||
657 | IWL_DEBUG_INFO(priv, "Unable to remove stations from device - device not ready\n"); | ||
658 | } else { | ||
659 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL); | ||
660 | } | ||
661 | } | ||
506 | 662 | ||
507 | spin_lock_irqsave(&priv->sta_lock, flags); | 663 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
664 | if (force) { | ||
665 | IWL_DEBUG_INFO(priv, "Clearing all station information in driver\n"); | ||
666 | priv->num_stations = 0; | ||
667 | memset(priv->stations, 0, sizeof(priv->stations)); | ||
668 | } else { | ||
669 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
670 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { | ||
671 | IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d \n", i); | ||
672 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
673 | cleared = true; | ||
674 | } | ||
675 | } | ||
676 | } | ||
677 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
508 | 678 | ||
509 | if (iwl_is_alive(priv) && | 679 | if (!cleared) |
510 | !test_bit(STATUS_EXIT_PENDING, &priv->status) && | 680 | IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); |
511 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) | 681 | } |
512 | IWL_ERR(priv, "Couldn't clear the station table\n"); | 682 | EXPORT_SYMBOL(iwl_clear_ucode_stations); |
513 | 683 | ||
514 | priv->num_stations = 0; | 684 | /** |
515 | memset(priv->stations, 0, sizeof(priv->stations)); | 685 | * iwl_restore_stations() - Restore driver known stations to device |
686 | * | ||
687 | * All stations considered active by driver, but not present in ucode, is | ||
688 | * restored. | ||
689 | * | ||
690 | * Function sleeps. | ||
691 | */ | ||
692 | void iwl_restore_stations(struct iwl_priv *priv) | ||
693 | { | ||
694 | struct iwl_station_entry *station; | ||
695 | unsigned long flags_spin; | ||
696 | int i; | ||
697 | bool found = false; | ||
698 | int ret; | ||
516 | 699 | ||
517 | /* clean ucode key table bit map */ | 700 | if (!iwl_is_ready(priv)) { |
518 | priv->ucode_key_table = 0; | 701 | IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n"); |
702 | return; | ||
703 | } | ||
519 | 704 | ||
520 | /* keep track of static keys */ | 705 | IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); |
521 | for (i = 0; i < WEP_KEYS_MAX ; i++) { | 706 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
522 | if (priv->wep_keys[i].key_size) | 707 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
523 | set_bit(i, &priv->ucode_key_table); | 708 | if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && |
709 | !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { | ||
710 | IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", | ||
711 | priv->stations[i].sta.sta.addr); | ||
712 | priv->stations[i].sta.mode = 0; | ||
713 | priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; | ||
714 | found = true; | ||
715 | } | ||
524 | } | 716 | } |
525 | 717 | ||
526 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 718 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
719 | if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { | ||
720 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
721 | station = &priv->stations[i]; | ||
722 | ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC); | ||
723 | if (ret) { | ||
724 | IWL_ERR(priv, "Adding station %pM failed.\n", | ||
725 | station->sta.sta.addr); | ||
726 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
727 | priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
728 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
729 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
730 | } | ||
731 | /* | ||
732 | * Rate scaling has already been initialized, send | ||
733 | * current LQ command | ||
734 | */ | ||
735 | if (station->lq) | ||
736 | iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true); | ||
737 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
738 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
743 | if (!found) | ||
744 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n"); | ||
745 | else | ||
746 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... complete.\n"); | ||
527 | } | 747 | } |
528 | EXPORT_SYMBOL(iwl_clear_stations_table); | 748 | EXPORT_SYMBOL(iwl_restore_stations); |
529 | 749 | ||
530 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 750 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) |
531 | { | 751 | { |
@@ -948,9 +1168,22 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv, | |||
948 | } | 1168 | } |
949 | #endif | 1169 | #endif |
950 | 1170 | ||
1171 | /** | ||
1172 | * iwl_send_lq_cmd() - Send link quality command | ||
1173 | * @init: This command is sent as part of station initialization right | ||
1174 | * after station has been added. | ||
1175 | * | ||
1176 | * The link quality command is sent as the last step of station creation. | ||
1177 | * This is the special case in which init is set and we call a callback in | ||
1178 | * this case to clear the state indicating that station creation is in | ||
1179 | * progress. | ||
1180 | */ | ||
951 | int iwl_send_lq_cmd(struct iwl_priv *priv, | 1181 | int iwl_send_lq_cmd(struct iwl_priv *priv, |
952 | struct iwl_link_quality_cmd *lq, u8 flags) | 1182 | struct iwl_link_quality_cmd *lq, u8 flags, bool init) |
953 | { | 1183 | { |
1184 | int ret = 0; | ||
1185 | unsigned long flags_spin; | ||
1186 | |||
954 | struct iwl_host_cmd cmd = { | 1187 | struct iwl_host_cmd cmd = { |
955 | .id = REPLY_TX_LINK_QUALITY_CMD, | 1188 | .id = REPLY_TX_LINK_QUALITY_CMD, |
956 | .len = sizeof(struct iwl_link_quality_cmd), | 1189 | .len = sizeof(struct iwl_link_quality_cmd), |
@@ -966,167 +1199,31 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
966 | lq->sta_id = IWL_AP_ID; | 1199 | lq->sta_id = IWL_AP_ID; |
967 | 1200 | ||
968 | iwl_dump_lq_cmd(priv, lq); | 1201 | iwl_dump_lq_cmd(priv, lq); |
1202 | BUG_ON(init && (cmd.flags & CMD_ASYNC)); | ||
969 | 1203 | ||
970 | if (iwl_is_associated(priv) && priv->assoc_station_added) | 1204 | iwl_dump_lq_cmd(priv, lq); |
971 | return iwl_send_cmd(priv, &cmd); | 1205 | ret = iwl_send_cmd(priv, &cmd); |
1206 | if (ret || (cmd.flags & CMD_ASYNC)) | ||
1207 | return ret; | ||
972 | 1208 | ||
1209 | if (init) { | ||
1210 | IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d \n", | ||
1211 | lq->sta_id); | ||
1212 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
1213 | priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
1214 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
1215 | } | ||
973 | return 0; | 1216 | return 0; |
974 | } | 1217 | } |
975 | EXPORT_SYMBOL(iwl_send_lq_cmd); | 1218 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
976 | 1219 | ||
977 | /** | 1220 | /** |
978 | * iwl_sta_init_lq - Initialize a station's hardware rate table | ||
979 | * | ||
980 | * The uCode's station table contains a table of fallback rates | ||
981 | * for automatic fallback during transmission. | ||
982 | * | ||
983 | * NOTE: This sets up a default set of values. These will be replaced later | ||
984 | * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of | ||
985 | * rc80211_simple. | ||
986 | * | ||
987 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
988 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
989 | * which requires station table entry to exist). | ||
990 | */ | ||
991 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) | ||
992 | { | ||
993 | int i, r; | ||
994 | struct iwl_link_quality_cmd link_cmd = { | ||
995 | .reserved1 = 0, | ||
996 | }; | ||
997 | u32 rate_flags; | ||
998 | |||
999 | /* Set up the rate scaling to start at selected rate, fall back | ||
1000 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
1001 | if (is_ap) | ||
1002 | r = IWL_RATE_54M_INDEX; | ||
1003 | else if (priv->band == IEEE80211_BAND_5GHZ) | ||
1004 | r = IWL_RATE_6M_INDEX; | ||
1005 | else | ||
1006 | r = IWL_RATE_1M_INDEX; | ||
1007 | |||
1008 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
1009 | rate_flags = 0; | ||
1010 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
1011 | rate_flags |= RATE_MCS_CCK_MSK; | ||
1012 | |||
1013 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | ||
1014 | RATE_MCS_ANT_POS; | ||
1015 | |||
1016 | link_cmd.rs_table[i].rate_n_flags = | ||
1017 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
1018 | r = iwl_get_prev_ieee_rate(r); | ||
1019 | } | ||
1020 | |||
1021 | link_cmd.general_params.single_stream_ant_msk = | ||
1022 | first_antenna(priv->hw_params.valid_tx_ant); | ||
1023 | link_cmd.general_params.dual_stream_ant_msk = 3; | ||
1024 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
1025 | link_cmd.agg_params.agg_time_limit = | ||
1026 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
1027 | |||
1028 | /* Update the rate scaling for control frame Tx to AP */ | ||
1029 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | ||
1030 | |||
1031 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
1032 | sizeof(link_cmd), &link_cmd, NULL); | ||
1033 | } | ||
1034 | |||
1035 | /** | ||
1036 | * iwl_rxon_add_station - add station into station table. | ||
1037 | * | ||
1038 | * there is only one AP station with id= IWL_AP_ID | ||
1039 | * NOTE: mutex must be held before calling this function | ||
1040 | */ | ||
1041 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | ||
1042 | { | ||
1043 | struct ieee80211_sta *sta; | ||
1044 | struct ieee80211_sta_ht_cap ht_config; | ||
1045 | struct ieee80211_sta_ht_cap *cur_ht_config = NULL; | ||
1046 | u8 sta_id; | ||
1047 | |||
1048 | /* | ||
1049 | * Set HT capabilities. It is ok to set this struct even if not using | ||
1050 | * HT config: the priv->current_ht_config.is_ht flag will just be false | ||
1051 | */ | ||
1052 | rcu_read_lock(); | ||
1053 | sta = ieee80211_find_sta(priv->vif, addr); | ||
1054 | if (sta) { | ||
1055 | memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); | ||
1056 | cur_ht_config = &ht_config; | ||
1057 | } | ||
1058 | rcu_read_unlock(); | ||
1059 | |||
1060 | /* Add station to device's station table */ | ||
1061 | sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); | ||
1062 | |||
1063 | /* Set up default rate scaling table in device's station table */ | ||
1064 | iwl_sta_init_lq(priv, addr, is_ap); | ||
1065 | |||
1066 | return sta_id; | ||
1067 | } | ||
1068 | EXPORT_SYMBOL(iwl_rxon_add_station); | ||
1069 | |||
1070 | /** | ||
1071 | * iwl_sta_init_bcast_lq - Initialize a bcast station's hardware rate table | ||
1072 | * | ||
1073 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
1074 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
1075 | * which requires station table entry to exist). | ||
1076 | */ | ||
1077 | static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) | ||
1078 | { | ||
1079 | int i, r; | ||
1080 | struct iwl_link_quality_cmd link_cmd = { | ||
1081 | .reserved1 = 0, | ||
1082 | }; | ||
1083 | u32 rate_flags; | ||
1084 | |||
1085 | /* Set up the rate scaling to start at selected rate, fall back | ||
1086 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
1087 | if (priv->band == IEEE80211_BAND_5GHZ) | ||
1088 | r = IWL_RATE_6M_INDEX; | ||
1089 | else | ||
1090 | r = IWL_RATE_1M_INDEX; | ||
1091 | |||
1092 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
1093 | rate_flags = 0; | ||
1094 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
1095 | rate_flags |= RATE_MCS_CCK_MSK; | ||
1096 | |||
1097 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | ||
1098 | RATE_MCS_ANT_POS; | ||
1099 | |||
1100 | link_cmd.rs_table[i].rate_n_flags = | ||
1101 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
1102 | r = iwl_get_prev_ieee_rate(r); | ||
1103 | } | ||
1104 | |||
1105 | link_cmd.general_params.single_stream_ant_msk = | ||
1106 | first_antenna(priv->hw_params.valid_tx_ant); | ||
1107 | link_cmd.general_params.dual_stream_ant_msk = 3; | ||
1108 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
1109 | link_cmd.agg_params.agg_time_limit = | ||
1110 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
1111 | |||
1112 | /* Update the rate scaling for control frame Tx to AP */ | ||
1113 | link_cmd.sta_id = priv->hw_params.bcast_sta_id; | ||
1114 | |||
1115 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
1116 | sizeof(link_cmd), &link_cmd, NULL); | ||
1117 | } | ||
1118 | |||
1119 | |||
1120 | /** | ||
1121 | * iwl_add_bcast_station - add broadcast station into station table. | 1221 | * iwl_add_bcast_station - add broadcast station into station table. |
1122 | */ | 1222 | */ |
1123 | void iwl_add_bcast_station(struct iwl_priv *priv) | 1223 | void iwl_add_bcast_station(struct iwl_priv *priv) |
1124 | { | 1224 | { |
1125 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1225 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); |
1126 | iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); | 1226 | iwl_add_local_station(priv, iwl_bcast_addr, true); |
1127 | |||
1128 | /* Set up default rate scaling table in device's station table */ | ||
1129 | iwl_sta_init_bcast_lq(priv); | ||
1130 | } | 1227 | } |
1131 | EXPORT_SYMBOL(iwl_add_bcast_station); | 1228 | EXPORT_SYMBOL(iwl_add_bcast_station); |
1132 | 1229 | ||
@@ -1136,7 +1233,14 @@ EXPORT_SYMBOL(iwl_add_bcast_station); | |||
1136 | void iwl3945_add_bcast_station(struct iwl_priv *priv) | 1233 | void iwl3945_add_bcast_station(struct iwl_priv *priv) |
1137 | { | 1234 | { |
1138 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1235 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); |
1139 | iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); | 1236 | iwl_add_local_station(priv, iwl_bcast_addr, false); |
1237 | /* | ||
1238 | * It is assumed that when station is added more initialization | ||
1239 | * needs to be done, but for 3945 it is not the case and we can | ||
1240 | * just release station table access right here. | ||
1241 | */ | ||
1242 | priv->stations[priv->hw_params.bcast_sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
1243 | |||
1140 | } | 1244 | } |
1141 | EXPORT_SYMBOL(iwl3945_add_bcast_station); | 1245 | EXPORT_SYMBOL(iwl3945_add_bcast_station); |
1142 | 1246 | ||
@@ -1159,6 +1263,13 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
1159 | /* If we are a client station in a BSS network, use the special | 1263 | /* If we are a client station in a BSS network, use the special |
1160 | * AP station entry (that's the only station we communicate with) */ | 1264 | * AP station entry (that's the only station we communicate with) */ |
1161 | case NL80211_IFTYPE_STATION: | 1265 | case NL80211_IFTYPE_STATION: |
1266 | /* | ||
1267 | * If addition of station not complete yet, which means | ||
1268 | * that rate scaling has not been initialized, then return | ||
1269 | * the broadcast station. | ||
1270 | */ | ||
1271 | if (!(priv->stations[IWL_AP_ID].used & IWL_STA_UCODE_ACTIVE)) | ||
1272 | return priv->hw_params.bcast_sta_id; | ||
1162 | return IWL_AP_ID; | 1273 | return IWL_AP_ID; |
1163 | 1274 | ||
1164 | /* If we are an AP, then find the station, or use BCAST */ | 1275 | /* If we are an AP, then find the station, or use BCAST */ |
@@ -1175,13 +1286,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | |||
1175 | if (sta_id != IWL_INVALID_STATION) | 1286 | if (sta_id != IWL_INVALID_STATION) |
1176 | return sta_id; | 1287 | return sta_id; |
1177 | 1288 | ||
1178 | /* Create new station table entry */ | ||
1179 | sta_id = iwl_add_station(priv, hdr->addr1, false, | ||
1180 | CMD_ASYNC, NULL); | ||
1181 | |||
1182 | if (sta_id != IWL_INVALID_STATION) | ||
1183 | return sta_id; | ||
1184 | |||
1185 | IWL_DEBUG_DROP(priv, "Station %pM not in station map. " | 1289 | IWL_DEBUG_DROP(priv, "Station %pM not in station map. " |
1186 | "Defaulting to broadcast...\n", | 1290 | "Defaulting to broadcast...\n", |
1187 | hdr->addr1); | 1291 | hdr->addr1); |
@@ -1291,3 +1395,19 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) | |||
1291 | 1395 | ||
1292 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 1396 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); |
1293 | } | 1397 | } |
1398 | |||
1399 | int iwl_mac_sta_remove(struct ieee80211_hw *hw, | ||
1400 | struct ieee80211_vif *vif, | ||
1401 | struct ieee80211_sta *sta) | ||
1402 | { | ||
1403 | int ret; | ||
1404 | struct iwl_priv *priv = hw->priv; | ||
1405 | IWL_DEBUG_INFO(priv, "received request to remove station %pM\n", | ||
1406 | sta->addr); | ||
1407 | ret = iwl_remove_station(priv, sta); | ||
1408 | if (ret) | ||
1409 | IWL_ERR(priv, "Error removing station %pM\n", | ||
1410 | sta->addr); | ||
1411 | return ret; | ||
1412 | } | ||
1413 | EXPORT_SYMBOL(iwl_mac_sta_remove); | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 2dc35fe28f56..87a34997a758 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h | |||
@@ -32,6 +32,12 @@ | |||
32 | #define HW_KEY_DYNAMIC 0 | 32 | #define HW_KEY_DYNAMIC 0 |
33 | #define HW_KEY_DEFAULT 1 | 33 | #define HW_KEY_DEFAULT 1 |
34 | 34 | ||
35 | #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ | ||
36 | #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ | ||
37 | #define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of | ||
38 | being activated */ | ||
39 | |||
40 | |||
35 | /** | 41 | /** |
36 | * iwl_find_station - Find station id for a given BSSID | 42 | * iwl_find_station - Find station id for a given BSSID |
37 | * @bssid: MAC address of station ID to find | 43 | * @bssid: MAC address of station ID to find |
@@ -51,18 +57,22 @@ void iwl_update_tkip_key(struct iwl_priv *priv, | |||
51 | struct ieee80211_key_conf *keyconf, | 57 | struct ieee80211_key_conf *keyconf, |
52 | const u8 *addr, u32 iv32, u16 *phase1key); | 58 | const u8 *addr, u32 iv32, u16 *phase1key); |
53 | 59 | ||
54 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); | ||
55 | void iwl_add_bcast_station(struct iwl_priv *priv); | 60 | void iwl_add_bcast_station(struct iwl_priv *priv); |
56 | void iwl3945_add_bcast_station(struct iwl_priv *priv); | 61 | void iwl3945_add_bcast_station(struct iwl_priv *priv); |
57 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap); | 62 | void iwl_restore_stations(struct iwl_priv *priv); |
58 | void iwl_clear_stations_table(struct iwl_priv *priv); | 63 | void iwl_clear_ucode_stations(struct iwl_priv *priv, bool force); |
59 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); | 64 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv); |
60 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); | 65 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); |
61 | int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); | 66 | int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); |
62 | int iwl_send_add_sta(struct iwl_priv *priv, | 67 | int iwl_send_add_sta(struct iwl_priv *priv, |
63 | struct iwl_addsta_cmd *sta, u8 flags); | 68 | struct iwl_addsta_cmd *sta, u8 flags); |
64 | u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | 69 | int iwl_add_local_station(struct iwl_priv *priv, const u8 *addr, bool init_rs); |
65 | struct ieee80211_sta_ht_cap *ht_info); | 70 | int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr, |
71 | bool is_ap, | ||
72 | struct ieee80211_sta_ht_cap *ht_info, | ||
73 | u8 *sta_id_r); | ||
74 | int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
75 | struct ieee80211_sta *sta); | ||
66 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); | 76 | void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); |
67 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, | 77 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, |
68 | const u8 *addr, int tid, u16 ssn); | 78 | const u8 *addr, int tid, u16 ssn); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d6222aabe6ed..1e481f3fcabf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -322,6 +322,8 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | |||
322 | q->high_mark = 2; | 322 | q->high_mark = 2; |
323 | 323 | ||
324 | q->write_ptr = q->read_ptr = 0; | 324 | q->write_ptr = q->read_ptr = 0; |
325 | q->last_read_ptr = 0; | ||
326 | q->repeat_same_read_ptr = 0; | ||
325 | 327 | ||
326 | return 0; | 328 | return 0; |
327 | } | 329 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 2579bbcaab36..4995134d7e4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -2480,8 +2480,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv) | |||
2480 | goto restart; | 2480 | goto restart; |
2481 | } | 2481 | } |
2482 | 2482 | ||
2483 | iwl_clear_stations_table(priv); | ||
2484 | |||
2485 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); | 2483 | rfkill = iwl_read_prph(priv, APMG_RFKILL_REG); |
2486 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); | 2484 | IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill); |
2487 | 2485 | ||
@@ -2503,6 +2501,13 @@ static void iwl3945_alive_start(struct iwl_priv *priv) | |||
2503 | /* After the ALIVE response, we can send commands to 3945 uCode */ | 2501 | /* After the ALIVE response, we can send commands to 3945 uCode */ |
2504 | set_bit(STATUS_ALIVE, &priv->status); | 2502 | set_bit(STATUS_ALIVE, &priv->status); |
2505 | 2503 | ||
2504 | if (priv->cfg->ops->lib->recover_from_tx_stall) { | ||
2505 | /* Enable timer to monitor the driver queues */ | ||
2506 | mod_timer(&priv->monitor_recover, | ||
2507 | jiffies + | ||
2508 | msecs_to_jiffies(priv->cfg->monitor_recover_period)); | ||
2509 | } | ||
2510 | |||
2506 | if (iwl_is_rfkill(priv)) | 2511 | if (iwl_is_rfkill(priv)) |
2507 | return; | 2512 | return; |
2508 | 2513 | ||
@@ -2558,7 +2563,8 @@ static void __iwl3945_down(struct iwl_priv *priv) | |||
2558 | if (!exit_pending) | 2563 | if (!exit_pending) |
2559 | set_bit(STATUS_EXIT_PENDING, &priv->status); | 2564 | set_bit(STATUS_EXIT_PENDING, &priv->status); |
2560 | 2565 | ||
2561 | iwl_clear_stations_table(priv); | 2566 | /* Station information will now be cleared in device */ |
2567 | iwl_clear_ucode_stations(priv, true); | ||
2562 | 2568 | ||
2563 | /* Unblock any waiting calls */ | 2569 | /* Unblock any waiting calls */ |
2564 | wake_up_interruptible_all(&priv->wait_command_queue); | 2570 | wake_up_interruptible_all(&priv->wait_command_queue); |
@@ -2692,8 +2698,6 @@ static int __iwl3945_up(struct iwl_priv *priv) | |||
2692 | 2698 | ||
2693 | for (i = 0; i < MAX_HW_RESTARTS; i++) { | 2699 | for (i = 0; i < MAX_HW_RESTARTS; i++) { |
2694 | 2700 | ||
2695 | iwl_clear_stations_table(priv); | ||
2696 | |||
2697 | /* load bootstrap state machine, | 2701 | /* load bootstrap state machine, |
2698 | * load bootstrap program into processor's memory, | 2702 | * load bootstrap program into processor's memory, |
2699 | * prepare to load the "initialize" uCode */ | 2703 | * prepare to load the "initialize" uCode */ |
@@ -3119,12 +3123,13 @@ void iwl3945_post_associate(struct iwl_priv *priv) | |||
3119 | case NL80211_IFTYPE_ADHOC: | 3123 | case NL80211_IFTYPE_ADHOC: |
3120 | 3124 | ||
3121 | priv->assoc_id = 1; | 3125 | priv->assoc_id = 1; |
3122 | iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL); | 3126 | iwl_add_local_station(priv, priv->bssid, false); |
3123 | iwl3945_sync_sta(priv, IWL_STA_ID, | 3127 | iwl3945_sync_sta(priv, IWL_STA_ID, |
3124 | (priv->band == IEEE80211_BAND_5GHZ) ? | 3128 | (priv->band == IEEE80211_BAND_5GHZ) ? |
3125 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, | 3129 | IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, |
3126 | CMD_ASYNC); | 3130 | CMD_ASYNC); |
3127 | iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); | 3131 | iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); |
3132 | |||
3128 | iwl3945_send_beacon_cmd(priv); | 3133 | iwl3945_send_beacon_cmd(priv); |
3129 | 3134 | ||
3130 | break; | 3135 | break; |
@@ -3309,7 +3314,7 @@ void iwl3945_config_ap(struct iwl_priv *priv) | |||
3309 | /* restore RXON assoc */ | 3314 | /* restore RXON assoc */ |
3310 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; | 3315 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; |
3311 | iwlcore_commit_rxon(priv); | 3316 | iwlcore_commit_rxon(priv); |
3312 | iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL); | 3317 | iwl_add_local_station(priv, iwl_bcast_addr, false); |
3313 | } | 3318 | } |
3314 | iwl3945_send_beacon_cmd(priv); | 3319 | iwl3945_send_beacon_cmd(priv); |
3315 | 3320 | ||
@@ -3376,6 +3381,38 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |||
3376 | return ret; | 3381 | return ret; |
3377 | } | 3382 | } |
3378 | 3383 | ||
3384 | static int iwl3945_mac_sta_add(struct ieee80211_hw *hw, | ||
3385 | struct ieee80211_vif *vif, | ||
3386 | struct ieee80211_sta *sta) | ||
3387 | { | ||
3388 | struct iwl_priv *priv = hw->priv; | ||
3389 | int ret; | ||
3390 | bool is_ap = priv->iw_mode == NL80211_IFTYPE_STATION; | ||
3391 | u8 sta_id; | ||
3392 | |||
3393 | IWL_DEBUG_INFO(priv, "received request to add station %pM\n", | ||
3394 | sta->addr); | ||
3395 | |||
3396 | ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap, | ||
3397 | &sta_id); | ||
3398 | if (ret) { | ||
3399 | IWL_ERR(priv, "Unable to add station %pM (%d)\n", | ||
3400 | sta->addr, ret); | ||
3401 | /* Should we return success if return code is EEXIST ? */ | ||
3402 | return ret; | ||
3403 | } | ||
3404 | |||
3405 | /* Initialize rate scaling */ | ||
3406 | IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM \n", | ||
3407 | sta->addr); | ||
3408 | iwl3945_rs_rate_init(priv, sta, sta_id); | ||
3409 | |||
3410 | return 0; | ||
3411 | |||
3412 | |||
3413 | |||
3414 | return ret; | ||
3415 | } | ||
3379 | /***************************************************************************** | 3416 | /***************************************************************************** |
3380 | * | 3417 | * |
3381 | * sysfs attributes | 3418 | * sysfs attributes |
@@ -3766,6 +3803,13 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv) | |||
3766 | 3803 | ||
3767 | iwl3945_hw_setup_deferred_work(priv); | 3804 | iwl3945_hw_setup_deferred_work(priv); |
3768 | 3805 | ||
3806 | if (priv->cfg->ops->lib->recover_from_tx_stall) { | ||
3807 | init_timer(&priv->monitor_recover); | ||
3808 | priv->monitor_recover.data = (unsigned long)priv; | ||
3809 | priv->monitor_recover.function = | ||
3810 | priv->cfg->ops->lib->recover_from_tx_stall; | ||
3811 | } | ||
3812 | |||
3769 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 3813 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
3770 | iwl3945_irq_tasklet, (unsigned long)priv); | 3814 | iwl3945_irq_tasklet, (unsigned long)priv); |
3771 | } | 3815 | } |
@@ -3778,6 +3822,8 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv) | |||
3778 | cancel_delayed_work(&priv->scan_check); | 3822 | cancel_delayed_work(&priv->scan_check); |
3779 | cancel_delayed_work(&priv->alive_start); | 3823 | cancel_delayed_work(&priv->alive_start); |
3780 | cancel_work_sync(&priv->beacon_update); | 3824 | cancel_work_sync(&priv->beacon_update); |
3825 | if (priv->cfg->ops->lib->recover_from_tx_stall) | ||
3826 | del_timer_sync(&priv->monitor_recover); | ||
3781 | } | 3827 | } |
3782 | 3828 | ||
3783 | static struct attribute *iwl3945_sysfs_entries[] = { | 3829 | static struct attribute *iwl3945_sysfs_entries[] = { |
@@ -3815,7 +3861,9 @@ static struct ieee80211_ops iwl3945_hw_ops = { | |||
3815 | .conf_tx = iwl_mac_conf_tx, | 3861 | .conf_tx = iwl_mac_conf_tx, |
3816 | .reset_tsf = iwl_mac_reset_tsf, | 3862 | .reset_tsf = iwl_mac_reset_tsf, |
3817 | .bss_info_changed = iwl_bss_info_changed, | 3863 | .bss_info_changed = iwl_bss_info_changed, |
3818 | .hw_scan = iwl_mac_hw_scan | 3864 | .hw_scan = iwl_mac_hw_scan, |
3865 | .sta_add = iwl3945_mac_sta_add, | ||
3866 | .sta_remove = iwl_mac_sta_remove, | ||
3819 | }; | 3867 | }; |
3820 | 3868 | ||
3821 | static int iwl3945_init_drv(struct iwl_priv *priv) | 3869 | static int iwl3945_init_drv(struct iwl_priv *priv) |
@@ -3834,9 +3882,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) | |||
3834 | mutex_init(&priv->mutex); | 3882 | mutex_init(&priv->mutex); |
3835 | mutex_init(&priv->sync_cmd_mutex); | 3883 | mutex_init(&priv->sync_cmd_mutex); |
3836 | 3884 | ||
3837 | /* Clear the driver's (not device's) station table */ | ||
3838 | iwl_clear_stations_table(priv); | ||
3839 | |||
3840 | priv->ieee_channels = NULL; | 3885 | priv->ieee_channels = NULL; |
3841 | priv->ieee_rates = NULL; | 3886 | priv->ieee_rates = NULL; |
3842 | priv->band = IEEE80211_BAND_2GHZ; | 3887 | priv->band = IEEE80211_BAND_2GHZ; |
@@ -4196,7 +4241,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) | |||
4196 | iwl3945_hw_txq_ctx_free(priv); | 4241 | iwl3945_hw_txq_ctx_free(priv); |
4197 | 4242 | ||
4198 | iwl3945_unset_hw_params(priv); | 4243 | iwl3945_unset_hw_params(priv); |
4199 | iwl_clear_stations_table(priv); | ||
4200 | 4244 | ||
4201 | /*netif_stop_queue(dev); */ | 4245 | /*netif_stop_queue(dev); */ |
4202 | flush_workqueue(priv->workqueue); | 4246 | flush_workqueue(priv->workqueue); |
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index f03d5e4e59c3..95d3d4c5e08b 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c | |||
@@ -31,6 +31,9 @@ u8 lbs_bg_rates[MAX_RATES] = | |||
31 | 0x00, 0x00 }; | 31 | 0x00, 0x00 }; |
32 | 32 | ||
33 | 33 | ||
34 | static int assoc_helper_wep_keys(struct lbs_private *priv, | ||
35 | struct assoc_request *assoc_req); | ||
36 | |||
34 | /** | 37 | /** |
35 | * @brief This function finds common rates between rates and card rates. | 38 | * @brief This function finds common rates between rates and card rates. |
36 | * | 39 | * |
@@ -610,7 +613,7 @@ static int lbs_assoc_post(struct lbs_private *priv, | |||
610 | 613 | ||
611 | if (status_code) { | 614 | if (status_code) { |
612 | lbs_mac_event_disconnected(priv); | 615 | lbs_mac_event_disconnected(priv); |
613 | ret = -1; | 616 | ret = status_code; |
614 | goto done; | 617 | goto done; |
615 | } | 618 | } |
616 | 619 | ||
@@ -813,7 +816,24 @@ static int lbs_try_associate(struct lbs_private *priv, | |||
813 | goto out; | 816 | goto out; |
814 | 817 | ||
815 | ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); | 818 | ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE); |
819 | /* If the association fails with current auth mode, let's | ||
820 | * try by changing the auth mode | ||
821 | */ | ||
822 | if ((priv->authtype_auto) && | ||
823 | (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) && | ||
824 | (assoc_req->secinfo.wep_enabled) && | ||
825 | (priv->connect_status != LBS_CONNECTED)) { | ||
826 | if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM) | ||
827 | priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | ||
828 | else | ||
829 | priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | ||
830 | if (!assoc_helper_wep_keys(priv, assoc_req)) | ||
831 | ret = lbs_associate(priv, assoc_req, | ||
832 | CMD_802_11_ASSOCIATE); | ||
833 | } | ||
816 | 834 | ||
835 | if (ret) | ||
836 | ret = -1; | ||
817 | out: | 837 | out: |
818 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | 838 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); |
819 | return ret; | 839 | return ret; |
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 6977ee820214..058d1720242e 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -133,6 +133,7 @@ struct lbs_private { | |||
133 | u8 wpa_ie_len; | 133 | u8 wpa_ie_len; |
134 | u16 wep_tx_keyidx; | 134 | u16 wep_tx_keyidx; |
135 | struct enc_key wep_keys[4]; | 135 | struct enc_key wep_keys[4]; |
136 | u8 authtype_auto; | ||
136 | 137 | ||
137 | /* Wake On LAN */ | 138 | /* Wake On LAN */ |
138 | uint32_t wol_criteria; | 139 | uint32_t wol_criteria; |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 28a1c9d1627a..3c889f43d909 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -835,6 +835,7 @@ static int lbs_init_adapter(struct lbs_private *priv) | |||
835 | priv->is_auto_deep_sleep_enabled = 0; | 835 | priv->is_auto_deep_sleep_enabled = 0; |
836 | priv->wakeup_dev_required = 0; | 836 | priv->wakeup_dev_required = 0; |
837 | init_waitqueue_head(&priv->ds_awake_q); | 837 | init_waitqueue_head(&priv->ds_awake_q); |
838 | priv->authtype_auto = 1; | ||
838 | 839 | ||
839 | mutex_init(&priv->lock); | 840 | mutex_init(&priv->lock); |
840 | 841 | ||
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 71f88a08e090..aad6263dee6d 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -1440,8 +1440,10 @@ static int lbs_set_encode(struct net_device *dev, | |||
1440 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); | 1440 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); |
1441 | 1441 | ||
1442 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | 1442 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { |
1443 | priv->authtype_auto = 0; | ||
1443 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | 1444 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; |
1444 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | 1445 | } else if (dwrq->flags & IW_ENCODE_OPEN) { |
1446 | priv->authtype_auto = 0; | ||
1445 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | 1447 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; |
1446 | } | 1448 | } |
1447 | 1449 | ||
@@ -1620,8 +1622,10 @@ static int lbs_set_encodeext(struct net_device *dev, | |||
1620 | goto out; | 1622 | goto out; |
1621 | 1623 | ||
1622 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | 1624 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { |
1625 | priv->authtype_auto = 0; | ||
1623 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; | 1626 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; |
1624 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | 1627 | } else if (dwrq->flags & IW_ENCODE_OPEN) { |
1628 | priv->authtype_auto = 0; | ||
1625 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; | 1629 | assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; |
1626 | } | 1630 | } |
1627 | 1631 | ||
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 31ca241f7753..29f9bc03190a 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c | |||
@@ -1505,46 +1505,44 @@ static const struct iw_priv_args orinoco_privtab[] = { | |||
1505 | * Structures to export the Wireless Handlers | 1505 | * Structures to export the Wireless Handlers |
1506 | */ | 1506 | */ |
1507 | 1507 | ||
1508 | #define STD_IW_HANDLER(id, func) \ | ||
1509 | [IW_IOCTL_IDX(id)] = (iw_handler) func | ||
1510 | static const iw_handler orinoco_handler[] = { | 1508 | static const iw_handler orinoco_handler[] = { |
1511 | STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit), | 1509 | IW_HANDLER(SIOCSIWCOMMIT, (iw_handler)orinoco_ioctl_commit), |
1512 | STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), | 1510 | IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname), |
1513 | STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq), | 1511 | IW_HANDLER(SIOCSIWFREQ, (iw_handler)orinoco_ioctl_setfreq), |
1514 | STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq), | 1512 | IW_HANDLER(SIOCGIWFREQ, (iw_handler)orinoco_ioctl_getfreq), |
1515 | STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode), | 1513 | IW_HANDLER(SIOCSIWMODE, (iw_handler)cfg80211_wext_siwmode), |
1516 | STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode), | 1514 | IW_HANDLER(SIOCGIWMODE, (iw_handler)cfg80211_wext_giwmode), |
1517 | STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens), | 1515 | IW_HANDLER(SIOCSIWSENS, (iw_handler)orinoco_ioctl_setsens), |
1518 | STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens), | 1516 | IW_HANDLER(SIOCGIWSENS, (iw_handler)orinoco_ioctl_getsens), |
1519 | STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange), | 1517 | IW_HANDLER(SIOCGIWRANGE, (iw_handler)cfg80211_wext_giwrange), |
1520 | STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), | 1518 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), |
1521 | STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), | 1519 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), |
1522 | STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), | 1520 | IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), |
1523 | STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), | 1521 | IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), |
1524 | STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), | 1522 | IW_HANDLER(SIOCSIWAP, (iw_handler)orinoco_ioctl_setwap), |
1525 | STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), | 1523 | IW_HANDLER(SIOCGIWAP, (iw_handler)orinoco_ioctl_getwap), |
1526 | STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), | 1524 | IW_HANDLER(SIOCSIWSCAN, (iw_handler)cfg80211_wext_siwscan), |
1527 | STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), | 1525 | IW_HANDLER(SIOCGIWSCAN, (iw_handler)cfg80211_wext_giwscan), |
1528 | STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), | 1526 | IW_HANDLER(SIOCSIWESSID, (iw_handler)orinoco_ioctl_setessid), |
1529 | STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), | 1527 | IW_HANDLER(SIOCGIWESSID, (iw_handler)orinoco_ioctl_getessid), |
1530 | STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate), | 1528 | IW_HANDLER(SIOCSIWRATE, (iw_handler)orinoco_ioctl_setrate), |
1531 | STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate), | 1529 | IW_HANDLER(SIOCGIWRATE, (iw_handler)orinoco_ioctl_getrate), |
1532 | STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts), | 1530 | IW_HANDLER(SIOCSIWRTS, (iw_handler)orinoco_ioctl_setrts), |
1533 | STD_IW_HANDLER(SIOCGIWRTS, orinoco_ioctl_getrts), | 1531 | IW_HANDLER(SIOCGIWRTS, (iw_handler)orinoco_ioctl_getrts), |
1534 | STD_IW_HANDLER(SIOCSIWFRAG, orinoco_ioctl_setfrag), | 1532 | IW_HANDLER(SIOCSIWFRAG, (iw_handler)orinoco_ioctl_setfrag), |
1535 | STD_IW_HANDLER(SIOCGIWFRAG, orinoco_ioctl_getfrag), | 1533 | IW_HANDLER(SIOCGIWFRAG, (iw_handler)orinoco_ioctl_getfrag), |
1536 | STD_IW_HANDLER(SIOCGIWRETRY, orinoco_ioctl_getretry), | 1534 | IW_HANDLER(SIOCGIWRETRY, (iw_handler)orinoco_ioctl_getretry), |
1537 | STD_IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode), | 1535 | IW_HANDLER(SIOCSIWENCODE, (iw_handler)orinoco_ioctl_setiwencode), |
1538 | STD_IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode), | 1536 | IW_HANDLER(SIOCGIWENCODE, (iw_handler)orinoco_ioctl_getiwencode), |
1539 | STD_IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower), | 1537 | IW_HANDLER(SIOCSIWPOWER, (iw_handler)orinoco_ioctl_setpower), |
1540 | STD_IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower), | 1538 | IW_HANDLER(SIOCGIWPOWER, (iw_handler)orinoco_ioctl_getpower), |
1541 | STD_IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), | 1539 | IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), |
1542 | STD_IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), | 1540 | IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), |
1543 | STD_IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), | 1541 | IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), |
1544 | STD_IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), | 1542 | IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), |
1545 | STD_IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), | 1543 | IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), |
1546 | STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), | 1544 | IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), |
1547 | STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), | 1545 | IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), |
1548 | }; | 1546 | }; |
1549 | 1547 | ||
1550 | 1548 | ||
@@ -1552,15 +1550,15 @@ static const iw_handler orinoco_handler[] = { | |||
1552 | Added typecasting since we no longer use iwreq_data -- Moustafa | 1550 | Added typecasting since we no longer use iwreq_data -- Moustafa |
1553 | */ | 1551 | */ |
1554 | static const iw_handler orinoco_private_handler[] = { | 1552 | static const iw_handler orinoco_private_handler[] = { |
1555 | [0] = (iw_handler) orinoco_ioctl_reset, | 1553 | [0] = (iw_handler)orinoco_ioctl_reset, |
1556 | [1] = (iw_handler) orinoco_ioctl_reset, | 1554 | [1] = (iw_handler)orinoco_ioctl_reset, |
1557 | [2] = (iw_handler) orinoco_ioctl_setport3, | 1555 | [2] = (iw_handler)orinoco_ioctl_setport3, |
1558 | [3] = (iw_handler) orinoco_ioctl_getport3, | 1556 | [3] = (iw_handler)orinoco_ioctl_getport3, |
1559 | [4] = (iw_handler) orinoco_ioctl_setpreamble, | 1557 | [4] = (iw_handler)orinoco_ioctl_setpreamble, |
1560 | [5] = (iw_handler) orinoco_ioctl_getpreamble, | 1558 | [5] = (iw_handler)orinoco_ioctl_getpreamble, |
1561 | [6] = (iw_handler) orinoco_ioctl_setibssport, | 1559 | [6] = (iw_handler)orinoco_ioctl_setibssport, |
1562 | [7] = (iw_handler) orinoco_ioctl_getibssport, | 1560 | [7] = (iw_handler)orinoco_ioctl_getibssport, |
1563 | [9] = (iw_handler) orinoco_ioctl_getrid, | 1561 | [9] = (iw_handler)orinoco_ioctl_getrid, |
1564 | }; | 1562 | }; |
1565 | 1563 | ||
1566 | const struct iw_handler_def orinoco_handler_def = { | 1564 | const struct iw_handler_def orinoco_handler_def = { |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 84c530aa52f9..4f5bdb528ef7 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -1113,10 +1113,10 @@ static const struct ethtool_ops netdev_ethtool_ops = { | |||
1113 | /* | 1113 | /* |
1114 | * Wireless Handler : get protocol name | 1114 | * Wireless Handler : get protocol name |
1115 | */ | 1115 | */ |
1116 | static int ray_get_name(struct net_device *dev, | 1116 | static int ray_get_name(struct net_device *dev, struct iw_request_info *info, |
1117 | struct iw_request_info *info, char *cwrq, char *extra) | 1117 | union iwreq_data *wrqu, char *extra) |
1118 | { | 1118 | { |
1119 | strcpy(cwrq, "IEEE 802.11-FH"); | 1119 | strcpy(wrqu->name, "IEEE 802.11-FH"); |
1120 | return 0; | 1120 | return 0; |
1121 | } | 1121 | } |
1122 | 1122 | ||
@@ -1124,9 +1124,8 @@ static int ray_get_name(struct net_device *dev, | |||
1124 | /* | 1124 | /* |
1125 | * Wireless Handler : set frequency | 1125 | * Wireless Handler : set frequency |
1126 | */ | 1126 | */ |
1127 | static int ray_set_freq(struct net_device *dev, | 1127 | static int ray_set_freq(struct net_device *dev, struct iw_request_info *info, |
1128 | struct iw_request_info *info, | 1128 | union iwreq_data *wrqu, char *extra) |
1129 | struct iw_freq *fwrq, char *extra) | ||
1130 | { | 1129 | { |
1131 | ray_dev_t *local = netdev_priv(dev); | 1130 | ray_dev_t *local = netdev_priv(dev); |
1132 | int err = -EINPROGRESS; /* Call commit handler */ | 1131 | int err = -EINPROGRESS; /* Call commit handler */ |
@@ -1136,10 +1135,10 @@ static int ray_set_freq(struct net_device *dev, | |||
1136 | return -EBUSY; | 1135 | return -EBUSY; |
1137 | 1136 | ||
1138 | /* Setting by channel number */ | 1137 | /* Setting by channel number */ |
1139 | if ((fwrq->m > USA_HOP_MOD) || (fwrq->e > 0)) | 1138 | if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0)) |
1140 | err = -EOPNOTSUPP; | 1139 | err = -EOPNOTSUPP; |
1141 | else | 1140 | else |
1142 | local->sparm.b5.a_hop_pattern = fwrq->m; | 1141 | local->sparm.b5.a_hop_pattern = wrqu->freq.m; |
1143 | 1142 | ||
1144 | return err; | 1143 | return err; |
1145 | } | 1144 | } |
@@ -1148,14 +1147,13 @@ static int ray_set_freq(struct net_device *dev, | |||
1148 | /* | 1147 | /* |
1149 | * Wireless Handler : get frequency | 1148 | * Wireless Handler : get frequency |
1150 | */ | 1149 | */ |
1151 | static int ray_get_freq(struct net_device *dev, | 1150 | static int ray_get_freq(struct net_device *dev, struct iw_request_info *info, |
1152 | struct iw_request_info *info, | 1151 | union iwreq_data *wrqu, char *extra) |
1153 | struct iw_freq *fwrq, char *extra) | ||
1154 | { | 1152 | { |
1155 | ray_dev_t *local = netdev_priv(dev); | 1153 | ray_dev_t *local = netdev_priv(dev); |
1156 | 1154 | ||
1157 | fwrq->m = local->sparm.b5.a_hop_pattern; | 1155 | wrqu->freq.m = local->sparm.b5.a_hop_pattern; |
1158 | fwrq->e = 0; | 1156 | wrqu->freq.e = 0; |
1159 | return 0; | 1157 | return 0; |
1160 | } | 1158 | } |
1161 | 1159 | ||
@@ -1163,9 +1161,8 @@ static int ray_get_freq(struct net_device *dev, | |||
1163 | /* | 1161 | /* |
1164 | * Wireless Handler : set ESSID | 1162 | * Wireless Handler : set ESSID |
1165 | */ | 1163 | */ |
1166 | static int ray_set_essid(struct net_device *dev, | 1164 | static int ray_set_essid(struct net_device *dev, struct iw_request_info *info, |
1167 | struct iw_request_info *info, | 1165 | union iwreq_data *wrqu, char *extra) |
1168 | struct iw_point *dwrq, char *extra) | ||
1169 | { | 1166 | { |
1170 | ray_dev_t *local = netdev_priv(dev); | 1167 | ray_dev_t *local = netdev_priv(dev); |
1171 | 1168 | ||
@@ -1174,19 +1171,17 @@ static int ray_set_essid(struct net_device *dev, | |||
1174 | return -EBUSY; | 1171 | return -EBUSY; |
1175 | 1172 | ||
1176 | /* Check if we asked for `any' */ | 1173 | /* Check if we asked for `any' */ |
1177 | if (dwrq->flags == 0) { | 1174 | if (wrqu->essid.flags == 0) |
1178 | /* Corey : can you do that ? */ | 1175 | /* Corey : can you do that ? */ |
1179 | return -EOPNOTSUPP; | 1176 | return -EOPNOTSUPP; |
1180 | } else { | ||
1181 | /* Check the size of the string */ | ||
1182 | if (dwrq->length > IW_ESSID_MAX_SIZE) { | ||
1183 | return -E2BIG; | ||
1184 | } | ||
1185 | 1177 | ||
1186 | /* Set the ESSID in the card */ | 1178 | /* Check the size of the string */ |
1187 | memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE); | 1179 | if (wrqu->essid.length > IW_ESSID_MAX_SIZE) |
1188 | memcpy(local->sparm.b5.a_current_ess_id, extra, dwrq->length); | 1180 | return -E2BIG; |
1189 | } | 1181 | |
1182 | /* Set the ESSID in the card */ | ||
1183 | memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE); | ||
1184 | memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length); | ||
1190 | 1185 | ||
1191 | return -EINPROGRESS; /* Call commit handler */ | 1186 | return -EINPROGRESS; /* Call commit handler */ |
1192 | } | 1187 | } |
@@ -1195,9 +1190,8 @@ static int ray_set_essid(struct net_device *dev, | |||
1195 | /* | 1190 | /* |
1196 | * Wireless Handler : get ESSID | 1191 | * Wireless Handler : get ESSID |
1197 | */ | 1192 | */ |
1198 | static int ray_get_essid(struct net_device *dev, | 1193 | static int ray_get_essid(struct net_device *dev, struct iw_request_info *info, |
1199 | struct iw_request_info *info, | 1194 | union iwreq_data *wrqu, char *extra) |
1200 | struct iw_point *dwrq, char *extra) | ||
1201 | { | 1195 | { |
1202 | ray_dev_t *local = netdev_priv(dev); | 1196 | ray_dev_t *local = netdev_priv(dev); |
1203 | 1197 | ||
@@ -1205,8 +1199,8 @@ static int ray_get_essid(struct net_device *dev, | |||
1205 | memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); | 1199 | memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE); |
1206 | 1200 | ||
1207 | /* Push it out ! */ | 1201 | /* Push it out ! */ |
1208 | dwrq->length = strlen(extra); | 1202 | wrqu->essid.length = strlen(extra); |
1209 | dwrq->flags = 1; /* active */ | 1203 | wrqu->essid.flags = 1; /* active */ |
1210 | 1204 | ||
1211 | return 0; | 1205 | return 0; |
1212 | } | 1206 | } |
@@ -1215,14 +1209,13 @@ static int ray_get_essid(struct net_device *dev, | |||
1215 | /* | 1209 | /* |
1216 | * Wireless Handler : get AP address | 1210 | * Wireless Handler : get AP address |
1217 | */ | 1211 | */ |
1218 | static int ray_get_wap(struct net_device *dev, | 1212 | static int ray_get_wap(struct net_device *dev, struct iw_request_info *info, |
1219 | struct iw_request_info *info, | 1213 | union iwreq_data *wrqu, char *extra) |
1220 | struct sockaddr *awrq, char *extra) | ||
1221 | { | 1214 | { |
1222 | ray_dev_t *local = netdev_priv(dev); | 1215 | ray_dev_t *local = netdev_priv(dev); |
1223 | 1216 | ||
1224 | memcpy(awrq->sa_data, local->bss_id, ETH_ALEN); | 1217 | memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN); |
1225 | awrq->sa_family = ARPHRD_ETHER; | 1218 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; |
1226 | 1219 | ||
1227 | return 0; | 1220 | return 0; |
1228 | } | 1221 | } |
@@ -1231,9 +1224,8 @@ static int ray_get_wap(struct net_device *dev, | |||
1231 | /* | 1224 | /* |
1232 | * Wireless Handler : set Bit-Rate | 1225 | * Wireless Handler : set Bit-Rate |
1233 | */ | 1226 | */ |
1234 | static int ray_set_rate(struct net_device *dev, | 1227 | static int ray_set_rate(struct net_device *dev, struct iw_request_info *info, |
1235 | struct iw_request_info *info, | 1228 | union iwreq_data *wrqu, char *extra) |
1236 | struct iw_param *vwrq, char *extra) | ||
1237 | { | 1229 | { |
1238 | ray_dev_t *local = netdev_priv(dev); | 1230 | ray_dev_t *local = netdev_priv(dev); |
1239 | 1231 | ||
@@ -1242,15 +1234,15 @@ static int ray_set_rate(struct net_device *dev, | |||
1242 | return -EBUSY; | 1234 | return -EBUSY; |
1243 | 1235 | ||
1244 | /* Check if rate is in range */ | 1236 | /* Check if rate is in range */ |
1245 | if ((vwrq->value != 1000000) && (vwrq->value != 2000000)) | 1237 | if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000)) |
1246 | return -EINVAL; | 1238 | return -EINVAL; |
1247 | 1239 | ||
1248 | /* Hack for 1.5 Mb/s instead of 2 Mb/s */ | 1240 | /* Hack for 1.5 Mb/s instead of 2 Mb/s */ |
1249 | if ((local->fw_ver == 0x55) && /* Please check */ | 1241 | if ((local->fw_ver == 0x55) && /* Please check */ |
1250 | (vwrq->value == 2000000)) | 1242 | (wrqu->bitrate.value == 2000000)) |
1251 | local->net_default_tx_rate = 3; | 1243 | local->net_default_tx_rate = 3; |
1252 | else | 1244 | else |
1253 | local->net_default_tx_rate = vwrq->value / 500000; | 1245 | local->net_default_tx_rate = wrqu->bitrate.value / 500000; |
1254 | 1246 | ||
1255 | return 0; | 1247 | return 0; |
1256 | } | 1248 | } |
@@ -1259,17 +1251,16 @@ static int ray_set_rate(struct net_device *dev, | |||
1259 | /* | 1251 | /* |
1260 | * Wireless Handler : get Bit-Rate | 1252 | * Wireless Handler : get Bit-Rate |
1261 | */ | 1253 | */ |
1262 | static int ray_get_rate(struct net_device *dev, | 1254 | static int ray_get_rate(struct net_device *dev, struct iw_request_info *info, |
1263 | struct iw_request_info *info, | 1255 | union iwreq_data *wrqu, char *extra) |
1264 | struct iw_param *vwrq, char *extra) | ||
1265 | { | 1256 | { |
1266 | ray_dev_t *local = netdev_priv(dev); | 1257 | ray_dev_t *local = netdev_priv(dev); |
1267 | 1258 | ||
1268 | if (local->net_default_tx_rate == 3) | 1259 | if (local->net_default_tx_rate == 3) |
1269 | vwrq->value = 2000000; /* Hum... */ | 1260 | wrqu->bitrate.value = 2000000; /* Hum... */ |
1270 | else | 1261 | else |
1271 | vwrq->value = local->net_default_tx_rate * 500000; | 1262 | wrqu->bitrate.value = local->net_default_tx_rate * 500000; |
1272 | vwrq->fixed = 0; /* We are in auto mode */ | 1263 | wrqu->bitrate.fixed = 0; /* We are in auto mode */ |
1273 | 1264 | ||
1274 | return 0; | 1265 | return 0; |
1275 | } | 1266 | } |
@@ -1278,19 +1269,18 @@ static int ray_get_rate(struct net_device *dev, | |||
1278 | /* | 1269 | /* |
1279 | * Wireless Handler : set RTS threshold | 1270 | * Wireless Handler : set RTS threshold |
1280 | */ | 1271 | */ |
1281 | static int ray_set_rts(struct net_device *dev, | 1272 | static int ray_set_rts(struct net_device *dev, struct iw_request_info *info, |
1282 | struct iw_request_info *info, | 1273 | union iwreq_data *wrqu, char *extra) |
1283 | struct iw_param *vwrq, char *extra) | ||
1284 | { | 1274 | { |
1285 | ray_dev_t *local = netdev_priv(dev); | 1275 | ray_dev_t *local = netdev_priv(dev); |
1286 | int rthr = vwrq->value; | 1276 | int rthr = wrqu->rts.value; |
1287 | 1277 | ||
1288 | /* Reject if card is already initialised */ | 1278 | /* Reject if card is already initialised */ |
1289 | if (local->card_status != CARD_AWAITING_PARAM) | 1279 | if (local->card_status != CARD_AWAITING_PARAM) |
1290 | return -EBUSY; | 1280 | return -EBUSY; |
1291 | 1281 | ||
1292 | /* if(wrq->u.rts.fixed == 0) we should complain */ | 1282 | /* if(wrq->u.rts.fixed == 0) we should complain */ |
1293 | if (vwrq->disabled) | 1283 | if (wrqu->rts.disabled) |
1294 | rthr = 32767; | 1284 | rthr = 32767; |
1295 | else { | 1285 | else { |
1296 | if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ | 1286 | if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */ |
@@ -1306,16 +1296,15 @@ static int ray_set_rts(struct net_device *dev, | |||
1306 | /* | 1296 | /* |
1307 | * Wireless Handler : get RTS threshold | 1297 | * Wireless Handler : get RTS threshold |
1308 | */ | 1298 | */ |
1309 | static int ray_get_rts(struct net_device *dev, | 1299 | static int ray_get_rts(struct net_device *dev, struct iw_request_info *info, |
1310 | struct iw_request_info *info, | 1300 | union iwreq_data *wrqu, char *extra) |
1311 | struct iw_param *vwrq, char *extra) | ||
1312 | { | 1301 | { |
1313 | ray_dev_t *local = netdev_priv(dev); | 1302 | ray_dev_t *local = netdev_priv(dev); |
1314 | 1303 | ||
1315 | vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8) | 1304 | wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8) |
1316 | + local->sparm.b5.a_rts_threshold[1]; | 1305 | + local->sparm.b5.a_rts_threshold[1]; |
1317 | vwrq->disabled = (vwrq->value == 32767); | 1306 | wrqu->rts.disabled = (wrqu->rts.value == 32767); |
1318 | vwrq->fixed = 1; | 1307 | wrqu->rts.fixed = 1; |
1319 | 1308 | ||
1320 | return 0; | 1309 | return 0; |
1321 | } | 1310 | } |
@@ -1324,19 +1313,18 @@ static int ray_get_rts(struct net_device *dev, | |||
1324 | /* | 1313 | /* |
1325 | * Wireless Handler : set Fragmentation threshold | 1314 | * Wireless Handler : set Fragmentation threshold |
1326 | */ | 1315 | */ |
1327 | static int ray_set_frag(struct net_device *dev, | 1316 | static int ray_set_frag(struct net_device *dev, struct iw_request_info *info, |
1328 | struct iw_request_info *info, | 1317 | union iwreq_data *wrqu, char *extra) |
1329 | struct iw_param *vwrq, char *extra) | ||
1330 | { | 1318 | { |
1331 | ray_dev_t *local = netdev_priv(dev); | 1319 | ray_dev_t *local = netdev_priv(dev); |
1332 | int fthr = vwrq->value; | 1320 | int fthr = wrqu->frag.value; |
1333 | 1321 | ||
1334 | /* Reject if card is already initialised */ | 1322 | /* Reject if card is already initialised */ |
1335 | if (local->card_status != CARD_AWAITING_PARAM) | 1323 | if (local->card_status != CARD_AWAITING_PARAM) |
1336 | return -EBUSY; | 1324 | return -EBUSY; |
1337 | 1325 | ||
1338 | /* if(wrq->u.frag.fixed == 0) should complain */ | 1326 | /* if(wrq->u.frag.fixed == 0) should complain */ |
1339 | if (vwrq->disabled) | 1327 | if (wrqu->frag.disabled) |
1340 | fthr = 32767; | 1328 | fthr = 32767; |
1341 | else { | 1329 | else { |
1342 | if ((fthr < 256) || (fthr > 2347)) /* To check out ! */ | 1330 | if ((fthr < 256) || (fthr > 2347)) /* To check out ! */ |
@@ -1352,16 +1340,15 @@ static int ray_set_frag(struct net_device *dev, | |||
1352 | /* | 1340 | /* |
1353 | * Wireless Handler : get Fragmentation threshold | 1341 | * Wireless Handler : get Fragmentation threshold |
1354 | */ | 1342 | */ |
1355 | static int ray_get_frag(struct net_device *dev, | 1343 | static int ray_get_frag(struct net_device *dev, struct iw_request_info *info, |
1356 | struct iw_request_info *info, | 1344 | union iwreq_data *wrqu, char *extra) |
1357 | struct iw_param *vwrq, char *extra) | ||
1358 | { | 1345 | { |
1359 | ray_dev_t *local = netdev_priv(dev); | 1346 | ray_dev_t *local = netdev_priv(dev); |
1360 | 1347 | ||
1361 | vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8) | 1348 | wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8) |
1362 | + local->sparm.b5.a_frag_threshold[1]; | 1349 | + local->sparm.b5.a_frag_threshold[1]; |
1363 | vwrq->disabled = (vwrq->value == 32767); | 1350 | wrqu->frag.disabled = (wrqu->frag.value == 32767); |
1364 | vwrq->fixed = 1; | 1351 | wrqu->frag.fixed = 1; |
1365 | 1352 | ||
1366 | return 0; | 1353 | return 0; |
1367 | } | 1354 | } |
@@ -1370,8 +1357,8 @@ static int ray_get_frag(struct net_device *dev, | |||
1370 | /* | 1357 | /* |
1371 | * Wireless Handler : set Mode of Operation | 1358 | * Wireless Handler : set Mode of Operation |
1372 | */ | 1359 | */ |
1373 | static int ray_set_mode(struct net_device *dev, | 1360 | static int ray_set_mode(struct net_device *dev, struct iw_request_info *info, |
1374 | struct iw_request_info *info, __u32 *uwrq, char *extra) | 1361 | union iwreq_data *wrqu, char *extra) |
1375 | { | 1362 | { |
1376 | ray_dev_t *local = netdev_priv(dev); | 1363 | ray_dev_t *local = netdev_priv(dev); |
1377 | int err = -EINPROGRESS; /* Call commit handler */ | 1364 | int err = -EINPROGRESS; /* Call commit handler */ |
@@ -1381,7 +1368,7 @@ static int ray_set_mode(struct net_device *dev, | |||
1381 | if (local->card_status != CARD_AWAITING_PARAM) | 1368 | if (local->card_status != CARD_AWAITING_PARAM) |
1382 | return -EBUSY; | 1369 | return -EBUSY; |
1383 | 1370 | ||
1384 | switch (*uwrq) { | 1371 | switch (wrqu->mode) { |
1385 | case IW_MODE_ADHOC: | 1372 | case IW_MODE_ADHOC: |
1386 | card_mode = 0; | 1373 | card_mode = 0; |
1387 | /* Fall through */ | 1374 | /* Fall through */ |
@@ -1399,15 +1386,15 @@ static int ray_set_mode(struct net_device *dev, | |||
1399 | /* | 1386 | /* |
1400 | * Wireless Handler : get Mode of Operation | 1387 | * Wireless Handler : get Mode of Operation |
1401 | */ | 1388 | */ |
1402 | static int ray_get_mode(struct net_device *dev, | 1389 | static int ray_get_mode(struct net_device *dev, struct iw_request_info *info, |
1403 | struct iw_request_info *info, __u32 *uwrq, char *extra) | 1390 | union iwreq_data *wrqu, char *extra) |
1404 | { | 1391 | { |
1405 | ray_dev_t *local = netdev_priv(dev); | 1392 | ray_dev_t *local = netdev_priv(dev); |
1406 | 1393 | ||
1407 | if (local->sparm.b5.a_network_type) | 1394 | if (local->sparm.b5.a_network_type) |
1408 | *uwrq = IW_MODE_INFRA; | 1395 | wrqu->mode = IW_MODE_INFRA; |
1409 | else | 1396 | else |
1410 | *uwrq = IW_MODE_ADHOC; | 1397 | wrqu->mode = IW_MODE_ADHOC; |
1411 | 1398 | ||
1412 | return 0; | 1399 | return 0; |
1413 | } | 1400 | } |
@@ -1416,16 +1403,15 @@ static int ray_get_mode(struct net_device *dev, | |||
1416 | /* | 1403 | /* |
1417 | * Wireless Handler : get range info | 1404 | * Wireless Handler : get range info |
1418 | */ | 1405 | */ |
1419 | static int ray_get_range(struct net_device *dev, | 1406 | static int ray_get_range(struct net_device *dev, struct iw_request_info *info, |
1420 | struct iw_request_info *info, | 1407 | union iwreq_data *wrqu, char *extra) |
1421 | struct iw_point *dwrq, char *extra) | ||
1422 | { | 1408 | { |
1423 | struct iw_range *range = (struct iw_range *)extra; | 1409 | struct iw_range *range = (struct iw_range *)extra; |
1424 | 1410 | ||
1425 | memset((char *)range, 0, sizeof(struct iw_range)); | 1411 | memset(range, 0, sizeof(struct iw_range)); |
1426 | 1412 | ||
1427 | /* Set the length (very important for backward compatibility) */ | 1413 | /* Set the length (very important for backward compatibility) */ |
1428 | dwrq->length = sizeof(struct iw_range); | 1414 | wrqu->data.length = sizeof(struct iw_range); |
1429 | 1415 | ||
1430 | /* Set the Wireless Extension versions */ | 1416 | /* Set the Wireless Extension versions */ |
1431 | range->we_version_compiled = WIRELESS_EXT; | 1417 | range->we_version_compiled = WIRELESS_EXT; |
@@ -1448,8 +1434,7 @@ static int ray_get_range(struct net_device *dev, | |||
1448 | /* | 1434 | /* |
1449 | * Wireless Private Handler : set framing mode | 1435 | * Wireless Private Handler : set framing mode |
1450 | */ | 1436 | */ |
1451 | static int ray_set_framing(struct net_device *dev, | 1437 | static int ray_set_framing(struct net_device *dev, struct iw_request_info *info, |
1452 | struct iw_request_info *info, | ||
1453 | union iwreq_data *wrqu, char *extra) | 1438 | union iwreq_data *wrqu, char *extra) |
1454 | { | 1439 | { |
1455 | translate = *(extra); /* Set framing mode */ | 1440 | translate = *(extra); /* Set framing mode */ |
@@ -1461,8 +1446,7 @@ static int ray_set_framing(struct net_device *dev, | |||
1461 | /* | 1446 | /* |
1462 | * Wireless Private Handler : get framing mode | 1447 | * Wireless Private Handler : get framing mode |
1463 | */ | 1448 | */ |
1464 | static int ray_get_framing(struct net_device *dev, | 1449 | static int ray_get_framing(struct net_device *dev, struct iw_request_info *info, |
1465 | struct iw_request_info *info, | ||
1466 | union iwreq_data *wrqu, char *extra) | 1450 | union iwreq_data *wrqu, char *extra) |
1467 | { | 1451 | { |
1468 | *(extra) = translate; | 1452 | *(extra) = translate; |
@@ -1474,8 +1458,7 @@ static int ray_get_framing(struct net_device *dev, | |||
1474 | /* | 1458 | /* |
1475 | * Wireless Private Handler : get country | 1459 | * Wireless Private Handler : get country |
1476 | */ | 1460 | */ |
1477 | static int ray_get_country(struct net_device *dev, | 1461 | static int ray_get_country(struct net_device *dev, struct iw_request_info *info, |
1478 | struct iw_request_info *info, | ||
1479 | union iwreq_data *wrqu, char *extra) | 1462 | union iwreq_data *wrqu, char *extra) |
1480 | { | 1463 | { |
1481 | *(extra) = country; | 1464 | *(extra) = country; |
@@ -1487,10 +1470,9 @@ static int ray_get_country(struct net_device *dev, | |||
1487 | /* | 1470 | /* |
1488 | * Commit handler : called after a bunch of SET operations | 1471 | * Commit handler : called after a bunch of SET operations |
1489 | */ | 1472 | */ |
1490 | static int ray_commit(struct net_device *dev, struct iw_request_info *info, /* NULL */ | 1473 | static int ray_commit(struct net_device *dev, struct iw_request_info *info, |
1491 | void *zwrq, /* NULL */ | 1474 | union iwreq_data *wrqu, char *extra) |
1492 | char *extra) | 1475 | { |
1493 | { /* NULL */ | ||
1494 | return 0; | 1476 | return 0; |
1495 | } | 1477 | } |
1496 | 1478 | ||
@@ -1531,28 +1513,28 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev) | |||
1531 | */ | 1513 | */ |
1532 | 1514 | ||
1533 | static const iw_handler ray_handler[] = { | 1515 | static const iw_handler ray_handler[] = { |
1534 | [SIOCSIWCOMMIT - SIOCIWFIRST] = (iw_handler) ray_commit, | 1516 | IW_HANDLER(SIOCSIWCOMMIT, ray_commit), |
1535 | [SIOCGIWNAME - SIOCIWFIRST] = (iw_handler) ray_get_name, | 1517 | IW_HANDLER(SIOCGIWNAME, ray_get_name), |
1536 | [SIOCSIWFREQ - SIOCIWFIRST] = (iw_handler) ray_set_freq, | 1518 | IW_HANDLER(SIOCSIWFREQ, ray_set_freq), |
1537 | [SIOCGIWFREQ - SIOCIWFIRST] = (iw_handler) ray_get_freq, | 1519 | IW_HANDLER(SIOCGIWFREQ, ray_get_freq), |
1538 | [SIOCSIWMODE - SIOCIWFIRST] = (iw_handler) ray_set_mode, | 1520 | IW_HANDLER(SIOCSIWMODE, ray_set_mode), |
1539 | [SIOCGIWMODE - SIOCIWFIRST] = (iw_handler) ray_get_mode, | 1521 | IW_HANDLER(SIOCGIWMODE, ray_get_mode), |
1540 | [SIOCGIWRANGE - SIOCIWFIRST] = (iw_handler) ray_get_range, | 1522 | IW_HANDLER(SIOCGIWRANGE, ray_get_range), |
1541 | #ifdef WIRELESS_SPY | 1523 | #ifdef WIRELESS_SPY |
1542 | [SIOCSIWSPY - SIOCIWFIRST] = (iw_handler) iw_handler_set_spy, | 1524 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), |
1543 | [SIOCGIWSPY - SIOCIWFIRST] = (iw_handler) iw_handler_get_spy, | 1525 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), |
1544 | [SIOCSIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy, | 1526 | IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), |
1545 | [SIOCGIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy, | 1527 | IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), |
1546 | #endif /* WIRELESS_SPY */ | 1528 | #endif /* WIRELESS_SPY */ |
1547 | [SIOCGIWAP - SIOCIWFIRST] = (iw_handler) ray_get_wap, | 1529 | IW_HANDLER(SIOCGIWAP, ray_get_wap), |
1548 | [SIOCSIWESSID - SIOCIWFIRST] = (iw_handler) ray_set_essid, | 1530 | IW_HANDLER(SIOCSIWESSID, ray_set_essid), |
1549 | [SIOCGIWESSID - SIOCIWFIRST] = (iw_handler) ray_get_essid, | 1531 | IW_HANDLER(SIOCGIWESSID, ray_get_essid), |
1550 | [SIOCSIWRATE - SIOCIWFIRST] = (iw_handler) ray_set_rate, | 1532 | IW_HANDLER(SIOCSIWRATE, ray_set_rate), |
1551 | [SIOCGIWRATE - SIOCIWFIRST] = (iw_handler) ray_get_rate, | 1533 | IW_HANDLER(SIOCGIWRATE, ray_get_rate), |
1552 | [SIOCSIWRTS - SIOCIWFIRST] = (iw_handler) ray_set_rts, | 1534 | IW_HANDLER(SIOCSIWRTS, ray_set_rts), |
1553 | [SIOCGIWRTS - SIOCIWFIRST] = (iw_handler) ray_get_rts, | 1535 | IW_HANDLER(SIOCGIWRTS, ray_get_rts), |
1554 | [SIOCSIWFRAG - SIOCIWFIRST] = (iw_handler) ray_set_frag, | 1536 | IW_HANDLER(SIOCSIWFRAG, ray_set_frag), |
1555 | [SIOCGIWFRAG - SIOCIWFIRST] = (iw_handler) ray_get_frag, | 1537 | IW_HANDLER(SIOCGIWFRAG, ray_get_frag), |
1556 | }; | 1538 | }; |
1557 | 1539 | ||
1558 | #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ | 1540 | #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */ |
@@ -1560,9 +1542,9 @@ static const iw_handler ray_handler[] = { | |||
1560 | #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ | 1542 | #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */ |
1561 | 1543 | ||
1562 | static const iw_handler ray_private_handler[] = { | 1544 | static const iw_handler ray_private_handler[] = { |
1563 | [0] = (iw_handler) ray_set_framing, | 1545 | [0] = ray_set_framing, |
1564 | [1] = (iw_handler) ray_get_framing, | 1546 | [1] = ray_get_framing, |
1565 | [3] = (iw_handler) ray_get_country, | 1547 | [3] = ray_get_country, |
1566 | }; | 1548 | }; |
1567 | 1549 | ||
1568 | static const struct iw_priv_args ray_private_args[] = { | 1550 | static const struct iw_priv_args ray_private_args[] = { |
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 0deb4fdf916b..8f11506f8310 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h | |||
@@ -53,6 +53,8 @@ enum { | |||
53 | DEBUG_MAC80211 = BIT(11), | 53 | DEBUG_MAC80211 = BIT(11), |
54 | DEBUG_CMD = BIT(12), | 54 | DEBUG_CMD = BIT(12), |
55 | DEBUG_ACX = BIT(13), | 55 | DEBUG_ACX = BIT(13), |
56 | DEBUG_SDIO = BIT(14), | ||
57 | DEBUG_FILTERS = BIT(15), | ||
56 | DEBUG_ALL = ~0, | 58 | DEBUG_ALL = ~0, |
57 | }; | 59 | }; |
58 | 60 | ||
@@ -344,12 +346,14 @@ struct wl1271_if_operations { | |||
344 | bool fixed); | 346 | bool fixed); |
345 | void (*reset)(struct wl1271 *wl); | 347 | void (*reset)(struct wl1271 *wl); |
346 | void (*init)(struct wl1271 *wl); | 348 | void (*init)(struct wl1271 *wl); |
349 | void (*power)(struct wl1271 *wl, bool enable); | ||
347 | struct device* (*dev)(struct wl1271 *wl); | 350 | struct device* (*dev)(struct wl1271 *wl); |
348 | void (*enable_irq)(struct wl1271 *wl); | 351 | void (*enable_irq)(struct wl1271 *wl); |
349 | void (*disable_irq)(struct wl1271 *wl); | 352 | void (*disable_irq)(struct wl1271 *wl); |
350 | }; | 353 | }; |
351 | 354 | ||
352 | struct wl1271 { | 355 | struct wl1271 { |
356 | struct platform_device *plat_dev; | ||
353 | struct ieee80211_hw *hw; | 357 | struct ieee80211_hw *hw; |
354 | bool mac80211_registered; | 358 | bool mac80211_registered; |
355 | 359 | ||
@@ -456,6 +460,7 @@ struct wl1271 { | |||
456 | /* Default key (for WEP) */ | 460 | /* Default key (for WEP) */ |
457 | u32 default_key; | 461 | u32 default_key; |
458 | 462 | ||
463 | unsigned int filters; | ||
459 | unsigned int rx_config; | 464 | unsigned int rx_config; |
460 | unsigned int rx_filter; | 465 | unsigned int rx_filter; |
461 | 466 | ||
@@ -483,6 +488,8 @@ struct wl1271 { | |||
483 | /* Current chipset configuration */ | 488 | /* Current chipset configuration */ |
484 | struct conf_drv_settings conf; | 489 | struct conf_drv_settings conf; |
485 | 490 | ||
491 | bool sg_enabled; | ||
492 | |||
486 | struct list_head list; | 493 | struct list_head list; |
487 | }; | 494 | }; |
488 | 495 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 60e20876e6d8..7e337cea9905 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c | |||
@@ -534,7 +534,7 @@ out: | |||
534 | } | 534 | } |
535 | 535 | ||
536 | 536 | ||
537 | int wl1271_acx_sg_enable(struct wl1271 *wl) | 537 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable) |
538 | { | 538 | { |
539 | struct acx_bt_wlan_coex *pta; | 539 | struct acx_bt_wlan_coex *pta; |
540 | int ret; | 540 | int ret; |
@@ -547,7 +547,10 @@ int wl1271_acx_sg_enable(struct wl1271 *wl) | |||
547 | goto out; | 547 | goto out; |
548 | } | 548 | } |
549 | 549 | ||
550 | pta->enable = SG_ENABLE; | 550 | if (enable) |
551 | pta->enable = wl->conf.sg.state; | ||
552 | else | ||
553 | pta->enable = CONF_SG_DISABLE; | ||
551 | 554 | ||
552 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); | 555 | ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta)); |
553 | if (ret < 0) { | 556 | if (ret < 0) { |
@@ -564,7 +567,7 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) | |||
564 | { | 567 | { |
565 | struct acx_bt_wlan_coex_param *param; | 568 | struct acx_bt_wlan_coex_param *param; |
566 | struct conf_sg_settings *c = &wl->conf.sg; | 569 | struct conf_sg_settings *c = &wl->conf.sg; |
567 | int ret; | 570 | int i, ret; |
568 | 571 | ||
569 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); | 572 | wl1271_debug(DEBUG_ACX, "acx sg cfg"); |
570 | 573 | ||
@@ -575,19 +578,9 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl) | |||
575 | } | 578 | } |
576 | 579 | ||
577 | /* BT-WLAN coext parameters */ | 580 | /* BT-WLAN coext parameters */ |
578 | param->per_threshold = cpu_to_le32(c->per_threshold); | 581 | for (i = 0; i < CONF_SG_PARAMS_MAX; i++) |
579 | param->max_scan_compensation_time = | 582 | param->params[i] = c->params[i]; |
580 | cpu_to_le32(c->max_scan_compensation_time); | 583 | param->param_idx = CONF_SG_PARAMS_ALL; |
581 | param->nfs_sample_interval = cpu_to_le16(c->nfs_sample_interval); | ||
582 | param->load_ratio = c->load_ratio; | ||
583 | param->auto_ps_mode = c->auto_ps_mode; | ||
584 | param->probe_req_compensation = c->probe_req_compensation; | ||
585 | param->scan_window_compensation = c->scan_window_compensation; | ||
586 | param->antenna_config = c->antenna_config; | ||
587 | param->beacon_miss_threshold = c->beacon_miss_threshold; | ||
588 | param->rate_adaptation_threshold = | ||
589 | cpu_to_le32(c->rate_adaptation_threshold); | ||
590 | param->rate_adaptation_snr = c->rate_adaptation_snr; | ||
591 | 584 | ||
592 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); | 585 | ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); |
593 | if (ret < 0) { | 586 | if (ret < 0) { |
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index aeccc98581eb..8e5870fa9609 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h | |||
@@ -392,81 +392,27 @@ struct acx_conn_monit_params { | |||
392 | __le32 bss_lose_timeout; /* number of TU's from synch fail */ | 392 | __le32 bss_lose_timeout; /* number of TU's from synch fail */ |
393 | } __attribute__ ((packed)); | 393 | } __attribute__ ((packed)); |
394 | 394 | ||
395 | enum { | ||
396 | SG_ENABLE = 0, | ||
397 | SG_DISABLE, | ||
398 | SG_SENSE_NO_ACTIVITY, | ||
399 | SG_SENSE_ACTIVE | ||
400 | }; | ||
401 | |||
402 | struct acx_bt_wlan_coex { | 395 | struct acx_bt_wlan_coex { |
403 | struct acx_header header; | 396 | struct acx_header header; |
404 | 397 | ||
405 | /* | ||
406 | * 0 -> PTA enabled | ||
407 | * 1 -> PTA disabled | ||
408 | * 2 -> sense no active mode, i.e. | ||
409 | * an interrupt is sent upon | ||
410 | * BT activity. | ||
411 | * 3 -> PTA is switched on in response | ||
412 | * to the interrupt sending. | ||
413 | */ | ||
414 | u8 enable; | 398 | u8 enable; |
415 | u8 pad[3]; | 399 | u8 pad[3]; |
416 | } __attribute__ ((packed)); | 400 | } __attribute__ ((packed)); |
417 | 401 | ||
418 | struct acx_dco_itrim_params { | 402 | struct acx_bt_wlan_coex_param { |
419 | struct acx_header header; | 403 | struct acx_header header; |
420 | 404 | ||
421 | u8 enable; | 405 | __le32 params[CONF_SG_PARAMS_MAX]; |
406 | u8 param_idx; | ||
422 | u8 padding[3]; | 407 | u8 padding[3]; |
423 | __le32 timeout; | ||
424 | } __attribute__ ((packed)); | 408 | } __attribute__ ((packed)); |
425 | 409 | ||
426 | #define PTA_ANTENNA_TYPE_DEF (0) | 410 | struct acx_dco_itrim_params { |
427 | #define PTA_BT_HP_MAXTIME_DEF (2000) | ||
428 | #define PTA_WLAN_HP_MAX_TIME_DEF (5000) | ||
429 | #define PTA_SENSE_DISABLE_TIMER_DEF (1350) | ||
430 | #define PTA_PROTECTIVE_RX_TIME_DEF (1500) | ||
431 | #define PTA_PROTECTIVE_TX_TIME_DEF (1500) | ||
432 | #define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000) | ||
433 | #define PTA_SIGNALING_TYPE_DEF (1) | ||
434 | #define PTA_AFH_LEVERAGE_ON_DEF (0) | ||
435 | #define PTA_NUMBER_QUIET_CYCLE_DEF (0) | ||
436 | #define PTA_MAX_NUM_CTS_DEF (3) | ||
437 | #define PTA_NUMBER_OF_WLAN_PACKETS_DEF (2) | ||
438 | #define PTA_NUMBER_OF_BT_PACKETS_DEF (2) | ||
439 | #define PTA_PROTECTIVE_RX_TIME_FAST_DEF (1500) | ||
440 | #define PTA_PROTECTIVE_TX_TIME_FAST_DEF (3000) | ||
441 | #define PTA_CYCLE_TIME_FAST_DEF (8700) | ||
442 | #define PTA_RX_FOR_AVALANCHE_DEF (5) | ||
443 | #define PTA_ELP_HP_DEF (0) | ||
444 | #define PTA_ANTI_STARVE_PERIOD_DEF (500) | ||
445 | #define PTA_ANTI_STARVE_NUM_CYCLE_DEF (4) | ||
446 | #define PTA_ALLOW_PA_SD_DEF (1) | ||
447 | #define PTA_TIME_BEFORE_BEACON_DEF (6300) | ||
448 | #define PTA_HPDM_MAX_TIME_DEF (1600) | ||
449 | #define PTA_TIME_OUT_NEXT_WLAN_DEF (2550) | ||
450 | #define PTA_AUTO_MODE_NO_CTS_DEF (0) | ||
451 | #define PTA_BT_HP_RESPECTED_DEF (3) | ||
452 | #define PTA_WLAN_RX_MIN_RATE_DEF (24) | ||
453 | #define PTA_ACK_MODE_DEF (1) | ||
454 | |||
455 | struct acx_bt_wlan_coex_param { | ||
456 | struct acx_header header; | 411 | struct acx_header header; |
457 | 412 | ||
458 | __le32 per_threshold; | 413 | u8 enable; |
459 | __le32 max_scan_compensation_time; | ||
460 | __le16 nfs_sample_interval; | ||
461 | u8 load_ratio; | ||
462 | u8 auto_ps_mode; | ||
463 | u8 probe_req_compensation; | ||
464 | u8 scan_window_compensation; | ||
465 | u8 antenna_config; | ||
466 | u8 beacon_miss_threshold; | ||
467 | __le32 rate_adaptation_threshold; | ||
468 | s8 rate_adaptation_snr; | ||
469 | u8 padding[3]; | 414 | u8 padding[3]; |
415 | __le32 timeout; | ||
470 | } __attribute__ ((packed)); | 416 | } __attribute__ ((packed)); |
471 | 417 | ||
472 | struct acx_energy_detection { | 418 | struct acx_energy_detection { |
@@ -1059,7 +1005,7 @@ int wl1271_acx_dco_itrim_params(struct wl1271 *wl); | |||
1059 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); | 1005 | int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); |
1060 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl); | 1006 | int wl1271_acx_beacon_filter_table(struct wl1271 *wl); |
1061 | int wl1271_acx_conn_monit_params(struct wl1271 *wl); | 1007 | int wl1271_acx_conn_monit_params(struct wl1271 *wl); |
1062 | int wl1271_acx_sg_enable(struct wl1271 *wl); | 1008 | int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); |
1063 | int wl1271_acx_sg_cfg(struct wl1271 *wl); | 1009 | int wl1271_acx_sg_cfg(struct wl1271 *wl); |
1064 | int wl1271_acx_cca_threshold(struct wl1271 *wl); | 1010 | int wl1271_acx_cca_threshold(struct wl1271 *wl); |
1065 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); | 1011 | int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index f88d52e87e82..41c6affbee29 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c | |||
@@ -228,6 +228,14 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) | |||
228 | nvs_len = sizeof(wl->nvs->nvs); | 228 | nvs_len = sizeof(wl->nvs->nvs); |
229 | nvs_ptr = (u8 *)wl->nvs->nvs; | 229 | nvs_ptr = (u8 *)wl->nvs->nvs; |
230 | 230 | ||
231 | /* update current MAC address to NVS */ | ||
232 | nvs_ptr[11] = wl->mac_addr[0]; | ||
233 | nvs_ptr[10] = wl->mac_addr[1]; | ||
234 | nvs_ptr[6] = wl->mac_addr[2]; | ||
235 | nvs_ptr[5] = wl->mac_addr[3]; | ||
236 | nvs_ptr[4] = wl->mac_addr[4]; | ||
237 | nvs_ptr[3] = wl->mac_addr[5]; | ||
238 | |||
231 | /* | 239 | /* |
232 | * Layout before the actual NVS tables: | 240 | * Layout before the actual NVS tables: |
233 | * 1 byte : burst length. | 241 | * 1 byte : burst length. |
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c index d59b3830a6a5..d005729e0312 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.c +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
27 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
28 | #include <linux/etherdevice.h> | 28 | #include <linux/etherdevice.h> |
29 | #include <linux/ieee80211.h> | ||
29 | 30 | ||
30 | #include "wl1271.h" | 31 | #include "wl1271.h" |
31 | #include "wl1271_reg.h" | 32 | #include "wl1271_reg.h" |
@@ -280,15 +281,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) | |||
280 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); | 281 | join->rx_filter_options = cpu_to_le32(wl->rx_filter); |
281 | join->bss_type = bss_type; | 282 | join->bss_type = bss_type; |
282 | 283 | ||
283 | /* | ||
284 | * FIXME: disable temporarily all filters because after commit | ||
285 | * 9cef8737 "mac80211: fix managed mode BSSID handling" broke | ||
286 | * association. The filter logic needs to be implemented properly | ||
287 | * and once that is done, this hack can be removed. | ||
288 | */ | ||
289 | join->rx_config_options = cpu_to_le32(0); | ||
290 | join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER); | ||
291 | |||
292 | if (wl->band == IEEE80211_BAND_2GHZ) | 284 | if (wl->band == IEEE80211_BAND_2GHZ) |
293 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | | 285 | join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | |
294 | CONF_HW_BIT_RATE_2MBPS | | 286 | CONF_HW_BIT_RATE_2MBPS | |
@@ -546,9 +538,9 @@ out: | |||
546 | return ret; | 538 | return ret; |
547 | } | 539 | } |
548 | 540 | ||
549 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | 541 | int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, |
550 | u8 active_scan, u8 high_prio, u8 band, | 542 | const u8 *ie, size_t ie_len, u8 active_scan, |
551 | u8 probe_requests) | 543 | u8 high_prio, u8 band, u8 probe_requests) |
552 | { | 544 | { |
553 | 545 | ||
554 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; | 546 | struct wl1271_cmd_trigger_scan_to *trigger = NULL; |
@@ -619,12 +611,13 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | |||
619 | 611 | ||
620 | params->params.num_channels = j; | 612 | params->params.num_channels = j; |
621 | 613 | ||
622 | if (len && ssid) { | 614 | if (ssid_len && ssid) { |
623 | params->params.ssid_len = len; | 615 | params->params.ssid_len = ssid_len; |
624 | memcpy(params->params.ssid, ssid, len); | 616 | memcpy(params->params.ssid, ssid, ssid_len); |
625 | } | 617 | } |
626 | 618 | ||
627 | ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band); | 619 | ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len, |
620 | ie, ie_len, ieee_band); | ||
628 | if (ret < 0) { | 621 | if (ret < 0) { |
629 | wl1271_error("PROBE request template failed"); | 622 | wl1271_error("PROBE request template failed"); |
630 | goto out; | 623 | goto out; |
@@ -655,9 +648,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | |||
655 | wl->scan.active = active_scan; | 648 | wl->scan.active = active_scan; |
656 | wl->scan.high_prio = high_prio; | 649 | wl->scan.high_prio = high_prio; |
657 | wl->scan.probe_requests = probe_requests; | 650 | wl->scan.probe_requests = probe_requests; |
658 | if (len && ssid) { | 651 | if (ssid_len && ssid) { |
659 | wl->scan.ssid_len = len; | 652 | wl->scan.ssid_len = ssid_len; |
660 | memcpy(wl->scan.ssid, ssid, len); | 653 | memcpy(wl->scan.ssid, ssid, ssid_len); |
661 | } else | 654 | } else |
662 | wl->scan.ssid_len = 0; | 655 | wl->scan.ssid_len = 0; |
663 | } | 656 | } |
@@ -714,155 +707,102 @@ out: | |||
714 | return ret; | 707 | return ret; |
715 | } | 708 | } |
716 | 709 | ||
717 | static int wl1271_build_basic_rates(u8 *rates, u8 band) | 710 | int wl1271_cmd_build_null_data(struct wl1271 *wl) |
718 | { | 711 | { |
719 | u8 index = 0; | 712 | struct sk_buff *skb = NULL; |
720 | 713 | int size; | |
721 | if (band == IEEE80211_BAND_2GHZ) { | 714 | void *ptr; |
722 | rates[index++] = | 715 | int ret = -ENOMEM; |
723 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; | ||
724 | rates[index++] = | ||
725 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; | ||
726 | rates[index++] = | ||
727 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; | ||
728 | rates[index++] = | ||
729 | IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; | ||
730 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
731 | rates[index++] = | ||
732 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; | ||
733 | rates[index++] = | ||
734 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; | ||
735 | rates[index++] = | ||
736 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; | ||
737 | } else { | ||
738 | wl1271_error("build_basic_rates invalid band: %d", band); | ||
739 | } | ||
740 | 716 | ||
741 | return index; | ||
742 | } | ||
743 | 717 | ||
744 | static int wl1271_build_extended_rates(u8 *rates, u8 band) | 718 | if (wl->bss_type == BSS_TYPE_IBSS) { |
745 | { | 719 | size = sizeof(struct wl12xx_null_data_template); |
746 | u8 index = 0; | 720 | ptr = NULL; |
747 | |||
748 | if (band == IEEE80211_BAND_2GHZ) { | ||
749 | rates[index++] = IEEE80211_OFDM_RATE_6MB; | ||
750 | rates[index++] = IEEE80211_OFDM_RATE_9MB; | ||
751 | rates[index++] = IEEE80211_OFDM_RATE_12MB; | ||
752 | rates[index++] = IEEE80211_OFDM_RATE_18MB; | ||
753 | rates[index++] = IEEE80211_OFDM_RATE_24MB; | ||
754 | rates[index++] = IEEE80211_OFDM_RATE_36MB; | ||
755 | rates[index++] = IEEE80211_OFDM_RATE_48MB; | ||
756 | rates[index++] = IEEE80211_OFDM_RATE_54MB; | ||
757 | } else if (band == IEEE80211_BAND_5GHZ) { | ||
758 | rates[index++] = | ||
759 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; | ||
760 | rates[index++] = | ||
761 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; | ||
762 | rates[index++] = | ||
763 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; | ||
764 | rates[index++] = | ||
765 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; | ||
766 | rates[index++] = | ||
767 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; | ||
768 | rates[index++] = | ||
769 | IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; | ||
770 | } else { | 721 | } else { |
771 | wl1271_error("build_basic_rates invalid band: %d", band); | 722 | skb = ieee80211_nullfunc_get(wl->hw, wl->vif); |
723 | if (!skb) | ||
724 | goto out; | ||
725 | size = skb->len; | ||
726 | ptr = skb->data; | ||
772 | } | 727 | } |
773 | 728 | ||
774 | return index; | 729 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size); |
775 | } | ||
776 | 730 | ||
777 | int wl1271_cmd_build_null_data(struct wl1271 *wl) | 731 | out: |
778 | { | 732 | dev_kfree_skb(skb); |
779 | struct wl12xx_null_data_template template; | 733 | if (ret) |
780 | 734 | wl1271_warning("cmd buld null data failed %d", ret); | |
781 | if (!is_zero_ether_addr(wl->bssid)) { | ||
782 | memcpy(template.header.da, wl->bssid, ETH_ALEN); | ||
783 | memcpy(template.header.bssid, wl->bssid, ETH_ALEN); | ||
784 | } else { | ||
785 | memset(template.header.da, 0xff, ETH_ALEN); | ||
786 | memset(template.header.bssid, 0xff, ETH_ALEN); | ||
787 | } | ||
788 | |||
789 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | ||
790 | template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
791 | IEEE80211_STYPE_NULLFUNC | | ||
792 | IEEE80211_FCTL_TODS); | ||
793 | 735 | ||
794 | return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, | 736 | return ret; |
795 | sizeof(template)); | ||
796 | 737 | ||
797 | } | 738 | } |
798 | 739 | ||
799 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) | 740 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) |
800 | { | 741 | { |
801 | struct wl12xx_ps_poll_template template; | 742 | struct sk_buff *skb; |
802 | 743 | int ret = 0; | |
803 | memcpy(template.bssid, wl->bssid, ETH_ALEN); | ||
804 | memcpy(template.ta, wl->mac_addr, ETH_ALEN); | ||
805 | |||
806 | /* aid in PS-Poll has its two MSBs each set to 1 */ | ||
807 | template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); | ||
808 | 744 | ||
809 | template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | 745 | skb = ieee80211_pspoll_get(wl->hw, wl->vif); |
746 | if (!skb) | ||
747 | goto out; | ||
810 | 748 | ||
811 | return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, | 749 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data, |
812 | sizeof(template)); | 750 | skb->len); |
813 | 751 | ||
752 | out: | ||
753 | dev_kfree_skb(skb); | ||
754 | return ret; | ||
814 | } | 755 | } |
815 | 756 | ||
816 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, | 757 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, |
817 | u8 band) | 758 | const u8 *ssid, size_t ssid_len, |
759 | const u8 *ie, size_t ie_len, u8 band) | ||
818 | { | 760 | { |
819 | struct wl12xx_probe_req_template template; | 761 | struct sk_buff *skb; |
820 | struct wl12xx_ie_rates *rates; | ||
821 | char *ptr; | ||
822 | u16 size; | ||
823 | int ret; | 762 | int ret; |
824 | 763 | ||
825 | ptr = (char *)&template; | 764 | skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, |
826 | size = sizeof(struct ieee80211_header); | 765 | ie, ie_len); |
827 | 766 | if (!skb) { | |
828 | memset(template.header.da, 0xff, ETH_ALEN); | 767 | ret = -ENOMEM; |
829 | memset(template.header.bssid, 0xff, ETH_ALEN); | 768 | goto out; |
830 | memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); | 769 | } |
831 | template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | 770 | |
832 | 771 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); | |
833 | /* IEs */ | ||
834 | /* SSID */ | ||
835 | template.ssid.header.id = WLAN_EID_SSID; | ||
836 | template.ssid.header.len = ssid_len; | ||
837 | if (ssid_len && ssid) | ||
838 | memcpy(template.ssid.ssid, ssid, ssid_len); | ||
839 | size += sizeof(struct wl12xx_ie_header) + ssid_len; | ||
840 | ptr += size; | ||
841 | |||
842 | /* Basic Rates */ | ||
843 | rates = (struct wl12xx_ie_rates *)ptr; | ||
844 | rates->header.id = WLAN_EID_SUPP_RATES; | ||
845 | rates->header.len = wl1271_build_basic_rates(rates->rates, band); | ||
846 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
847 | ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
848 | |||
849 | /* Extended rates */ | ||
850 | rates = (struct wl12xx_ie_rates *)ptr; | ||
851 | rates->header.id = WLAN_EID_EXT_SUPP_RATES; | ||
852 | rates->header.len = wl1271_build_extended_rates(rates->rates, band); | ||
853 | size += sizeof(struct wl12xx_ie_header) + rates->header.len; | ||
854 | |||
855 | wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); | ||
856 | 772 | ||
857 | if (band == IEEE80211_BAND_2GHZ) | 773 | if (band == IEEE80211_BAND_2GHZ) |
858 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | 774 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, |
859 | &template, size); | 775 | skb->data, skb->len); |
860 | else | 776 | else |
861 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, | 777 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, |
862 | &template, size); | 778 | skb->data, skb->len); |
779 | |||
780 | out: | ||
781 | dev_kfree_skb(skb); | ||
863 | return ret; | 782 | return ret; |
864 | } | 783 | } |
865 | 784 | ||
785 | int wl1271_build_qos_null_data(struct wl1271 *wl) | ||
786 | { | ||
787 | struct ieee80211_qos_hdr template; | ||
788 | |||
789 | memset(&template, 0, sizeof(template)); | ||
790 | |||
791 | memcpy(template.addr1, wl->bssid, ETH_ALEN); | ||
792 | memcpy(template.addr2, wl->mac_addr, ETH_ALEN); | ||
793 | memcpy(template.addr3, wl->bssid, ETH_ALEN); | ||
794 | |||
795 | template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
796 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
797 | IEEE80211_FCTL_TODS); | ||
798 | |||
799 | /* FIXME: not sure what priority to use here */ | ||
800 | template.qos_ctrl = cpu_to_le16(0); | ||
801 | |||
802 | return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template, | ||
803 | sizeof(template)); | ||
804 | } | ||
805 | |||
866 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) | 806 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) |
867 | { | 807 | { |
868 | struct wl1271_cmd_set_keys *cmd; | 808 | struct wl1271_cmd_set_keys *cmd; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h index 4297205b8d6d..6324bbf36843 100644 --- a/drivers/net/wireless/wl12xx/wl1271_cmd.h +++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h | |||
@@ -41,15 +41,17 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); | |||
41 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send); | 41 | int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send); |
42 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | 42 | int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, |
43 | size_t len); | 43 | size_t len); |
44 | int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | 44 | int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, |
45 | u8 active_scan, u8 high_prio, u8 band, | 45 | const u8 *ie, size_t ie_len, u8 active_scan, |
46 | u8 probe_requests); | 46 | u8 high_prio, u8 band, u8 probe_requests); |
47 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, | 47 | int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, |
48 | void *buf, size_t buf_len); | 48 | void *buf, size_t buf_len); |
49 | int wl1271_cmd_build_null_data(struct wl1271 *wl); | 49 | int wl1271_cmd_build_null_data(struct wl1271 *wl); |
50 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); | 50 | int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid); |
51 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, | 51 | int wl1271_cmd_build_probe_req(struct wl1271 *wl, |
52 | u8 band); | 52 | const u8 *ssid, size_t ssid_len, |
53 | const u8 *ie, size_t ie_len, u8 band); | ||
54 | int wl1271_build_qos_null_data(struct wl1271 *wl); | ||
53 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); | 55 | int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id); |
54 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, | 56 | int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, |
55 | u8 key_size, const u8 *key, const u8 *addr, | 57 | u8 key_size, const u8 *key, const u8 *addr, |
diff --git a/drivers/net/wireless/wl12xx/wl1271_conf.h b/drivers/net/wireless/wl12xx/wl1271_conf.h index 6f9e75cc5640..7fcfe06b1412 100644 --- a/drivers/net/wireless/wl12xx/wl1271_conf.h +++ b/drivers/net/wireless/wl12xx/wl1271_conf.h | |||
@@ -65,110 +65,318 @@ enum { | |||
65 | CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, | 65 | CONF_HW_RATE_INDEX_MAX = CONF_HW_RATE_INDEX_54MBPS, |
66 | }; | 66 | }; |
67 | 67 | ||
68 | struct conf_sg_settings { | 68 | enum { |
69 | CONF_SG_DISABLE = 0, | ||
70 | CONF_SG_PROTECTIVE, | ||
71 | CONF_SG_OPPORTUNISTIC | ||
72 | }; | ||
73 | |||
74 | enum { | ||
69 | /* | 75 | /* |
70 | * Defines the PER threshold in PPM of the BT voice of which reaching | 76 | * PER threshold in PPM of the BT voice |
71 | * this value will trigger raising the priority of the BT voice by | ||
72 | * the BT IP until next NFS sample interval time as defined in | ||
73 | * nfs_sample_interval. | ||
74 | * | 77 | * |
75 | * Unit: PER value in PPM (parts per million) | 78 | * Range: 0 - 10000000 |
76 | * #Error_packets / #Total_packets | 79 | */ |
80 | CONF_SG_BT_PER_THRESHOLD = 0, | ||
77 | 81 | ||
78 | * Range: u32 | 82 | /* |
83 | * Number of consequent RX_ACTIVE activities to override BT voice | ||
84 | * frames to ensure WLAN connection | ||
85 | * | ||
86 | * Range: 0 - 100 | ||
87 | */ | ||
88 | CONF_SG_HV3_MAX_OVERRIDE, | ||
89 | |||
90 | /* | ||
91 | * Defines the PER threshold of the BT voice | ||
92 | * | ||
93 | * Range: 0 - 65000 | ||
94 | */ | ||
95 | CONF_SG_BT_NFS_SAMPLE_INTERVAL, | ||
96 | |||
97 | /* | ||
98 | * Defines the load ratio of BT | ||
99 | * | ||
100 | * Range: 0 - 100 (%) | ||
101 | */ | ||
102 | CONF_SG_BT_LOAD_RATIO, | ||
103 | |||
104 | /* | ||
105 | * Defines whether the SG will force WLAN host to enter/exit PSM | ||
106 | * | ||
107 | * Range: 1 - SG can force, 0 - host handles PSM | ||
108 | */ | ||
109 | CONF_SG_AUTO_PS_MODE, | ||
110 | |||
111 | /* | ||
112 | * Compensation percentage of probe requests when scan initiated | ||
113 | * during BT voice/ACL link. | ||
114 | * | ||
115 | * Range: 0 - 255 (%) | ||
116 | */ | ||
117 | CONF_SG_AUTO_SCAN_PROBE_REQ, | ||
118 | |||
119 | /* | ||
120 | * Compensation percentage of probe requests when active scan initiated | ||
121 | * during BT voice | ||
122 | * | ||
123 | * Range: 0 - 255 (%) | ||
124 | */ | ||
125 | CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, | ||
126 | |||
127 | /* | ||
128 | * Defines antenna configuration (single/dual antenna) | ||
129 | * | ||
130 | * Range: 0 - single antenna, 1 - dual antenna | ||
131 | */ | ||
132 | CONF_SG_ANTENNA_CONFIGURATION, | ||
133 | |||
134 | /* | ||
135 | * The threshold (percent) of max consequtive beacon misses before | ||
136 | * increasing priority of beacon reception. | ||
137 | * | ||
138 | * Range: 0 - 100 (%) | ||
139 | */ | ||
140 | CONF_SG_BEACON_MISS_PERCENT, | ||
141 | |||
142 | /* | ||
143 | * The rate threshold below which receiving a data frame from the AP | ||
144 | * will increase the priority of the data frame above BT traffic. | ||
145 | * | ||
146 | * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54 | ||
147 | */ | ||
148 | CONF_SG_RATE_ADAPT_THRESH, | ||
149 | |||
150 | /* | ||
151 | * Not used currently. | ||
152 | * | ||
153 | * Range: 0 | ||
154 | */ | ||
155 | CONF_SG_RATE_ADAPT_SNR, | ||
156 | |||
157 | /* | ||
158 | * Configure the min and max time BT gains the antenna | ||
159 | * in WLAN PSM / BT master basic rate | ||
160 | * | ||
161 | * Range: 0 - 255 (ms) | ||
162 | */ | ||
163 | CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR, | ||
164 | CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR, | ||
165 | |||
166 | /* | ||
167 | * The time after it expires no new WLAN trigger frame is trasmitted | ||
168 | * in WLAN PSM / BT master basic rate | ||
169 | * | ||
170 | * Range: 0 - 255 (ms) | ||
171 | */ | ||
172 | CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR, | ||
173 | |||
174 | /* | ||
175 | * Configure the min and max time BT gains the antenna | ||
176 | * in WLAN PSM / BT slave basic rate | ||
177 | * | ||
178 | * Range: 0 - 255 (ms) | ||
79 | */ | 179 | */ |
80 | u32 per_threshold; | 180 | CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR, |
181 | CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR, | ||
81 | 182 | ||
82 | /* | 183 | /* |
83 | * This value is an absolute time in micro-seconds to limit the | 184 | * The time after it expires no new WLAN trigger frame is trasmitted |
84 | * maximum scan duration compensation while in SG | 185 | * in WLAN PSM / BT slave basic rate |
186 | * | ||
187 | * Range: 0 - 255 (ms) | ||
85 | */ | 188 | */ |
86 | u32 max_scan_compensation_time; | 189 | CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR, |
87 | 190 | ||
88 | /* Defines the PER threshold of the BT voice of which reaching this | 191 | /* |
89 | * value will trigger raising the priority of the BT voice until next | 192 | * Configure the min and max time BT gains the antenna |
90 | * NFS sample interval time as defined in sample_interval. | 193 | * in WLAN PSM / BT master EDR |
91 | * | 194 | * |
92 | * Unit: msec | 195 | * Range: 0 - 255 (ms) |
93 | * Range: 1-65000 | ||
94 | */ | 196 | */ |
95 | u16 nfs_sample_interval; | 197 | CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR, |
198 | CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR, | ||
96 | 199 | ||
97 | /* | 200 | /* |
98 | * Defines the load ratio for the BT. | 201 | * The time after it expires no new WLAN trigger frame is trasmitted |
99 | * The WLAN ratio is: 100 - load_ratio | 202 | * in WLAN PSM / BT master EDR |
100 | * | 203 | * |
101 | * Unit: Percent | 204 | * Range: 0 - 255 (ms) |
102 | * Range: 0-100 | ||
103 | */ | 205 | */ |
104 | u8 load_ratio; | 206 | CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR, |
105 | 207 | ||
106 | /* | 208 | /* |
107 | * true - Co-ex is allowed to enter/exit P.S automatically and | 209 | * Configure the min and max time BT gains the antenna |
108 | * transparently to the host | 210 | * in WLAN PSM / BT slave EDR |
109 | * | 211 | * |
110 | * false - Co-ex is disallowed to enter/exit P.S and will trigger an | 212 | * Range: 0 - 255 (ms) |
111 | * event to the host to notify for the need to enter/exit P.S | 213 | */ |
112 | * due to BT change state | 214 | CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR, |
215 | CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR, | ||
216 | |||
217 | /* | ||
218 | * The time after it expires no new WLAN trigger frame is trasmitted | ||
219 | * in WLAN PSM / BT slave EDR | ||
113 | * | 220 | * |
221 | * Range: 0 - 255 (ms) | ||
114 | */ | 222 | */ |
115 | u8 auto_ps_mode; | 223 | CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR, |
116 | 224 | ||
117 | /* | 225 | /* |
118 | * This parameter defines the compensation percentage of num of probe | 226 | * RX guard time before the beginning of a new BT voice frame during |
119 | * requests in case scan is initiated during BT voice/BT ACL | 227 | * which no new WLAN trigger frame is transmitted. |
120 | * guaranteed link. | ||
121 | * | 228 | * |
122 | * Unit: Percent | 229 | * Range: 0 - 100000 (us) |
123 | * Range: 0-255 (0 - No compensation) | ||
124 | */ | 230 | */ |
125 | u8 probe_req_compensation; | 231 | CONF_SG_RXT, |
126 | 232 | ||
127 | /* | 233 | /* |
128 | * This parameter defines the compensation percentage of scan window | 234 | * TX guard time before the beginning of a new BT voice frame during |
129 | * size in case scan is initiated during BT voice/BT ACL Guaranteed | 235 | * which no new WLAN frame is transmitted. |
130 | * link. | ||
131 | * | 236 | * |
132 | * Unit: Percent | 237 | * Range: 0 - 100000 (us) |
133 | * Range: 0-255 (0 - No compensation) | ||
134 | */ | 238 | */ |
135 | u8 scan_window_compensation; | 239 | |
240 | CONF_SG_TXT, | ||
136 | 241 | ||
137 | /* | 242 | /* |
138 | * Defines the antenna configuration. | 243 | * Enable adaptive RXT/TXT algorithm. If disabled, the host values |
244 | * will be utilized. | ||
139 | * | 245 | * |
140 | * Range: 0 - Single Antenna; 1 - Dual Antenna | 246 | * Range: 0 - disable, 1 - enable |
141 | */ | 247 | */ |
142 | u8 antenna_config; | 248 | CONF_SG_ADAPTIVE_RXT_TXT, |
143 | 249 | ||
144 | /* | 250 | /* |
145 | * The percent out of the Max consecutive beacon miss roaming trigger | 251 | * The used WLAN legacy service period during active BT ACL link |
146 | * which is the threshold for raising the priority of beacon | ||
147 | * reception. | ||
148 | * | 252 | * |
149 | * Range: 1-100 | 253 | * Range: 0 - 255 (ms) |
150 | * N = MaxConsecutiveBeaconMiss | ||
151 | * P = coexMaxConsecutiveBeaconMissPrecent | ||
152 | * Threshold = MIN( N-1, round(N * P / 100)) | ||
153 | */ | 254 | */ |
154 | u8 beacon_miss_threshold; | 255 | CONF_SG_PS_POLL_TIMEOUT, |
155 | 256 | ||
156 | /* | 257 | /* |
157 | * The RX rate threshold below which rate adaptation is assumed to be | 258 | * The used WLAN UPSD service period during active BT ACL link |
158 | * occurring at the AP which will raise priority for ACTIVE_RX and RX | ||
159 | * SP. | ||
160 | * | 259 | * |
161 | * Range: HW_BIT_RATE_* | 260 | * Range: 0 - 255 (ms) |
162 | */ | 261 | */ |
163 | u32 rate_adaptation_threshold; | 262 | CONF_SG_UPSD_TIMEOUT, |
164 | 263 | ||
165 | /* | 264 | /* |
166 | * The SNR above which the RX rate threshold indicating AP rate | 265 | * Configure the min and max time BT gains the antenna |
167 | * adaptation is valid | 266 | * in WLAN Active / BT master EDR |
168 | * | 267 | * |
169 | * Range: -128 - 127 | 268 | * Range: 0 - 255 (ms) |
170 | */ | 269 | */ |
171 | s8 rate_adaptation_snr; | 270 | CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR, |
271 | CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR, | ||
272 | |||
273 | /* | ||
274 | * The maximum time WLAN can gain the antenna for | ||
275 | * in WLAN Active / BT master EDR | ||
276 | * | ||
277 | * Range: 0 - 255 (ms) | ||
278 | */ | ||
279 | CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR, | ||
280 | |||
281 | /* | ||
282 | * Configure the min and max time BT gains the antenna | ||
283 | * in WLAN Active / BT slave EDR | ||
284 | * | ||
285 | * Range: 0 - 255 (ms) | ||
286 | */ | ||
287 | CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR, | ||
288 | CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR, | ||
289 | |||
290 | /* | ||
291 | * The maximum time WLAN can gain the antenna for | ||
292 | * in WLAN Active / BT slave EDR | ||
293 | * | ||
294 | * Range: 0 - 255 (ms) | ||
295 | */ | ||
296 | CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR, | ||
297 | |||
298 | /* | ||
299 | * Configure the min and max time BT gains the antenna | ||
300 | * in WLAN Active / BT basic rate | ||
301 | * | ||
302 | * Range: 0 - 255 (ms) | ||
303 | */ | ||
304 | CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR, | ||
305 | CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR, | ||
306 | |||
307 | /* | ||
308 | * The maximum time WLAN can gain the antenna for | ||
309 | * in WLAN Active / BT basic rate | ||
310 | * | ||
311 | * Range: 0 - 255 (ms) | ||
312 | */ | ||
313 | CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR, | ||
314 | |||
315 | /* | ||
316 | * Compensation percentage of WLAN passive scan window if initiated | ||
317 | * during BT voice | ||
318 | * | ||
319 | * Range: 0 - 1000 (%) | ||
320 | */ | ||
321 | CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, | ||
322 | |||
323 | /* | ||
324 | * Compensation percentage of WLAN passive scan window if initiated | ||
325 | * during BT A2DP | ||
326 | * | ||
327 | * Range: 0 - 1000 (%) | ||
328 | */ | ||
329 | CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP, | ||
330 | |||
331 | /* | ||
332 | * Fixed time ensured for BT traffic to gain the antenna during WLAN | ||
333 | * passive scan. | ||
334 | * | ||
335 | * Range: 0 - 1000 ms | ||
336 | */ | ||
337 | CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME, | ||
338 | |||
339 | /* | ||
340 | * Fixed time ensured for WLAN traffic to gain the antenna during WLAN | ||
341 | * passive scan. | ||
342 | * | ||
343 | * Range: 0 - 1000 ms | ||
344 | */ | ||
345 | CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME, | ||
346 | |||
347 | /* | ||
348 | * Number of consequent BT voice frames not interrupted by WLAN | ||
349 | * | ||
350 | * Range: 0 - 100 | ||
351 | */ | ||
352 | CONF_SG_HV3_MAX_SERVED, | ||
353 | |||
354 | /* | ||
355 | * Protection time of the DHCP procedure. | ||
356 | * | ||
357 | * Range: 0 - 100000 (ms) | ||
358 | */ | ||
359 | CONF_SG_DHCP_TIME, | ||
360 | |||
361 | /* | ||
362 | * Compensation percentage of WLAN active scan window if initiated | ||
363 | * during BT A2DP | ||
364 | * | ||
365 | * Range: 0 - 1000 (%) | ||
366 | */ | ||
367 | CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, | ||
368 | CONF_SG_TEMP_PARAM_1, | ||
369 | CONF_SG_TEMP_PARAM_2, | ||
370 | CONF_SG_TEMP_PARAM_3, | ||
371 | CONF_SG_TEMP_PARAM_4, | ||
372 | CONF_SG_TEMP_PARAM_5, | ||
373 | CONF_SG_PARAMS_MAX, | ||
374 | CONF_SG_PARAMS_ALL = 0xff | ||
375 | }; | ||
376 | |||
377 | struct conf_sg_settings { | ||
378 | __le32 params[CONF_SG_PARAMS_MAX]; | ||
379 | u8 state; | ||
172 | }; | 380 | }; |
173 | 381 | ||
174 | enum conf_rx_queue_type { | 382 | enum conf_rx_queue_type { |
diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 8d7588ca68fd..3c0f5b1ac272 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "wl1271.h" | 28 | #include "wl1271.h" |
29 | #include "wl1271_acx.h" | 29 | #include "wl1271_acx.h" |
30 | #include "wl1271_ps.h" | 30 | #include "wl1271_ps.h" |
31 | #include "wl1271_io.h" | ||
31 | 32 | ||
32 | /* ms */ | 33 | /* ms */ |
33 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 | 34 | #define WL1271_DEBUGFS_STATS_LIFETIME 1000 |
@@ -276,13 +277,10 @@ static ssize_t gpio_power_write(struct file *file, | |||
276 | goto out; | 277 | goto out; |
277 | } | 278 | } |
278 | 279 | ||
279 | if (value) { | 280 | if (value) |
280 | wl->set_power(true); | 281 | wl1271_power_on(wl); |
281 | set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | 282 | else |
282 | } else { | 283 | wl1271_power_off(wl); |
283 | wl->set_power(false); | ||
284 | clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
285 | } | ||
286 | 284 | ||
287 | out: | 285 | out: |
288 | mutex_unlock(&wl->mutex); | 286 | mutex_unlock(&wl->mutex); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 5533519a1418..4d35af96c597 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c | |||
@@ -44,7 +44,9 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, | |||
44 | * scanning as it checks that. | 44 | * scanning as it checks that. |
45 | */ | 45 | */ |
46 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | 46 | clear_bit(WL1271_FLAG_SCANNING, &wl->flags); |
47 | /* FIXME: ie missing! */ | ||
47 | wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, | 48 | wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, |
49 | NULL, 0, | ||
48 | wl->scan.active, | 50 | wl->scan.active, |
49 | wl->scan.high_prio, | 51 | wl->scan.high_prio, |
50 | WL1271_SCAN_BAND_5_GHZ, | 52 | WL1271_SCAN_BAND_5_GHZ, |
diff --git a/drivers/net/wireless/wl12xx/wl1271_init.c b/drivers/net/wireless/wl12xx/wl1271_init.c index 86c30a86a456..d9335fc2a575 100644 --- a/drivers/net/wireless/wl12xx/wl1271_init.c +++ b/drivers/net/wireless/wl12xx/wl1271_init.c | |||
@@ -160,11 +160,11 @@ int wl1271_init_pta(struct wl1271 *wl) | |||
160 | { | 160 | { |
161 | int ret; | 161 | int ret; |
162 | 162 | ||
163 | ret = wl1271_acx_sg_enable(wl); | 163 | ret = wl1271_acx_sg_cfg(wl); |
164 | if (ret < 0) | 164 | if (ret < 0) |
165 | return ret; | 165 | return ret; |
166 | 166 | ||
167 | ret = wl1271_acx_sg_cfg(wl); | 167 | ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); |
168 | if (ret < 0) | 168 | if (ret < 0) |
169 | return ret; | 169 | return ret; |
170 | 170 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_io.h b/drivers/net/wireless/wl12xx/wl1271_io.h index 95d2168f8af4..d8837ef0bb40 100644 --- a/drivers/net/wireless/wl12xx/wl1271_io.h +++ b/drivers/net/wireless/wl12xx/wl1271_io.h | |||
@@ -138,6 +138,18 @@ static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) | |||
138 | wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); | 138 | wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val); |
139 | } | 139 | } |
140 | 140 | ||
141 | static inline void wl1271_power_off(struct wl1271 *wl) | ||
142 | { | ||
143 | wl->if_ops->power(wl, false); | ||
144 | clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
145 | } | ||
146 | |||
147 | static inline void wl1271_power_on(struct wl1271 *wl) | ||
148 | { | ||
149 | wl->if_ops->power(wl, true); | ||
150 | set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
151 | } | ||
152 | |||
141 | 153 | ||
142 | /* Top Register IO */ | 154 | /* Top Register IO */ |
143 | void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); | 155 | void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val); |
@@ -149,6 +161,7 @@ int wl1271_set_partition(struct wl1271 *wl, | |||
149 | /* Functions from wl1271_main.c */ | 161 | /* Functions from wl1271_main.c */ |
150 | 162 | ||
151 | int wl1271_register_hw(struct wl1271 *wl); | 163 | int wl1271_register_hw(struct wl1271 *wl); |
164 | void wl1271_unregister_hw(struct wl1271 *wl); | ||
152 | int wl1271_init_ieee80211(struct wl1271 *wl); | 165 | int wl1271_init_ieee80211(struct wl1271 *wl); |
153 | struct ieee80211_hw *wl1271_alloc_hw(void); | 166 | struct ieee80211_hw *wl1271_alloc_hw(void); |
154 | int wl1271_free_hw(struct wl1271 *wl); | 167 | int wl1271_free_hw(struct wl1271 *wl); |
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0a4ff7b02f59..3daba6c0c77f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/etherdevice.h> | 29 | #include <linux/etherdevice.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <linux/inetdevice.h> | 31 | #include <linux/inetdevice.h> |
32 | #include <linux/platform_device.h> | ||
32 | 33 | ||
33 | #include "wl1271.h" | 34 | #include "wl1271.h" |
34 | #include "wl12xx_80211.h" | 35 | #include "wl12xx_80211.h" |
@@ -48,17 +49,57 @@ | |||
48 | 49 | ||
49 | static struct conf_drv_settings default_conf = { | 50 | static struct conf_drv_settings default_conf = { |
50 | .sg = { | 51 | .sg = { |
51 | .per_threshold = 7500, | 52 | .params = { |
52 | .max_scan_compensation_time = 120000, | 53 | [CONF_SG_BT_PER_THRESHOLD] = 7500, |
53 | .nfs_sample_interval = 400, | 54 | [CONF_SG_HV3_MAX_OVERRIDE] = 0, |
54 | .load_ratio = 50, | 55 | [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, |
55 | .auto_ps_mode = 0, | 56 | [CONF_SG_BT_LOAD_RATIO] = 50, |
56 | .probe_req_compensation = 170, | 57 | [CONF_SG_AUTO_PS_MODE] = 0, |
57 | .scan_window_compensation = 50, | 58 | [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, |
58 | .antenna_config = 0, | 59 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, |
59 | .beacon_miss_threshold = 60, | 60 | [CONF_SG_ANTENNA_CONFIGURATION] = 0, |
60 | .rate_adaptation_threshold = CONF_HW_BIT_RATE_12MBPS, | 61 | [CONF_SG_BEACON_MISS_PERCENT] = 60, |
61 | .rate_adaptation_snr = 0 | 62 | [CONF_SG_RATE_ADAPT_THRESH] = 12, |
63 | [CONF_SG_RATE_ADAPT_SNR] = 0, | ||
64 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, | ||
65 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30, | ||
66 | [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8, | ||
67 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, | ||
68 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50, | ||
69 | /* Note: with UPSD, this should be 4 */ | ||
70 | [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8, | ||
71 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, | ||
72 | [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, | ||
73 | [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20, | ||
74 | /* Note: with UPDS, this should be 15 */ | ||
75 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, | ||
76 | /* Note: with UPDS, this should be 50 */ | ||
77 | [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40, | ||
78 | /* Note: with UPDS, this should be 10 */ | ||
79 | [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20, | ||
80 | [CONF_SG_RXT] = 1200, | ||
81 | [CONF_SG_TXT] = 1000, | ||
82 | [CONF_SG_ADAPTIVE_RXT_TXT] = 1, | ||
83 | [CONF_SG_PS_POLL_TIMEOUT] = 10, | ||
84 | [CONF_SG_UPSD_TIMEOUT] = 10, | ||
85 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, | ||
86 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, | ||
87 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, | ||
88 | [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, | ||
89 | [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, | ||
90 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, | ||
91 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, | ||
92 | [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, | ||
93 | [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, | ||
94 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, | ||
95 | [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, | ||
96 | [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, | ||
97 | [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, | ||
98 | [CONF_SG_HV3_MAX_SERVED] = 6, | ||
99 | [CONF_SG_DHCP_TIME] = 5000, | ||
100 | [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, | ||
101 | }, | ||
102 | .state = CONF_SG_PROTECTIVE, | ||
62 | }, | 103 | }, |
63 | .rx = { | 104 | .rx = { |
64 | .rx_msdu_life_time = 512000, | 105 | .rx_msdu_life_time = 512000, |
@@ -240,6 +281,21 @@ static struct conf_drv_settings default_conf = { | |||
240 | } | 281 | } |
241 | }; | 282 | }; |
242 | 283 | ||
284 | static void wl1271_device_release(struct device *dev) | ||
285 | { | ||
286 | |||
287 | } | ||
288 | |||
289 | static struct platform_device wl1271_device = { | ||
290 | .name = "wl1271", | ||
291 | .id = -1, | ||
292 | |||
293 | /* device model insists to have a release function */ | ||
294 | .dev = { | ||
295 | .release = wl1271_device_release, | ||
296 | }, | ||
297 | }; | ||
298 | |||
243 | static LIST_HEAD(wl_list); | 299 | static LIST_HEAD(wl_list); |
244 | 300 | ||
245 | static void wl1271_conf_init(struct wl1271 *wl) | 301 | static void wl1271_conf_init(struct wl1271 *wl) |
@@ -359,18 +415,6 @@ static int wl1271_plt_init(struct wl1271 *wl) | |||
359 | return ret; | 415 | return ret; |
360 | } | 416 | } |
361 | 417 | ||
362 | static void wl1271_power_off(struct wl1271 *wl) | ||
363 | { | ||
364 | wl->set_power(false); | ||
365 | clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
366 | } | ||
367 | |||
368 | static void wl1271_power_on(struct wl1271 *wl) | ||
369 | { | ||
370 | wl->set_power(true); | ||
371 | set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||
372 | } | ||
373 | |||
374 | static void wl1271_fw_status(struct wl1271 *wl, | 418 | static void wl1271_fw_status(struct wl1271 *wl, |
375 | struct wl1271_fw_status *status) | 419 | struct wl1271_fw_status *status) |
376 | { | 420 | { |
@@ -526,40 +570,6 @@ out: | |||
526 | return ret; | 570 | return ret; |
527 | } | 571 | } |
528 | 572 | ||
529 | static int wl1271_update_mac_addr(struct wl1271 *wl) | ||
530 | { | ||
531 | int ret = 0; | ||
532 | u8 *nvs_ptr = (u8 *)wl->nvs->nvs; | ||
533 | |||
534 | /* get mac address from the NVS */ | ||
535 | wl->mac_addr[0] = nvs_ptr[11]; | ||
536 | wl->mac_addr[1] = nvs_ptr[10]; | ||
537 | wl->mac_addr[2] = nvs_ptr[6]; | ||
538 | wl->mac_addr[3] = nvs_ptr[5]; | ||
539 | wl->mac_addr[4] = nvs_ptr[4]; | ||
540 | wl->mac_addr[5] = nvs_ptr[3]; | ||
541 | |||
542 | /* FIXME: if it is a zero-address, we should bail out. Now, instead, | ||
543 | we randomize an address */ | ||
544 | if (is_zero_ether_addr(wl->mac_addr)) { | ||
545 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
546 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
547 | get_random_bytes(wl->mac_addr + 3, 3); | ||
548 | |||
549 | /* update this address to the NVS */ | ||
550 | nvs_ptr[11] = wl->mac_addr[0]; | ||
551 | nvs_ptr[10] = wl->mac_addr[1]; | ||
552 | nvs_ptr[6] = wl->mac_addr[2]; | ||
553 | nvs_ptr[5] = wl->mac_addr[3]; | ||
554 | nvs_ptr[4] = wl->mac_addr[4]; | ||
555 | nvs_ptr[3] = wl->mac_addr[5]; | ||
556 | } | ||
557 | |||
558 | SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | static int wl1271_fetch_nvs(struct wl1271 *wl) | 573 | static int wl1271_fetch_nvs(struct wl1271 *wl) |
564 | { | 574 | { |
565 | const struct firmware *fw; | 575 | const struct firmware *fw; |
@@ -589,8 +599,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) | |||
589 | 599 | ||
590 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); | 600 | memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file)); |
591 | 601 | ||
592 | ret = wl1271_update_mac_addr(wl); | ||
593 | |||
594 | out: | 602 | out: |
595 | release_firmware(fw); | 603 | release_firmware(fw); |
596 | 604 | ||
@@ -908,13 +916,58 @@ static struct notifier_block wl1271_dev_notifier = { | |||
908 | 916 | ||
909 | static int wl1271_op_start(struct ieee80211_hw *hw) | 917 | static int wl1271_op_start(struct ieee80211_hw *hw) |
910 | { | 918 | { |
919 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||
920 | |||
921 | /* | ||
922 | * We have to delay the booting of the hardware because | ||
923 | * we need to know the local MAC address before downloading and | ||
924 | * initializing the firmware. The MAC address cannot be changed | ||
925 | * after boot, and without the proper MAC address, the firmware | ||
926 | * will not function properly. | ||
927 | * | ||
928 | * The MAC address is first known when the corresponding interface | ||
929 | * is added. That is where we will initialize the hardware. | ||
930 | */ | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static void wl1271_op_stop(struct ieee80211_hw *hw) | ||
936 | { | ||
937 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
938 | } | ||
939 | |||
940 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||
941 | struct ieee80211_vif *vif) | ||
942 | { | ||
911 | struct wl1271 *wl = hw->priv; | 943 | struct wl1271 *wl = hw->priv; |
912 | int retries = WL1271_BOOT_RETRIES; | 944 | int retries = WL1271_BOOT_RETRIES; |
913 | int ret = 0; | 945 | int ret = 0; |
914 | 946 | ||
915 | wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | 947 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", |
948 | vif->type, vif->addr); | ||
916 | 949 | ||
917 | mutex_lock(&wl->mutex); | 950 | mutex_lock(&wl->mutex); |
951 | if (wl->vif) { | ||
952 | ret = -EBUSY; | ||
953 | goto out; | ||
954 | } | ||
955 | |||
956 | wl->vif = vif; | ||
957 | |||
958 | switch (vif->type) { | ||
959 | case NL80211_IFTYPE_STATION: | ||
960 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
961 | break; | ||
962 | case NL80211_IFTYPE_ADHOC: | ||
963 | wl->bss_type = BSS_TYPE_IBSS; | ||
964 | break; | ||
965 | default: | ||
966 | ret = -EOPNOTSUPP; | ||
967 | goto out; | ||
968 | } | ||
969 | |||
970 | memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||
918 | 971 | ||
919 | if (wl->state != WL1271_STATE_OFF) { | 972 | if (wl->state != WL1271_STATE_OFF) { |
920 | wl1271_error("cannot start because not in off state: %d", | 973 | wl1271_error("cannot start because not in off state: %d", |
@@ -970,19 +1023,20 @@ out: | |||
970 | return ret; | 1023 | return ret; |
971 | } | 1024 | } |
972 | 1025 | ||
973 | static void wl1271_op_stop(struct ieee80211_hw *hw) | 1026 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, |
1027 | struct ieee80211_vif *vif) | ||
974 | { | 1028 | { |
975 | struct wl1271 *wl = hw->priv; | 1029 | struct wl1271 *wl = hw->priv; |
976 | int i; | 1030 | int i; |
977 | 1031 | ||
978 | wl1271_info("down"); | ||
979 | |||
980 | wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); | ||
981 | |||
982 | unregister_inetaddr_notifier(&wl1271_dev_notifier); | 1032 | unregister_inetaddr_notifier(&wl1271_dev_notifier); |
983 | list_del(&wl->list); | ||
984 | 1033 | ||
985 | mutex_lock(&wl->mutex); | 1034 | mutex_lock(&wl->mutex); |
1035 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1036 | |||
1037 | wl1271_info("down"); | ||
1038 | |||
1039 | list_del(&wl->list); | ||
986 | 1040 | ||
987 | WARN_ON(wl->state != WL1271_STATE_ON); | 1041 | WARN_ON(wl->state != WL1271_STATE_ON); |
988 | 1042 | ||
@@ -1026,6 +1080,8 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1026 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; | 1080 | wl->rate_set = CONF_TX_RATE_MASK_BASIC; |
1027 | wl->sta_rate_set = 0; | 1081 | wl->sta_rate_set = 0; |
1028 | wl->flags = 0; | 1082 | wl->flags = 0; |
1083 | wl->vif = NULL; | ||
1084 | wl->filters = 0; | ||
1029 | 1085 | ||
1030 | for (i = 0; i < NUM_TX_QUEUES; i++) | 1086 | for (i = 0; i < NUM_TX_QUEUES; i++) |
1031 | wl->tx_blocks_freed[i] = 0; | 1087 | wl->tx_blocks_freed[i] = 0; |
@@ -1034,119 +1090,39 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | |||
1034 | mutex_unlock(&wl->mutex); | 1090 | mutex_unlock(&wl->mutex); |
1035 | } | 1091 | } |
1036 | 1092 | ||
1037 | static int wl1271_op_add_interface(struct ieee80211_hw *hw, | 1093 | static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) |
1038 | struct ieee80211_vif *vif) | ||
1039 | { | 1094 | { |
1040 | struct wl1271 *wl = hw->priv; | 1095 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; |
1041 | int ret = 0; | 1096 | wl->rx_filter = WL1271_DEFAULT_RX_FILTER; |
1042 | 1097 | ||
1043 | wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | 1098 | /* combine requested filters with current filter config */ |
1044 | vif->type, vif->addr); | 1099 | filters = wl->filters | filters; |
1045 | 1100 | ||
1046 | mutex_lock(&wl->mutex); | 1101 | wl1271_debug(DEBUG_FILTERS, "RX filters set: "); |
1047 | if (wl->vif) { | ||
1048 | ret = -EBUSY; | ||
1049 | goto out; | ||
1050 | } | ||
1051 | 1102 | ||
1052 | wl->vif = vif; | 1103 | if (filters & FIF_PROMISC_IN_BSS) { |
1053 | 1104 | wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS"); | |
1054 | switch (vif->type) { | 1105 | wl->rx_config &= ~CFG_UNI_FILTER_EN; |
1055 | case NL80211_IFTYPE_STATION: | 1106 | wl->rx_config |= CFG_BSSID_FILTER_EN; |
1056 | wl->bss_type = BSS_TYPE_STA_BSS; | ||
1057 | break; | ||
1058 | case NL80211_IFTYPE_ADHOC: | ||
1059 | wl->bss_type = BSS_TYPE_IBSS; | ||
1060 | break; | ||
1061 | default: | ||
1062 | ret = -EOPNOTSUPP; | ||
1063 | goto out; | ||
1064 | } | 1107 | } |
1065 | 1108 | if (filters & FIF_BCN_PRBRESP_PROMISC) { | |
1066 | /* FIXME: what if conf->mac_addr changes? */ | 1109 | wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC"); |
1067 | 1110 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | |
1068 | out: | 1111 | wl->rx_config &= ~CFG_SSID_FILTER_EN; |
1069 | mutex_unlock(&wl->mutex); | ||
1070 | return ret; | ||
1071 | } | ||
1072 | |||
1073 | static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||
1074 | struct ieee80211_vif *vif) | ||
1075 | { | ||
1076 | struct wl1271 *wl = hw->priv; | ||
1077 | |||
1078 | mutex_lock(&wl->mutex); | ||
1079 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); | ||
1080 | wl->vif = NULL; | ||
1081 | mutex_unlock(&wl->mutex); | ||
1082 | } | ||
1083 | |||
1084 | #if 0 | ||
1085 | static int wl1271_op_config_interface(struct ieee80211_hw *hw, | ||
1086 | struct ieee80211_vif *vif, | ||
1087 | struct ieee80211_if_conf *conf) | ||
1088 | { | ||
1089 | struct wl1271 *wl = hw->priv; | ||
1090 | struct sk_buff *beacon; | ||
1091 | int ret; | ||
1092 | |||
1093 | wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM", | ||
1094 | conf->bssid); | ||
1095 | wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid, | ||
1096 | conf->ssid_len); | ||
1097 | |||
1098 | mutex_lock(&wl->mutex); | ||
1099 | |||
1100 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1101 | if (ret < 0) | ||
1102 | goto out; | ||
1103 | |||
1104 | if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) { | ||
1105 | wl1271_debug(DEBUG_MAC80211, "bssid changed"); | ||
1106 | |||
1107 | memcpy(wl->bssid, conf->bssid, ETH_ALEN); | ||
1108 | |||
1109 | ret = wl1271_cmd_join(wl, wl->bss_type); | ||
1110 | if (ret < 0) | ||
1111 | goto out_sleep; | ||
1112 | |||
1113 | ret = wl1271_cmd_build_null_data(wl); | ||
1114 | if (ret < 0) | ||
1115 | goto out_sleep; | ||
1116 | } | 1112 | } |
1117 | 1113 | if (filters & FIF_OTHER_BSS) { | |
1118 | wl->ssid_len = conf->ssid_len; | 1114 | wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS"); |
1119 | if (wl->ssid_len) | 1115 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; |
1120 | memcpy(wl->ssid, conf->ssid, wl->ssid_len); | 1116 | } |
1121 | 1117 | if (filters & FIF_CONTROL) { | |
1122 | if (conf->changed & IEEE80211_IFCC_BEACON) { | 1118 | wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL"); |
1123 | beacon = ieee80211_beacon_get(hw, vif); | 1119 | wl->rx_filter |= CFG_RX_CTL_EN; |
1124 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | 1120 | } |
1125 | beacon->data, beacon->len); | 1121 | if (filters & FIF_FCSFAIL) { |
1126 | 1122 | wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL"); | |
1127 | if (ret < 0) { | 1123 | wl->rx_filter |= CFG_RX_FCS_ERROR; |
1128 | dev_kfree_skb(beacon); | ||
1129 | goto out_sleep; | ||
1130 | } | ||
1131 | |||
1132 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, | ||
1133 | beacon->data, beacon->len); | ||
1134 | |||
1135 | dev_kfree_skb(beacon); | ||
1136 | |||
1137 | if (ret < 0) | ||
1138 | goto out_sleep; | ||
1139 | } | 1124 | } |
1140 | |||
1141 | out_sleep: | ||
1142 | wl1271_ps_elp_sleep(wl); | ||
1143 | |||
1144 | out: | ||
1145 | mutex_unlock(&wl->mutex); | ||
1146 | |||
1147 | return ret; | ||
1148 | } | 1125 | } |
1149 | #endif | ||
1150 | 1126 | ||
1151 | static int wl1271_join_channel(struct wl1271 *wl, int channel) | 1127 | static int wl1271_join_channel(struct wl1271 *wl, int channel) |
1152 | { | 1128 | { |
@@ -1155,12 +1131,12 @@ static int wl1271_join_channel(struct wl1271 *wl, int channel) | |||
1155 | static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, | 1131 | static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, |
1156 | 0xad, 0xbe, 0xef }; | 1132 | 0xad, 0xbe, 0xef }; |
1157 | 1133 | ||
1158 | /* disable mac filter, so we hear everything */ | ||
1159 | wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||
1160 | |||
1161 | wl->channel = channel; | 1134 | wl->channel = channel; |
1162 | memcpy(wl->bssid, dummy_bssid, ETH_ALEN); | 1135 | memcpy(wl->bssid, dummy_bssid, ETH_ALEN); |
1163 | 1136 | ||
1137 | /* pass through frames from all BSS */ | ||
1138 | wl1271_configure_filters(wl, FIF_OTHER_BSS); | ||
1139 | |||
1164 | /* the dummy join is performed always with STATION BSS type to allow | 1140 | /* the dummy join is performed always with STATION BSS type to allow |
1165 | also ad-hoc mode to listen to the surroundings without sending any | 1141 | also ad-hoc mode to listen to the surroundings without sending any |
1166 | beacons yet. */ | 1142 | beacons yet. */ |
@@ -1186,7 +1162,9 @@ static int wl1271_unjoin_channel(struct wl1271 *wl) | |||
1186 | clear_bit(WL1271_FLAG_JOINED, &wl->flags); | 1162 | clear_bit(WL1271_FLAG_JOINED, &wl->flags); |
1187 | wl->channel = 0; | 1163 | wl->channel = 0; |
1188 | memset(wl->bssid, 0, ETH_ALEN); | 1164 | memset(wl->bssid, 0, ETH_ALEN); |
1189 | wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | 1165 | |
1166 | /* stop filterting packets based on bssid */ | ||
1167 | wl1271_configure_filters(wl, FIF_OTHER_BSS); | ||
1190 | 1168 | ||
1191 | out: | 1169 | out: |
1192 | return ret; | 1170 | return ret; |
@@ -1359,14 +1337,14 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, | |||
1359 | if (ret < 0) | 1337 | if (ret < 0) |
1360 | goto out_sleep; | 1338 | goto out_sleep; |
1361 | 1339 | ||
1362 | kfree(fp); | ||
1363 | |||
1364 | /* FIXME: We still need to set our filters properly */ | ||
1365 | |||
1366 | /* determine, whether supported filter values have changed */ | 1340 | /* determine, whether supported filter values have changed */ |
1367 | if (changed == 0) | 1341 | if (changed == 0) |
1368 | goto out_sleep; | 1342 | goto out_sleep; |
1369 | 1343 | ||
1344 | /* configure filters */ | ||
1345 | wl->filters = *total; | ||
1346 | wl1271_configure_filters(wl, 0); | ||
1347 | |||
1370 | /* apply configured filters */ | 1348 | /* apply configured filters */ |
1371 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); | 1349 | ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); |
1372 | if (ret < 0) | 1350 | if (ret < 0) |
@@ -1377,6 +1355,7 @@ out_sleep: | |||
1377 | 1355 | ||
1378 | out: | 1356 | out: |
1379 | mutex_unlock(&wl->mutex); | 1357 | mutex_unlock(&wl->mutex); |
1358 | kfree(fp); | ||
1380 | } | 1359 | } |
1381 | 1360 | ||
1382 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 1361 | static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
@@ -1522,10 +1501,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, | |||
1522 | goto out; | 1501 | goto out; |
1523 | 1502 | ||
1524 | if (wl1271_11a_enabled()) | 1503 | if (wl1271_11a_enabled()) |
1525 | ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, | 1504 | ret = wl1271_cmd_scan(hw->priv, ssid, len, |
1505 | req->ie, req->ie_len, 1, 0, | ||
1526 | WL1271_SCAN_BAND_DUAL, 3); | 1506 | WL1271_SCAN_BAND_DUAL, 3); |
1527 | else | 1507 | else |
1528 | ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0, | 1508 | ret = wl1271_cmd_scan(hw->priv, ssid, len, |
1509 | req->ie, req->ie_len, 1, 0, | ||
1529 | WL1271_SCAN_BAND_2_4_GHZ, 3); | 1510 | WL1271_SCAN_BAND_2_4_GHZ, 3); |
1530 | 1511 | ||
1531 | wl1271_ps_elp_sleep(wl); | 1512 | wl1271_ps_elp_sleep(wl); |
@@ -1638,14 +1619,14 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | |||
1638 | * and enable the BSSID filter | 1619 | * and enable the BSSID filter |
1639 | */ | 1620 | */ |
1640 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { | 1621 | memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { |
1641 | wl->rx_config |= CFG_BSSID_FILTER_EN; | ||
1642 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | 1622 | memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); |
1623 | |||
1643 | ret = wl1271_cmd_build_null_data(wl); | 1624 | ret = wl1271_cmd_build_null_data(wl); |
1644 | if (ret < 0) { | 1625 | if (ret < 0) |
1645 | wl1271_warning("cmd buld null data failed %d", | ||
1646 | ret); | ||
1647 | goto out_sleep; | 1626 | goto out_sleep; |
1648 | } | 1627 | |
1628 | /* filter out all packets not from this BSSID */ | ||
1629 | wl1271_configure_filters(wl, 0); | ||
1649 | 1630 | ||
1650 | /* Need to update the BSSID (for filtering etc) */ | 1631 | /* Need to update the BSSID (for filtering etc) */ |
1651 | do_join = true; | 1632 | do_join = true; |
@@ -1735,6 +1716,7 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1735 | const struct ieee80211_tx_queue_params *params) | 1716 | const struct ieee80211_tx_queue_params *params) |
1736 | { | 1717 | { |
1737 | struct wl1271 *wl = hw->priv; | 1718 | struct wl1271 *wl = hw->priv; |
1719 | u8 ps_scheme; | ||
1738 | int ret; | 1720 | int ret; |
1739 | 1721 | ||
1740 | mutex_lock(&wl->mutex); | 1722 | mutex_lock(&wl->mutex); |
@@ -1745,17 +1727,22 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1745 | if (ret < 0) | 1727 | if (ret < 0) |
1746 | goto out; | 1728 | goto out; |
1747 | 1729 | ||
1730 | /* the txop is confed in units of 32us by the mac80211, we need us */ | ||
1748 | ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), | 1731 | ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), |
1749 | params->cw_min, params->cw_max, | 1732 | params->cw_min, params->cw_max, |
1750 | params->aifs, params->txop); | 1733 | params->aifs, params->txop << 5); |
1751 | if (ret < 0) | 1734 | if (ret < 0) |
1752 | goto out_sleep; | 1735 | goto out_sleep; |
1753 | 1736 | ||
1737 | if (params->uapsd) | ||
1738 | ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER; | ||
1739 | else | ||
1740 | ps_scheme = CONF_PS_SCHEME_LEGACY; | ||
1741 | |||
1754 | ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), | 1742 | ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), |
1755 | CONF_CHANNEL_TYPE_EDCF, | 1743 | CONF_CHANNEL_TYPE_EDCF, |
1756 | wl1271_tx_get_queue(queue), | 1744 | wl1271_tx_get_queue(queue), |
1757 | CONF_PS_SCHEME_LEGACY_PSPOLL, | 1745 | ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0); |
1758 | CONF_ACK_POLICY_LEGACY, 0, 0); | ||
1759 | if (ret < 0) | 1746 | if (ret < 0) |
1760 | goto out_sleep; | 1747 | goto out_sleep; |
1761 | 1748 | ||
@@ -1925,7 +1912,6 @@ static const struct ieee80211_ops wl1271_ops = { | |||
1925 | .add_interface = wl1271_op_add_interface, | 1912 | .add_interface = wl1271_op_add_interface, |
1926 | .remove_interface = wl1271_op_remove_interface, | 1913 | .remove_interface = wl1271_op_remove_interface, |
1927 | .config = wl1271_op_config, | 1914 | .config = wl1271_op_config, |
1928 | /* .config_interface = wl1271_op_config_interface, */ | ||
1929 | .prepare_multicast = wl1271_op_prepare_multicast, | 1915 | .prepare_multicast = wl1271_op_prepare_multicast, |
1930 | .configure_filter = wl1271_op_configure_filter, | 1916 | .configure_filter = wl1271_op_configure_filter, |
1931 | .tx = wl1271_op_tx, | 1917 | .tx = wl1271_op_tx, |
@@ -1937,6 +1923,68 @@ static const struct ieee80211_ops wl1271_ops = { | |||
1937 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) | 1923 | CFG80211_TESTMODE_CMD(wl1271_tm_cmd) |
1938 | }; | 1924 | }; |
1939 | 1925 | ||
1926 | static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev, | ||
1927 | struct device_attribute *attr, | ||
1928 | char *buf) | ||
1929 | { | ||
1930 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
1931 | ssize_t len; | ||
1932 | |||
1933 | /* FIXME: what's the maximum length of buf? page size?*/ | ||
1934 | len = 500; | ||
1935 | |||
1936 | mutex_lock(&wl->mutex); | ||
1937 | len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n", | ||
1938 | wl->sg_enabled); | ||
1939 | mutex_unlock(&wl->mutex); | ||
1940 | |||
1941 | return len; | ||
1942 | |||
1943 | } | ||
1944 | |||
1945 | static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, | ||
1946 | struct device_attribute *attr, | ||
1947 | const char *buf, size_t count) | ||
1948 | { | ||
1949 | struct wl1271 *wl = dev_get_drvdata(dev); | ||
1950 | unsigned long res; | ||
1951 | int ret; | ||
1952 | |||
1953 | ret = strict_strtoul(buf, 10, &res); | ||
1954 | |||
1955 | if (ret < 0) { | ||
1956 | wl1271_warning("incorrect value written to bt_coex_mode"); | ||
1957 | return count; | ||
1958 | } | ||
1959 | |||
1960 | mutex_lock(&wl->mutex); | ||
1961 | |||
1962 | res = !!res; | ||
1963 | |||
1964 | if (res == wl->sg_enabled) | ||
1965 | goto out; | ||
1966 | |||
1967 | wl->sg_enabled = res; | ||
1968 | |||
1969 | if (wl->state == WL1271_STATE_OFF) | ||
1970 | goto out; | ||
1971 | |||
1972 | ret = wl1271_ps_elp_wakeup(wl, false); | ||
1973 | if (ret < 0) | ||
1974 | goto out; | ||
1975 | |||
1976 | wl1271_acx_sg_enable(wl, wl->sg_enabled); | ||
1977 | wl1271_ps_elp_sleep(wl); | ||
1978 | |||
1979 | out: | ||
1980 | mutex_unlock(&wl->mutex); | ||
1981 | return count; | ||
1982 | } | ||
1983 | |||
1984 | static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, | ||
1985 | wl1271_sysfs_show_bt_coex_state, | ||
1986 | wl1271_sysfs_store_bt_coex_state); | ||
1987 | |||
1940 | int wl1271_register_hw(struct wl1271 *wl) | 1988 | int wl1271_register_hw(struct wl1271 *wl) |
1941 | { | 1989 | { |
1942 | int ret; | 1990 | int ret; |
@@ -1960,6 +2008,14 @@ int wl1271_register_hw(struct wl1271 *wl) | |||
1960 | } | 2008 | } |
1961 | EXPORT_SYMBOL_GPL(wl1271_register_hw); | 2009 | EXPORT_SYMBOL_GPL(wl1271_register_hw); |
1962 | 2010 | ||
2011 | void wl1271_unregister_hw(struct wl1271 *wl) | ||
2012 | { | ||
2013 | ieee80211_unregister_hw(wl->hw); | ||
2014 | wl->mac80211_registered = false; | ||
2015 | |||
2016 | } | ||
2017 | EXPORT_SYMBOL_GPL(wl1271_unregister_hw); | ||
2018 | |||
1963 | int wl1271_init_ieee80211(struct wl1271 *wl) | 2019 | int wl1271_init_ieee80211(struct wl1271 *wl) |
1964 | { | 2020 | { |
1965 | /* The tx descriptor buffer and the TKIP space. */ | 2021 | /* The tx descriptor buffer and the TKIP space. */ |
@@ -1974,6 +2030,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl) | |||
1974 | IEEE80211_HW_NOISE_DBM | | 2030 | IEEE80211_HW_NOISE_DBM | |
1975 | IEEE80211_HW_BEACON_FILTER | | 2031 | IEEE80211_HW_BEACON_FILTER | |
1976 | IEEE80211_HW_SUPPORTS_PS | | 2032 | IEEE80211_HW_SUPPORTS_PS | |
2033 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
1977 | IEEE80211_HW_HAS_RATE_CONTROL; | 2034 | IEEE80211_HW_HAS_RATE_CONTROL; |
1978 | 2035 | ||
1979 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 2036 | wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
@@ -1984,6 +2041,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl) | |||
1984 | if (wl1271_11a_enabled()) | 2041 | if (wl1271_11a_enabled()) |
1985 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; | 2042 | wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz; |
1986 | 2043 | ||
2044 | wl->hw->queues = 4; | ||
2045 | |||
1987 | SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); | 2046 | SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl)); |
1988 | 2047 | ||
1989 | return 0; | 2048 | return 0; |
@@ -1995,21 +2054,34 @@ EXPORT_SYMBOL_GPL(wl1271_init_ieee80211); | |||
1995 | struct ieee80211_hw *wl1271_alloc_hw(void) | 2054 | struct ieee80211_hw *wl1271_alloc_hw(void) |
1996 | { | 2055 | { |
1997 | struct ieee80211_hw *hw; | 2056 | struct ieee80211_hw *hw; |
2057 | struct platform_device *plat_dev = NULL; | ||
1998 | struct wl1271 *wl; | 2058 | struct wl1271 *wl; |
1999 | int i; | 2059 | int i, ret; |
2060 | static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf}; | ||
2000 | 2061 | ||
2001 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); | 2062 | hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); |
2002 | if (!hw) { | 2063 | if (!hw) { |
2003 | wl1271_error("could not alloc ieee80211_hw"); | 2064 | wl1271_error("could not alloc ieee80211_hw"); |
2004 | return ERR_PTR(-ENOMEM); | 2065 | ret = -ENOMEM; |
2066 | goto err_hw_alloc; | ||
2005 | } | 2067 | } |
2006 | 2068 | ||
2069 | plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL); | ||
2070 | if (!plat_dev) { | ||
2071 | wl1271_error("could not allocate platform_device"); | ||
2072 | ret = -ENOMEM; | ||
2073 | goto err_plat_alloc; | ||
2074 | } | ||
2075 | |||
2076 | memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device)); | ||
2077 | |||
2007 | wl = hw->priv; | 2078 | wl = hw->priv; |
2008 | memset(wl, 0, sizeof(*wl)); | 2079 | memset(wl, 0, sizeof(*wl)); |
2009 | 2080 | ||
2010 | INIT_LIST_HEAD(&wl->list); | 2081 | INIT_LIST_HEAD(&wl->list); |
2011 | 2082 | ||
2012 | wl->hw = hw; | 2083 | wl->hw = hw; |
2084 | wl->plat_dev = plat_dev; | ||
2013 | 2085 | ||
2014 | skb_queue_head_init(&wl->tx_queue); | 2086 | skb_queue_head_init(&wl->tx_queue); |
2015 | 2087 | ||
@@ -2027,6 +2099,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2027 | wl->band = IEEE80211_BAND_2GHZ; | 2099 | wl->band = IEEE80211_BAND_2GHZ; |
2028 | wl->vif = NULL; | 2100 | wl->vif = NULL; |
2029 | wl->flags = 0; | 2101 | wl->flags = 0; |
2102 | wl->sg_enabled = true; | ||
2030 | 2103 | ||
2031 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | 2104 | for (i = 0; i < ACX_TX_DESCRIPTORS; i++) |
2032 | wl->tx_frames[i] = NULL; | 2105 | wl->tx_frames[i] = NULL; |
@@ -2036,18 +2109,55 @@ struct ieee80211_hw *wl1271_alloc_hw(void) | |||
2036 | wl->state = WL1271_STATE_OFF; | 2109 | wl->state = WL1271_STATE_OFF; |
2037 | mutex_init(&wl->mutex); | 2110 | mutex_init(&wl->mutex); |
2038 | 2111 | ||
2112 | /* | ||
2113 | * FIXME: we should use a zero MAC address here, but for now we | ||
2114 | * generate a random Nokia address. | ||
2115 | */ | ||
2116 | memcpy(wl->mac_addr, nokia_oui, 3); | ||
2117 | get_random_bytes(wl->mac_addr + 3, 3); | ||
2118 | |||
2039 | /* Apply default driver configuration. */ | 2119 | /* Apply default driver configuration. */ |
2040 | wl1271_conf_init(wl); | 2120 | wl1271_conf_init(wl); |
2041 | 2121 | ||
2042 | wl1271_debugfs_init(wl); | 2122 | wl1271_debugfs_init(wl); |
2043 | 2123 | ||
2124 | /* Register platform device */ | ||
2125 | ret = platform_device_register(wl->plat_dev); | ||
2126 | if (ret) { | ||
2127 | wl1271_error("couldn't register platform device"); | ||
2128 | goto err_hw; | ||
2129 | } | ||
2130 | dev_set_drvdata(&wl->plat_dev->dev, wl); | ||
2131 | |||
2132 | /* Create sysfs file to control bt coex state */ | ||
2133 | ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); | ||
2134 | if (ret < 0) { | ||
2135 | wl1271_error("failed to create sysfs file bt_coex_state"); | ||
2136 | goto err_platform; | ||
2137 | } | ||
2138 | |||
2044 | return hw; | 2139 | return hw; |
2140 | |||
2141 | err_platform: | ||
2142 | platform_device_unregister(wl->plat_dev); | ||
2143 | |||
2144 | err_hw: | ||
2145 | wl1271_debugfs_exit(wl); | ||
2146 | kfree(plat_dev); | ||
2147 | |||
2148 | err_plat_alloc: | ||
2149 | ieee80211_free_hw(hw); | ||
2150 | |||
2151 | err_hw_alloc: | ||
2152 | |||
2153 | return ERR_PTR(ret); | ||
2045 | } | 2154 | } |
2046 | EXPORT_SYMBOL_GPL(wl1271_alloc_hw); | 2155 | EXPORT_SYMBOL_GPL(wl1271_alloc_hw); |
2047 | 2156 | ||
2048 | int wl1271_free_hw(struct wl1271 *wl) | 2157 | int wl1271_free_hw(struct wl1271 *wl) |
2049 | { | 2158 | { |
2050 | ieee80211_unregister_hw(wl->hw); | 2159 | platform_device_unregister(wl->plat_dev); |
2160 | kfree(wl->plat_dev); | ||
2051 | 2161 | ||
2052 | wl1271_debugfs_exit(wl); | 2162 | wl1271_debugfs_exit(wl); |
2053 | 2163 | ||
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c index 1f204db30c27..3c03de74dbfc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_sdio.c +++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c | |||
@@ -102,15 +102,14 @@ static void wl1271_sdio_init(struct wl1271 *wl) | |||
102 | } | 102 | } |
103 | 103 | ||
104 | static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, | 104 | static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, |
105 | size_t len, bool fixed) | 105 | size_t len, bool fixed) |
106 | { | 106 | { |
107 | int ret; | 107 | int ret; |
108 | struct sdio_func *func = wl_to_func(wl); | 108 | struct sdio_func *func = wl_to_func(wl); |
109 | 109 | ||
110 | sdio_claim_host(func); | ||
111 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | 110 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { |
112 | ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); | 111 | ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret); |
113 | wl1271_debug(DEBUG_SPI, "sdio read 52 addr 0x%x, byte 0x%02x", | 112 | wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x", |
114 | addr, ((u8 *)buf)[0]); | 113 | addr, ((u8 *)buf)[0]); |
115 | } else { | 114 | } else { |
116 | if (fixed) | 115 | if (fixed) |
@@ -118,32 +117,30 @@ static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf, | |||
118 | else | 117 | else |
119 | ret = sdio_memcpy_fromio(func, buf, addr, len); | 118 | ret = sdio_memcpy_fromio(func, buf, addr, len); |
120 | 119 | ||
121 | wl1271_debug(DEBUG_SPI, "sdio read 53 addr 0x%x, %d bytes", | 120 | wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %d bytes", |
122 | addr, len); | 121 | addr, len); |
123 | wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len); | 122 | wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); |
124 | } | 123 | } |
125 | 124 | ||
126 | if (ret) | 125 | if (ret) |
127 | wl1271_error("sdio read failed (%d)", ret); | 126 | wl1271_error("sdio read failed (%d)", ret); |
128 | 127 | ||
129 | sdio_release_host(func); | ||
130 | } | 128 | } |
131 | 129 | ||
132 | static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, | 130 | static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, |
133 | size_t len, bool fixed) | 131 | size_t len, bool fixed) |
134 | { | 132 | { |
135 | int ret; | 133 | int ret; |
136 | struct sdio_func *func = wl_to_func(wl); | 134 | struct sdio_func *func = wl_to_func(wl); |
137 | 135 | ||
138 | sdio_claim_host(func); | ||
139 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { | 136 | if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) { |
140 | sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); | 137 | sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret); |
141 | wl1271_debug(DEBUG_SPI, "sdio write 52 addr 0x%x, byte 0x%02x", | 138 | wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x", |
142 | addr, ((u8 *)buf)[0]); | 139 | addr, ((u8 *)buf)[0]); |
143 | } else { | 140 | } else { |
144 | wl1271_debug(DEBUG_SPI, "sdio write 53 addr 0x%x, %d bytes", | 141 | wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %d bytes", |
145 | addr, len); | 142 | addr, len); |
146 | wl1271_dump_ascii(DEBUG_SPI, "data: ", buf, len); | 143 | wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len); |
147 | 144 | ||
148 | if (fixed) | 145 | if (fixed) |
149 | ret = sdio_writesb(func, addr, buf, len); | 146 | ret = sdio_writesb(func, addr, buf, len); |
@@ -153,7 +150,23 @@ static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf, | |||
153 | if (ret) | 150 | if (ret) |
154 | wl1271_error("sdio write failed (%d)", ret); | 151 | wl1271_error("sdio write failed (%d)", ret); |
155 | 152 | ||
156 | sdio_release_host(func); | 153 | } |
154 | |||
155 | static void wl1271_sdio_set_power(struct wl1271 *wl, bool enable) | ||
156 | { | ||
157 | struct sdio_func *func = wl_to_func(wl); | ||
158 | |||
159 | /* Let the SDIO stack handle wlan_enable control, so we | ||
160 | * keep host claimed while wlan is in use to keep wl1271 | ||
161 | * alive. | ||
162 | */ | ||
163 | if (enable) { | ||
164 | sdio_claim_host(func); | ||
165 | sdio_enable_func(func); | ||
166 | } else { | ||
167 | sdio_disable_func(func); | ||
168 | sdio_release_host(func); | ||
169 | } | ||
157 | } | 170 | } |
158 | 171 | ||
159 | static struct wl1271_if_operations sdio_ops = { | 172 | static struct wl1271_if_operations sdio_ops = { |
@@ -161,15 +174,12 @@ static struct wl1271_if_operations sdio_ops = { | |||
161 | .write = wl1271_sdio_raw_write, | 174 | .write = wl1271_sdio_raw_write, |
162 | .reset = wl1271_sdio_reset, | 175 | .reset = wl1271_sdio_reset, |
163 | .init = wl1271_sdio_init, | 176 | .init = wl1271_sdio_init, |
177 | .power = wl1271_sdio_set_power, | ||
164 | .dev = wl1271_sdio_wl_to_dev, | 178 | .dev = wl1271_sdio_wl_to_dev, |
165 | .enable_irq = wl1271_sdio_enable_interrupts, | 179 | .enable_irq = wl1271_sdio_enable_interrupts, |
166 | .disable_irq = wl1271_sdio_disable_interrupts | 180 | .disable_irq = wl1271_sdio_disable_interrupts |
167 | }; | 181 | }; |
168 | 182 | ||
169 | static void wl1271_sdio_set_power(bool enable) | ||
170 | { | ||
171 | } | ||
172 | |||
173 | static int __devinit wl1271_probe(struct sdio_func *func, | 183 | static int __devinit wl1271_probe(struct sdio_func *func, |
174 | const struct sdio_device_id *id) | 184 | const struct sdio_device_id *id) |
175 | { | 185 | { |
@@ -190,8 +200,6 @@ static int __devinit wl1271_probe(struct sdio_func *func, | |||
190 | wl->if_priv = func; | 200 | wl->if_priv = func; |
191 | wl->if_ops = &sdio_ops; | 201 | wl->if_ops = &sdio_ops; |
192 | 202 | ||
193 | wl->set_power = wl1271_sdio_set_power; | ||
194 | |||
195 | /* Grab access to FN0 for ELP reg. */ | 203 | /* Grab access to FN0 for ELP reg. */ |
196 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | 204 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; |
197 | 205 | ||
@@ -220,28 +228,18 @@ static int __devinit wl1271_probe(struct sdio_func *func, | |||
220 | if (ret) | 228 | if (ret) |
221 | goto out_irq; | 229 | goto out_irq; |
222 | 230 | ||
223 | sdio_claim_host(func); | ||
224 | sdio_set_drvdata(func, wl); | 231 | sdio_set_drvdata(func, wl); |
225 | 232 | ||
226 | ret = sdio_enable_func(func); | ||
227 | if (ret) | ||
228 | goto out_release; | ||
229 | |||
230 | sdio_release_host(func); | ||
231 | |||
232 | wl1271_notice("initialized"); | 233 | wl1271_notice("initialized"); |
233 | 234 | ||
234 | return 0; | 235 | return 0; |
235 | 236 | ||
236 | out_release: | ||
237 | sdio_release_host(func); | ||
238 | |||
239 | out_irq: | 237 | out_irq: |
240 | free_irq(wl->irq, wl); | 238 | free_irq(wl->irq, wl); |
241 | 239 | ||
242 | 240 | ||
243 | out_free: | 241 | out_free: |
244 | ieee80211_free_hw(hw); | 242 | wl1271_free_hw(wl); |
245 | 243 | ||
246 | return ret; | 244 | return ret; |
247 | } | 245 | } |
@@ -250,24 +248,10 @@ static void __devexit wl1271_remove(struct sdio_func *func) | |||
250 | { | 248 | { |
251 | struct wl1271 *wl = sdio_get_drvdata(func); | 249 | struct wl1271 *wl = sdio_get_drvdata(func); |
252 | 250 | ||
253 | ieee80211_unregister_hw(wl->hw); | ||
254 | |||
255 | sdio_claim_host(func); | ||
256 | sdio_disable_func(func); | ||
257 | sdio_release_host(func); | ||
258 | |||
259 | free_irq(wl->irq, wl); | 251 | free_irq(wl->irq, wl); |
260 | 252 | ||
261 | kfree(wl->target_mem_map); | 253 | wl1271_unregister_hw(wl); |
262 | vfree(wl->fw); | 254 | wl1271_free_hw(wl); |
263 | wl->fw = NULL; | ||
264 | kfree(wl->nvs); | ||
265 | wl->nvs = NULL; | ||
266 | |||
267 | kfree(wl->fw_status); | ||
268 | kfree(wl->tx_res_if); | ||
269 | |||
270 | ieee80211_free_hw(wl->hw); | ||
271 | } | 255 | } |
272 | 256 | ||
273 | static struct sdio_driver wl1271_sdio_driver = { | 257 | static struct sdio_driver wl1271_sdio_driver = { |
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.c b/drivers/net/wireless/wl12xx/wl1271_spi.c index ed285fec2a08..f44b05a32b0d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_spi.c +++ b/drivers/net/wireless/wl12xx/wl1271_spi.c | |||
@@ -23,7 +23,6 @@ | |||
23 | 23 | ||
24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/crc7.h> | 26 | #include <linux/crc7.h> |
28 | #include <linux/spi/spi.h> | 27 | #include <linux/spi/spi.h> |
29 | #include <linux/spi/wl12xx.h> | 28 | #include <linux/spi/wl12xx.h> |
@@ -332,26 +331,18 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) | |||
332 | return IRQ_HANDLED; | 331 | return IRQ_HANDLED; |
333 | } | 332 | } |
334 | 333 | ||
335 | static void wl1271_device_release(struct device *dev) | 334 | static void wl1271_spi_set_power(struct wl1271 *wl, bool enable) |
336 | { | 335 | { |
337 | 336 | if (wl->set_power) | |
337 | wl->set_power(enable); | ||
338 | } | 338 | } |
339 | 339 | ||
340 | static struct platform_device wl1271_device = { | ||
341 | .name = "wl1271", | ||
342 | .id = -1, | ||
343 | |||
344 | /* device model insists to have a release function */ | ||
345 | .dev = { | ||
346 | .release = wl1271_device_release, | ||
347 | }, | ||
348 | }; | ||
349 | |||
350 | static struct wl1271_if_operations spi_ops = { | 340 | static struct wl1271_if_operations spi_ops = { |
351 | .read = wl1271_spi_raw_read, | 341 | .read = wl1271_spi_raw_read, |
352 | .write = wl1271_spi_raw_write, | 342 | .write = wl1271_spi_raw_write, |
353 | .reset = wl1271_spi_reset, | 343 | .reset = wl1271_spi_reset, |
354 | .init = wl1271_spi_init, | 344 | .init = wl1271_spi_init, |
345 | .power = wl1271_spi_set_power, | ||
355 | .dev = wl1271_spi_wl_to_dev, | 346 | .dev = wl1271_spi_wl_to_dev, |
356 | .enable_irq = wl1271_spi_enable_interrupts, | 347 | .enable_irq = wl1271_spi_enable_interrupts, |
357 | .disable_irq = wl1271_spi_disable_interrupts | 348 | .disable_irq = wl1271_spi_disable_interrupts |
@@ -415,33 +406,23 @@ static int __devinit wl1271_probe(struct spi_device *spi) | |||
415 | 406 | ||
416 | disable_irq(wl->irq); | 407 | disable_irq(wl->irq); |
417 | 408 | ||
418 | ret = platform_device_register(&wl1271_device); | ||
419 | if (ret) { | ||
420 | wl1271_error("couldn't register platform device"); | ||
421 | goto out_irq; | ||
422 | } | ||
423 | dev_set_drvdata(&wl1271_device.dev, wl); | ||
424 | |||
425 | ret = wl1271_init_ieee80211(wl); | 409 | ret = wl1271_init_ieee80211(wl); |
426 | if (ret) | 410 | if (ret) |
427 | goto out_platform; | 411 | goto out_irq; |
428 | 412 | ||
429 | ret = wl1271_register_hw(wl); | 413 | ret = wl1271_register_hw(wl); |
430 | if (ret) | 414 | if (ret) |
431 | goto out_platform; | 415 | goto out_irq; |
432 | 416 | ||
433 | wl1271_notice("initialized"); | 417 | wl1271_notice("initialized"); |
434 | 418 | ||
435 | return 0; | 419 | return 0; |
436 | 420 | ||
437 | out_platform: | ||
438 | platform_device_unregister(&wl1271_device); | ||
439 | |||
440 | out_irq: | 421 | out_irq: |
441 | free_irq(wl->irq, wl); | 422 | free_irq(wl->irq, wl); |
442 | 423 | ||
443 | out_free: | 424 | out_free: |
444 | ieee80211_free_hw(hw); | 425 | wl1271_free_hw(wl); |
445 | 426 | ||
446 | return ret; | 427 | return ret; |
447 | } | 428 | } |
@@ -450,9 +431,9 @@ static int __devexit wl1271_remove(struct spi_device *spi) | |||
450 | { | 431 | { |
451 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); | 432 | struct wl1271 *wl = dev_get_drvdata(&spi->dev); |
452 | 433 | ||
453 | platform_device_unregister(&wl1271_device); | ||
454 | free_irq(wl->irq, wl); | 434 | free_irq(wl->irq, wl); |
455 | 435 | ||
436 | wl1271_unregister_hw(wl); | ||
456 | wl1271_free_hw(wl); | 437 | wl1271_free_hw(wl); |
457 | 438 | ||
458 | return 0; | 439 | return 0; |
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index 8b9f6b4f5652..5e6c27a57415 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h | |||
@@ -125,9 +125,6 @@ struct wl1271_tx_hw_res_if { | |||
125 | 125 | ||
126 | static inline int wl1271_tx_get_queue(int queue) | 126 | static inline int wl1271_tx_get_queue(int queue) |
127 | { | 127 | { |
128 | /* FIXME: use best effort until WMM is enabled */ | ||
129 | return CONF_TX_AC_BE; | ||
130 | |||
131 | switch (queue) { | 128 | switch (queue) { |
132 | case 0: | 129 | case 0: |
133 | return CONF_TX_AC_VO; | 130 | return CONF_TX_AC_VO; |
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 7b9621de239f..65dd502eab0d 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -1834,32 +1834,32 @@ out: | |||
1834 | } | 1834 | } |
1835 | 1835 | ||
1836 | static const iw_handler wl3501_handler[] = { | 1836 | static const iw_handler wl3501_handler[] = { |
1837 | [SIOCGIWNAME - SIOCIWFIRST] = wl3501_get_name, | 1837 | IW_HANDLER(SIOCGIWNAME, wl3501_get_name), |
1838 | [SIOCSIWFREQ - SIOCIWFIRST] = wl3501_set_freq, | 1838 | IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq), |
1839 | [SIOCGIWFREQ - SIOCIWFIRST] = wl3501_get_freq, | 1839 | IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq), |
1840 | [SIOCSIWMODE - SIOCIWFIRST] = wl3501_set_mode, | 1840 | IW_HANDLER(SIOCSIWMODE, wl3501_set_mode), |
1841 | [SIOCGIWMODE - SIOCIWFIRST] = wl3501_get_mode, | 1841 | IW_HANDLER(SIOCGIWMODE, wl3501_get_mode), |
1842 | [SIOCGIWSENS - SIOCIWFIRST] = wl3501_get_sens, | 1842 | IW_HANDLER(SIOCGIWSENS, wl3501_get_sens), |
1843 | [SIOCGIWRANGE - SIOCIWFIRST] = wl3501_get_range, | 1843 | IW_HANDLER(SIOCGIWRANGE, wl3501_get_range), |
1844 | [SIOCSIWSPY - SIOCIWFIRST] = iw_handler_set_spy, | 1844 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), |
1845 | [SIOCGIWSPY - SIOCIWFIRST] = iw_handler_get_spy, | 1845 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), |
1846 | [SIOCSIWTHRSPY - SIOCIWFIRST] = iw_handler_set_thrspy, | 1846 | IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), |
1847 | [SIOCGIWTHRSPY - SIOCIWFIRST] = iw_handler_get_thrspy, | 1847 | IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), |
1848 | [SIOCSIWAP - SIOCIWFIRST] = wl3501_set_wap, | 1848 | IW_HANDLER(SIOCSIWAP, wl3501_set_wap), |
1849 | [SIOCGIWAP - SIOCIWFIRST] = wl3501_get_wap, | 1849 | IW_HANDLER(SIOCGIWAP, wl3501_get_wap), |
1850 | [SIOCSIWSCAN - SIOCIWFIRST] = wl3501_set_scan, | 1850 | IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan), |
1851 | [SIOCGIWSCAN - SIOCIWFIRST] = wl3501_get_scan, | 1851 | IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan), |
1852 | [SIOCSIWESSID - SIOCIWFIRST] = wl3501_set_essid, | 1852 | IW_HANDLER(SIOCSIWESSID, wl3501_set_essid), |
1853 | [SIOCGIWESSID - SIOCIWFIRST] = wl3501_get_essid, | 1853 | IW_HANDLER(SIOCGIWESSID, wl3501_get_essid), |
1854 | [SIOCSIWNICKN - SIOCIWFIRST] = wl3501_set_nick, | 1854 | IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick), |
1855 | [SIOCGIWNICKN - SIOCIWFIRST] = wl3501_get_nick, | 1855 | IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick), |
1856 | [SIOCGIWRATE - SIOCIWFIRST] = wl3501_get_rate, | 1856 | IW_HANDLER(SIOCGIWRATE, wl3501_get_rate), |
1857 | [SIOCGIWRTS - SIOCIWFIRST] = wl3501_get_rts_threshold, | 1857 | IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold), |
1858 | [SIOCGIWFRAG - SIOCIWFIRST] = wl3501_get_frag_threshold, | 1858 | IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold), |
1859 | [SIOCGIWTXPOW - SIOCIWFIRST] = wl3501_get_txpow, | 1859 | IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow), |
1860 | [SIOCGIWRETRY - SIOCIWFIRST] = wl3501_get_retry, | 1860 | IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry), |
1861 | [SIOCGIWENCODE - SIOCIWFIRST] = wl3501_get_encode, | 1861 | IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode), |
1862 | [SIOCGIWPOWER - SIOCIWFIRST] = wl3501_get_power, | 1862 | IW_HANDLER(SIOCGIWPOWER, wl3501_get_power), |
1863 | }; | 1863 | }; |
1864 | 1864 | ||
1865 | static const struct iw_handler_def wl3501_handler_def = { | 1865 | static const struct iw_handler_def wl3501_handler_def = { |