diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-06-04 06:56:01 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-06-04 07:02:42 -0400 |
commit | 51217cee3a94d5409d6ee2ac090ae96bc9a06757 (patch) | |
tree | 373c5ebf9e87ef81feb1d02feaf06f673fcf9a13 | |
parent | ff40b425f04144771920b79672d6691910c7def7 (diff) | |
parent | 99e94940697adec4f84758adb2db71f4a82c7ba5 (diff) |
Merge remote-tracking branch 'wireless-next/master' into HEAD
Merge to get the wil6210 changes that a cfg80211 change needs.
A conflict in drivers/net/wireless/ath/ath9k/init.c was just
whitespace changes.
Also fix a semantic conflict due to cw1200 using WoWLAN which
I had modified in my tree.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
161 files changed, 19929 insertions, 1995 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 3d7782b9f90d..e5069c223391 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2299,6 +2299,11 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com> | |||
2299 | S: Maintained | 2299 | S: Maintained |
2300 | F: sound/pci/cs5535audio/ | 2300 | F: sound/pci/cs5535audio/ |
2301 | 2301 | ||
2302 | CW1200 WLAN driver | ||
2303 | M: Solomon Peachy <pizza@shaftnet.org> | ||
2304 | S: Maintained | ||
2305 | F: drivers/net/wireless/cw1200/ | ||
2306 | |||
2302 | CX18 VIDEO4LINUX DRIVER | 2307 | CX18 VIDEO4LINUX DRIVER |
2303 | M: Andy Walls <awalls@md.metrocast.net> | 2308 | M: Andy Walls <awalls@md.metrocast.net> |
2304 | L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) | 2309 | L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) |
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 8934298a638d..de15b4f4b237 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c | |||
@@ -72,12 +72,12 @@ fail: | |||
72 | * R/W ops. | 72 | * R/W ops. |
73 | **************************************************/ | 73 | **************************************************/ |
74 | 74 | ||
75 | static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom) | 75 | static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom, |
76 | size_t words) | ||
76 | { | 77 | { |
77 | int i; | 78 | int i; |
78 | for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++) | 79 | for (i = 0; i < words; i++) |
79 | sprom[i] = bcma_read16(bus->drv_cc.core, | 80 | sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2)); |
80 | offset + (i * 2)); | ||
81 | } | 81 | } |
82 | 82 | ||
83 | /************************************************** | 83 | /************************************************** |
@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data) | |||
124 | return t[crc ^ data]; | 124 | return t[crc ^ data]; |
125 | } | 125 | } |
126 | 126 | ||
127 | static u8 bcma_sprom_crc(const u16 *sprom) | 127 | static u8 bcma_sprom_crc(const u16 *sprom, size_t words) |
128 | { | 128 | { |
129 | int word; | 129 | int word; |
130 | u8 crc = 0xFF; | 130 | u8 crc = 0xFF; |
131 | 131 | ||
132 | for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) { | 132 | for (word = 0; word < words - 1; word++) { |
133 | crc = bcma_crc8(crc, sprom[word] & 0x00FF); | 133 | crc = bcma_crc8(crc, sprom[word] & 0x00FF); |
134 | crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8); | 134 | crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8); |
135 | } | 135 | } |
136 | crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF); | 136 | crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF); |
137 | crc ^= 0xFF; | 137 | crc ^= 0xFF; |
138 | 138 | ||
139 | return crc; | 139 | return crc; |
140 | } | 140 | } |
141 | 141 | ||
142 | static int bcma_sprom_check_crc(const u16 *sprom) | 142 | static int bcma_sprom_check_crc(const u16 *sprom, size_t words) |
143 | { | 143 | { |
144 | u8 crc; | 144 | u8 crc; |
145 | u8 expected_crc; | 145 | u8 expected_crc; |
146 | u16 tmp; | 146 | u16 tmp; |
147 | 147 | ||
148 | crc = bcma_sprom_crc(sprom); | 148 | crc = bcma_sprom_crc(sprom, words); |
149 | tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC; | 149 | tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC; |
150 | expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; | 150 | expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; |
151 | if (crc != expected_crc) | 151 | if (crc != expected_crc) |
152 | return -EPROTO; | 152 | return -EPROTO; |
@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom) | |||
154 | return 0; | 154 | return 0; |
155 | } | 155 | } |
156 | 156 | ||
157 | static int bcma_sprom_valid(const u16 *sprom) | 157 | static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom, |
158 | size_t words) | ||
158 | { | 159 | { |
159 | u16 revision; | 160 | u16 revision; |
160 | int err; | 161 | int err; |
161 | 162 | ||
162 | err = bcma_sprom_check_crc(sprom); | 163 | err = bcma_sprom_check_crc(sprom, words); |
163 | if (err) | 164 | if (err) |
164 | return err; | 165 | return err; |
165 | 166 | ||
166 | revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV; | 167 | revision = sprom[words - 1] & SSB_SPROM_REVISION_REV; |
167 | if (revision != 8 && revision != 9) { | 168 | if (revision != 8 && revision != 9 && revision != 10) { |
168 | pr_err("Unsupported SPROM revision: %d\n", revision); | 169 | pr_err("Unsupported SPROM revision: %d\n", revision); |
169 | return -ENOENT; | 170 | return -ENOENT; |
170 | } | 171 | } |
171 | 172 | ||
173 | bus->sprom.revision = revision; | ||
174 | bcma_debug(bus, "Found SPROM revision %d\n", revision); | ||
175 | |||
172 | return 0; | 176 | return 0; |
173 | } | 177 | } |
174 | 178 | ||
@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) | |||
208 | BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != | 212 | BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) != |
209 | ARRAY_SIZE(bus->sprom.core_pwr_info)); | 213 | ARRAY_SIZE(bus->sprom.core_pwr_info)); |
210 | 214 | ||
211 | bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & | ||
212 | SSB_SPROM_REVISION_REV; | ||
213 | |||
214 | for (i = 0; i < 3; i++) { | 215 | for (i = 0; i < 3; i++) { |
215 | v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; | 216 | v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i]; |
216 | *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); | 217 | *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v); |
@@ -502,7 +503,6 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) | |||
502 | case BCMA_CHIP_ID_BCM4331: | 503 | case BCMA_CHIP_ID_BCM4331: |
503 | present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; | 504 | present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; |
504 | break; | 505 | break; |
505 | |||
506 | case BCMA_CHIP_ID_BCM43224: | 506 | case BCMA_CHIP_ID_BCM43224: |
507 | case BCMA_CHIP_ID_BCM43225: | 507 | case BCMA_CHIP_ID_BCM43225: |
508 | /* for these chips OTP is always available */ | 508 | /* for these chips OTP is always available */ |
@@ -550,7 +550,9 @@ int bcma_sprom_get(struct bcma_bus *bus) | |||
550 | { | 550 | { |
551 | u16 offset = BCMA_CC_SPROM; | 551 | u16 offset = BCMA_CC_SPROM; |
552 | u16 *sprom; | 552 | u16 *sprom; |
553 | int err = 0; | 553 | size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4, |
554 | SSB_SPROMSIZE_WORDS_R10, }; | ||
555 | int i, err = 0; | ||
554 | 556 | ||
555 | if (!bus->drv_cc.core) | 557 | if (!bus->drv_cc.core) |
556 | return -EOPNOTSUPP; | 558 | return -EOPNOTSUPP; |
@@ -579,32 +581,37 @@ int bcma_sprom_get(struct bcma_bus *bus) | |||
579 | } | 581 | } |
580 | } | 582 | } |
581 | 583 | ||
582 | sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), | ||
583 | GFP_KERNEL); | ||
584 | if (!sprom) | ||
585 | return -ENOMEM; | ||
586 | |||
587 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || | 584 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || |
588 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) | 585 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) |
589 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); | 586 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); |
590 | 587 | ||
591 | bcma_debug(bus, "SPROM offset 0x%x\n", offset); | 588 | bcma_debug(bus, "SPROM offset 0x%x\n", offset); |
592 | bcma_sprom_read(bus, offset, sprom); | 589 | for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) { |
590 | size_t words = sprom_sizes[i]; | ||
591 | |||
592 | sprom = kcalloc(words, sizeof(u16), GFP_KERNEL); | ||
593 | if (!sprom) | ||
594 | return -ENOMEM; | ||
595 | |||
596 | bcma_sprom_read(bus, offset, sprom, words); | ||
597 | err = bcma_sprom_valid(bus, sprom, words); | ||
598 | if (!err) | ||
599 | break; | ||
600 | |||
601 | kfree(sprom); | ||
602 | } | ||
593 | 603 | ||
594 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || | 604 | if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || |
595 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) | 605 | bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) |
596 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); | 606 | bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); |
597 | 607 | ||
598 | err = bcma_sprom_valid(sprom); | ||
599 | if (err) { | 608 | if (err) { |
600 | bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n"); | 609 | bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n"); |
601 | err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); | 610 | err = bcma_fill_sprom_with_fallback(bus, &bus->sprom); |
602 | goto out; | 611 | } else { |
612 | bcma_sprom_extract_r8(bus, sprom); | ||
613 | kfree(sprom); | ||
603 | } | 614 | } |
604 | 615 | ||
605 | bcma_sprom_extract_r8(bus, sprom); | ||
606 | |||
607 | out: | ||
608 | kfree(sprom); | ||
609 | return err; | 616 | return err; |
610 | } | 617 | } |
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f8f0156dff4e..200020eb3005 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -280,5 +280,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig" | |||
280 | source "drivers/net/wireless/ti/Kconfig" | 280 | source "drivers/net/wireless/ti/Kconfig" |
281 | source "drivers/net/wireless/zd1211rw/Kconfig" | 281 | source "drivers/net/wireless/zd1211rw/Kconfig" |
282 | source "drivers/net/wireless/mwifiex/Kconfig" | 282 | source "drivers/net/wireless/mwifiex/Kconfig" |
283 | source "drivers/net/wireless/cw1200/Kconfig" | ||
283 | 284 | ||
284 | endif # WLAN | 285 | endif # WLAN |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 67156efe14c4..0fab227025be 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -57,3 +57,5 @@ obj-$(CONFIG_MWIFIEX) += mwifiex/ | |||
57 | 57 | ||
58 | obj-$(CONFIG_BRCMFMAC) += brcm80211/ | 58 | obj-$(CONFIG_BRCMFMAC) += brcm80211/ |
59 | obj-$(CONFIG_BRCMSMAC) += brcm80211/ | 59 | obj-$(CONFIG_BRCMSMAC) += brcm80211/ |
60 | |||
61 | obj-$(CONFIG_CW1200) += cw1200/ | ||
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 17507dc8a1e7..ec33c8007b29 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig | |||
@@ -84,14 +84,6 @@ config ATH9K_DFS_CERTIFIED | |||
84 | developed. At this point enabling this option won't do anything | 84 | developed. At this point enabling this option won't do anything |
85 | except increase code size. | 85 | except increase code size. |
86 | 86 | ||
87 | config ATH9K_MAC_DEBUG | ||
88 | bool "Atheros MAC statistics" | ||
89 | depends on ATH9K_DEBUGFS | ||
90 | default y | ||
91 | ---help--- | ||
92 | This option enables collection of statistics for Rx/Tx status | ||
93 | data and some other MAC related statistics | ||
94 | |||
95 | config ATH9K_RATE_CONTROL | 87 | config ATH9K_RATE_CONTROL |
96 | bool "Atheros ath9k rate control" | 88 | bool "Atheros ath9k rate control" |
97 | depends on ATH9K | 89 | depends on ATH9K |
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 7ecd40f07a74..e91725bf401c 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c | |||
@@ -118,10 +118,10 @@ static void ath9k_ani_restart(struct ath_hw *ah) | |||
118 | { | 118 | { |
119 | struct ar5416AniState *aniState; | 119 | struct ar5416AniState *aniState; |
120 | 120 | ||
121 | if (!DO_ANI(ah)) | 121 | if (!ah->curchan) |
122 | return; | 122 | return; |
123 | 123 | ||
124 | aniState = &ah->curchan->ani; | 124 | aniState = &ah->ani; |
125 | aniState->listenTime = 0; | 125 | aniState->listenTime = 0; |
126 | 126 | ||
127 | ENABLE_REGWRITE_BUFFER(ah); | 127 | ENABLE_REGWRITE_BUFFER(ah); |
@@ -143,7 +143,7 @@ static void ath9k_ani_restart(struct ath_hw *ah) | |||
143 | static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, | 143 | static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, |
144 | bool scan) | 144 | bool scan) |
145 | { | 145 | { |
146 | struct ar5416AniState *aniState = &ah->curchan->ani; | 146 | struct ar5416AniState *aniState = &ah->ani; |
147 | struct ath_common *common = ath9k_hw_common(ah); | 147 | struct ath_common *common = ath9k_hw_common(ah); |
148 | const struct ani_ofdm_level_entry *entry_ofdm; | 148 | const struct ani_ofdm_level_entry *entry_ofdm; |
149 | const struct ani_cck_level_entry *entry_cck; | 149 | const struct ani_cck_level_entry *entry_cck; |
@@ -195,10 +195,10 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) | |||
195 | { | 195 | { |
196 | struct ar5416AniState *aniState; | 196 | struct ar5416AniState *aniState; |
197 | 197 | ||
198 | if (!DO_ANI(ah)) | 198 | if (!ah->curchan) |
199 | return; | 199 | return; |
200 | 200 | ||
201 | aniState = &ah->curchan->ani; | 201 | aniState = &ah->ani; |
202 | 202 | ||
203 | if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) | 203 | if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) |
204 | ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); | 204 | ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); |
@@ -210,7 +210,7 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) | |||
210 | static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, | 210 | static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, |
211 | bool scan) | 211 | bool scan) |
212 | { | 212 | { |
213 | struct ar5416AniState *aniState = &ah->curchan->ani; | 213 | struct ar5416AniState *aniState = &ah->ani; |
214 | struct ath_common *common = ath9k_hw_common(ah); | 214 | struct ath_common *common = ath9k_hw_common(ah); |
215 | const struct ani_ofdm_level_entry *entry_ofdm; | 215 | const struct ani_ofdm_level_entry *entry_ofdm; |
216 | const struct ani_cck_level_entry *entry_cck; | 216 | const struct ani_cck_level_entry *entry_cck; |
@@ -251,10 +251,10 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) | |||
251 | { | 251 | { |
252 | struct ar5416AniState *aniState; | 252 | struct ar5416AniState *aniState; |
253 | 253 | ||
254 | if (!DO_ANI(ah)) | 254 | if (!ah->curchan) |
255 | return; | 255 | return; |
256 | 256 | ||
257 | aniState = &ah->curchan->ani; | 257 | aniState = &ah->ani; |
258 | 258 | ||
259 | if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) | 259 | if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) |
260 | ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, | 260 | ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, |
@@ -269,7 +269,7 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) | |||
269 | { | 269 | { |
270 | struct ar5416AniState *aniState; | 270 | struct ar5416AniState *aniState; |
271 | 271 | ||
272 | aniState = &ah->curchan->ani; | 272 | aniState = &ah->ani; |
273 | 273 | ||
274 | /* lower OFDM noise immunity */ | 274 | /* lower OFDM noise immunity */ |
275 | if (aniState->ofdmNoiseImmunityLevel > 0 && | 275 | if (aniState->ofdmNoiseImmunityLevel > 0 && |
@@ -292,12 +292,12 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) | |||
292 | */ | 292 | */ |
293 | void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) | 293 | void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) |
294 | { | 294 | { |
295 | struct ar5416AniState *aniState = &ah->curchan->ani; | 295 | struct ar5416AniState *aniState = &ah->ani; |
296 | struct ath9k_channel *chan = ah->curchan; | 296 | struct ath9k_channel *chan = ah->curchan; |
297 | struct ath_common *common = ath9k_hw_common(ah); | 297 | struct ath_common *common = ath9k_hw_common(ah); |
298 | int ofdm_nil, cck_nil; | 298 | int ofdm_nil, cck_nil; |
299 | 299 | ||
300 | if (!DO_ANI(ah)) | 300 | if (!ah->curchan) |
301 | return; | 301 | return; |
302 | 302 | ||
303 | BUG_ON(aniState == NULL); | 303 | BUG_ON(aniState == NULL); |
@@ -380,7 +380,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) | |||
380 | static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) | 380 | static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) |
381 | { | 381 | { |
382 | struct ath_common *common = ath9k_hw_common(ah); | 382 | struct ath_common *common = ath9k_hw_common(ah); |
383 | struct ar5416AniState *aniState = &ah->curchan->ani; | 383 | struct ar5416AniState *aniState = &ah->ani; |
384 | u32 phyCnt1, phyCnt2; | 384 | u32 phyCnt1, phyCnt2; |
385 | int32_t listenTime; | 385 | int32_t listenTime; |
386 | 386 | ||
@@ -415,10 +415,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) | |||
415 | struct ath_common *common = ath9k_hw_common(ah); | 415 | struct ath_common *common = ath9k_hw_common(ah); |
416 | u32 ofdmPhyErrRate, cckPhyErrRate; | 416 | u32 ofdmPhyErrRate, cckPhyErrRate; |
417 | 417 | ||
418 | if (!DO_ANI(ah)) | 418 | if (!ah->curchan) |
419 | return; | 419 | return; |
420 | 420 | ||
421 | aniState = &ah->curchan->ani; | 421 | aniState = &ah->ani; |
422 | if (!ath9k_hw_ani_read_counters(ah)) | 422 | if (!ath9k_hw_ani_read_counters(ah)) |
423 | return; | 423 | return; |
424 | 424 | ||
@@ -490,32 +490,22 @@ EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); | |||
490 | void ath9k_hw_ani_init(struct ath_hw *ah) | 490 | void ath9k_hw_ani_init(struct ath_hw *ah) |
491 | { | 491 | { |
492 | struct ath_common *common = ath9k_hw_common(ah); | 492 | struct ath_common *common = ath9k_hw_common(ah); |
493 | int i; | 493 | struct ar5416AniState *ani = &ah->ani; |
494 | 494 | ||
495 | ath_dbg(common, ANI, "Initialize ANI\n"); | 495 | ath_dbg(common, ANI, "Initialize ANI\n"); |
496 | 496 | ||
497 | ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; | 497 | ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; |
498 | ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; | 498 | ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; |
499 | |||
500 | ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; | 499 | ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; |
501 | ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; | 500 | ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; |
502 | 501 | ||
503 | for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { | 502 | ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; |
504 | struct ath9k_channel *chan = &ah->channels[i]; | 503 | ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; |
505 | struct ar5416AniState *ani = &chan->ani; | 504 | ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false; |
506 | 505 | ani->ofdmsTurn = true; | |
507 | ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; | 506 | ani->ofdmWeakSigDetect = true; |
508 | 507 | ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; | |
509 | ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; | 508 | ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; |
510 | |||
511 | ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false; | ||
512 | |||
513 | ani->ofdmsTurn = true; | ||
514 | |||
515 | ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; | ||
516 | ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; | ||
517 | ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; | ||
518 | } | ||
519 | 509 | ||
520 | /* | 510 | /* |
521 | * since we expect some ongoing maintenance on the tables, let's sanity | 511 | * since we expect some ongoing maintenance on the tables, let's sanity |
@@ -524,9 +514,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) | |||
524 | ah->aniperiod = ATH9K_ANI_PERIOD; | 514 | ah->aniperiod = ATH9K_ANI_PERIOD; |
525 | ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; | 515 | ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; |
526 | 516 | ||
527 | if (ah->config.enable_ani) | ||
528 | ah->proc_phyerr |= HAL_PROCESS_ANI; | ||
529 | |||
530 | ath9k_ani_restart(ah); | 517 | ath9k_ani_restart(ah); |
531 | ath9k_enable_mib_counters(ah); | 518 | ath9k_enable_mib_counters(ah); |
532 | } | 519 | } |
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index dddb1361039a..78b9fa9f6455 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h | |||
@@ -17,10 +17,6 @@ | |||
17 | #ifndef ANI_H | 17 | #ifndef ANI_H |
18 | #define ANI_H | 18 | #define ANI_H |
19 | 19 | ||
20 | #define HAL_PROCESS_ANI 0x00000001 | ||
21 | |||
22 | #define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan) | ||
23 | |||
24 | #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) | 20 | #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) |
25 | 21 | ||
26 | /* units are errors per second */ | 22 | /* units are errors per second */ |
@@ -38,11 +34,7 @@ | |||
38 | #define ATH9K_ANI_CCK_TRIG_LOW 300 | 34 | #define ATH9K_ANI_CCK_TRIG_LOW 300 |
39 | 35 | ||
40 | #define ATH9K_ANI_NOISE_IMMUNE_LVL 4 | 36 | #define ATH9K_ANI_NOISE_IMMUNE_LVL 4 |
41 | #define ATH9K_ANI_USE_OFDM_WEAK_SIG true | ||
42 | #define ATH9K_ANI_CCK_WEAK_SIG_THR false | ||
43 | |||
44 | #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 | 37 | #define ATH9K_ANI_SPUR_IMMUNE_LVL 3 |
45 | |||
46 | #define ATH9K_ANI_FIRSTEP_LVL 2 | 38 | #define ATH9K_ANI_FIRSTEP_LVL 2 |
47 | 39 | ||
48 | #define ATH9K_ANI_RSSI_THR_HIGH 40 | 40 | #define ATH9K_ANI_RSSI_THR_HIGH 40 |
@@ -111,7 +103,7 @@ struct ar5416AniState { | |||
111 | u8 mrcCCK; | 103 | u8 mrcCCK; |
112 | u8 spurImmunityLevel; | 104 | u8 spurImmunityLevel; |
113 | u8 firstepLevel; | 105 | u8 firstepLevel; |
114 | u8 ofdmWeakSigDetect; | 106 | bool ofdmWeakSigDetect; |
115 | u32 listenTime; | 107 | u32 listenTime; |
116 | u32 ofdmPhyErrCount; | 108 | u32 ofdmPhyErrCount; |
117 | u32 cckPhyErrCount; | 109 | u32 cckPhyErrCount; |
@@ -119,8 +111,6 @@ struct ar5416AniState { | |||
119 | }; | 111 | }; |
120 | 112 | ||
121 | struct ar5416Stats { | 113 | struct ar5416Stats { |
122 | u32 ast_ani_niup; | ||
123 | u32 ast_ani_nidown; | ||
124 | u32 ast_ani_spurup; | 114 | u32 ast_ani_spurup; |
125 | u32 ast_ani_spurdown; | 115 | u32 ast_ani_spurdown; |
126 | u32 ast_ani_ofdmon; | 116 | u32 ast_ani_ofdmon; |
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 391da5ad6a99..d1acfe98918a 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c | |||
@@ -931,7 +931,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, | |||
931 | { | 931 | { |
932 | struct ath_common *common = ath9k_hw_common(ah); | 932 | struct ath_common *common = ath9k_hw_common(ah); |
933 | struct ath9k_channel *chan = ah->curchan; | 933 | struct ath9k_channel *chan = ah->curchan; |
934 | struct ar5416AniState *aniState = &chan->ani; | 934 | struct ar5416AniState *aniState = &ah->ani; |
935 | s32 value, value2; | 935 | s32 value, value2; |
936 | 936 | ||
937 | switch (cmd & ah->ani_function) { | 937 | switch (cmd & ah->ani_function) { |
@@ -1207,7 +1207,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1207 | { | 1207 | { |
1208 | struct ath_common *common = ath9k_hw_common(ah); | 1208 | struct ath_common *common = ath9k_hw_common(ah); |
1209 | struct ath9k_channel *chan = ah->curchan; | 1209 | struct ath9k_channel *chan = ah->curchan; |
1210 | struct ar5416AniState *aniState = &chan->ani; | 1210 | struct ar5416AniState *aniState = &ah->ani; |
1211 | struct ath9k_ani_default *iniDef; | 1211 | struct ath9k_ani_default *iniDef; |
1212 | u32 val; | 1212 | u32 val; |
1213 | 1213 | ||
@@ -1251,7 +1251,7 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1251 | /* these levels just got reset to defaults by the INI */ | 1251 | /* these levels just got reset to defaults by the INI */ |
1252 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; | 1252 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; |
1253 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; | 1253 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; |
1254 | aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; | 1254 | aniState->ofdmWeakSigDetect = true; |
1255 | aniState->mrcCCK = false; /* not available on pre AR9003 */ | 1255 | aniState->mrcCCK = false; /* not available on pre AR9003 */ |
1256 | } | 1256 | } |
1257 | 1257 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 830daa12feb6..8dc2d089cdef 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c | |||
@@ -38,10 +38,6 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah) | |||
38 | else | 38 | else |
39 | INIT_INI_ARRAY(&ah->iniPcieSerdes, | 39 | INIT_INI_ARRAY(&ah->iniPcieSerdes, |
40 | ar9280PciePhy_clkreq_always_on_L1_9280); | 40 | ar9280PciePhy_clkreq_always_on_L1_9280); |
41 | #ifdef CONFIG_PM_SLEEP | ||
42 | INIT_INI_ARRAY(&ah->iniPcieSerdesWow, | ||
43 | ar9280PciePhy_awow); | ||
44 | #endif | ||
45 | 41 | ||
46 | if (AR_SREV_9287_11_OR_LATER(ah)) { | 42 | if (AR_SREV_9287_11_OR_LATER(ah)) { |
47 | INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); | 43 | INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); |
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index beb6162cf97c..4d18c66a6790 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h | |||
@@ -925,20 +925,6 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { | |||
925 | {0x00004044, 0x00000000}, | 925 | {0x00004044, 0x00000000}, |
926 | }; | 926 | }; |
927 | 927 | ||
928 | static const u32 ar9280PciePhy_awow[][2] = { | ||
929 | /* Addr allmodes */ | ||
930 | {0x00004040, 0x9248fd00}, | ||
931 | {0x00004040, 0x24924924}, | ||
932 | {0x00004040, 0xa8000019}, | ||
933 | {0x00004040, 0x13160820}, | ||
934 | {0x00004040, 0xe5980560}, | ||
935 | {0x00004040, 0xc01dcffd}, | ||
936 | {0x00004040, 0x1aaabe41}, | ||
937 | {0x00004040, 0xbe105554}, | ||
938 | {0x00004040, 0x00043007}, | ||
939 | {0x00004044, 0x00000000}, | ||
940 | }; | ||
941 | |||
942 | static const u32 ar9285Modes_9285_1_2[][5] = { | 928 | static const u32 ar9285Modes_9285_1_2[][5] = { |
943 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ | 929 | /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ |
944 | {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, | 930 | {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 301bf72c53bf..5163abd3937c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c | |||
@@ -469,6 +469,7 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |||
469 | 469 | ||
470 | rxs->rs_status = 0; | 470 | rxs->rs_status = 0; |
471 | rxs->rs_flags = 0; | 471 | rxs->rs_flags = 0; |
472 | rxs->flag = 0; | ||
472 | 473 | ||
473 | rxs->rs_datalen = rxsp->status2 & AR_DataLen; | 474 | rxs->rs_datalen = rxsp->status2 & AR_DataLen; |
474 | rxs->rs_tstamp = rxsp->status3; | 475 | rxs->rs_tstamp = rxsp->status3; |
@@ -493,8 +494,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |||
493 | rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; | 494 | rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; |
494 | rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; | 495 | rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; |
495 | rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); | 496 | rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); |
496 | rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; | 497 | rxs->flag |= (rxsp->status4 & AR_GI) ? RX_FLAG_SHORT_GI : 0; |
497 | rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; | 498 | rxs->flag |= (rxsp->status4 & AR_2040) ? RX_FLAG_40MHZ : 0; |
498 | 499 | ||
499 | rxs->evm0 = rxsp->status6; | 500 | rxs->evm0 = rxsp->status6; |
500 | rxs->evm1 = rxsp->status7; | 501 | rxs->evm1 = rxsp->status7; |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 09c1f9da67a0..6343cc91953e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c | |||
@@ -454,6 +454,8 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) | |||
454 | if (accum_cnt <= thresh_accum_cnt) | 454 | if (accum_cnt <= thresh_accum_cnt) |
455 | continue; | 455 | continue; |
456 | 456 | ||
457 | max_index++; | ||
458 | |||
457 | /* sum(tx amplitude) */ | 459 | /* sum(tx amplitude) */ |
458 | accum_tx = ((data_L[i] >> 16) & 0xffff) | | 460 | accum_tx = ((data_L[i] >> 16) & 0xffff) | |
459 | ((data_U[i] & 0x7ff) << 16); | 461 | ((data_U[i] & 0x7ff) << 16); |
@@ -468,20 +470,21 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) | |||
468 | 470 | ||
469 | accum_tx <<= scale_factor; | 471 | accum_tx <<= scale_factor; |
470 | accum_rx <<= scale_factor; | 472 | accum_rx <<= scale_factor; |
471 | x_est[i + 1] = (((accum_tx + accum_cnt) / accum_cnt) + 32) >> | 473 | x_est[max_index] = |
472 | scale_factor; | 474 | (((accum_tx + accum_cnt) / accum_cnt) + 32) >> |
475 | scale_factor; | ||
473 | 476 | ||
474 | Y[i + 1] = ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> | 477 | Y[max_index] = |
478 | ((((accum_rx + accum_cnt) / accum_cnt) + 32) >> | ||
475 | scale_factor) + | 479 | scale_factor) + |
476 | (1 << scale_factor) * max_index + 16; | 480 | (1 << scale_factor) * i + 16; |
477 | 481 | ||
478 | if (accum_ang >= (1 << 26)) | 482 | if (accum_ang >= (1 << 26)) |
479 | accum_ang -= 1 << 27; | 483 | accum_ang -= 1 << 27; |
480 | 484 | ||
481 | theta[i + 1] = ((accum_ang * (1 << scale_factor)) + accum_cnt) / | 485 | theta[max_index] = |
482 | accum_cnt; | 486 | ((accum_ang * (1 << scale_factor)) + accum_cnt) / |
483 | 487 | accum_cnt; | |
484 | max_index++; | ||
485 | } | 488 | } |
486 | 489 | ||
487 | /* | 490 | /* |
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 2bf6548dd143..0d053503b8bf 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -904,7 +904,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, | |||
904 | { | 904 | { |
905 | struct ath_common *common = ath9k_hw_common(ah); | 905 | struct ath_common *common = ath9k_hw_common(ah); |
906 | struct ath9k_channel *chan = ah->curchan; | 906 | struct ath9k_channel *chan = ah->curchan; |
907 | struct ar5416AniState *aniState = &chan->ani; | 907 | struct ar5416AniState *aniState = &ah->ani; |
908 | s32 value, value2; | 908 | s32 value, value2; |
909 | 909 | ||
910 | switch (cmd & ah->ani_function) { | 910 | switch (cmd & ah->ani_function) { |
@@ -1172,7 +1172,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1172 | struct ath9k_ani_default *iniDef; | 1172 | struct ath9k_ani_default *iniDef; |
1173 | u32 val; | 1173 | u32 val; |
1174 | 1174 | ||
1175 | aniState = &ah->curchan->ani; | 1175 | aniState = &ah->ani; |
1176 | iniDef = &aniState->iniDef; | 1176 | iniDef = &aniState->iniDef; |
1177 | 1177 | ||
1178 | ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", | 1178 | ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", |
@@ -1213,7 +1213,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1213 | /* these levels just got reset to defaults by the INI */ | 1213 | /* these levels just got reset to defaults by the INI */ |
1214 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; | 1214 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; |
1215 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; | 1215 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; |
1216 | aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; | 1216 | aniState->ofdmWeakSigDetect = true; |
1217 | aniState->mrcCCK = true; | 1217 | aniState->mrcCCK = true; |
1218 | } | 1218 | } |
1219 | 1219 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 8a1888d02070..579ed9c40b3f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -646,6 +646,7 @@ enum sc_op_flags { | |||
646 | SC_OP_ANI_RUN, | 646 | SC_OP_ANI_RUN, |
647 | SC_OP_PRIM_STA_VIF, | 647 | SC_OP_PRIM_STA_VIF, |
648 | SC_OP_HW_RESET, | 648 | SC_OP_HW_RESET, |
649 | SC_OP_SCANNING, | ||
649 | }; | 650 | }; |
650 | 651 | ||
651 | /* Powersave flags */ | 652 | /* Powersave flags */ |
@@ -759,7 +760,6 @@ struct ath_softc { | |||
759 | struct rchan *rfs_chan_spec_scan; | 760 | struct rchan *rfs_chan_spec_scan; |
760 | enum spectral_mode spectral_mode; | 761 | enum spectral_mode spectral_mode; |
761 | struct ath_spec_scan spec_config; | 762 | struct ath_spec_scan spec_config; |
762 | int scanning; | ||
763 | 763 | ||
764 | #ifdef CONFIG_PM_SLEEP | 764 | #ifdef CONFIG_PM_SLEEP |
765 | atomic_t wow_got_bmiss_intr; | 765 | atomic_t wow_got_bmiss_intr; |
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 2ff570f7f8ff..fd1eebab8647 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -39,7 +39,8 @@ static void ath9k_beaconq_config(struct ath_softc *sc) | |||
39 | 39 | ||
40 | ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); | 40 | ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); |
41 | 41 | ||
42 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | 42 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || |
43 | sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { | ||
43 | /* Always burst out beacon and CAB traffic. */ | 44 | /* Always burst out beacon and CAB traffic. */ |
44 | qi.tqi_aifs = 1; | 45 | qi.tqi_aifs = 1; |
45 | qi.tqi_cwmin = 0; | 46 | qi.tqi_cwmin = 0; |
@@ -273,7 +274,8 @@ static int ath9k_beacon_choose_slot(struct ath_softc *sc) | |||
273 | u64 tsf; | 274 | u64 tsf; |
274 | int slot; | 275 | int slot; |
275 | 276 | ||
276 | if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) { | 277 | if (sc->sc_ah->opmode != NL80211_IFTYPE_AP && |
278 | sc->sc_ah->opmode != NL80211_IFTYPE_MESH_POINT) { | ||
277 | ath_dbg(common, BEACON, "slot 0, tsf: %llu\n", | 279 | ath_dbg(common, BEACON, "slot 0, tsf: %llu\n", |
278 | ath9k_hw_gettsf64(sc->sc_ah)); | 280 | ath9k_hw_gettsf64(sc->sc_ah)); |
279 | return 0; | 281 | return 0; |
@@ -765,10 +767,10 @@ void ath9k_set_beacon(struct ath_softc *sc) | |||
765 | 767 | ||
766 | switch (sc->sc_ah->opmode) { | 768 | switch (sc->sc_ah->opmode) { |
767 | case NL80211_IFTYPE_AP: | 769 | case NL80211_IFTYPE_AP: |
770 | case NL80211_IFTYPE_MESH_POINT: | ||
768 | ath9k_beacon_config_ap(sc, cur_conf); | 771 | ath9k_beacon_config_ap(sc, cur_conf); |
769 | break; | 772 | break; |
770 | case NL80211_IFTYPE_ADHOC: | 773 | case NL80211_IFTYPE_ADHOC: |
771 | case NL80211_IFTYPE_MESH_POINT: | ||
772 | ath9k_beacon_config_adhoc(sc, cur_conf); | 774 | ath9k_beacon_config_adhoc(sc, cur_conf); |
773 | break; | 775 | break; |
774 | case NL80211_IFTYPE_STATION: | 776 | case NL80211_IFTYPE_STATION: |
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index e6307b86363a..7852f6e59964 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c | |||
@@ -173,25 +173,69 @@ static const struct file_operations fops_rx_chainmask = { | |||
173 | .llseek = default_llseek, | 173 | .llseek = default_llseek, |
174 | }; | 174 | }; |
175 | 175 | ||
176 | static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf, | 176 | static ssize_t read_file_ani(struct file *file, char __user *user_buf, |
177 | size_t count, loff_t *ppos) | 177 | size_t count, loff_t *ppos) |
178 | { | 178 | { |
179 | struct ath_softc *sc = file->private_data; | 179 | struct ath_softc *sc = file->private_data; |
180 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 180 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
181 | char buf[32]; | 181 | struct ath_hw *ah = sc->sc_ah; |
182 | unsigned int len; | 182 | unsigned int len = 0, size = 1024; |
183 | ssize_t retval = 0; | ||
184 | char *buf; | ||
183 | 185 | ||
184 | len = sprintf(buf, "%d\n", common->disable_ani); | 186 | buf = kzalloc(size, GFP_KERNEL); |
185 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 187 | if (buf == NULL) |
188 | return -ENOMEM; | ||
189 | |||
190 | if (common->disable_ani) { | ||
191 | len += snprintf(buf + len, size - len, "%s: %s\n", | ||
192 | "ANI", "DISABLED"); | ||
193 | goto exit; | ||
194 | } | ||
195 | |||
196 | len += snprintf(buf + len, size - len, "%15s: %s\n", | ||
197 | "ANI", "ENABLED"); | ||
198 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
199 | "ANI RESET", ah->stats.ast_ani_reset); | ||
200 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
201 | "SPUR UP", ah->stats.ast_ani_spurup); | ||
202 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
203 | "SPUR DOWN", ah->stats.ast_ani_spurup); | ||
204 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
205 | "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon); | ||
206 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
207 | "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff); | ||
208 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
209 | "MRC-CCK ON", ah->stats.ast_ani_ccklow); | ||
210 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
211 | "MRC-CCK OFF", ah->stats.ast_ani_cckhigh); | ||
212 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
213 | "FIR-STEP UP", ah->stats.ast_ani_stepup); | ||
214 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
215 | "FIR-STEP DOWN", ah->stats.ast_ani_stepdown); | ||
216 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
217 | "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero); | ||
218 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
219 | "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs); | ||
220 | len += snprintf(buf + len, size - len, "%15s: %u\n", | ||
221 | "CCK ERRORS", ah->stats.ast_ani_cckerrs); | ||
222 | exit: | ||
223 | if (len > size) | ||
224 | len = size; | ||
225 | |||
226 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
227 | kfree(buf); | ||
228 | |||
229 | return retval; | ||
186 | } | 230 | } |
187 | 231 | ||
188 | static ssize_t write_file_disable_ani(struct file *file, | 232 | static ssize_t write_file_ani(struct file *file, |
189 | const char __user *user_buf, | 233 | const char __user *user_buf, |
190 | size_t count, loff_t *ppos) | 234 | size_t count, loff_t *ppos) |
191 | { | 235 | { |
192 | struct ath_softc *sc = file->private_data; | 236 | struct ath_softc *sc = file->private_data; |
193 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 237 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
194 | unsigned long disable_ani; | 238 | unsigned long ani; |
195 | char buf[32]; | 239 | char buf[32]; |
196 | ssize_t len; | 240 | ssize_t len; |
197 | 241 | ||
@@ -200,12 +244,15 @@ static ssize_t write_file_disable_ani(struct file *file, | |||
200 | return -EFAULT; | 244 | return -EFAULT; |
201 | 245 | ||
202 | buf[len] = '\0'; | 246 | buf[len] = '\0'; |
203 | if (strict_strtoul(buf, 0, &disable_ani)) | 247 | if (strict_strtoul(buf, 0, &ani)) |
204 | return -EINVAL; | 248 | return -EINVAL; |
205 | 249 | ||
206 | common->disable_ani = !!disable_ani; | 250 | if (ani < 0 || ani > 1) |
251 | return -EINVAL; | ||
252 | |||
253 | common->disable_ani = !ani; | ||
207 | 254 | ||
208 | if (disable_ani) { | 255 | if (common->disable_ani) { |
209 | clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); | 256 | clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); |
210 | ath_stop_ani(sc); | 257 | ath_stop_ani(sc); |
211 | } else { | 258 | } else { |
@@ -215,9 +262,9 @@ static ssize_t write_file_disable_ani(struct file *file, | |||
215 | return count; | 262 | return count; |
216 | } | 263 | } |
217 | 264 | ||
218 | static const struct file_operations fops_disable_ani = { | 265 | static const struct file_operations fops_ani = { |
219 | .read = read_file_disable_ani, | 266 | .read = read_file_ani, |
220 | .write = write_file_disable_ani, | 267 | .write = write_file_ani, |
221 | .open = simple_open, | 268 | .open = simple_open, |
222 | .owner = THIS_MODULE, | 269 | .owner = THIS_MODULE, |
223 | .llseek = default_llseek, | 270 | .llseek = default_llseek, |
@@ -738,8 +785,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, | |||
738 | struct ath_tx_status *ts, struct ath_txq *txq, | 785 | struct ath_tx_status *ts, struct ath_txq *txq, |
739 | unsigned int flags) | 786 | unsigned int flags) |
740 | { | 787 | { |
741 | #define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\ | ||
742 | [sc->debug.tsidx].c) | ||
743 | int qnum = txq->axq_qnum; | 788 | int qnum = txq->axq_qnum; |
744 | 789 | ||
745 | TX_STAT_INC(qnum, tx_pkts_all); | 790 | TX_STAT_INC(qnum, tx_pkts_all); |
@@ -771,37 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, | |||
771 | TX_STAT_INC(qnum, data_underrun); | 816 | TX_STAT_INC(qnum, data_underrun); |
772 | if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) | 817 | if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) |
773 | TX_STAT_INC(qnum, delim_underrun); | 818 | TX_STAT_INC(qnum, delim_underrun); |
774 | |||
775 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
776 | spin_lock(&sc->debug.samp_lock); | ||
777 | TX_SAMP_DBG(jiffies) = jiffies; | ||
778 | TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; | ||
779 | TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1; | ||
780 | TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2; | ||
781 | TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0; | ||
782 | TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1; | ||
783 | TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2; | ||
784 | TX_SAMP_DBG(rateindex) = ts->ts_rateindex; | ||
785 | TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK); | ||
786 | TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry; | ||
787 | TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry; | ||
788 | TX_SAMP_DBG(rssi) = ts->ts_rssi; | ||
789 | TX_SAMP_DBG(tid) = ts->tid; | ||
790 | TX_SAMP_DBG(qid) = ts->qid; | ||
791 | |||
792 | if (ts->ts_flags & ATH9K_TX_BA) { | ||
793 | TX_SAMP_DBG(ba_low) = ts->ba_low; | ||
794 | TX_SAMP_DBG(ba_high) = ts->ba_high; | ||
795 | } else { | ||
796 | TX_SAMP_DBG(ba_low) = 0; | ||
797 | TX_SAMP_DBG(ba_high) = 0; | ||
798 | } | ||
799 | |||
800 | sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; | ||
801 | spin_unlock(&sc->debug.samp_lock); | ||
802 | #endif | ||
803 | |||
804 | #undef TX_SAMP_DBG | ||
805 | } | 819 | } |
806 | 820 | ||
807 | static const struct file_operations fops_xmit = { | 821 | static const struct file_operations fops_xmit = { |
@@ -915,8 +929,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, | |||
915 | void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) | 929 | void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) |
916 | { | 930 | { |
917 | #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ | 931 | #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ |
918 | #define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ | ||
919 | [sc->debug.rsidx].c) | ||
920 | 932 | ||
921 | RX_STAT_INC(rx_pkts_all); | 933 | RX_STAT_INC(rx_pkts_all); |
922 | sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; | 934 | sc->debug.stats.rxstats.rx_bytes_all += rs->rs_datalen; |
@@ -940,27 +952,7 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) | |||
940 | RX_PHY_ERR_INC(rs->rs_phyerr); | 952 | RX_PHY_ERR_INC(rs->rs_phyerr); |
941 | } | 953 | } |
942 | 954 | ||
943 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
944 | spin_lock(&sc->debug.samp_lock); | ||
945 | RX_SAMP_DBG(jiffies) = jiffies; | ||
946 | RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; | ||
947 | RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1; | ||
948 | RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2; | ||
949 | RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0; | ||
950 | RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1; | ||
951 | RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2; | ||
952 | RX_SAMP_DBG(antenna) = rs->rs_antenna; | ||
953 | RX_SAMP_DBG(rssi) = rs->rs_rssi; | ||
954 | RX_SAMP_DBG(rate) = rs->rs_rate; | ||
955 | RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon; | ||
956 | |||
957 | sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; | ||
958 | spin_unlock(&sc->debug.samp_lock); | ||
959 | |||
960 | #endif | ||
961 | |||
962 | #undef RX_PHY_ERR_INC | 955 | #undef RX_PHY_ERR_INC |
963 | #undef RX_SAMP_DBG | ||
964 | } | 956 | } |
965 | 957 | ||
966 | static const struct file_operations fops_recv = { | 958 | static const struct file_operations fops_recv = { |
@@ -1485,283 +1477,6 @@ static const struct file_operations fops_modal_eeprom = { | |||
1485 | .llseek = default_llseek, | 1477 | .llseek = default_llseek, |
1486 | }; | 1478 | }; |
1487 | 1479 | ||
1488 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
1489 | |||
1490 | void ath9k_debug_samp_bb_mac(struct ath_softc *sc) | ||
1491 | { | ||
1492 | #define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) | ||
1493 | struct ath_hw *ah = sc->sc_ah; | ||
1494 | struct ath_common *common = ath9k_hw_common(ah); | ||
1495 | unsigned long flags; | ||
1496 | int i; | ||
1497 | |||
1498 | ath9k_ps_wakeup(sc); | ||
1499 | |||
1500 | spin_lock_bh(&sc->debug.samp_lock); | ||
1501 | |||
1502 | spin_lock_irqsave(&common->cc_lock, flags); | ||
1503 | ath_hw_cycle_counters_update(common); | ||
1504 | |||
1505 | ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles; | ||
1506 | ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy; | ||
1507 | ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame; | ||
1508 | ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame; | ||
1509 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
1510 | |||
1511 | ATH_SAMP_DBG(noise) = ah->noise; | ||
1512 | |||
1513 | REG_WRITE_D(ah, AR_MACMISC, | ||
1514 | ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | | ||
1515 | (AR_MACMISC_MISC_OBS_BUS_1 << | ||
1516 | AR_MACMISC_MISC_OBS_BUS_MSB_S))); | ||
1517 | |||
1518 | for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) | ||
1519 | ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah, | ||
1520 | AR_DMADBG_0 + (i * sizeof(u32))); | ||
1521 | |||
1522 | ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1); | ||
1523 | ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR); | ||
1524 | |||
1525 | memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist, | ||
1526 | sizeof(ATH_SAMP_DBG(nfCalHist))); | ||
1527 | |||
1528 | sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES; | ||
1529 | spin_unlock_bh(&sc->debug.samp_lock); | ||
1530 | ath9k_ps_restore(sc); | ||
1531 | |||
1532 | #undef ATH_SAMP_DBG | ||
1533 | } | ||
1534 | |||
1535 | static int open_file_bb_mac_samps(struct inode *inode, struct file *file) | ||
1536 | { | ||
1537 | #define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c | ||
1538 | struct ath_softc *sc = inode->i_private; | ||
1539 | struct ath_hw *ah = sc->sc_ah; | ||
1540 | struct ath_common *common = ath9k_hw_common(ah); | ||
1541 | struct ieee80211_conf *conf = &common->hw->conf; | ||
1542 | struct ath_dbg_bb_mac_samp *bb_mac_samp; | ||
1543 | struct ath9k_nfcal_hist *h; | ||
1544 | int i, j, qcuOffset = 0, dcuOffset = 0; | ||
1545 | u32 *qcuBase, *dcuBase, size = 30000, len = 0; | ||
1546 | u32 sampidx = 0; | ||
1547 | u8 *buf; | ||
1548 | u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; | ||
1549 | u8 nread; | ||
1550 | |||
1551 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) | ||
1552 | return -EAGAIN; | ||
1553 | |||
1554 | buf = vmalloc(size); | ||
1555 | if (!buf) | ||
1556 | return -ENOMEM; | ||
1557 | bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); | ||
1558 | if (!bb_mac_samp) { | ||
1559 | vfree(buf); | ||
1560 | return -ENOMEM; | ||
1561 | } | ||
1562 | /* Account the current state too */ | ||
1563 | ath9k_debug_samp_bb_mac(sc); | ||
1564 | |||
1565 | spin_lock_bh(&sc->debug.samp_lock); | ||
1566 | memcpy(bb_mac_samp, sc->debug.bb_mac_samp, | ||
1567 | sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); | ||
1568 | len += snprintf(buf + len, size - len, | ||
1569 | "Current Sample Index: %d\n", sc->debug.sampidx); | ||
1570 | spin_unlock_bh(&sc->debug.samp_lock); | ||
1571 | |||
1572 | len += snprintf(buf + len, size - len, | ||
1573 | "Raw DMA Debug Dump:\n"); | ||
1574 | len += snprintf(buf + len, size - len, "Sample |\t"); | ||
1575 | for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) | ||
1576 | len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i); | ||
1577 | len += snprintf(buf + len, size - len, "\n"); | ||
1578 | |||
1579 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1580 | len += snprintf(buf + len, size - len, "%d\t", sampidx); | ||
1581 | |||
1582 | for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) | ||
1583 | len += snprintf(buf + len, size - len, " %08x\t", | ||
1584 | ATH_SAMP_DBG(dma_dbg_reg_vals[i])); | ||
1585 | len += snprintf(buf + len, size - len, "\n"); | ||
1586 | } | ||
1587 | len += snprintf(buf + len, size - len, "\n"); | ||
1588 | |||
1589 | len += snprintf(buf + len, size - len, | ||
1590 | "Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); | ||
1591 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1592 | qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); | ||
1593 | dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); | ||
1594 | |||
1595 | for (i = 0; i < ATH9K_NUM_QUEUES; i++, | ||
1596 | qcuOffset += 4, dcuOffset += 5) { | ||
1597 | if (i == 8) { | ||
1598 | qcuOffset = 0; | ||
1599 | qcuBase++; | ||
1600 | } | ||
1601 | |||
1602 | if (i == 6) { | ||
1603 | dcuOffset = 0; | ||
1604 | dcuBase++; | ||
1605 | } | ||
1606 | if (!sc->debug.stats.txstats[i].queued) | ||
1607 | continue; | ||
1608 | |||
1609 | len += snprintf(buf + len, size - len, | ||
1610 | "%4d %7d %2x %1x %2x %2x\n", | ||
1611 | sampidx, i, | ||
1612 | (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, | ||
1613 | (*qcuBase & (0x8 << qcuOffset)) >> | ||
1614 | (qcuOffset + 3), | ||
1615 | ATH_SAMP_DBG(dma_dbg_reg_vals[2]) & | ||
1616 | (0x7 << (i * 3)) >> (i * 3), | ||
1617 | (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); | ||
1618 | } | ||
1619 | len += snprintf(buf + len, size - len, "\n"); | ||
1620 | } | ||
1621 | len += snprintf(buf + len, size - len, | ||
1622 | "samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp " | ||
1623 | "ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 " | ||
1624 | "txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n"); | ||
1625 | |||
1626 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1627 | qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); | ||
1628 | dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); | ||
1629 | |||
1630 | len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx, | ||
1631 | (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18, | ||
1632 | (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22); | ||
1633 | len += snprintf(buf + len, size - len, "%7x %8x ", | ||
1634 | (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26, | ||
1635 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3)); | ||
1636 | len += snprintf(buf + len, size - len, "%7x %7x ", | ||
1637 | (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25, | ||
1638 | (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27); | ||
1639 | len += snprintf(buf + len, size - len, "%7d %12d ", | ||
1640 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2, | ||
1641 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10); | ||
1642 | len += snprintf(buf + len, size - len, "%12d %12d ", | ||
1643 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11, | ||
1644 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12); | ||
1645 | len += snprintf(buf + len, size - len, "%12d %12d ", | ||
1646 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13, | ||
1647 | (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17); | ||
1648 | len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n", | ||
1649 | ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr)); | ||
1650 | } | ||
1651 | |||
1652 | len += snprintf(buf + len, size - len, | ||
1653 | "Sample ChNoise Chain privNF #Reading Readings\n"); | ||
1654 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1655 | h = ATH_SAMP_DBG(nfCalHist); | ||
1656 | if (!ATH_SAMP_DBG(noise)) | ||
1657 | continue; | ||
1658 | |||
1659 | for (i = 0; i < NUM_NF_READINGS; i++) { | ||
1660 | if (!(chainmask & (1 << i)) || | ||
1661 | ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) | ||
1662 | continue; | ||
1663 | |||
1664 | nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - | ||
1665 | h[i].invalidNFcount; | ||
1666 | len += snprintf(buf + len, size - len, | ||
1667 | "%4d %5d %4d\t %d\t %d\t", | ||
1668 | sampidx, ATH_SAMP_DBG(noise), | ||
1669 | i, h[i].privNF, nread); | ||
1670 | for (j = 0; j < nread; j++) | ||
1671 | len += snprintf(buf + len, size - len, | ||
1672 | " %d", h[i].nfCalBuffer[j]); | ||
1673 | len += snprintf(buf + len, size - len, "\n"); | ||
1674 | } | ||
1675 | } | ||
1676 | len += snprintf(buf + len, size - len, "\nCycle counters:\n" | ||
1677 | "Sample Total Rxbusy Rxframes Txframes\n"); | ||
1678 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1679 | if (!ATH_SAMP_DBG(cc.cycles)) | ||
1680 | continue; | ||
1681 | len += snprintf(buf + len, size - len, | ||
1682 | "%4d %08x %08x %08x %08x\n", | ||
1683 | sampidx, ATH_SAMP_DBG(cc.cycles), | ||
1684 | ATH_SAMP_DBG(cc.rx_busy), | ||
1685 | ATH_SAMP_DBG(cc.rx_frame), | ||
1686 | ATH_SAMP_DBG(cc.tx_frame)); | ||
1687 | } | ||
1688 | |||
1689 | len += snprintf(buf + len, size - len, "Tx status Dump :\n"); | ||
1690 | len += snprintf(buf + len, size - len, | ||
1691 | "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb " | ||
1692 | "isok rts_fail data_fail rate tid qid " | ||
1693 | "ba_low ba_high tx_before(ms)\n"); | ||
1694 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1695 | for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { | ||
1696 | if (!ATH_SAMP_DBG(ts[i].jiffies)) | ||
1697 | continue; | ||
1698 | len += snprintf(buf + len, size - len, "%-14d" | ||
1699 | "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d " | ||
1700 | "%-9d %-4d %-3d %-3d %08x %08x %-11d\n", | ||
1701 | sampidx, | ||
1702 | ATH_SAMP_DBG(ts[i].rssi_ctl0), | ||
1703 | ATH_SAMP_DBG(ts[i].rssi_ctl1), | ||
1704 | ATH_SAMP_DBG(ts[i].rssi_ctl2), | ||
1705 | ATH_SAMP_DBG(ts[i].rssi_ext0), | ||
1706 | ATH_SAMP_DBG(ts[i].rssi_ext1), | ||
1707 | ATH_SAMP_DBG(ts[i].rssi_ext2), | ||
1708 | ATH_SAMP_DBG(ts[i].rssi), | ||
1709 | ATH_SAMP_DBG(ts[i].isok), | ||
1710 | ATH_SAMP_DBG(ts[i].rts_fail_cnt), | ||
1711 | ATH_SAMP_DBG(ts[i].data_fail_cnt), | ||
1712 | ATH_SAMP_DBG(ts[i].rateindex), | ||
1713 | ATH_SAMP_DBG(ts[i].tid), | ||
1714 | ATH_SAMP_DBG(ts[i].qid), | ||
1715 | ATH_SAMP_DBG(ts[i].ba_low), | ||
1716 | ATH_SAMP_DBG(ts[i].ba_high), | ||
1717 | jiffies_to_msecs(jiffies - | ||
1718 | ATH_SAMP_DBG(ts[i].jiffies))); | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | len += snprintf(buf + len, size - len, "Rx status Dump :\n"); | ||
1723 | len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 " | ||
1724 | "ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n"); | ||
1725 | for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { | ||
1726 | for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { | ||
1727 | if (!ATH_SAMP_DBG(rs[i].jiffies)) | ||
1728 | continue; | ||
1729 | len += snprintf(buf + len, size - len, "%-14d" | ||
1730 | "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n", | ||
1731 | sampidx, | ||
1732 | ATH_SAMP_DBG(rs[i].rssi_ctl0), | ||
1733 | ATH_SAMP_DBG(rs[i].rssi_ctl1), | ||
1734 | ATH_SAMP_DBG(rs[i].rssi_ctl2), | ||
1735 | ATH_SAMP_DBG(rs[i].rssi_ext0), | ||
1736 | ATH_SAMP_DBG(rs[i].rssi_ext1), | ||
1737 | ATH_SAMP_DBG(rs[i].rssi_ext2), | ||
1738 | ATH_SAMP_DBG(rs[i].rssi), | ||
1739 | ATH_SAMP_DBG(rs[i].is_mybeacon) ? | ||
1740 | "True" : "False", | ||
1741 | ATH_SAMP_DBG(rs[i].antenna), | ||
1742 | ATH_SAMP_DBG(rs[i].rate), | ||
1743 | jiffies_to_msecs(jiffies - | ||
1744 | ATH_SAMP_DBG(rs[i].jiffies))); | ||
1745 | } | ||
1746 | } | ||
1747 | |||
1748 | vfree(bb_mac_samp); | ||
1749 | file->private_data = buf; | ||
1750 | |||
1751 | return 0; | ||
1752 | #undef ATH_SAMP_DBG | ||
1753 | } | ||
1754 | |||
1755 | static const struct file_operations fops_samps = { | ||
1756 | .open = open_file_bb_mac_samps, | ||
1757 | .read = ath9k_debugfs_read_buf, | ||
1758 | .release = ath9k_debugfs_release_buf, | ||
1759 | .owner = THIS_MODULE, | ||
1760 | .llseek = default_llseek, | ||
1761 | }; | ||
1762 | |||
1763 | #endif | ||
1764 | |||
1765 | #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT | 1480 | #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT |
1766 | static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, | 1481 | static ssize_t read_file_btcoex(struct file *file, char __user *user_buf, |
1767 | size_t count, loff_t *ppos) | 1482 | size_t count, loff_t *ppos) |
@@ -2051,8 +1766,8 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
2051 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask); | 1766 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask); |
2052 | debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, | 1767 | debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, |
2053 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); | 1768 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); |
2054 | debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, | 1769 | debugfs_create_file("ani", S_IRUSR | S_IWUSR, |
2055 | sc->debug.debugfs_phy, sc, &fops_disable_ani); | 1770 | sc->debug.debugfs_phy, sc, &fops_ani); |
2056 | debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1771 | debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
2057 | &sc->sc_ah->config.enable_paprd); | 1772 | &sc->sc_ah->config.enable_paprd); |
2058 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1773 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
@@ -2087,11 +1802,6 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
2087 | debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, | 1802 | debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, |
2088 | sc->debug.debugfs_phy, sc, | 1803 | sc->debug.debugfs_phy, sc, |
2089 | &fops_spectral_fft_period); | 1804 | &fops_spectral_fft_period); |
2090 | |||
2091 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
2092 | debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, | ||
2093 | &fops_samps); | ||
2094 | #endif | ||
2095 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, | 1805 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, |
2096 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); | 1806 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); |
2097 | debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, | 1807 | debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, |
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 794a7ec83a24..9719378f7c73 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h | |||
@@ -251,56 +251,10 @@ struct ath_stats { | |||
251 | u32 reset[__RESET_TYPE_MAX]; | 251 | u32 reset[__RESET_TYPE_MAX]; |
252 | }; | 252 | }; |
253 | 253 | ||
254 | #define ATH_DBG_MAX_SAMPLES 10 | ||
255 | struct ath_dbg_bb_mac_samp { | ||
256 | u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS]; | ||
257 | u32 pcu_obs, pcu_cr, noise; | ||
258 | struct { | ||
259 | u64 jiffies; | ||
260 | int8_t rssi_ctl0; | ||
261 | int8_t rssi_ctl1; | ||
262 | int8_t rssi_ctl2; | ||
263 | int8_t rssi_ext0; | ||
264 | int8_t rssi_ext1; | ||
265 | int8_t rssi_ext2; | ||
266 | int8_t rssi; | ||
267 | bool isok; | ||
268 | u8 rts_fail_cnt; | ||
269 | u8 data_fail_cnt; | ||
270 | u8 rateindex; | ||
271 | u8 qid; | ||
272 | u8 tid; | ||
273 | u32 ba_low; | ||
274 | u32 ba_high; | ||
275 | } ts[ATH_DBG_MAX_SAMPLES]; | ||
276 | struct { | ||
277 | u64 jiffies; | ||
278 | int8_t rssi_ctl0; | ||
279 | int8_t rssi_ctl1; | ||
280 | int8_t rssi_ctl2; | ||
281 | int8_t rssi_ext0; | ||
282 | int8_t rssi_ext1; | ||
283 | int8_t rssi_ext2; | ||
284 | int8_t rssi; | ||
285 | bool is_mybeacon; | ||
286 | u8 antenna; | ||
287 | u8 rate; | ||
288 | } rs[ATH_DBG_MAX_SAMPLES]; | ||
289 | struct ath_cycle_counters cc; | ||
290 | struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; | ||
291 | }; | ||
292 | |||
293 | struct ath9k_debug { | 254 | struct ath9k_debug { |
294 | struct dentry *debugfs_phy; | 255 | struct dentry *debugfs_phy; |
295 | u32 regidx; | 256 | u32 regidx; |
296 | struct ath_stats stats; | 257 | struct ath_stats stats; |
297 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
298 | spinlock_t samp_lock; | ||
299 | struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; | ||
300 | u8 sampidx; | ||
301 | u8 tsidx; | ||
302 | u8 rsidx; | ||
303 | #endif | ||
304 | }; | 258 | }; |
305 | 259 | ||
306 | int ath9k_init_debug(struct ath_hw *ah); | 260 | int ath9k_init_debug(struct ath_hw *ah); |
@@ -359,17 +313,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, | |||
359 | 313 | ||
360 | #endif /* CONFIG_ATH9K_DEBUGFS */ | 314 | #endif /* CONFIG_ATH9K_DEBUGFS */ |
361 | 315 | ||
362 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
363 | |||
364 | void ath9k_debug_samp_bb_mac(struct ath_softc *sc); | ||
365 | |||
366 | #else | ||
367 | |||
368 | static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) | ||
369 | { | ||
370 | } | ||
371 | |||
372 | #endif | ||
373 | |||
374 | |||
375 | #endif /* DEBUG_H */ | 316 | #endif /* DEBUG_H */ |
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index d3b099d7898b..0085e643132f 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -208,6 +208,9 @@ struct ath9k_htc_target_rx_stats { | |||
208 | case NL80211_IFTYPE_AP: \ | 208 | case NL80211_IFTYPE_AP: \ |
209 | _priv->num_ap_vif++; \ | 209 | _priv->num_ap_vif++; \ |
210 | break; \ | 210 | break; \ |
211 | case NL80211_IFTYPE_MESH_POINT: \ | ||
212 | _priv->num_mbss_vif++; \ | ||
213 | break; \ | ||
211 | default: \ | 214 | default: \ |
212 | break; \ | 215 | break; \ |
213 | } \ | 216 | } \ |
@@ -224,6 +227,9 @@ struct ath9k_htc_target_rx_stats { | |||
224 | case NL80211_IFTYPE_AP: \ | 227 | case NL80211_IFTYPE_AP: \ |
225 | _priv->num_ap_vif--; \ | 228 | _priv->num_ap_vif--; \ |
226 | break; \ | 229 | break; \ |
230 | case NL80211_IFTYPE_MESH_POINT: \ | ||
231 | _priv->num_mbss_vif--; \ | ||
232 | break; \ | ||
227 | default: \ | 233 | default: \ |
228 | break; \ | 234 | break; \ |
229 | } \ | 235 | } \ |
@@ -450,6 +456,7 @@ struct ath9k_htc_priv { | |||
450 | u8 sta_slot; | 456 | u8 sta_slot; |
451 | u8 vif_sta_pos[ATH9K_HTC_MAX_VIF]; | 457 | u8 vif_sta_pos[ATH9K_HTC_MAX_VIF]; |
452 | u8 num_ibss_vif; | 458 | u8 num_ibss_vif; |
459 | u8 num_mbss_vif; | ||
453 | u8 num_sta_vif; | 460 | u8 num_sta_vif; |
454 | u8 num_sta_assoc_vif; | 461 | u8 num_sta_assoc_vif; |
455 | u8 num_ap_vif; | 462 | u8 num_ap_vif; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index f13f458dd656..e0c03bd64182 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -28,7 +28,8 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv) | |||
28 | 28 | ||
29 | ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); | 29 | ath9k_hw_get_txq_props(ah, priv->beaconq, &qi); |
30 | 30 | ||
31 | if (priv->ah->opmode == NL80211_IFTYPE_AP) { | 31 | if (priv->ah->opmode == NL80211_IFTYPE_AP || |
32 | priv->ah->opmode == NL80211_IFTYPE_MESH_POINT) { | ||
32 | qi.tqi_aifs = 1; | 33 | qi.tqi_aifs = 1; |
33 | qi.tqi_cwmin = 0; | 34 | qi.tqi_cwmin = 0; |
34 | qi.tqi_cwmax = 0; | 35 | qi.tqi_cwmax = 0; |
@@ -628,6 +629,7 @@ void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv, | |||
628 | case NL80211_IFTYPE_ADHOC: | 629 | case NL80211_IFTYPE_ADHOC: |
629 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); | 630 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); |
630 | break; | 631 | break; |
632 | case NL80211_IFTYPE_MESH_POINT: | ||
631 | case NL80211_IFTYPE_AP: | 633 | case NL80211_IFTYPE_AP: |
632 | ath9k_htc_beacon_config_ap(priv, cur_conf); | 634 | ath9k_htc_beacon_config_ap(priv, cur_conf); |
633 | break; | 635 | break; |
@@ -649,6 +651,7 @@ void ath9k_htc_beacon_reconfig(struct ath9k_htc_priv *priv) | |||
649 | case NL80211_IFTYPE_ADHOC: | 651 | case NL80211_IFTYPE_ADHOC: |
650 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); | 652 | ath9k_htc_beacon_config_adhoc(priv, cur_conf); |
651 | break; | 653 | break; |
654 | case NL80211_IFTYPE_MESH_POINT: | ||
652 | case NL80211_IFTYPE_AP: | 655 | case NL80211_IFTYPE_AP: |
653 | ath9k_htc_beacon_config_ap(priv, cur_conf); | 656 | ath9k_htc_beacon_config_ap(priv, cur_conf); |
654 | break; | 657 | break; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index a47f5e05fc04..59f64367e8ca 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c | |||
@@ -698,7 +698,8 @@ static const struct ieee80211_iface_limit if_limits[] = { | |||
698 | { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | | 698 | { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | |
699 | BIT(NL80211_IFTYPE_P2P_CLIENT) }, | 699 | BIT(NL80211_IFTYPE_P2P_CLIENT) }, |
700 | { .max = 2, .types = BIT(NL80211_IFTYPE_AP) | | 700 | { .max = 2, .types = BIT(NL80211_IFTYPE_AP) | |
701 | BIT(NL80211_IFTYPE_P2P_GO) }, | 701 | BIT(NL80211_IFTYPE_P2P_GO) | |
702 | BIT(NL80211_IFTYPE_MESH_POINT) }, | ||
702 | }; | 703 | }; |
703 | 704 | ||
704 | static const struct ieee80211_iface_combination if_comb = { | 705 | static const struct ieee80211_iface_combination if_comb = { |
@@ -721,6 +722,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, | |||
721 | IEEE80211_HW_SUPPORTS_PS | | 722 | IEEE80211_HW_SUPPORTS_PS | |
722 | IEEE80211_HW_PS_NULLFUNC_STACK | | 723 | IEEE80211_HW_PS_NULLFUNC_STACK | |
723 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 724 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
725 | IEEE80211_HW_MFP_CAPABLE | | ||
724 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; | 726 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; |
725 | 727 | ||
726 | hw->wiphy->interface_modes = | 728 | hw->wiphy->interface_modes = |
@@ -728,7 +730,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, | |||
728 | BIT(NL80211_IFTYPE_ADHOC) | | 730 | BIT(NL80211_IFTYPE_ADHOC) | |
729 | BIT(NL80211_IFTYPE_AP) | | 731 | BIT(NL80211_IFTYPE_AP) | |
730 | BIT(NL80211_IFTYPE_P2P_GO) | | 732 | BIT(NL80211_IFTYPE_P2P_GO) | |
731 | BIT(NL80211_IFTYPE_P2P_CLIENT); | 733 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
734 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
732 | 735 | ||
733 | hw->wiphy->iface_combinations = &if_comb; | 736 | hw->wiphy->iface_combinations = &if_comb; |
734 | hw->wiphy->n_iface_combinations = 1; | 737 | hw->wiphy->n_iface_combinations = 1; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 0743a47cef8f..34869c2405aa 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -113,7 +113,9 @@ static void ath9k_htc_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
113 | struct ath9k_htc_priv *priv = data; | 113 | struct ath9k_htc_priv *priv = data; |
114 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 114 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
115 | 115 | ||
116 | if ((vif->type == NL80211_IFTYPE_AP) && bss_conf->enable_beacon) | 116 | if ((vif->type == NL80211_IFTYPE_AP || |
117 | vif->type == NL80211_IFTYPE_MESH_POINT) && | ||
118 | bss_conf->enable_beacon) | ||
117 | priv->reconfig_beacon = true; | 119 | priv->reconfig_beacon = true; |
118 | 120 | ||
119 | if (bss_conf->assoc) { | 121 | if (bss_conf->assoc) { |
@@ -180,6 +182,8 @@ static void ath9k_htc_set_opmode(struct ath9k_htc_priv *priv) | |||
180 | priv->ah->opmode = NL80211_IFTYPE_ADHOC; | 182 | priv->ah->opmode = NL80211_IFTYPE_ADHOC; |
181 | else if (priv->num_ap_vif) | 183 | else if (priv->num_ap_vif) |
182 | priv->ah->opmode = NL80211_IFTYPE_AP; | 184 | priv->ah->opmode = NL80211_IFTYPE_AP; |
185 | else if (priv->num_mbss_vif) | ||
186 | priv->ah->opmode = NL80211_IFTYPE_MESH_POINT; | ||
183 | else | 187 | else |
184 | priv->ah->opmode = NL80211_IFTYPE_STATION; | 188 | priv->ah->opmode = NL80211_IFTYPE_STATION; |
185 | 189 | ||
@@ -810,8 +814,7 @@ void ath9k_htc_ani_work(struct work_struct *work) | |||
810 | } | 814 | } |
811 | 815 | ||
812 | /* Verify whether we must check ANI */ | 816 | /* Verify whether we must check ANI */ |
813 | if (ah->config.enable_ani && | 817 | if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { |
814 | (timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { | ||
815 | aniflag = true; | 818 | aniflag = true; |
816 | common->ani.checkani_timer = timestamp; | 819 | common->ani.checkani_timer = timestamp; |
817 | } | 820 | } |
@@ -841,8 +844,7 @@ set_timer: | |||
841 | * short calibration and long calibration. | 844 | * short calibration and long calibration. |
842 | */ | 845 | */ |
843 | cal_interval = ATH_LONG_CALINTERVAL; | 846 | cal_interval = ATH_LONG_CALINTERVAL; |
844 | if (ah->config.enable_ani) | 847 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); |
845 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | ||
846 | if (!common->ani.caldone) | 848 | if (!common->ani.caldone) |
847 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 849 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
848 | 850 | ||
@@ -1052,6 +1054,9 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1052 | case NL80211_IFTYPE_AP: | 1054 | case NL80211_IFTYPE_AP: |
1053 | hvif.opmode = HTC_M_HOSTAP; | 1055 | hvif.opmode = HTC_M_HOSTAP; |
1054 | break; | 1056 | break; |
1057 | case NL80211_IFTYPE_MESH_POINT: | ||
1058 | hvif.opmode = HTC_M_WDS; /* close enough */ | ||
1059 | break; | ||
1055 | default: | 1060 | default: |
1056 | ath_err(common, | 1061 | ath_err(common, |
1057 | "Interface type %d not yet supported\n", vif->type); | 1062 | "Interface type %d not yet supported\n", vif->type); |
@@ -1084,6 +1089,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, | |||
1084 | INC_VIF(priv, vif->type); | 1089 | INC_VIF(priv, vif->type); |
1085 | 1090 | ||
1086 | if ((vif->type == NL80211_IFTYPE_AP) || | 1091 | if ((vif->type == NL80211_IFTYPE_AP) || |
1092 | (vif->type == NL80211_IFTYPE_MESH_POINT) || | ||
1087 | (vif->type == NL80211_IFTYPE_ADHOC)) | 1093 | (vif->type == NL80211_IFTYPE_ADHOC)) |
1088 | ath9k_htc_assign_bslot(priv, vif); | 1094 | ath9k_htc_assign_bslot(priv, vif); |
1089 | 1095 | ||
@@ -1134,6 +1140,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1134 | DEC_VIF(priv, vif->type); | 1140 | DEC_VIF(priv, vif->type); |
1135 | 1141 | ||
1136 | if ((vif->type == NL80211_IFTYPE_AP) || | 1142 | if ((vif->type == NL80211_IFTYPE_AP) || |
1143 | vif->type == NL80211_IFTYPE_MESH_POINT || | ||
1137 | (vif->type == NL80211_IFTYPE_ADHOC)) | 1144 | (vif->type == NL80211_IFTYPE_ADHOC)) |
1138 | ath9k_htc_remove_bslot(priv, vif); | 1145 | ath9k_htc_remove_bslot(priv, vif); |
1139 | 1146 | ||
@@ -1525,9 +1532,10 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1525 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { | 1532 | if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) { |
1526 | /* | 1533 | /* |
1527 | * Disable SWBA interrupt only if there are no | 1534 | * Disable SWBA interrupt only if there are no |
1528 | * AP/IBSS interfaces. | 1535 | * concurrent AP/mesh or IBSS interfaces. |
1529 | */ | 1536 | */ |
1530 | if ((priv->num_ap_vif <= 1) || priv->num_ibss_vif) { | 1537 | if ((priv->num_ap_vif + priv->num_mbss_vif <= 1) || |
1538 | priv->num_ibss_vif) { | ||
1531 | ath_dbg(common, CONFIG, | 1539 | ath_dbg(common, CONFIG, |
1532 | "Beacon disabled for BSS: %pM\n", | 1540 | "Beacon disabled for BSS: %pM\n", |
1533 | bss_conf->bssid); | 1541 | bss_conf->bssid); |
@@ -1538,12 +1546,15 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, | |||
1538 | 1546 | ||
1539 | if (changed & BSS_CHANGED_BEACON_INT) { | 1547 | if (changed & BSS_CHANGED_BEACON_INT) { |
1540 | /* | 1548 | /* |
1541 | * Reset the HW TSF for the first AP interface. | 1549 | * Reset the HW TSF for the first AP or mesh interface. |
1542 | */ | 1550 | */ |
1543 | if ((priv->ah->opmode == NL80211_IFTYPE_AP) && | 1551 | if (priv->nvifs == 1 && |
1544 | (priv->nvifs == 1) && | 1552 | ((priv->ah->opmode == NL80211_IFTYPE_AP && |
1545 | (priv->num_ap_vif == 1) && | 1553 | vif->type == NL80211_IFTYPE_AP && |
1546 | (vif->type == NL80211_IFTYPE_AP)) { | 1554 | priv->num_ap_vif == 1) || |
1555 | (priv->ah->opmode == NL80211_IFTYPE_MESH_POINT && | ||
1556 | vif->type == NL80211_IFTYPE_MESH_POINT && | ||
1557 | priv->num_mbss_vif == 1))) { | ||
1547 | set_bit(OP_TSF_RESET, &priv->op_flags); | 1558 | set_bit(OP_TSF_RESET, &priv->op_flags); |
1548 | } | 1559 | } |
1549 | ath_dbg(common, CONFIG, | 1560 | ath_dbg(common, CONFIG, |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 6bd0e92ea2aa..e602c9519709 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -887,7 +887,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) | |||
887 | if (priv->rxfilter & FIF_PSPOLL) | 887 | if (priv->rxfilter & FIF_PSPOLL) |
888 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | 888 | rfilt |= ATH9K_RX_FILTER_PSPOLL; |
889 | 889 | ||
890 | if (priv->nvifs > 1) | 890 | if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS) |
891 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; | 891 | rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; |
892 | 892 | ||
893 | return rfilt; | 893 | return rfilt; |
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 7f25da8444fe..a13f6cea2ba7 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c | |||
@@ -452,7 +452,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) | |||
452 | ah->config.pcie_clock_req = 0; | 452 | ah->config.pcie_clock_req = 0; |
453 | ah->config.pcie_waen = 0; | 453 | ah->config.pcie_waen = 0; |
454 | ah->config.analog_shiftreg = 1; | 454 | ah->config.analog_shiftreg = 1; |
455 | ah->config.enable_ani = true; | ||
456 | 455 | ||
457 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { | 456 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { |
458 | ah->config.spurchans[i][0] = AR_NO_SPUR; | 457 | ah->config.spurchans[i][0] = AR_NO_SPUR; |
@@ -549,8 +548,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) | |||
549 | ah->eep_ops->get_eeprom_ver(ah), | 548 | ah->eep_ops->get_eeprom_ver(ah), |
550 | ah->eep_ops->get_eeprom_rev(ah)); | 549 | ah->eep_ops->get_eeprom_rev(ah)); |
551 | 550 | ||
552 | if (ah->config.enable_ani) | 551 | ath9k_hw_ani_init(ah); |
553 | ath9k_hw_ani_init(ah); | ||
554 | 552 | ||
555 | return 0; | 553 | return 0; |
556 | } | 554 | } |
@@ -1245,10 +1243,10 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) | |||
1245 | 1243 | ||
1246 | switch (opmode) { | 1244 | switch (opmode) { |
1247 | case NL80211_IFTYPE_ADHOC: | 1245 | case NL80211_IFTYPE_ADHOC: |
1248 | case NL80211_IFTYPE_MESH_POINT: | ||
1249 | set |= AR_STA_ID1_ADHOC; | 1246 | set |= AR_STA_ID1_ADHOC; |
1250 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | 1247 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
1251 | break; | 1248 | break; |
1249 | case NL80211_IFTYPE_MESH_POINT: | ||
1252 | case NL80211_IFTYPE_AP: | 1250 | case NL80211_IFTYPE_AP: |
1253 | set |= AR_STA_ID1_STA_AP; | 1251 | set |= AR_STA_ID1_STA_AP; |
1254 | /* fall through */ | 1252 | /* fall through */ |
@@ -2246,12 +2244,12 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | |||
2246 | 2244 | ||
2247 | switch (ah->opmode) { | 2245 | switch (ah->opmode) { |
2248 | case NL80211_IFTYPE_ADHOC: | 2246 | case NL80211_IFTYPE_ADHOC: |
2249 | case NL80211_IFTYPE_MESH_POINT: | ||
2250 | REG_SET_BIT(ah, AR_TXCFG, | 2247 | REG_SET_BIT(ah, AR_TXCFG, |
2251 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); | 2248 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); |
2252 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + | 2249 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + |
2253 | TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); | 2250 | TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); |
2254 | flags |= AR_NDP_TIMER_EN; | 2251 | flags |= AR_NDP_TIMER_EN; |
2252 | case NL80211_IFTYPE_MESH_POINT: | ||
2255 | case NL80211_IFTYPE_AP: | 2253 | case NL80211_IFTYPE_AP: |
2256 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); | 2254 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); |
2257 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - | 2255 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - |
@@ -2595,13 +2593,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2595 | pCap->hw_caps |= ATH9K_HW_CAP_RTT; | 2593 | pCap->hw_caps |= ATH9K_HW_CAP_RTT; |
2596 | } | 2594 | } |
2597 | 2595 | ||
2598 | if (AR_SREV_9280_20_OR_LATER(ah)) { | 2596 | if (AR_SREV_9462(ah)) |
2599 | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | | 2597 | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE; |
2600 | ATH9K_HW_WOW_PATTERN_MATCH_EXACT; | ||
2601 | |||
2602 | if (AR_SREV_9280(ah)) | ||
2603 | pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD; | ||
2604 | } | ||
2605 | 2598 | ||
2606 | if (AR_SREV_9300_20_OR_LATER(ah) && | 2599 | if (AR_SREV_9300_20_OR_LATER(ah) && |
2607 | ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) | 2600 | ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index ae3034374bc4..7d259b7dc254 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -246,9 +246,7 @@ enum ath9k_hw_caps { | |||
246 | ATH9K_HW_CAP_MCI = BIT(15), | 246 | ATH9K_HW_CAP_MCI = BIT(15), |
247 | ATH9K_HW_CAP_DFS = BIT(16), | 247 | ATH9K_HW_CAP_DFS = BIT(16), |
248 | ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), | 248 | ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), |
249 | ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18), | 249 | ATH9K_HW_CAP_PAPRD = BIT(18), |
250 | ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19), | ||
251 | ATH9K_HW_CAP_PAPRD = BIT(20), | ||
252 | }; | 250 | }; |
253 | 251 | ||
254 | /* | 252 | /* |
@@ -291,7 +289,6 @@ struct ath9k_ops_config { | |||
291 | u32 ofdm_trig_high; | 289 | u32 ofdm_trig_high; |
292 | u32 cck_trig_high; | 290 | u32 cck_trig_high; |
293 | u32 cck_trig_low; | 291 | u32 cck_trig_low; |
294 | u32 enable_ani; | ||
295 | u32 enable_paprd; | 292 | u32 enable_paprd; |
296 | int serialize_regmode; | 293 | int serialize_regmode; |
297 | bool rx_intr_mitigation; | 294 | bool rx_intr_mitigation; |
@@ -423,7 +420,6 @@ struct ath9k_hw_cal_data { | |||
423 | 420 | ||
424 | struct ath9k_channel { | 421 | struct ath9k_channel { |
425 | struct ieee80211_channel *chan; | 422 | struct ieee80211_channel *chan; |
426 | struct ar5416AniState ani; | ||
427 | u16 channel; | 423 | u16 channel; |
428 | u32 channelFlags; | 424 | u32 channelFlags; |
429 | u32 chanmode; | 425 | u32 chanmode; |
@@ -854,10 +850,10 @@ struct ath_hw { | |||
854 | u32 globaltxtimeout; | 850 | u32 globaltxtimeout; |
855 | 851 | ||
856 | /* ANI */ | 852 | /* ANI */ |
857 | u32 proc_phyerr; | ||
858 | u32 aniperiod; | 853 | u32 aniperiod; |
859 | enum ath9k_ani_cmd ani_function; | 854 | enum ath9k_ani_cmd ani_function; |
860 | u32 ani_skip_count; | 855 | u32 ani_skip_count; |
856 | struct ar5416AniState ani; | ||
861 | 857 | ||
862 | #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT | 858 | #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT |
863 | struct ath_btcoex_hw btcoex_hw; | 859 | struct ath_btcoex_hw btcoex_hw; |
@@ -882,9 +878,6 @@ struct ath_hw { | |||
882 | struct ar5416IniArray iniBank6; | 878 | struct ar5416IniArray iniBank6; |
883 | struct ar5416IniArray iniAddac; | 879 | struct ar5416IniArray iniAddac; |
884 | struct ar5416IniArray iniPcieSerdes; | 880 | struct ar5416IniArray iniPcieSerdes; |
885 | #ifdef CONFIG_PM_SLEEP | ||
886 | struct ar5416IniArray iniPcieSerdesWow; | ||
887 | #endif | ||
888 | struct ar5416IniArray iniPcieSerdesLowPower; | 881 | struct ar5416IniArray iniPcieSerdesLowPower; |
889 | struct ar5416IniArray iniModesFastClock; | 882 | struct ar5416IniArray iniModesFastClock; |
890 | struct ar5416IniArray iniAdditional; | 883 | struct ar5416IniArray iniAdditional; |
@@ -1165,8 +1158,6 @@ static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
1165 | } | 1158 | } |
1166 | #endif | 1159 | #endif |
1167 | 1160 | ||
1168 | |||
1169 | |||
1170 | #define ATH9K_CLOCK_RATE_CCK 22 | 1161 | #define ATH9K_CLOCK_RATE_CCK 22 |
1171 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 | 1162 | #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 |
1172 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 | 1163 | #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 |
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index f993362e9e13..f359b0d7078d 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/ath9k_platform.h> | 21 | #include <linux/ath9k_platform.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/relay.h> | 23 | #include <linux/relay.h> |
24 | #include <net/ieee80211_radiotap.h> | ||
24 | 25 | ||
25 | #include "ath9k.h" | 26 | #include "ath9k.h" |
26 | 27 | ||
@@ -613,9 +614,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, | |||
613 | spin_lock_init(&sc->sc_serial_rw); | 614 | spin_lock_init(&sc->sc_serial_rw); |
614 | spin_lock_init(&sc->sc_pm_lock); | 615 | spin_lock_init(&sc->sc_pm_lock); |
615 | mutex_init(&sc->mutex); | 616 | mutex_init(&sc->mutex); |
616 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
617 | spin_lock_init(&sc->debug.samp_lock); | ||
618 | #endif | ||
619 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); | 617 | tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); |
620 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, | 618 | tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, |
621 | (unsigned long)sc); | 619 | (unsigned long)sc); |
@@ -778,12 +776,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
778 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 776 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
779 | IEEE80211_HW_SUPPORTS_RC_TABLE; | 777 | IEEE80211_HW_SUPPORTS_RC_TABLE; |
780 | 778 | ||
781 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 779 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { |
782 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | 780 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; |
781 | |||
782 | if (AR_SREV_9280_20_OR_LATER(ah)) | ||
783 | hw->radiotap_mcs_details |= | ||
784 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | ||
785 | } | ||
783 | 786 | ||
784 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) | 787 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) |
785 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 788 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
786 | 789 | ||
790 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; | ||
791 | |||
787 | hw->wiphy->interface_modes = | 792 | hw->wiphy->interface_modes = |
788 | BIT(NL80211_IFTYPE_P2P_GO) | | 793 | BIT(NL80211_IFTYPE_P2P_GO) | |
789 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 794 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
@@ -804,14 +809,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
804 | hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 809 | hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
805 | 810 | ||
806 | #ifdef CONFIG_PM_SLEEP | 811 | #ifdef CONFIG_PM_SLEEP |
807 | |||
808 | if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && | 812 | if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && |
809 | device_can_wakeup(sc->dev)) | 813 | device_can_wakeup(sc->dev)) |
810 | hw->wiphy->wowlan = &ath9k_wowlan_support; | 814 | hw->wiphy->wowlan = &ath9k_wowlan_support; |
811 | 815 | ||
812 | atomic_set(&sc->wow_sleep_proc_intr, -1); | 816 | atomic_set(&sc->wow_sleep_proc_intr, -1); |
813 | atomic_set(&sc->wow_got_bmiss_intr, -1); | 817 | atomic_set(&sc->wow_got_bmiss_intr, -1); |
814 | |||
815 | #endif | 818 | #endif |
816 | 819 | ||
817 | hw->queues = 4; | 820 | hw->queues = 4; |
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 849259b07370..fff5d3ccc663 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c | |||
@@ -390,9 +390,7 @@ void ath_ani_calibrate(unsigned long data) | |||
390 | } | 390 | } |
391 | 391 | ||
392 | /* Verify whether we must check ANI */ | 392 | /* Verify whether we must check ANI */ |
393 | if (sc->sc_ah->config.enable_ani | 393 | if ((timestamp - common->ani.checkani_timer) >= ah->config.ani_poll_interval) { |
394 | && (timestamp - common->ani.checkani_timer) >= | ||
395 | ah->config.ani_poll_interval) { | ||
396 | aniflag = true; | 394 | aniflag = true; |
397 | common->ani.checkani_timer = timestamp; | 395 | common->ani.checkani_timer = timestamp; |
398 | } | 396 | } |
@@ -418,7 +416,6 @@ void ath_ani_calibrate(unsigned long data) | |||
418 | longcal ? "long" : "", shortcal ? "short" : "", | 416 | longcal ? "long" : "", shortcal ? "short" : "", |
419 | aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); | 417 | aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); |
420 | 418 | ||
421 | ath9k_debug_samp_bb_mac(sc); | ||
422 | ath9k_ps_restore(sc); | 419 | ath9k_ps_restore(sc); |
423 | 420 | ||
424 | set_timer: | 421 | set_timer: |
@@ -428,9 +425,7 @@ set_timer: | |||
428 | * short calibration and long calibration. | 425 | * short calibration and long calibration. |
429 | */ | 426 | */ |
430 | cal_interval = ATH_LONG_CALINTERVAL; | 427 | cal_interval = ATH_LONG_CALINTERVAL; |
431 | if (sc->sc_ah->config.enable_ani) | 428 | cal_interval = min(cal_interval, (u32)ah->config.ani_poll_interval); |
432 | cal_interval = min(cal_interval, | ||
433 | (u32)ah->config.ani_poll_interval); | ||
434 | if (!common->ani.caldone) | 429 | if (!common->ani.caldone) |
435 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 430 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
436 | 431 | ||
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 498fee04afa0..d055e389abfc 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c | |||
@@ -547,6 +547,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
547 | 547 | ||
548 | rs->rs_status = 0; | 548 | rs->rs_status = 0; |
549 | rs->rs_flags = 0; | 549 | rs->rs_flags = 0; |
550 | rs->flag = 0; | ||
550 | 551 | ||
551 | rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; | 552 | rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen; |
552 | rs->rs_tstamp = ads.AR_RcvTimestamp; | 553 | rs->rs_tstamp = ads.AR_RcvTimestamp; |
@@ -586,10 +587,17 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, | |||
586 | rs->rs_moreaggr = | 587 | rs->rs_moreaggr = |
587 | (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; | 588 | (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; |
588 | rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); | 589 | rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); |
589 | rs->rs_flags = | 590 | |
590 | (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; | 591 | /* directly mapped flags for ieee80211_rx_status */ |
591 | rs->rs_flags |= | 592 | rs->flag |= |
592 | (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; | 593 | (ads.ds_rxstatus3 & AR_GI) ? RX_FLAG_SHORT_GI : 0; |
594 | rs->flag |= | ||
595 | (ads.ds_rxstatus3 & AR_2040) ? RX_FLAG_40MHZ : 0; | ||
596 | if (AR_SREV_9280_20_OR_LATER(ah)) | ||
597 | rs->flag |= | ||
598 | (ads.ds_rxstatus3 & AR_STBC) ? | ||
599 | /* we can only Nss=1 STBC */ | ||
600 | (1 << RX_FLAG_STBC_SHIFT) : 0; | ||
593 | 601 | ||
594 | if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) | 602 | if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) |
595 | rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; | 603 | rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; |
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 5865f92998e1..b02dfce964b4 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h | |||
@@ -149,6 +149,7 @@ struct ath_rx_status { | |||
149 | u32 evm2; | 149 | u32 evm2; |
150 | u32 evm3; | 150 | u32 evm3; |
151 | u32 evm4; | 151 | u32 evm4; |
152 | u32 flag; /* see enum mac80211_rx_flags */ | ||
152 | }; | 153 | }; |
153 | 154 | ||
154 | struct ath_htc_rx_status { | 155 | struct ath_htc_rx_status { |
@@ -533,7 +534,8 @@ struct ar5416_desc { | |||
533 | #define AR_2040 0x00000002 | 534 | #define AR_2040 0x00000002 |
534 | #define AR_Parallel40 0x00000004 | 535 | #define AR_Parallel40 0x00000004 |
535 | #define AR_Parallel40_S 2 | 536 | #define AR_Parallel40_S 2 |
536 | #define AR_RxStatusRsvd30 0x000000f8 | 537 | #define AR_STBC 0x00000008 /* on ar9280 and later */ |
538 | #define AR_RxStatusRsvd30 0x000000f0 | ||
537 | #define AR_RxAntenna 0xffffff00 | 539 | #define AR_RxAntenna 0xffffff00 |
538 | #define AR_RxAntenna_S 8 | 540 | #define AR_RxAntenna_S 8 |
539 | 541 | ||
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a18414b5948b..cc5a98b8d187 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -193,7 +193,6 @@ static bool ath_prepare_reset(struct ath_softc *sc) | |||
193 | ath_stop_ani(sc); | 193 | ath_stop_ani(sc); |
194 | del_timer_sync(&sc->rx_poll_timer); | 194 | del_timer_sync(&sc->rx_poll_timer); |
195 | 195 | ||
196 | ath9k_debug_samp_bb_mac(sc); | ||
197 | ath9k_hw_disable_interrupts(ah); | 196 | ath9k_hw_disable_interrupts(ah); |
198 | 197 | ||
199 | if (!ath_drain_all_txq(sc)) | 198 | if (!ath_drain_all_txq(sc)) |
@@ -1273,7 +1272,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
1273 | curchan->center_freq); | 1272 | curchan->center_freq); |
1274 | } else { | 1273 | } else { |
1275 | /* perform spectral scan if requested. */ | 1274 | /* perform spectral scan if requested. */ |
1276 | if (sc->scanning && | 1275 | if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && |
1277 | sc->spectral_mode == SPECTRAL_CHANSCAN) | 1276 | sc->spectral_mode == SPECTRAL_CHANSCAN) |
1278 | ath9k_spectral_scan_trigger(hw); | 1277 | ath9k_spectral_scan_trigger(hw); |
1279 | } | 1278 | } |
@@ -1689,7 +1688,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1689 | struct ath_softc *sc = hw->priv; | 1688 | struct ath_softc *sc = hw->priv; |
1690 | int ret = 0; | 1689 | int ret = 0; |
1691 | 1690 | ||
1692 | local_bh_disable(); | 1691 | mutex_lock(&sc->mutex); |
1693 | 1692 | ||
1694 | switch (action) { | 1693 | switch (action) { |
1695 | case IEEE80211_AMPDU_RX_START: | 1694 | case IEEE80211_AMPDU_RX_START: |
@@ -1720,7 +1719,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1720 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); | 1719 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); |
1721 | } | 1720 | } |
1722 | 1721 | ||
1723 | local_bh_enable(); | 1722 | mutex_unlock(&sc->mutex); |
1724 | 1723 | ||
1725 | return ret; | 1724 | return ret; |
1726 | } | 1725 | } |
@@ -2004,7 +2003,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
2004 | { | 2003 | { |
2005 | struct ath_hw *ah = sc->sc_ah; | 2004 | struct ath_hw *ah = sc->sc_ah; |
2006 | struct ath_common *common = ath9k_hw_common(ah); | 2005 | struct ath_common *common = ath9k_hw_common(ah); |
2007 | struct ath9k_hw_capabilities *pcaps = &ah->caps; | ||
2008 | int pattern_count = 0; | 2006 | int pattern_count = 0; |
2009 | int i, byte_cnt; | 2007 | int i, byte_cnt; |
2010 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; | 2008 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; |
@@ -2074,36 +2072,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
2074 | 2072 | ||
2075 | /* Create Disassociate pattern mask */ | 2073 | /* Create Disassociate pattern mask */ |
2076 | 2074 | ||
2077 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { | 2075 | dis_deauth_mask[0] = 0xfe; |
2078 | 2076 | dis_deauth_mask[1] = 0x03; | |
2079 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { | 2077 | dis_deauth_mask[2] = 0xc0; |
2080 | /* | ||
2081 | * for AR9280, because of hardware limitation, the | ||
2082 | * first 4 bytes have to be matched for all patterns. | ||
2083 | * the mask for disassociation and de-auth pattern | ||
2084 | * matching need to enable the first 4 bytes. | ||
2085 | * also the duration field needs to be filled. | ||
2086 | */ | ||
2087 | dis_deauth_mask[0] = 0xf0; | ||
2088 | |||
2089 | /* | ||
2090 | * fill in duration field | ||
2091 | FIXME: what is the exact value ? | ||
2092 | */ | ||
2093 | dis_deauth_pattern[2] = 0xff; | ||
2094 | dis_deauth_pattern[3] = 0xff; | ||
2095 | } else { | ||
2096 | dis_deauth_mask[0] = 0xfe; | ||
2097 | } | ||
2098 | |||
2099 | dis_deauth_mask[1] = 0x03; | ||
2100 | dis_deauth_mask[2] = 0xc0; | ||
2101 | } else { | ||
2102 | dis_deauth_mask[0] = 0xef; | ||
2103 | dis_deauth_mask[1] = 0x3f; | ||
2104 | dis_deauth_mask[2] = 0x00; | ||
2105 | dis_deauth_mask[3] = 0xfc; | ||
2106 | } | ||
2107 | 2078 | ||
2108 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); | 2079 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); |
2109 | 2080 | ||
@@ -2339,15 +2310,13 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) | |||
2339 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | 2310 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) |
2340 | { | 2311 | { |
2341 | struct ath_softc *sc = hw->priv; | 2312 | struct ath_softc *sc = hw->priv; |
2342 | 2313 | set_bit(SC_OP_SCANNING, &sc->sc_flags); | |
2343 | sc->scanning = 1; | ||
2344 | } | 2314 | } |
2345 | 2315 | ||
2346 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | 2316 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) |
2347 | { | 2317 | { |
2348 | struct ath_softc *sc = hw->priv; | 2318 | struct ath_softc *sc = hw->priv; |
2349 | 2319 | clear_bit(SC_OP_SCANNING, &sc->sc_flags); | |
2350 | sc->scanning = 0; | ||
2351 | } | 2320 | } |
2352 | 2321 | ||
2353 | struct ieee80211_ops ath9k_ops = { | 2322 | struct ieee80211_ops ath9k_ops = { |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 8be2b5d8c155..865e043e8aa6 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -868,10 +868,7 @@ static int ath9k_process_rate(struct ath_common *common, | |||
868 | if (rx_stats->rs_rate & 0x80) { | 868 | if (rx_stats->rs_rate & 0x80) { |
869 | /* HT rate */ | 869 | /* HT rate */ |
870 | rxs->flag |= RX_FLAG_HT; | 870 | rxs->flag |= RX_FLAG_HT; |
871 | if (rx_stats->rs_flags & ATH9K_RX_2040) | 871 | rxs->flag |= rx_stats->flag; |
872 | rxs->flag |= RX_FLAG_40MHZ; | ||
873 | if (rx_stats->rs_flags & ATH9K_RX_GI) | ||
874 | rxs->flag |= RX_FLAG_SHORT_GI; | ||
875 | rxs->rate_idx = rx_stats->rs_rate & 0x7f; | 872 | rxs->rate_idx = rx_stats->rs_rate & 0x7f; |
876 | return 0; | 873 | return 0; |
877 | } | 874 | } |
@@ -958,11 +955,11 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, | |||
958 | if (rx_stats->rs_more) | 955 | if (rx_stats->rs_more) |
959 | return 0; | 956 | return 0; |
960 | 957 | ||
961 | ath9k_process_rssi(common, hw, hdr, rx_stats); | ||
962 | |||
963 | if (ath9k_process_rate(common, hw, rx_stats, rx_status)) | 958 | if (ath9k_process_rate(common, hw, rx_stats, rx_status)) |
964 | return -EINVAL; | 959 | return -EINVAL; |
965 | 960 | ||
961 | ath9k_process_rssi(common, hw, hdr, rx_stats); | ||
962 | |||
966 | rx_status->band = hw->conf.chandef.chan->band; | 963 | rx_status->band = hw->conf.chandef.chan->band; |
967 | rx_status->freq = hw->conf.chandef.chan->center_freq; | 964 | rx_status->freq = hw->conf.chandef.chan->center_freq; |
968 | rx_status->signal = ah->noise + rx_stats->rs_rssi; | 965 | rx_status->signal = ah->noise + rx_stats->rs_rssi; |
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index 9f8563091bea..81c88dd606dc 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c | |||
@@ -34,17 +34,6 @@ const char *ath9k_hw_wow_event_to_string(u32 wow_event) | |||
34 | } | 34 | } |
35 | EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); | 35 | EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); |
36 | 36 | ||
37 | static void ath9k_hw_config_serdes_wow_sleep(struct ath_hw *ah) | ||
38 | { | ||
39 | int i; | ||
40 | |||
41 | for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++) | ||
42 | REG_WRITE(ah, INI_RA(&ah->iniPcieSerdesWow, i, 0), | ||
43 | INI_RA(&ah->iniPcieSerdesWow, i, 1)); | ||
44 | |||
45 | usleep_range(1000, 1500); | ||
46 | } | ||
47 | |||
48 | static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) | 37 | static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) |
49 | { | 38 | { |
50 | struct ath_common *common = ath9k_hw_common(ah); | 39 | struct ath_common *common = ath9k_hw_common(ah); |
@@ -58,15 +47,8 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) | |||
58 | ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", | 47 | ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", |
59 | REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); | 48 | REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); |
60 | return; | 49 | return; |
61 | } else { | ||
62 | if (!AR_SREV_9300_20_OR_LATER(ah)) | ||
63 | REG_WRITE(ah, AR_RXDP, 0x0); | ||
64 | } | 50 | } |
65 | 51 | ||
66 | /* AR9280 WoW has sleep issue, do not set it to sleep */ | ||
67 | if (AR_SREV_9280_20(ah)) | ||
68 | return; | ||
69 | |||
70 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); | 52 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); |
71 | } | 53 | } |
72 | 54 | ||
@@ -84,27 +66,16 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) | |||
84 | 66 | ||
85 | /* set the transmit buffer */ | 67 | /* set the transmit buffer */ |
86 | ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); | 68 | ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); |
87 | |||
88 | if (!(AR_SREV_9300_20_OR_LATER(ah))) | ||
89 | ctl[0] += (KAL_ANTENNA_MODE << 25); | ||
90 | |||
91 | ctl[1] = 0; | 69 | ctl[1] = 0; |
92 | ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ | 70 | ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ |
93 | ctl[4] = 0; | 71 | ctl[4] = 0; |
94 | ctl[7] = (ah->txchainmask) << 2; | 72 | ctl[7] = (ah->txchainmask) << 2; |
95 | 73 | ctl[2] = 0xf << 16; /* tx_tries 0 */ | |
96 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
97 | ctl[2] = 0xf << 16; /* tx_tries 0 */ | ||
98 | else | ||
99 | ctl[2] = 0x7 << 16; /* tx_tries 0 */ | ||
100 | |||
101 | 74 | ||
102 | for (i = 0; i < KAL_NUM_DESC_WORDS; i++) | 75 | for (i = 0; i < KAL_NUM_DESC_WORDS; i++) |
103 | REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); | 76 | REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); |
104 | 77 | ||
105 | /* for AR9300 family 13 descriptor words */ | 78 | REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); |
106 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
107 | REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); | ||
108 | 79 | ||
109 | data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | | 80 | data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | |
110 | (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); | 81 | (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); |
@@ -183,9 +154,6 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, | |||
183 | 154 | ||
184 | ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); | 155 | ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); |
185 | 156 | ||
186 | if (!AR_SREV_9285_12_OR_LATER(ah)) | ||
187 | return; | ||
188 | |||
189 | if (pattern_count < 4) { | 157 | if (pattern_count < 4) { |
190 | /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ | 158 | /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ |
191 | set = (pattern_len & AR_WOW_LENGTH_MAX) << | 159 | set = (pattern_len & AR_WOW_LENGTH_MAX) << |
@@ -207,6 +175,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) | |||
207 | { | 175 | { |
208 | u32 wow_status = 0; | 176 | u32 wow_status = 0; |
209 | u32 val = 0, rval; | 177 | u32 val = 0, rval; |
178 | |||
210 | /* | 179 | /* |
211 | * read the WoW status register to know | 180 | * read the WoW status register to know |
212 | * the wakeup reason | 181 | * the wakeup reason |
@@ -223,19 +192,14 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) | |||
223 | val &= ah->wow_event_mask; | 192 | val &= ah->wow_event_mask; |
224 | 193 | ||
225 | if (val) { | 194 | if (val) { |
226 | |||
227 | if (val & AR_WOW_MAGIC_PAT_FOUND) | 195 | if (val & AR_WOW_MAGIC_PAT_FOUND) |
228 | wow_status |= AH_WOW_MAGIC_PATTERN_EN; | 196 | wow_status |= AH_WOW_MAGIC_PATTERN_EN; |
229 | |||
230 | if (AR_WOW_PATTERN_FOUND(val)) | 197 | if (AR_WOW_PATTERN_FOUND(val)) |
231 | wow_status |= AH_WOW_USER_PATTERN_EN; | 198 | wow_status |= AH_WOW_USER_PATTERN_EN; |
232 | |||
233 | if (val & AR_WOW_KEEP_ALIVE_FAIL) | 199 | if (val & AR_WOW_KEEP_ALIVE_FAIL) |
234 | wow_status |= AH_WOW_LINK_CHANGE; | 200 | wow_status |= AH_WOW_LINK_CHANGE; |
235 | |||
236 | if (val & AR_WOW_BEACON_FAIL) | 201 | if (val & AR_WOW_BEACON_FAIL) |
237 | wow_status |= AH_WOW_BEACON_MISS; | 202 | wow_status |= AH_WOW_BEACON_MISS; |
238 | |||
239 | } | 203 | } |
240 | 204 | ||
241 | /* | 205 | /* |
@@ -255,17 +219,6 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) | |||
255 | AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); | 219 | AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); |
256 | 220 | ||
257 | /* | 221 | /* |
258 | * tie reset register for AR9002 family of chipsets | ||
259 | * NB: not tieing it back might have some repurcussions. | ||
260 | */ | ||
261 | |||
262 | if (!AR_SREV_9300_20_OR_LATER(ah)) { | ||
263 | REG_SET_BIT(ah, AR_WA, AR_WA_UNTIE_RESET_EN | | ||
264 | AR_WA_POR_SHORT | AR_WA_RESET_EN); | ||
265 | } | ||
266 | |||
267 | |||
268 | /* | ||
269 | * restore the beacon threshold to init value | 222 | * restore the beacon threshold to init value |
270 | */ | 223 | */ |
271 | REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); | 224 | REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); |
@@ -277,8 +230,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) | |||
277 | * reset to our Chip's Power On Reset so that any PCI-E | 230 | * reset to our Chip's Power On Reset so that any PCI-E |
278 | * reset from the bus will not reset our chip | 231 | * reset from the bus will not reset our chip |
279 | */ | 232 | */ |
280 | 233 | if (ah->is_pciexpress) | |
281 | if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress) | ||
282 | ath9k_hw_configpcipowersave(ah, false); | 234 | ath9k_hw_configpcipowersave(ah, false); |
283 | 235 | ||
284 | ah->wow_event_mask = 0; | 236 | ah->wow_event_mask = 0; |
@@ -298,7 +250,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
298 | * are from the 'pattern_enable' in this function and | 250 | * are from the 'pattern_enable' in this function and |
299 | * 'pattern_count' of ath9k_hw_wow_apply_pattern() | 251 | * 'pattern_count' of ath9k_hw_wow_apply_pattern() |
300 | */ | 252 | */ |
301 | |||
302 | wow_event_mask = ah->wow_event_mask; | 253 | wow_event_mask = ah->wow_event_mask; |
303 | 254 | ||
304 | /* | 255 | /* |
@@ -306,50 +257,15 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
306 | * WOW sleep, we do want the Reset from the PCI-E to disturb | 257 | * WOW sleep, we do want the Reset from the PCI-E to disturb |
307 | * our hw state | 258 | * our hw state |
308 | */ | 259 | */ |
309 | |||
310 | if (ah->is_pciexpress) { | 260 | if (ah->is_pciexpress) { |
311 | |||
312 | /* | 261 | /* |
313 | * we need to untie the internal POR (power-on-reset) | 262 | * we need to untie the internal POR (power-on-reset) |
314 | * to the external PCI-E reset. We also need to tie | 263 | * to the external PCI-E reset. We also need to tie |
315 | * the PCI-E Phy reset to the PCI-E reset. | 264 | * the PCI-E Phy reset to the PCI-E reset. |
316 | */ | 265 | */ |
317 | 266 | set = AR_WA_RESET_EN | AR_WA_POR_SHORT; | |
318 | if (AR_SREV_9300_20_OR_LATER(ah)) { | 267 | clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; |
319 | set = AR_WA_RESET_EN | AR_WA_POR_SHORT; | 268 | REG_RMW(ah, AR_WA, set, clr); |
320 | clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; | ||
321 | REG_RMW(ah, AR_WA, set, clr); | ||
322 | } else { | ||
323 | if (AR_SREV_9285(ah) || AR_SREV_9287(ah)) | ||
324 | set = AR9285_WA_DEFAULT; | ||
325 | else | ||
326 | set = AR9280_WA_DEFAULT; | ||
327 | |||
328 | /* | ||
329 | * In AR9280 and AR9285, bit 14 in WA register | ||
330 | * (disable L1) should only be set when device | ||
331 | * enters D3 state and be cleared when device | ||
332 | * comes back to D0 | ||
333 | */ | ||
334 | |||
335 | if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) | ||
336 | set |= AR_WA_D3_L1_DISABLE; | ||
337 | |||
338 | clr = AR_WA_UNTIE_RESET_EN; | ||
339 | set |= AR_WA_RESET_EN | AR_WA_POR_SHORT; | ||
340 | REG_RMW(ah, AR_WA, set, clr); | ||
341 | |||
342 | /* | ||
343 | * for WoW sleep, we reprogram the SerDes so that the | ||
344 | * PLL and CLK REQ are both enabled. This uses more | ||
345 | * power but otherwise WoW sleep is unstable and the | ||
346 | * chip may disappear. | ||
347 | */ | ||
348 | |||
349 | if (AR_SREV_9285_12_OR_LATER(ah)) | ||
350 | ath9k_hw_config_serdes_wow_sleep(ah); | ||
351 | |||
352 | } | ||
353 | } | 269 | } |
354 | 270 | ||
355 | /* | 271 | /* |
@@ -378,7 +294,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
378 | * Program default values for pattern backoff, aifs/slot/KAL count, | 294 | * Program default values for pattern backoff, aifs/slot/KAL count, |
379 | * beacon miss timeout, KAL timeout, etc. | 295 | * beacon miss timeout, KAL timeout, etc. |
380 | */ | 296 | */ |
381 | |||
382 | set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); | 297 | set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); |
383 | REG_SET_BIT(ah, AR_WOW_PATTERN, set); | 298 | REG_SET_BIT(ah, AR_WOW_PATTERN, set); |
384 | 299 | ||
@@ -398,7 +313,7 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
398 | /* | 313 | /* |
399 | * Keep alive timo in ms except AR9280 | 314 | * Keep alive timo in ms except AR9280 |
400 | */ | 315 | */ |
401 | if (!pattern_enable || AR_SREV_9280(ah)) | 316 | if (!pattern_enable) |
402 | set = AR_WOW_KEEP_ALIVE_NEVER; | 317 | set = AR_WOW_KEEP_ALIVE_NEVER; |
403 | else | 318 | else |
404 | set = KAL_TIMEOUT * 32; | 319 | set = KAL_TIMEOUT * 32; |
@@ -420,7 +335,6 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
420 | /* | 335 | /* |
421 | * Configure MAC WoW Registers | 336 | * Configure MAC WoW Registers |
422 | */ | 337 | */ |
423 | |||
424 | set = 0; | 338 | set = 0; |
425 | /* Send keep alive timeouts anyway */ | 339 | /* Send keep alive timeouts anyway */ |
426 | clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; | 340 | clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; |
@@ -430,16 +344,9 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
430 | else | 344 | else |
431 | set = AR_WOW_KEEP_ALIVE_FAIL_DIS; | 345 | set = AR_WOW_KEEP_ALIVE_FAIL_DIS; |
432 | 346 | ||
433 | /* | ||
434 | * FIXME: For now disable keep alive frame | ||
435 | * failure. This seems to sometimes trigger | ||
436 | * unnecessary wake up with AR9485 chipsets. | ||
437 | */ | ||
438 | set = AR_WOW_KEEP_ALIVE_FAIL_DIS; | 347 | set = AR_WOW_KEEP_ALIVE_FAIL_DIS; |
439 | |||
440 | REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); | 348 | REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); |
441 | 349 | ||
442 | |||
443 | /* | 350 | /* |
444 | * we are relying on a bmiss failure. ensure we have | 351 | * we are relying on a bmiss failure. ensure we have |
445 | * enough threshold to prevent false positives | 352 | * enough threshold to prevent false positives |
@@ -473,14 +380,8 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
473 | set |= AR_WOW_MAC_INTR_EN; | 380 | set |= AR_WOW_MAC_INTR_EN; |
474 | REG_RMW(ah, AR_WOW_PATTERN, set, clr); | 381 | REG_RMW(ah, AR_WOW_PATTERN, set, clr); |
475 | 382 | ||
476 | /* | 383 | REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, |
477 | * For AR9285 and later version of chipsets | 384 | AR_WOW_PATTERN_SUPPORTED); |
478 | * enable WoW pattern match for packets less | ||
479 | * than 256 bytes for all patterns | ||
480 | */ | ||
481 | if (AR_SREV_9285_12_OR_LATER(ah)) | ||
482 | REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, | ||
483 | AR_WOW_PATTERN_SUPPORTED); | ||
484 | 385 | ||
485 | /* | 386 | /* |
486 | * Set the power states appropriately and enable PME | 387 | * Set the power states appropriately and enable PME |
@@ -488,43 +389,32 @@ void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) | |||
488 | clr = 0; | 389 | clr = 0; |
489 | set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | | 390 | set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | |
490 | AR_PMCTRL_PWR_PM_CTRL_ENA; | 391 | AR_PMCTRL_PWR_PM_CTRL_ENA; |
491 | /* | ||
492 | * This is needed for AR9300 chipsets to wake-up | ||
493 | * the host. | ||
494 | */ | ||
495 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
496 | clr = AR_PCIE_PM_CTRL_ENA; | ||
497 | 392 | ||
393 | clr = AR_PCIE_PM_CTRL_ENA; | ||
498 | REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); | 394 | REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); |
499 | 395 | ||
500 | if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { | 396 | /* |
501 | /* | 397 | * this is needed to prevent the chip waking up |
502 | * this is needed to prevent the chip waking up | 398 | * the host within 3-4 seconds with certain |
503 | * the host within 3-4 seconds with certain | 399 | * platform/BIOS. The fix is to enable |
504 | * platform/BIOS. The fix is to enable | 400 | * D1 & D3 to match original definition and |
505 | * D1 & D3 to match original definition and | 401 | * also match the OTP value. Anyway this |
506 | * also match the OTP value. Anyway this | 402 | * is more related to SW WOW. |
507 | * is more related to SW WOW. | 403 | */ |
508 | */ | 404 | clr = AR_PMCTRL_PWR_STATE_D1D3; |
509 | clr = AR_PMCTRL_PWR_STATE_D1D3; | 405 | REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); |
510 | REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); | ||
511 | |||
512 | set = AR_PMCTRL_PWR_STATE_D1D3_REAL; | ||
513 | REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); | ||
514 | } | ||
515 | |||
516 | 406 | ||
407 | set = AR_PMCTRL_PWR_STATE_D1D3_REAL; | ||
408 | REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); | ||
517 | 409 | ||
518 | REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); | 410 | REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); |
519 | 411 | ||
520 | if (AR_SREV_9300_20_OR_LATER(ah)) { | 412 | /* to bring down WOW power low margin */ |
521 | /* to bring down WOW power low margin */ | 413 | set = BIT(13); |
522 | set = BIT(13); | 414 | REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); |
523 | REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); | 415 | /* HW WoW */ |
524 | /* HW WoW */ | 416 | clr = BIT(5); |
525 | clr = BIT(5); | 417 | REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); |
526 | REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); | ||
527 | } | ||
528 | 418 | ||
529 | ath9k_hw_set_powermode_wow_sleep(ah); | 419 | ath9k_hw_set_powermode_wow_sleep(ah); |
530 | ah->wow_event_mask = wow_event_mask; | 420 | ah->wow_event_mask = wow_event_mask; |
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index bac3d98a0cfb..5644ac54facc 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig | |||
@@ -27,3 +27,15 @@ config WIL6210_ISR_COR | |||
27 | self-clear when accessed for debug purposes, it makes | 27 | self-clear when accessed for debug purposes, it makes |
28 | such monitoring impossible. | 28 | such monitoring impossible. |
29 | Say y unless you debug interrupts | 29 | Say y unless you debug interrupts |
30 | |||
31 | config ATH6KL_TRACING | ||
32 | bool "wil6210 tracing support" | ||
33 | depends on WIL6210 | ||
34 | depends on EVENT_TRACING | ||
35 | default y | ||
36 | ---help--- | ||
37 | Say Y here to enable tracepoints for the wil6210 driver | ||
38 | using the kernel tracing infrastructure. Select this | ||
39 | option if you are interested in debugging the driver. | ||
40 | |||
41 | If unsure, say Y to make it easier to debug problems. | ||
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index d288eea0a26a..f891d514d881 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile | |||
@@ -1,15 +1,20 @@ | |||
1 | obj-$(CONFIG_WIL6210) += wil6210.o | 1 | obj-$(CONFIG_WIL6210) += wil6210.o |
2 | 2 | ||
3 | wil6210-objs := main.o | 3 | wil6210-y := main.o |
4 | wil6210-objs += netdev.o | 4 | wil6210-y += netdev.o |
5 | wil6210-objs += cfg80211.o | 5 | wil6210-y += cfg80211.o |
6 | wil6210-objs += pcie_bus.o | 6 | wil6210-y += pcie_bus.o |
7 | wil6210-objs += debugfs.o | 7 | wil6210-y += debugfs.o |
8 | wil6210-objs += wmi.o | 8 | wil6210-y += wmi.o |
9 | wil6210-objs += interrupt.o | 9 | wil6210-y += interrupt.o |
10 | wil6210-objs += txrx.o | 10 | wil6210-y += txrx.o |
11 | wil6210-y += debug.o | ||
12 | wil6210-$(CONFIG_WIL6210_TRACING) += trace.o | ||
11 | 13 | ||
12 | ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) | 14 | ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) |
13 | subdir-ccflags-y += -Werror | 15 | subdir-ccflags-y += -Werror |
14 | endif | 16 | endif |
17 | # for tracing framework to find trace.h | ||
18 | CFLAGS_trace.o := -I$(src) | ||
19 | |||
15 | subdir-ccflags-y += -D__CHECK_ENDIAN__ | 20 | subdir-ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c5d4a87abaaf..4eb05d0818c3 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c | |||
@@ -322,12 +322,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, | |||
322 | * FW don't support scan after connection attempt | 322 | * FW don't support scan after connection attempt |
323 | */ | 323 | */ |
324 | set_bit(wil_status_dontscan, &wil->status); | 324 | set_bit(wil_status_dontscan, &wil->status); |
325 | set_bit(wil_status_fwconnecting, &wil->status); | ||
325 | 326 | ||
326 | rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); | 327 | rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); |
327 | if (rc == 0) { | 328 | if (rc == 0) { |
328 | /* Connect can take lots of time */ | 329 | /* Connect can take lots of time */ |
329 | mod_timer(&wil->connect_timer, | 330 | mod_timer(&wil->connect_timer, |
330 | jiffies + msecs_to_jiffies(2000)); | 331 | jiffies + msecs_to_jiffies(2000)); |
332 | } else { | ||
333 | clear_bit(wil_status_dontscan, &wil->status); | ||
334 | clear_bit(wil_status_fwconnecting, &wil->status); | ||
331 | } | 335 | } |
332 | 336 | ||
333 | out: | 337 | out: |
diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c new file mode 100644 index 000000000000..9eeabf4a5879 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/debug.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Qualcomm Atheros, 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 "wil6210.h" | ||
18 | #include "trace.h" | ||
19 | |||
20 | int wil_err(struct wil6210_priv *wil, const char *fmt, ...) | ||
21 | { | ||
22 | struct net_device *ndev = wil_to_ndev(wil); | ||
23 | struct va_format vaf = { | ||
24 | .fmt = fmt, | ||
25 | }; | ||
26 | va_list args; | ||
27 | int ret; | ||
28 | |||
29 | va_start(args, fmt); | ||
30 | vaf.va = &args; | ||
31 | ret = netdev_err(ndev, "%pV", &vaf); | ||
32 | trace_wil6210_log_err(&vaf); | ||
33 | va_end(args); | ||
34 | |||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | int wil_info(struct wil6210_priv *wil, const char *fmt, ...) | ||
39 | { | ||
40 | struct net_device *ndev = wil_to_ndev(wil); | ||
41 | struct va_format vaf = { | ||
42 | .fmt = fmt, | ||
43 | }; | ||
44 | va_list args; | ||
45 | int ret; | ||
46 | |||
47 | va_start(args, fmt); | ||
48 | vaf.va = &args; | ||
49 | ret = netdev_info(ndev, "%pV", &vaf); | ||
50 | trace_wil6210_log_info(&vaf); | ||
51 | va_end(args); | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...) | ||
57 | { | ||
58 | struct va_format vaf = { | ||
59 | .fmt = fmt, | ||
60 | }; | ||
61 | va_list args; | ||
62 | |||
63 | va_start(args, fmt); | ||
64 | vaf.va = &args; | ||
65 | trace_wil6210_log_dbg(&vaf); | ||
66 | va_end(args); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 727b1f53e6ad..e8308ec30970 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c | |||
@@ -418,9 +418,15 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data) | |||
418 | if (skb) { | 418 | if (skb) { |
419 | unsigned char printbuf[16 * 3 + 2]; | 419 | unsigned char printbuf[16 * 3 + 2]; |
420 | int i = 0; | 420 | int i = 0; |
421 | int len = skb_headlen(skb); | 421 | int len = le16_to_cpu(d->dma.length); |
422 | void *p = skb->data; | 422 | void *p = skb->data; |
423 | 423 | ||
424 | if (len != skb_headlen(skb)) { | ||
425 | seq_printf(s, "!!! len: desc = %d skb = %d\n", | ||
426 | len, skb_headlen(skb)); | ||
427 | len = min_t(int, len, skb_headlen(skb)); | ||
428 | } | ||
429 | |||
424 | seq_printf(s, " len = %d\n", len); | 430 | seq_printf(s, " len = %d\n", len); |
425 | 431 | ||
426 | while (i < len) { | 432 | while (i < len) { |
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index e3c1e7684f9c..8205d3e4ab66 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | 18 | ||
19 | #include "wil6210.h" | 19 | #include "wil6210.h" |
20 | #include "trace.h" | ||
20 | 21 | ||
21 | /** | 22 | /** |
22 | * Theory of operation: | 23 | * Theory of operation: |
@@ -103,14 +104,14 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) | |||
103 | clear_bit(wil_status_irqen, &wil->status); | 104 | clear_bit(wil_status_irqen, &wil->status); |
104 | } | 105 | } |
105 | 106 | ||
106 | static void wil6210_unmask_irq_tx(struct wil6210_priv *wil) | 107 | void wil6210_unmask_irq_tx(struct wil6210_priv *wil) |
107 | { | 108 | { |
108 | iowrite32(WIL6210_IMC_TX, wil->csr + | 109 | iowrite32(WIL6210_IMC_TX, wil->csr + |
109 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | 110 | HOSTADDR(RGF_DMA_EP_TX_ICR) + |
110 | offsetof(struct RGF_ICR, IMC)); | 111 | offsetof(struct RGF_ICR, IMC)); |
111 | } | 112 | } |
112 | 113 | ||
113 | static void wil6210_unmask_irq_rx(struct wil6210_priv *wil) | 114 | void wil6210_unmask_irq_rx(struct wil6210_priv *wil) |
114 | { | 115 | { |
115 | iowrite32(WIL6210_IMC_RX, wil->csr + | 116 | iowrite32(WIL6210_IMC_RX, wil->csr + |
116 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | 117 | HOSTADDR(RGF_DMA_EP_RX_ICR) + |
@@ -168,6 +169,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
168 | HOSTADDR(RGF_DMA_EP_RX_ICR) + | 169 | HOSTADDR(RGF_DMA_EP_RX_ICR) + |
169 | offsetof(struct RGF_ICR, ICR)); | 170 | offsetof(struct RGF_ICR, ICR)); |
170 | 171 | ||
172 | trace_wil6210_irq_rx(isr); | ||
171 | wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); | 173 | wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); |
172 | 174 | ||
173 | if (!isr) { | 175 | if (!isr) { |
@@ -180,13 +182,14 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) | |||
180 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { | 182 | if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) { |
181 | wil_dbg_irq(wil, "RX done\n"); | 183 | wil_dbg_irq(wil, "RX done\n"); |
182 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; | 184 | isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE; |
183 | wil_rx_handle(wil); | 185 | wil_dbg_txrx(wil, "NAPI schedule\n"); |
186 | napi_schedule(&wil->napi_rx); | ||
184 | } | 187 | } |
185 | 188 | ||
186 | if (isr) | 189 | if (isr) |
187 | wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); | 190 | wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr); |
188 | 191 | ||
189 | wil6210_unmask_irq_rx(wil); | 192 | /* Rx IRQ will be enabled when NAPI processing finished */ |
190 | 193 | ||
191 | return IRQ_HANDLED; | 194 | return IRQ_HANDLED; |
192 | } | 195 | } |
@@ -198,6 +201,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
198 | HOSTADDR(RGF_DMA_EP_TX_ICR) + | 201 | HOSTADDR(RGF_DMA_EP_TX_ICR) + |
199 | offsetof(struct RGF_ICR, ICR)); | 202 | offsetof(struct RGF_ICR, ICR)); |
200 | 203 | ||
204 | trace_wil6210_irq_tx(isr); | ||
201 | wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); | 205 | wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); |
202 | 206 | ||
203 | if (!isr) { | 207 | if (!isr) { |
@@ -208,23 +212,17 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) | |||
208 | wil6210_mask_irq_tx(wil); | 212 | wil6210_mask_irq_tx(wil); |
209 | 213 | ||
210 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { | 214 | if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) { |
211 | uint i; | ||
212 | wil_dbg_irq(wil, "TX done\n"); | 215 | wil_dbg_irq(wil, "TX done\n"); |
216 | napi_schedule(&wil->napi_tx); | ||
213 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; | 217 | isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; |
214 | for (i = 0; i < 24; i++) { | 218 | /* clear also all VRING interrupts */ |
215 | u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i); | 219 | isr &= ~(BIT(25) - 1UL); |
216 | if (isr & mask) { | ||
217 | isr &= ~mask; | ||
218 | wil_dbg_irq(wil, "TX done(%i)\n", i); | ||
219 | wil_tx_complete(wil, i); | ||
220 | } | ||
221 | } | ||
222 | } | 220 | } |
223 | 221 | ||
224 | if (isr) | 222 | if (isr) |
225 | wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); | 223 | wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); |
226 | 224 | ||
227 | wil6210_unmask_irq_tx(wil); | 225 | /* Tx IRQ will be enabled when NAPI processing finished */ |
228 | 226 | ||
229 | return IRQ_HANDLED; | 227 | return IRQ_HANDLED; |
230 | } | 228 | } |
@@ -256,6 +254,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) | |||
256 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + | 254 | HOSTADDR(RGF_DMA_EP_MISC_ICR) + |
257 | offsetof(struct RGF_ICR, ICR)); | 255 | offsetof(struct RGF_ICR, ICR)); |
258 | 256 | ||
257 | trace_wil6210_irq_misc(isr); | ||
259 | wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); | 258 | wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); |
260 | 259 | ||
261 | if (!isr) { | 260 | if (!isr) { |
@@ -301,6 +300,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) | |||
301 | struct wil6210_priv *wil = cookie; | 300 | struct wil6210_priv *wil = cookie; |
302 | u32 isr = wil->isr_misc; | 301 | u32 isr = wil->isr_misc; |
303 | 302 | ||
303 | trace_wil6210_irq_misc_thread(isr); | ||
304 | wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); | 304 | wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr); |
305 | 305 | ||
306 | if (isr & ISR_MISC_FW_ERROR) { | 306 | if (isr & ISR_MISC_FW_ERROR) { |
@@ -408,6 +408,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) | |||
408 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) | 408 | if (wil6210_debug_irq_mask(wil, pseudo_cause)) |
409 | return IRQ_NONE; | 409 | return IRQ_NONE; |
410 | 410 | ||
411 | trace_wil6210_irq_pseudo(pseudo_cause); | ||
411 | wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); | 412 | wil_dbg_irq(wil, "Pseudo IRQ 0x%08x\n", pseudo_cause); |
412 | 413 | ||
413 | wil6210_mask_irq_pseudo(wil); | 414 | wil6210_mask_irq_pseudo(wil); |
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index a0478e2f6868..c97b864667c5 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c | |||
@@ -56,27 +56,21 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid) | |||
56 | { | 56 | { |
57 | uint i; | 57 | uint i; |
58 | struct net_device *ndev = wil_to_ndev(wil); | 58 | struct net_device *ndev = wil_to_ndev(wil); |
59 | struct wireless_dev *wdev = wil->wdev; | ||
60 | 59 | ||
61 | wil_dbg_misc(wil, "%s()\n", __func__); | 60 | wil_dbg_misc(wil, "%s()\n", __func__); |
62 | 61 | ||
63 | wil_link_off(wil); | 62 | wil_link_off(wil); |
64 | clear_bit(wil_status_fwconnected, &wil->status); | 63 | if (test_bit(wil_status_fwconnected, &wil->status)) { |
65 | 64 | clear_bit(wil_status_fwconnected, &wil->status); | |
66 | switch (wdev->sme_state) { | 65 | cfg80211_disconnected(ndev, |
67 | case CFG80211_SME_CONNECTED: | 66 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
68 | cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE, | ||
69 | NULL, 0, GFP_KERNEL); | 67 | NULL, 0, GFP_KERNEL); |
70 | break; | 68 | } else if (test_bit(wil_status_fwconnecting, &wil->status)) { |
71 | case CFG80211_SME_CONNECTING: | ||
72 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, | 69 | cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, |
73 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 70 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
74 | GFP_KERNEL); | 71 | GFP_KERNEL); |
75 | break; | ||
76 | default: | ||
77 | break; | ||
78 | } | 72 | } |
79 | 73 | clear_bit(wil_status_fwconnecting, &wil->status); | |
80 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) | 74 | for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) |
81 | wil_vring_fini_tx(wil, i); | 75 | wil_vring_fini_tx(wil, i); |
82 | 76 | ||
@@ -365,6 +359,9 @@ static int __wil_up(struct wil6210_priv *wil) | |||
365 | /* Rx VRING. After MAC and beacon */ | 359 | /* Rx VRING. After MAC and beacon */ |
366 | wil_rx_init(wil); | 360 | wil_rx_init(wil); |
367 | 361 | ||
362 | napi_enable(&wil->napi_rx); | ||
363 | napi_enable(&wil->napi_tx); | ||
364 | |||
368 | return 0; | 365 | return 0; |
369 | } | 366 | } |
370 | 367 | ||
@@ -381,6 +378,9 @@ int wil_up(struct wil6210_priv *wil) | |||
381 | 378 | ||
382 | static int __wil_down(struct wil6210_priv *wil) | 379 | static int __wil_down(struct wil6210_priv *wil) |
383 | { | 380 | { |
381 | napi_disable(&wil->napi_rx); | ||
382 | napi_disable(&wil->napi_tx); | ||
383 | |||
384 | if (wil->scan_request) { | 384 | if (wil->scan_request) { |
385 | cfg80211_scan_done(wil->scan_request, true); | 385 | cfg80211_scan_done(wil->scan_request, true); |
386 | wil->scan_request = NULL; | 386 | wil->scan_request = NULL; |
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 098a8ec6b841..29dd1e58cb17 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c | |||
@@ -40,6 +40,55 @@ static const struct net_device_ops wil_netdev_ops = { | |||
40 | .ndo_validate_addr = eth_validate_addr, | 40 | .ndo_validate_addr = eth_validate_addr, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static int wil6210_netdev_poll_rx(struct napi_struct *napi, int budget) | ||
44 | { | ||
45 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, | ||
46 | napi_rx); | ||
47 | int quota = budget; | ||
48 | int done; | ||
49 | |||
50 | wil_rx_handle(wil, "a); | ||
51 | done = budget - quota; | ||
52 | |||
53 | if (done <= 1) { /* burst ends - only one packet processed */ | ||
54 | napi_complete(napi); | ||
55 | wil6210_unmask_irq_rx(wil); | ||
56 | wil_dbg_txrx(wil, "NAPI RX complete\n"); | ||
57 | } | ||
58 | |||
59 | wil_dbg_txrx(wil, "NAPI RX poll(%d) done %d\n", budget, done); | ||
60 | |||
61 | return done; | ||
62 | } | ||
63 | |||
64 | static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) | ||
65 | { | ||
66 | struct wil6210_priv *wil = container_of(napi, struct wil6210_priv, | ||
67 | napi_tx); | ||
68 | int tx_done = 0; | ||
69 | uint i; | ||
70 | |||
71 | /* always process ALL Tx complete, regardless budget - it is fast */ | ||
72 | for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { | ||
73 | struct vring *vring = &wil->vring_tx[i]; | ||
74 | |||
75 | if (!vring->va) | ||
76 | continue; | ||
77 | |||
78 | tx_done += wil_tx_complete(wil, i); | ||
79 | } | ||
80 | |||
81 | if (tx_done <= 1) { /* burst ends - only one packet processed */ | ||
82 | napi_complete(napi); | ||
83 | wil6210_unmask_irq_tx(wil); | ||
84 | wil_dbg_txrx(wil, "NAPI TX complete\n"); | ||
85 | } | ||
86 | |||
87 | wil_dbg_txrx(wil, "NAPI TX poll(%d) done %d\n", budget, tx_done); | ||
88 | |||
89 | return min(tx_done, budget); | ||
90 | } | ||
91 | |||
43 | void *wil_if_alloc(struct device *dev, void __iomem *csr) | 92 | void *wil_if_alloc(struct device *dev, void __iomem *csr) |
44 | { | 93 | { |
45 | struct net_device *ndev; | 94 | struct net_device *ndev; |
@@ -81,6 +130,11 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr) | |||
81 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); | 130 | SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); |
82 | wdev->netdev = ndev; | 131 | wdev->netdev = ndev; |
83 | 132 | ||
133 | netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx, | ||
134 | WIL6210_NAPI_BUDGET); | ||
135 | netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, | ||
136 | WIL6210_NAPI_BUDGET); | ||
137 | |||
84 | wil_link_off(wil); | 138 | wil_link_off(wil); |
85 | 139 | ||
86 | return wil; | 140 | return wil; |
diff --git a/drivers/net/wireless/ath/wil6210/trace.c b/drivers/net/wireless/ath/wil6210/trace.c new file mode 100644 index 000000000000..cd2534b9c5aa --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/trace.c | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Qualcomm Atheros, 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 <linux/module.h> | ||
18 | |||
19 | #define CREATE_TRACE_POINTS | ||
20 | #include "trace.h" | ||
diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h new file mode 100644 index 000000000000..eff1239be53a --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/trace.h | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Qualcomm Atheros, 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 | #undef TRACE_SYSTEM | ||
18 | #define TRACE_SYSTEM wil6210 | ||
19 | #if !defined(WIL6210_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) | ||
20 | #define WIL6210_TRACE_H | ||
21 | |||
22 | #include <linux/tracepoint.h> | ||
23 | #include "wil6210.h" | ||
24 | #include "txrx.h" | ||
25 | |||
26 | /* create empty functions when tracing is disabled */ | ||
27 | #if !defined(CONFIG_WIL6210_TRACING) || defined(__CHECKER__) | ||
28 | |||
29 | #undef TRACE_EVENT | ||
30 | #define TRACE_EVENT(name, proto, ...) \ | ||
31 | static inline void trace_ ## name(proto) {} | ||
32 | #undef DECLARE_EVENT_CLASS | ||
33 | #define DECLARE_EVENT_CLASS(...) | ||
34 | #undef DEFINE_EVENT | ||
35 | #define DEFINE_EVENT(evt_class, name, proto, ...) \ | ||
36 | static inline void trace_ ## name(proto) {} | ||
37 | #endif /* !CONFIG_WIL6210_TRACING || defined(__CHECKER__) */ | ||
38 | |||
39 | DECLARE_EVENT_CLASS(wil6210_wmi, | ||
40 | TP_PROTO(u16 id, void *buf, u16 buf_len), | ||
41 | |||
42 | TP_ARGS(id, buf, buf_len), | ||
43 | |||
44 | TP_STRUCT__entry( | ||
45 | __field(u16, id) | ||
46 | __field(u16, buf_len) | ||
47 | __dynamic_array(u8, buf, buf_len) | ||
48 | ), | ||
49 | |||
50 | TP_fast_assign( | ||
51 | __entry->id = id; | ||
52 | __entry->buf_len = buf_len; | ||
53 | memcpy(__get_dynamic_array(buf), buf, buf_len); | ||
54 | ), | ||
55 | |||
56 | TP_printk( | ||
57 | "id 0x%04x len %d", | ||
58 | __entry->id, __entry->buf_len | ||
59 | ) | ||
60 | ); | ||
61 | |||
62 | DEFINE_EVENT(wil6210_wmi, wil6210_wmi_cmd, | ||
63 | TP_PROTO(u16 id, void *buf, u16 buf_len), | ||
64 | TP_ARGS(id, buf, buf_len) | ||
65 | ); | ||
66 | |||
67 | DEFINE_EVENT(wil6210_wmi, wil6210_wmi_event, | ||
68 | TP_PROTO(u16 id, void *buf, u16 buf_len), | ||
69 | TP_ARGS(id, buf, buf_len) | ||
70 | ); | ||
71 | |||
72 | #define WIL6210_MSG_MAX (200) | ||
73 | |||
74 | DECLARE_EVENT_CLASS(wil6210_log_event, | ||
75 | TP_PROTO(struct va_format *vaf), | ||
76 | TP_ARGS(vaf), | ||
77 | TP_STRUCT__entry( | ||
78 | __dynamic_array(char, msg, WIL6210_MSG_MAX) | ||
79 | ), | ||
80 | TP_fast_assign( | ||
81 | WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), | ||
82 | WIL6210_MSG_MAX, | ||
83 | vaf->fmt, | ||
84 | *vaf->va) >= WIL6210_MSG_MAX); | ||
85 | ), | ||
86 | TP_printk("%s", __get_str(msg)) | ||
87 | ); | ||
88 | |||
89 | DEFINE_EVENT(wil6210_log_event, wil6210_log_err, | ||
90 | TP_PROTO(struct va_format *vaf), | ||
91 | TP_ARGS(vaf) | ||
92 | ); | ||
93 | |||
94 | DEFINE_EVENT(wil6210_log_event, wil6210_log_info, | ||
95 | TP_PROTO(struct va_format *vaf), | ||
96 | TP_ARGS(vaf) | ||
97 | ); | ||
98 | |||
99 | DEFINE_EVENT(wil6210_log_event, wil6210_log_dbg, | ||
100 | TP_PROTO(struct va_format *vaf), | ||
101 | TP_ARGS(vaf) | ||
102 | ); | ||
103 | |||
104 | #define wil_pseudo_irq_cause(x) __print_flags(x, "|", \ | ||
105 | {BIT_DMA_PSEUDO_CAUSE_RX, "Rx" }, \ | ||
106 | {BIT_DMA_PSEUDO_CAUSE_TX, "Tx" }, \ | ||
107 | {BIT_DMA_PSEUDO_CAUSE_MISC, "Misc" }) | ||
108 | |||
109 | TRACE_EVENT(wil6210_irq_pseudo, | ||
110 | TP_PROTO(u32 x), | ||
111 | TP_ARGS(x), | ||
112 | TP_STRUCT__entry( | ||
113 | __field(u32, x) | ||
114 | ), | ||
115 | TP_fast_assign( | ||
116 | __entry->x = x; | ||
117 | ), | ||
118 | TP_printk("cause 0x%08x : %s", __entry->x, | ||
119 | wil_pseudo_irq_cause(__entry->x)) | ||
120 | ); | ||
121 | |||
122 | DECLARE_EVENT_CLASS(wil6210_irq, | ||
123 | TP_PROTO(u32 x), | ||
124 | TP_ARGS(x), | ||
125 | TP_STRUCT__entry( | ||
126 | __field(u32, x) | ||
127 | ), | ||
128 | TP_fast_assign( | ||
129 | __entry->x = x; | ||
130 | ), | ||
131 | TP_printk("cause 0x%08x", __entry->x) | ||
132 | ); | ||
133 | |||
134 | DEFINE_EVENT(wil6210_irq, wil6210_irq_rx, | ||
135 | TP_PROTO(u32 x), | ||
136 | TP_ARGS(x) | ||
137 | ); | ||
138 | |||
139 | DEFINE_EVENT(wil6210_irq, wil6210_irq_tx, | ||
140 | TP_PROTO(u32 x), | ||
141 | TP_ARGS(x) | ||
142 | ); | ||
143 | |||
144 | DEFINE_EVENT(wil6210_irq, wil6210_irq_misc, | ||
145 | TP_PROTO(u32 x), | ||
146 | TP_ARGS(x) | ||
147 | ); | ||
148 | |||
149 | DEFINE_EVENT(wil6210_irq, wil6210_irq_misc_thread, | ||
150 | TP_PROTO(u32 x), | ||
151 | TP_ARGS(x) | ||
152 | ); | ||
153 | |||
154 | TRACE_EVENT(wil6210_rx, | ||
155 | TP_PROTO(u16 index, struct vring_rx_desc *d), | ||
156 | TP_ARGS(index, d), | ||
157 | TP_STRUCT__entry( | ||
158 | __field(u16, index) | ||
159 | __field(unsigned int, len) | ||
160 | __field(u8, mid) | ||
161 | __field(u8, cid) | ||
162 | __field(u8, tid) | ||
163 | __field(u8, type) | ||
164 | __field(u8, subtype) | ||
165 | __field(u16, seq) | ||
166 | __field(u8, mcs) | ||
167 | ), | ||
168 | TP_fast_assign( | ||
169 | __entry->index = index; | ||
170 | __entry->len = d->dma.length; | ||
171 | __entry->mid = wil_rxdesc_mid(d); | ||
172 | __entry->cid = wil_rxdesc_cid(d); | ||
173 | __entry->tid = wil_rxdesc_tid(d); | ||
174 | __entry->type = wil_rxdesc_ftype(d); | ||
175 | __entry->subtype = wil_rxdesc_subtype(d); | ||
176 | __entry->seq = wil_rxdesc_seq(d); | ||
177 | __entry->mcs = wil_rxdesc_mcs(d); | ||
178 | ), | ||
179 | TP_printk("index %d len %d mid %d cid %d tid %d mcs %d seq 0x%03x" | ||
180 | " type 0x%1x subtype 0x%1x", __entry->index, __entry->len, | ||
181 | __entry->mid, __entry->cid, __entry->tid, __entry->mcs, | ||
182 | __entry->seq, __entry->type, __entry->subtype) | ||
183 | ); | ||
184 | |||
185 | TRACE_EVENT(wil6210_tx, | ||
186 | TP_PROTO(u8 vring, u16 index, unsigned int len, u8 frags), | ||
187 | TP_ARGS(vring, index, len, frags), | ||
188 | TP_STRUCT__entry( | ||
189 | __field(u8, vring) | ||
190 | __field(u8, frags) | ||
191 | __field(u16, index) | ||
192 | __field(unsigned int, len) | ||
193 | ), | ||
194 | TP_fast_assign( | ||
195 | __entry->vring = vring; | ||
196 | __entry->frags = frags; | ||
197 | __entry->index = index; | ||
198 | __entry->len = len; | ||
199 | ), | ||
200 | TP_printk("vring %d index %d len %d frags %d", | ||
201 | __entry->vring, __entry->index, __entry->len, __entry->frags) | ||
202 | ); | ||
203 | |||
204 | TRACE_EVENT(wil6210_tx_done, | ||
205 | TP_PROTO(u8 vring, u16 index, unsigned int len, u8 err), | ||
206 | TP_ARGS(vring, index, len, err), | ||
207 | TP_STRUCT__entry( | ||
208 | __field(u8, vring) | ||
209 | __field(u8, err) | ||
210 | __field(u16, index) | ||
211 | __field(unsigned int, len) | ||
212 | ), | ||
213 | TP_fast_assign( | ||
214 | __entry->vring = vring; | ||
215 | __entry->index = index; | ||
216 | __entry->len = len; | ||
217 | __entry->err = err; | ||
218 | ), | ||
219 | TP_printk("vring %d index %d len %d err 0x%02x", | ||
220 | __entry->vring, __entry->index, __entry->len, | ||
221 | __entry->err) | ||
222 | ); | ||
223 | |||
224 | #endif /* WIL6210_TRACE_H || TRACE_HEADER_MULTI_READ*/ | ||
225 | |||
226 | #if defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__) | ||
227 | /* we don't want to use include/trace/events */ | ||
228 | #undef TRACE_INCLUDE_PATH | ||
229 | #define TRACE_INCLUDE_PATH . | ||
230 | #undef TRACE_INCLUDE_FILE | ||
231 | #define TRACE_INCLUDE_FILE trace | ||
232 | |||
233 | /* This part must be outside protection */ | ||
234 | #include <trace/define_trace.h> | ||
235 | #endif /* defined(CONFIG_WIL6210_TRACING) && !defined(__CHECKER__) */ | ||
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 797024507c71..00dffeda983e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "wil6210.h" | 22 | #include "wil6210.h" |
23 | #include "wmi.h" | 23 | #include "wmi.h" |
24 | #include "txrx.h" | 24 | #include "txrx.h" |
25 | #include "trace.h" | ||
25 | 26 | ||
26 | static bool rtap_include_phy_info; | 27 | static bool rtap_include_phy_info; |
27 | module_param(rtap_include_phy_info, bool, S_IRUGO); | 28 | module_param(rtap_include_phy_info, bool, S_IRUGO); |
@@ -89,8 +90,8 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring) | |||
89 | * we can use any | 90 | * we can use any |
90 | */ | 91 | */ |
91 | for (i = 0; i < vring->size; i++) { | 92 | for (i = 0; i < vring->size; i++) { |
92 | volatile struct vring_tx_desc *d = &(vring->va[i].tx); | 93 | volatile struct vring_tx_desc *_d = &(vring->va[i].tx); |
93 | d->dma.status = TX_DMA_STATUS_DU; | 94 | _d->dma.status = TX_DMA_STATUS_DU; |
94 | } | 95 | } |
95 | 96 | ||
96 | wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, | 97 | wil_dbg_misc(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size, |
@@ -106,30 +107,39 @@ static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring, | |||
106 | size_t sz = vring->size * sizeof(vring->va[0]); | 107 | size_t sz = vring->size * sizeof(vring->va[0]); |
107 | 108 | ||
108 | while (!wil_vring_is_empty(vring)) { | 109 | while (!wil_vring_is_empty(vring)) { |
110 | dma_addr_t pa; | ||
111 | struct sk_buff *skb; | ||
112 | u16 dmalen; | ||
113 | |||
109 | if (tx) { | 114 | if (tx) { |
110 | volatile struct vring_tx_desc *d = | 115 | struct vring_tx_desc dd, *d = ⅆ |
116 | volatile struct vring_tx_desc *_d = | ||
111 | &vring->va[vring->swtail].tx; | 117 | &vring->va[vring->swtail].tx; |
112 | dma_addr_t pa = d->dma.addr_low | | 118 | |
113 | ((u64)d->dma.addr_high << 32); | 119 | *d = *_d; |
114 | struct sk_buff *skb = vring->ctx[vring->swtail]; | 120 | pa = wil_desc_addr(&d->dma.addr); |
121 | dmalen = le16_to_cpu(d->dma.length); | ||
122 | skb = vring->ctx[vring->swtail]; | ||
115 | if (skb) { | 123 | if (skb) { |
116 | dma_unmap_single(dev, pa, d->dma.length, | 124 | dma_unmap_single(dev, pa, dmalen, |
117 | DMA_TO_DEVICE); | 125 | DMA_TO_DEVICE); |
118 | dev_kfree_skb_any(skb); | 126 | dev_kfree_skb_any(skb); |
119 | vring->ctx[vring->swtail] = NULL; | 127 | vring->ctx[vring->swtail] = NULL; |
120 | } else { | 128 | } else { |
121 | dma_unmap_page(dev, pa, d->dma.length, | 129 | dma_unmap_page(dev, pa, dmalen, |
122 | DMA_TO_DEVICE); | 130 | DMA_TO_DEVICE); |
123 | } | 131 | } |
124 | vring->swtail = wil_vring_next_tail(vring); | 132 | vring->swtail = wil_vring_next_tail(vring); |
125 | } else { /* rx */ | 133 | } else { /* rx */ |
126 | volatile struct vring_rx_desc *d = | 134 | struct vring_rx_desc dd, *d = ⅆ |
135 | volatile struct vring_rx_desc *_d = | ||
127 | &vring->va[vring->swtail].rx; | 136 | &vring->va[vring->swtail].rx; |
128 | dma_addr_t pa = d->dma.addr_low | | 137 | |
129 | ((u64)d->dma.addr_high << 32); | 138 | *d = *_d; |
130 | struct sk_buff *skb = vring->ctx[vring->swhead]; | 139 | pa = wil_desc_addr(&d->dma.addr); |
131 | dma_unmap_single(dev, pa, d->dma.length, | 140 | dmalen = le16_to_cpu(d->dma.length); |
132 | DMA_FROM_DEVICE); | 141 | skb = vring->ctx[vring->swhead]; |
142 | dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE); | ||
133 | kfree_skb(skb); | 143 | kfree_skb(skb); |
134 | wil_vring_advance_head(vring, 1); | 144 | wil_vring_advance_head(vring, 1); |
135 | } | 145 | } |
@@ -151,7 +161,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | |||
151 | { | 161 | { |
152 | struct device *dev = wil_to_dev(wil); | 162 | struct device *dev = wil_to_dev(wil); |
153 | unsigned int sz = RX_BUF_LEN; | 163 | unsigned int sz = RX_BUF_LEN; |
154 | volatile struct vring_rx_desc *d = &(vring->va[i].rx); | 164 | struct vring_rx_desc dd, *d = ⅆ |
165 | volatile struct vring_rx_desc *_d = &(vring->va[i].rx); | ||
155 | dma_addr_t pa; | 166 | dma_addr_t pa; |
156 | 167 | ||
157 | /* TODO align */ | 168 | /* TODO align */ |
@@ -169,13 +180,13 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, | |||
169 | } | 180 | } |
170 | 181 | ||
171 | d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; | 182 | d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT; |
172 | d->dma.addr_low = lower_32_bits(pa); | 183 | wil_desc_addr_set(&d->dma.addr, pa); |
173 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
174 | /* ip_length don't care */ | 184 | /* ip_length don't care */ |
175 | /* b11 don't care */ | 185 | /* b11 don't care */ |
176 | /* error don't care */ | 186 | /* error don't care */ |
177 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | 187 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ |
178 | d->dma.length = sz; | 188 | d->dma.length = cpu_to_le16(sz); |
189 | *_d = *d; | ||
179 | vring->ctx[i] = skb; | 190 | vring->ctx[i] = skb; |
180 | 191 | ||
181 | return 0; | 192 | return 0; |
@@ -321,11 +332,12 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
321 | { | 332 | { |
322 | struct device *dev = wil_to_dev(wil); | 333 | struct device *dev = wil_to_dev(wil); |
323 | struct net_device *ndev = wil_to_ndev(wil); | 334 | struct net_device *ndev = wil_to_ndev(wil); |
324 | volatile struct vring_rx_desc *d; | 335 | volatile struct vring_rx_desc *_d; |
325 | struct vring_rx_desc *d1; | 336 | struct vring_rx_desc *d; |
326 | struct sk_buff *skb; | 337 | struct sk_buff *skb; |
327 | dma_addr_t pa; | 338 | dma_addr_t pa; |
328 | unsigned int sz = RX_BUF_LEN; | 339 | unsigned int sz = RX_BUF_LEN; |
340 | u16 dmalen; | ||
329 | u8 ftype; | 341 | u8 ftype; |
330 | u8 ds_bits; | 342 | u8 ds_bits; |
331 | 343 | ||
@@ -334,32 +346,44 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
334 | if (wil_vring_is_empty(vring)) | 346 | if (wil_vring_is_empty(vring)) |
335 | return NULL; | 347 | return NULL; |
336 | 348 | ||
337 | d = &(vring->va[vring->swhead].rx); | 349 | _d = &(vring->va[vring->swhead].rx); |
338 | if (!(d->dma.status & RX_DMA_STATUS_DU)) { | 350 | if (!(_d->dma.status & RX_DMA_STATUS_DU)) { |
339 | /* it is not error, we just reached end of Rx done area */ | 351 | /* it is not error, we just reached end of Rx done area */ |
340 | return NULL; | 352 | return NULL; |
341 | } | 353 | } |
342 | 354 | ||
343 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | ||
344 | skb = vring->ctx[vring->swhead]; | 355 | skb = vring->ctx[vring->swhead]; |
356 | d = wil_skb_rxdesc(skb); | ||
357 | *d = *_d; | ||
358 | pa = wil_desc_addr(&d->dma.addr); | ||
359 | vring->ctx[vring->swhead] = NULL; | ||
360 | wil_vring_advance_head(vring, 1); | ||
361 | |||
345 | dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); | 362 | dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); |
346 | skb_trim(skb, d->dma.length); | 363 | dmalen = le16_to_cpu(d->dma.length); |
347 | 364 | ||
348 | d1 = wil_skb_rxdesc(skb); | 365 | trace_wil6210_rx(vring->swhead, d); |
349 | *d1 = *d; | 366 | wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, dmalen); |
367 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, | ||
368 | (const void *)d, sizeof(*d), false); | ||
350 | 369 | ||
351 | wil->stats.last_mcs_rx = wil_rxdesc_mcs(d1); | 370 | if (dmalen > sz) { |
371 | wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); | ||
372 | kfree_skb(skb); | ||
373 | return NULL; | ||
374 | } | ||
375 | skb_trim(skb, dmalen); | ||
376 | |||
377 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | ||
378 | skb->data, skb_headlen(skb), false); | ||
379 | |||
380 | |||
381 | wil->stats.last_mcs_rx = wil_rxdesc_mcs(d); | ||
352 | 382 | ||
353 | /* use radiotap header only if required */ | 383 | /* use radiotap header only if required */ |
354 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) | 384 | if (ndev->type == ARPHRD_IEEE80211_RADIOTAP) |
355 | wil_rx_add_radiotap_header(wil, skb); | 385 | wil_rx_add_radiotap_header(wil, skb); |
356 | 386 | ||
357 | wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length); | ||
358 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4, | ||
359 | (const void *)d, sizeof(*d), false); | ||
360 | |||
361 | wil_vring_advance_head(vring, 1); | ||
362 | |||
363 | /* no extra checks if in sniffer mode */ | 387 | /* no extra checks if in sniffer mode */ |
364 | if (ndev->type != ARPHRD_ETHER) | 388 | if (ndev->type != ARPHRD_ETHER) |
365 | return skb; | 389 | return skb; |
@@ -368,7 +392,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
368 | * Driver should recognize it by frame type, that is found | 392 | * Driver should recognize it by frame type, that is found |
369 | * in Rx descriptor. If type is not data, it is 802.11 frame as is | 393 | * in Rx descriptor. If type is not data, it is 802.11 frame as is |
370 | */ | 394 | */ |
371 | ftype = wil_rxdesc_ftype(d1) << 2; | 395 | ftype = wil_rxdesc_ftype(d) << 2; |
372 | if (ftype != IEEE80211_FTYPE_DATA) { | 396 | if (ftype != IEEE80211_FTYPE_DATA) { |
373 | wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); | 397 | wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype); |
374 | /* TODO: process it */ | 398 | /* TODO: process it */ |
@@ -383,7 +407,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, | |||
383 | return NULL; | 407 | return NULL; |
384 | } | 408 | } |
385 | 409 | ||
386 | ds_bits = wil_rxdesc_ds_bits(d1); | 410 | ds_bits = wil_rxdesc_ds_bits(d); |
387 | if (ds_bits == 1) { | 411 | if (ds_bits == 1) { |
388 | /* | 412 | /* |
389 | * HW bug - in ToDS mode, i.e. Rx on AP side, | 413 | * HW bug - in ToDS mode, i.e. Rx on AP side, |
@@ -425,6 +449,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) | |||
425 | 449 | ||
426 | /* | 450 | /* |
427 | * Pass Rx packet to the netif. Update statistics. | 451 | * Pass Rx packet to the netif. Update statistics. |
452 | * Called in softirq context (NAPI poll). | ||
428 | */ | 453 | */ |
429 | static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | 454 | static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) |
430 | { | 455 | { |
@@ -433,10 +458,7 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |||
433 | 458 | ||
434 | skb_orphan(skb); | 459 | skb_orphan(skb); |
435 | 460 | ||
436 | if (in_interrupt()) | 461 | rc = netif_receive_skb(skb); |
437 | rc = netif_rx(skb); | ||
438 | else | ||
439 | rc = netif_rx_ni(skb); | ||
440 | 462 | ||
441 | if (likely(rc == NET_RX_SUCCESS)) { | 463 | if (likely(rc == NET_RX_SUCCESS)) { |
442 | ndev->stats.rx_packets++; | 464 | ndev->stats.rx_packets++; |
@@ -450,9 +472,9 @@ static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) | |||
450 | /** | 472 | /** |
451 | * Proceed all completed skb's from Rx VRING | 473 | * Proceed all completed skb's from Rx VRING |
452 | * | 474 | * |
453 | * Safe to call from IRQ | 475 | * Safe to call from NAPI poll, i.e. softirq with interrupts enabled |
454 | */ | 476 | */ |
455 | void wil_rx_handle(struct wil6210_priv *wil) | 477 | void wil_rx_handle(struct wil6210_priv *wil, int *quota) |
456 | { | 478 | { |
457 | struct net_device *ndev = wil_to_ndev(wil); | 479 | struct net_device *ndev = wil_to_ndev(wil); |
458 | struct vring *v = &wil->vring_rx; | 480 | struct vring *v = &wil->vring_rx; |
@@ -463,9 +485,8 @@ void wil_rx_handle(struct wil6210_priv *wil) | |||
463 | return; | 485 | return; |
464 | } | 486 | } |
465 | wil_dbg_txrx(wil, "%s()\n", __func__); | 487 | wil_dbg_txrx(wil, "%s()\n", __func__); |
466 | while (NULL != (skb = wil_vring_reap_rx(wil, v))) { | 488 | while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) { |
467 | wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, | 489 | (*quota)--; |
468 | skb->data, skb_headlen(skb), false); | ||
469 | 490 | ||
470 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { | 491 | if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { |
471 | skb->dev = ndev; | 492 | skb->dev = ndev; |
@@ -600,17 +621,15 @@ static struct vring *wil_find_tx_vring(struct wil6210_priv *wil, | |||
600 | return NULL; | 621 | return NULL; |
601 | } | 622 | } |
602 | 623 | ||
603 | static int wil_tx_desc_map(volatile struct vring_tx_desc *d, | 624 | static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len) |
604 | dma_addr_t pa, u32 len) | ||
605 | { | 625 | { |
606 | d->dma.addr_low = lower_32_bits(pa); | 626 | wil_desc_addr_set(&d->dma.addr, pa); |
607 | d->dma.addr_high = (u16)upper_32_bits(pa); | ||
608 | d->dma.ip_length = 0; | 627 | d->dma.ip_length = 0; |
609 | /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ | 628 | /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/ |
610 | d->dma.b11 = 0/*14 | BIT(7)*/; | 629 | d->dma.b11 = 0/*14 | BIT(7)*/; |
611 | d->dma.error = 0; | 630 | d->dma.error = 0; |
612 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ | 631 | d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */ |
613 | d->dma.length = len; | 632 | d->dma.length = cpu_to_le16((u16)len); |
614 | d->dma.d0 = 0; | 633 | d->dma.d0 = 0; |
615 | d->mac.d[0] = 0; | 634 | d->mac.d[0] = 0; |
616 | d->mac.d[1] = 0; | 635 | d->mac.d[1] = 0; |
@@ -630,7 +649,8 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
630 | struct sk_buff *skb) | 649 | struct sk_buff *skb) |
631 | { | 650 | { |
632 | struct device *dev = wil_to_dev(wil); | 651 | struct device *dev = wil_to_dev(wil); |
633 | volatile struct vring_tx_desc *d; | 652 | struct vring_tx_desc dd, *d = ⅆ |
653 | volatile struct vring_tx_desc *_d; | ||
634 | u32 swhead = vring->swhead; | 654 | u32 swhead = vring->swhead; |
635 | int avail = wil_vring_avail_tx(vring); | 655 | int avail = wil_vring_avail_tx(vring); |
636 | int nr_frags = skb_shinfo(skb)->nr_frags; | 656 | int nr_frags = skb_shinfo(skb)->nr_frags; |
@@ -648,7 +668,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
648 | 1 + nr_frags); | 668 | 1 + nr_frags); |
649 | return -ENOMEM; | 669 | return -ENOMEM; |
650 | } | 670 | } |
651 | d = &(vring->va[i].tx); | 671 | _d = &(vring->va[i].tx); |
652 | 672 | ||
653 | /* FIXME FW can accept only unicast frames for the peer */ | 673 | /* FIXME FW can accept only unicast frames for the peer */ |
654 | memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); | 674 | memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN); |
@@ -667,25 +687,30 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
667 | wil_tx_desc_map(d, pa, skb_headlen(skb)); | 687 | wil_tx_desc_map(d, pa, skb_headlen(skb)); |
668 | d->mac.d[2] |= ((nr_frags + 1) << | 688 | d->mac.d[2] |= ((nr_frags + 1) << |
669 | MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); | 689 | MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS); |
690 | if (nr_frags) | ||
691 | *_d = *d; | ||
692 | |||
670 | /* middle segments */ | 693 | /* middle segments */ |
671 | for (f = 0; f < nr_frags; f++) { | 694 | for (f = 0; f < nr_frags; f++) { |
672 | const struct skb_frag_struct *frag = | 695 | const struct skb_frag_struct *frag = |
673 | &skb_shinfo(skb)->frags[f]; | 696 | &skb_shinfo(skb)->frags[f]; |
674 | int len = skb_frag_size(frag); | 697 | int len = skb_frag_size(frag); |
675 | i = (swhead + f + 1) % vring->size; | 698 | i = (swhead + f + 1) % vring->size; |
676 | d = &(vring->va[i].tx); | 699 | _d = &(vring->va[i].tx); |
677 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), | 700 | pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag), |
678 | DMA_TO_DEVICE); | 701 | DMA_TO_DEVICE); |
679 | if (unlikely(dma_mapping_error(dev, pa))) | 702 | if (unlikely(dma_mapping_error(dev, pa))) |
680 | goto dma_error; | 703 | goto dma_error; |
681 | wil_tx_desc_map(d, pa, len); | 704 | wil_tx_desc_map(d, pa, len); |
682 | vring->ctx[i] = NULL; | 705 | vring->ctx[i] = NULL; |
706 | *_d = *d; | ||
683 | } | 707 | } |
684 | /* for the last seg only */ | 708 | /* for the last seg only */ |
685 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); | 709 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); |
686 | d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ | 710 | d->dma.d0 |= BIT(9); /* BUG: undocumented bit */ |
687 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); | 711 | d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); |
688 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); | 712 | d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS); |
713 | *_d = *d; | ||
689 | 714 | ||
690 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, | 715 | wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4, |
691 | (const void *)d, sizeof(*d), false); | 716 | (const void *)d, sizeof(*d), false); |
@@ -693,6 +718,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
693 | /* advance swhead */ | 718 | /* advance swhead */ |
694 | wil_vring_advance_head(vring, nr_frags + 1); | 719 | wil_vring_advance_head(vring, nr_frags + 1); |
695 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); | 720 | wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead); |
721 | trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); | ||
696 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); | 722 | iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); |
697 | /* hold reference to skb | 723 | /* hold reference to skb |
698 | * to prevent skb release before accounting | 724 | * to prevent skb release before accounting |
@@ -705,14 +731,18 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, | |||
705 | /* unmap what we have mapped */ | 731 | /* unmap what we have mapped */ |
706 | /* Note: increment @f to operate with positive index */ | 732 | /* Note: increment @f to operate with positive index */ |
707 | for (f++; f > 0; f--) { | 733 | for (f++; f > 0; f--) { |
734 | u16 dmalen; | ||
735 | |||
708 | i = (swhead + f) % vring->size; | 736 | i = (swhead + f) % vring->size; |
709 | d = &(vring->va[i].tx); | 737 | _d = &(vring->va[i].tx); |
710 | d->dma.status = TX_DMA_STATUS_DU; | 738 | *d = *_d; |
711 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | 739 | _d->dma.status = TX_DMA_STATUS_DU; |
740 | pa = wil_desc_addr(&d->dma.addr); | ||
741 | dmalen = le16_to_cpu(d->dma.length); | ||
712 | if (vring->ctx[i]) | 742 | if (vring->ctx[i]) |
713 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | 743 | dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); |
714 | else | 744 | else |
715 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | 745 | dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); |
716 | } | 746 | } |
717 | 747 | ||
718 | return -EINVAL; | 748 | return -EINVAL; |
@@ -761,7 +791,6 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
761 | break; /* goto drop; */ | 791 | break; /* goto drop; */ |
762 | } | 792 | } |
763 | drop: | 793 | drop: |
764 | netif_tx_stop_all_queues(ndev); | ||
765 | ndev->stats.tx_dropped++; | 794 | ndev->stats.tx_dropped++; |
766 | dev_kfree_skb_any(skb); | 795 | dev_kfree_skb_any(skb); |
767 | 796 | ||
@@ -771,41 +800,48 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
771 | /** | 800 | /** |
772 | * Clean up transmitted skb's from the Tx VRING | 801 | * Clean up transmitted skb's from the Tx VRING |
773 | * | 802 | * |
803 | * Return number of descriptors cleared | ||
804 | * | ||
774 | * Safe to call from IRQ | 805 | * Safe to call from IRQ |
775 | */ | 806 | */ |
776 | void wil_tx_complete(struct wil6210_priv *wil, int ringid) | 807 | int wil_tx_complete(struct wil6210_priv *wil, int ringid) |
777 | { | 808 | { |
778 | struct net_device *ndev = wil_to_ndev(wil); | 809 | struct net_device *ndev = wil_to_ndev(wil); |
779 | struct device *dev = wil_to_dev(wil); | 810 | struct device *dev = wil_to_dev(wil); |
780 | struct vring *vring = &wil->vring_tx[ringid]; | 811 | struct vring *vring = &wil->vring_tx[ringid]; |
812 | int done = 0; | ||
781 | 813 | ||
782 | if (!vring->va) { | 814 | if (!vring->va) { |
783 | wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); | 815 | wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid); |
784 | return; | 816 | return 0; |
785 | } | 817 | } |
786 | 818 | ||
787 | wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); | 819 | wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid); |
788 | 820 | ||
789 | while (!wil_vring_is_empty(vring)) { | 821 | while (!wil_vring_is_empty(vring)) { |
790 | volatile struct vring_tx_desc *d1 = | 822 | volatile struct vring_tx_desc *_d = |
791 | &vring->va[vring->swtail].tx; | 823 | &vring->va[vring->swtail].tx; |
792 | struct vring_tx_desc dd, *d = ⅆ | 824 | struct vring_tx_desc dd, *d = ⅆ |
793 | dma_addr_t pa; | 825 | dma_addr_t pa; |
794 | struct sk_buff *skb; | 826 | struct sk_buff *skb; |
827 | u16 dmalen; | ||
795 | 828 | ||
796 | dd = *d1; | 829 | *d = *_d; |
797 | 830 | ||
798 | if (!(d->dma.status & TX_DMA_STATUS_DU)) | 831 | if (!(d->dma.status & TX_DMA_STATUS_DU)) |
799 | break; | 832 | break; |
800 | 833 | ||
834 | dmalen = le16_to_cpu(d->dma.length); | ||
835 | trace_wil6210_tx_done(ringid, vring->swtail, dmalen, | ||
836 | d->dma.error); | ||
801 | wil_dbg_txrx(wil, | 837 | wil_dbg_txrx(wil, |
802 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", | 838 | "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n", |
803 | vring->swtail, d->dma.length, d->dma.status, | 839 | vring->swtail, dmalen, d->dma.status, |
804 | d->dma.error); | 840 | d->dma.error); |
805 | wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, | 841 | wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4, |
806 | (const void *)d, sizeof(*d), false); | 842 | (const void *)d, sizeof(*d), false); |
807 | 843 | ||
808 | pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32); | 844 | pa = wil_desc_addr(&d->dma.addr); |
809 | skb = vring->ctx[vring->swtail]; | 845 | skb = vring->ctx[vring->swtail]; |
810 | if (skb) { | 846 | if (skb) { |
811 | if (d->dma.error == 0) { | 847 | if (d->dma.error == 0) { |
@@ -815,18 +851,21 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid) | |||
815 | ndev->stats.tx_errors++; | 851 | ndev->stats.tx_errors++; |
816 | } | 852 | } |
817 | 853 | ||
818 | dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE); | 854 | dma_unmap_single(dev, pa, dmalen, DMA_TO_DEVICE); |
819 | dev_kfree_skb_any(skb); | 855 | dev_kfree_skb_any(skb); |
820 | vring->ctx[vring->swtail] = NULL; | 856 | vring->ctx[vring->swtail] = NULL; |
821 | } else { | 857 | } else { |
822 | dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE); | 858 | dma_unmap_page(dev, pa, dmalen, DMA_TO_DEVICE); |
823 | } | 859 | } |
824 | d->dma.addr_low = 0; | 860 | d->dma.addr.addr_low = 0; |
825 | d->dma.addr_high = 0; | 861 | d->dma.addr.addr_high = 0; |
826 | d->dma.length = 0; | 862 | d->dma.length = 0; |
827 | d->dma.status = TX_DMA_STATUS_DU; | 863 | d->dma.status = TX_DMA_STATUS_DU; |
828 | vring->swtail = wil_vring_next_tail(vring); | 864 | vring->swtail = wil_vring_next_tail(vring); |
865 | done++; | ||
829 | } | 866 | } |
830 | if (wil_vring_avail_tx(vring) > vring->size/4) | 867 | if (wil_vring_avail_tx(vring) > vring->size/4) |
831 | netif_tx_wake_all_queues(wil_to_ndev(wil)); | 868 | netif_tx_wake_all_queues(wil_to_ndev(wil)); |
869 | |||
870 | return done; | ||
832 | } | 871 | } |
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index adef12fb2aee..23c0781cdb93 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h | |||
@@ -27,6 +27,28 @@ | |||
27 | #define WIL6210_RTAP_SIZE (128) | 27 | #define WIL6210_RTAP_SIZE (128) |
28 | 28 | ||
29 | /* Tx/Rx path */ | 29 | /* Tx/Rx path */ |
30 | |||
31 | /* | ||
32 | * Common representation of physical address in Vring | ||
33 | */ | ||
34 | struct vring_dma_addr { | ||
35 | __le32 addr_low; | ||
36 | __le16 addr_high; | ||
37 | } __packed; | ||
38 | |||
39 | static inline dma_addr_t wil_desc_addr(struct vring_dma_addr *addr) | ||
40 | { | ||
41 | return le32_to_cpu(addr->addr_low) | | ||
42 | ((u64)le16_to_cpu(addr->addr_high) << 32); | ||
43 | } | ||
44 | |||
45 | static inline void wil_desc_addr_set(struct vring_dma_addr *addr, | ||
46 | dma_addr_t pa) | ||
47 | { | ||
48 | addr->addr_low = cpu_to_le32(lower_32_bits(pa)); | ||
49 | addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa)); | ||
50 | } | ||
51 | |||
30 | /* | 52 | /* |
31 | * Tx descriptor - MAC part | 53 | * Tx descriptor - MAC part |
32 | * [dword 0] | 54 | * [dword 0] |
@@ -216,13 +238,12 @@ struct vring_tx_mac { | |||
216 | 238 | ||
217 | struct vring_tx_dma { | 239 | struct vring_tx_dma { |
218 | u32 d0; | 240 | u32 d0; |
219 | u32 addr_low; | 241 | struct vring_dma_addr addr; |
220 | u16 addr_high; | ||
221 | u8 ip_length; | 242 | u8 ip_length; |
222 | u8 b11; /* 0..6: mac_length; 7:ip_version */ | 243 | u8 b11; /* 0..6: mac_length; 7:ip_version */ |
223 | u8 error; /* 0..2: err; 3..7: reserved; */ | 244 | u8 error; /* 0..2: err; 3..7: reserved; */ |
224 | u8 status; /* 0: used; 1..7; reserved */ | 245 | u8 status; /* 0: used; 1..7; reserved */ |
225 | u16 length; | 246 | __le16 length; |
226 | } __packed; | 247 | } __packed; |
227 | 248 | ||
228 | /* | 249 | /* |
@@ -315,13 +336,12 @@ struct vring_rx_mac { | |||
315 | 336 | ||
316 | struct vring_rx_dma { | 337 | struct vring_rx_dma { |
317 | u32 d0; | 338 | u32 d0; |
318 | u32 addr_low; | 339 | struct vring_dma_addr addr; |
319 | u16 addr_high; | ||
320 | u8 ip_length; | 340 | u8 ip_length; |
321 | u8 b11; | 341 | u8 b11; |
322 | u8 error; | 342 | u8 error; |
323 | u8 status; | 343 | u8 status; |
324 | u16 length; | 344 | __le16 length; |
325 | } __packed; | 345 | } __packed; |
326 | 346 | ||
327 | struct vring_tx_desc { | 347 | struct vring_tx_desc { |
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 8f76ecd8a7e5..373cf656f5b0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h | |||
@@ -34,9 +34,11 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) | |||
34 | 34 | ||
35 | #define WIL6210_MEM_SIZE (2*1024*1024UL) | 35 | #define WIL6210_MEM_SIZE (2*1024*1024UL) |
36 | 36 | ||
37 | #define WIL6210_RX_RING_SIZE (128) | 37 | #define WIL6210_RX_RING_SIZE (128) |
38 | #define WIL6210_TX_RING_SIZE (128) | 38 | #define WIL6210_TX_RING_SIZE (128) |
39 | #define WIL6210_MAX_TX_RINGS (24) | 39 | #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ |
40 | #define WIL6210_MAX_CID (8) /* HW limit */ | ||
41 | #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ | ||
40 | 42 | ||
41 | /* Hardware definitions begin */ | 43 | /* Hardware definitions begin */ |
42 | 44 | ||
@@ -184,6 +186,7 @@ struct vring { | |||
184 | 186 | ||
185 | enum { /* for wil6210_priv.status */ | 187 | enum { /* for wil6210_priv.status */ |
186 | wil_status_fwready = 0, | 188 | wil_status_fwready = 0, |
189 | wil_status_fwconnecting, | ||
187 | wil_status_fwconnected, | 190 | wil_status_fwconnected, |
188 | wil_status_dontscan, | 191 | wil_status_dontscan, |
189 | wil_status_reset_done, | 192 | wil_status_reset_done, |
@@ -239,6 +242,8 @@ struct wil6210_priv { | |||
239 | * - consumed in thread by wmi_event_worker | 242 | * - consumed in thread by wmi_event_worker |
240 | */ | 243 | */ |
241 | spinlock_t wmi_ev_lock; | 244 | spinlock_t wmi_ev_lock; |
245 | struct napi_struct napi_rx; | ||
246 | struct napi_struct napi_tx; | ||
242 | /* DMA related */ | 247 | /* DMA related */ |
243 | struct vring vring_rx; | 248 | struct vring vring_rx; |
244 | struct vring vring_tx[WIL6210_MAX_TX_RINGS]; | 249 | struct vring vring_tx[WIL6210_MAX_TX_RINGS]; |
@@ -267,9 +272,13 @@ struct wil6210_priv { | |||
267 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) | 272 | #define wil_to_ndev(i) (wil_to_wdev(i)->netdev) |
268 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) | 273 | #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) |
269 | 274 | ||
270 | #define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg) | 275 | int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); |
271 | #define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg) | 276 | int wil_err(struct wil6210_priv *wil, const char *fmt, ...); |
272 | #define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg) | 277 | int wil_info(struct wil6210_priv *wil, const char *fmt, ...); |
278 | #define wil_dbg(wil, fmt, arg...) do { \ | ||
279 | netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ | ||
280 | wil_dbg_trace(wil, fmt, ##arg); \ | ||
281 | } while (0) | ||
273 | 282 | ||
274 | #define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) | 283 | #define wil_dbg_irq(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg) |
275 | #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) | 284 | #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) |
@@ -356,10 +365,12 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, | |||
356 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); | 365 | void wil_vring_fini_tx(struct wil6210_priv *wil, int id); |
357 | 366 | ||
358 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); | 367 | netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); |
359 | void wil_tx_complete(struct wil6210_priv *wil, int ringid); | 368 | int wil_tx_complete(struct wil6210_priv *wil, int ringid); |
369 | void wil6210_unmask_irq_tx(struct wil6210_priv *wil); | ||
360 | 370 | ||
361 | /* RX API */ | 371 | /* RX API */ |
362 | void wil_rx_handle(struct wil6210_priv *wil); | 372 | void wil_rx_handle(struct wil6210_priv *wil, int *quota); |
373 | void wil6210_unmask_irq_rx(struct wil6210_priv *wil); | ||
363 | 374 | ||
364 | int wil_iftype_nl2wmi(enum nl80211_iftype type); | 375 | int wil_iftype_nl2wmi(enum nl80211_iftype type); |
365 | 376 | ||
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 45b04e383f9a..527ffb543821 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "wil6210.h" | 20 | #include "wil6210.h" |
21 | #include "txrx.h" | 21 | #include "txrx.h" |
22 | #include "wmi.h" | 22 | #include "wmi.h" |
23 | #include "trace.h" | ||
23 | 24 | ||
24 | /** | 25 | /** |
25 | * WMI event receiving - theory of operations | 26 | * WMI event receiving - theory of operations |
@@ -246,6 +247,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) | |||
246 | iowrite32(r->head = next_head, wil->csr + HOST_MBOX + | 247 | iowrite32(r->head = next_head, wil->csr + HOST_MBOX + |
247 | offsetof(struct wil6210_mbox_ctl, tx.head)); | 248 | offsetof(struct wil6210_mbox_ctl, tx.head)); |
248 | 249 | ||
250 | trace_wil6210_wmi_cmd(cmdid, buf, len); | ||
251 | |||
249 | /* interrupt to FW */ | 252 | /* interrupt to FW */ |
250 | iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); | 253 | iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); |
251 | 254 | ||
@@ -406,7 +409,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
406 | 409 | ||
407 | if ((wdev->iftype == NL80211_IFTYPE_STATION) || | 410 | if ((wdev->iftype == NL80211_IFTYPE_STATION) || |
408 | (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { | 411 | (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { |
409 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | 412 | if (!test_bit(wil_status_fwconnecting, &wil->status)) { |
410 | wil_err(wil, "Not in connecting state\n"); | 413 | wil_err(wil, "Not in connecting state\n"); |
411 | return; | 414 | return; |
412 | } | 415 | } |
@@ -430,6 +433,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) | |||
430 | 433 | ||
431 | cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); | 434 | cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL); |
432 | } | 435 | } |
436 | clear_bit(wil_status_fwconnecting, &wil->status); | ||
433 | set_bit(wil_status_fwconnected, &wil->status); | 437 | set_bit(wil_status_fwconnected, &wil->status); |
434 | 438 | ||
435 | /* FIXME FW can transmit only ucast frames to peer */ | 439 | /* FIXME FW can transmit only ucast frames to peer */ |
@@ -635,8 +639,9 @@ void wmi_recv_cmd(struct wil6210_priv *wil) | |||
635 | hdr.flags); | 639 | hdr.flags); |
636 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && | 640 | if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && |
637 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { | 641 | (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { |
638 | wil_dbg_wmi(wil, "WMI event 0x%04x\n", | 642 | u16 id = le16_to_cpu(evt->event.wmi.id); |
639 | evt->event.wmi.id); | 643 | wil_dbg_wmi(wil, "WMI event 0x%04x\n", id); |
644 | trace_wil6210_wmi_event(id, &evt->event.wmi, len); | ||
640 | } | 645 | } |
641 | wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, | 646 | wil_hex_dump_wmi("evt ", DUMP_PREFIX_OFFSET, 16, 1, |
642 | &evt->event.hdr, sizeof(hdr) + len, true); | 647 | &evt->event.hdr, sizeof(hdr) + len, true); |
@@ -724,7 +729,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan) | |||
724 | .bcon_interval = cpu_to_le16(bi), | 729 | .bcon_interval = cpu_to_le16(bi), |
725 | .network_type = wmi_nettype, | 730 | .network_type = wmi_nettype, |
726 | .disable_sec_offload = 1, | 731 | .disable_sec_offload = 1, |
727 | .channel = chan, | 732 | .channel = chan - 1, |
728 | }; | 733 | }; |
729 | struct { | 734 | struct { |
730 | struct wil6210_mbox_hdr_wmi wmi; | 735 | struct wil6210_mbox_hdr_wmi wmi; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 44fa0cdbf97b..11400b39cf0b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | |||
@@ -606,7 +606,8 @@ static int brcmf_sdio_pd_remove(struct platform_device *pdev) | |||
606 | static struct platform_driver brcmf_sdio_pd = { | 606 | static struct platform_driver brcmf_sdio_pd = { |
607 | .remove = brcmf_sdio_pd_remove, | 607 | .remove = brcmf_sdio_pd_remove, |
608 | .driver = { | 608 | .driver = { |
609 | .name = BRCMFMAC_SDIO_PDATA_NAME | 609 | .name = BRCMFMAC_SDIO_PDATA_NAME, |
610 | .owner = THIS_MODULE, | ||
610 | } | 611 | } |
611 | }; | 612 | }; |
612 | 613 | ||
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 1585cc5bf866..bd982856d385 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c | |||
@@ -900,7 +900,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, | |||
900 | if (supr_status) { | 900 | if (supr_status) { |
901 | update_rate = false; | 901 | update_rate = false; |
902 | if (supr_status == TX_STATUS_SUPR_BADCH) { | 902 | if (supr_status == TX_STATUS_SUPR_BADCH) { |
903 | brcms_err(wlc->hw->d11core, | 903 | brcms_dbg_ht(wlc->hw->d11core, |
904 | "%s: Pkt tx suppressed, illegal channel possibly %d\n", | 904 | "%s: Pkt tx suppressed, illegal channel possibly %d\n", |
905 | __func__, CHSPEC_CHANNEL( | 905 | __func__, CHSPEC_CHANNEL( |
906 | wlc->default_bss->chanspec)); | 906 | wlc->default_bss->chanspec)); |
diff --git a/drivers/net/wireless/cw1200/Kconfig b/drivers/net/wireless/cw1200/Kconfig new file mode 100644 index 000000000000..7a585d4e9c8e --- /dev/null +++ b/drivers/net/wireless/cw1200/Kconfig | |||
@@ -0,0 +1,45 @@ | |||
1 | config CW1200 | ||
2 | tristate "CW1200 WLAN support" | ||
3 | depends on MAC80211 && CFG80211 | ||
4 | help | ||
5 | This is a driver for the ST-E CW1100 & CW1200 WLAN chipsets. | ||
6 | This option just enables the driver core, see below for | ||
7 | specific bus support. | ||
8 | |||
9 | if CW1200 | ||
10 | |||
11 | config CW1200_WLAN_SDIO | ||
12 | tristate "Support SDIO platforms" | ||
13 | depends on CW1200 && MMC | ||
14 | help | ||
15 | Enable support for the CW1200 connected via an SDIO bus. | ||
16 | By default this driver only supports the Sagrad SG901-1091/1098 EVK | ||
17 | and similar designs that utilize a hardware reset circuit. To | ||
18 | support different CW1200 SDIO designs you will need to override | ||
19 | the default platform data by calling cw1200_sdio_set_platform_data() | ||
20 | in your board setup file. | ||
21 | |||
22 | config CW1200_WLAN_SPI | ||
23 | tristate "Support SPI platforms" | ||
24 | depends on CW1200 && SPI | ||
25 | help | ||
26 | Enables support for the CW1200 connected via a SPI bus. You will | ||
27 | need to add appropriate platform data glue in your board setup | ||
28 | file. | ||
29 | |||
30 | menu "Driver debug features" | ||
31 | depends on CW1200 && DEBUG_FS | ||
32 | |||
33 | config CW1200_ETF | ||
34 | bool "Enable CW1200 Engineering Test Framework hooks" | ||
35 | help | ||
36 | If you don't know what this is, just say N. | ||
37 | |||
38 | config CW1200_ITP | ||
39 | bool "Enable ITP access" | ||
40 | help | ||
41 | If you don't know what this is, just say N. | ||
42 | |||
43 | endmenu | ||
44 | |||
45 | endif | ||
diff --git a/drivers/net/wireless/cw1200/Makefile b/drivers/net/wireless/cw1200/Makefile new file mode 100644 index 000000000000..bc6cbf91f26e --- /dev/null +++ b/drivers/net/wireless/cw1200/Makefile | |||
@@ -0,0 +1,22 @@ | |||
1 | cw1200_core-y := \ | ||
2 | fwio.o \ | ||
3 | txrx.o \ | ||
4 | main.o \ | ||
5 | queue.o \ | ||
6 | hwio.o \ | ||
7 | bh.o \ | ||
8 | wsm.o \ | ||
9 | sta.o \ | ||
10 | scan.o \ | ||
11 | debug.o | ||
12 | cw1200_core-$(CONFIG_CW1200_ITP) += itp.o | ||
13 | cw1200_core-$(CONFIG_PM) += pm.o | ||
14 | |||
15 | # CFLAGS_sta.o += -DDEBUG | ||
16 | |||
17 | cw1200_wlan_sdio-y := cw1200_sdio.o | ||
18 | cw1200_wlan_spi-y := cw1200_spi.o | ||
19 | |||
20 | obj-$(CONFIG_CW1200) += cw1200_core.o | ||
21 | obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o | ||
22 | obj-$(CONFIG_CW1200_WLAN_SPI) += cw1200_wlan_spi.o | ||
diff --git a/drivers/net/wireless/cw1200/bh.c b/drivers/net/wireless/cw1200/bh.c new file mode 100644 index 000000000000..324b57001da0 --- /dev/null +++ b/drivers/net/wireless/cw1200/bh.c | |||
@@ -0,0 +1,616 @@ | |||
1 | /* | ||
2 | * Device handling thread implementation for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * ST-Ericsson UMAC CW1200 driver, which is | ||
9 | * Copyright (c) 2010, ST-Ericsson | ||
10 | * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <net/mac80211.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/timer.h> | ||
21 | |||
22 | #include "cw1200.h" | ||
23 | #include "bh.h" | ||
24 | #include "hwio.h" | ||
25 | #include "wsm.h" | ||
26 | #include "hwbus.h" | ||
27 | #include "debug.h" | ||
28 | #include "fwio.h" | ||
29 | |||
30 | static int cw1200_bh(void *arg); | ||
31 | |||
32 | #define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) | ||
33 | /* an SPI message cannot be bigger than (2"12-1)*2 bytes | ||
34 | * "*2" to cvt to bytes */ | ||
35 | #define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) | ||
36 | #define PIGGYBACK_CTRL_REG (2) | ||
37 | #define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) | ||
38 | |||
39 | /* Suspend state privates */ | ||
40 | enum cw1200_bh_pm_state { | ||
41 | CW1200_BH_RESUMED = 0, | ||
42 | CW1200_BH_SUSPEND, | ||
43 | CW1200_BH_SUSPENDED, | ||
44 | CW1200_BH_RESUME, | ||
45 | }; | ||
46 | |||
47 | typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv, | ||
48 | u8 *data, size_t size); | ||
49 | |||
50 | static void cw1200_bh_work(struct work_struct *work) | ||
51 | { | ||
52 | struct cw1200_common *priv = | ||
53 | container_of(work, struct cw1200_common, bh_work); | ||
54 | cw1200_bh(priv); | ||
55 | } | ||
56 | |||
57 | int cw1200_register_bh(struct cw1200_common *priv) | ||
58 | { | ||
59 | int err = 0; | ||
60 | /* Realtime workqueue */ | ||
61 | priv->bh_workqueue = alloc_workqueue("cw1200_bh", | ||
62 | WQ_MEM_RECLAIM | WQ_HIGHPRI | ||
63 | | WQ_CPU_INTENSIVE, 1); | ||
64 | |||
65 | if (!priv->bh_workqueue) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | INIT_WORK(&priv->bh_work, cw1200_bh_work); | ||
69 | |||
70 | pr_debug("[BH] register.\n"); | ||
71 | |||
72 | atomic_set(&priv->bh_rx, 0); | ||
73 | atomic_set(&priv->bh_tx, 0); | ||
74 | atomic_set(&priv->bh_term, 0); | ||
75 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); | ||
76 | priv->bh_error = 0; | ||
77 | priv->hw_bufs_used = 0; | ||
78 | priv->buf_id_tx = 0; | ||
79 | priv->buf_id_rx = 0; | ||
80 | init_waitqueue_head(&priv->bh_wq); | ||
81 | init_waitqueue_head(&priv->bh_evt_wq); | ||
82 | |||
83 | err = !queue_work(priv->bh_workqueue, &priv->bh_work); | ||
84 | WARN_ON(err); | ||
85 | return err; | ||
86 | } | ||
87 | |||
88 | void cw1200_unregister_bh(struct cw1200_common *priv) | ||
89 | { | ||
90 | atomic_add(1, &priv->bh_term); | ||
91 | wake_up(&priv->bh_wq); | ||
92 | |||
93 | flush_workqueue(priv->bh_workqueue); | ||
94 | |||
95 | destroy_workqueue(priv->bh_workqueue); | ||
96 | priv->bh_workqueue = NULL; | ||
97 | |||
98 | pr_debug("[BH] unregistered.\n"); | ||
99 | } | ||
100 | |||
101 | void cw1200_irq_handler(struct cw1200_common *priv) | ||
102 | { | ||
103 | pr_debug("[BH] irq.\n"); | ||
104 | |||
105 | /* Disable Interrupts! */ | ||
106 | /* NOTE: hwbus_ops->lock already held */ | ||
107 | __cw1200_irq_enable(priv, 0); | ||
108 | |||
109 | if (/* WARN_ON */(priv->bh_error)) | ||
110 | return; | ||
111 | |||
112 | if (atomic_add_return(1, &priv->bh_rx) == 1) | ||
113 | wake_up(&priv->bh_wq); | ||
114 | } | ||
115 | EXPORT_SYMBOL_GPL(cw1200_irq_handler); | ||
116 | |||
117 | void cw1200_bh_wakeup(struct cw1200_common *priv) | ||
118 | { | ||
119 | pr_debug("[BH] wakeup.\n"); | ||
120 | if (priv->bh_error) { | ||
121 | pr_err("[BH] wakeup failed (BH error)\n"); | ||
122 | return; | ||
123 | } | ||
124 | |||
125 | if (atomic_add_return(1, &priv->bh_tx) == 1) | ||
126 | wake_up(&priv->bh_wq); | ||
127 | } | ||
128 | |||
129 | int cw1200_bh_suspend(struct cw1200_common *priv) | ||
130 | { | ||
131 | pr_debug("[BH] suspend.\n"); | ||
132 | if (priv->bh_error) { | ||
133 | wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n"); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND); | ||
138 | wake_up(&priv->bh_wq); | ||
139 | return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || | ||
140 | (CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)), | ||
141 | 1 * HZ) ? 0 : -ETIMEDOUT; | ||
142 | } | ||
143 | |||
144 | int cw1200_bh_resume(struct cw1200_common *priv) | ||
145 | { | ||
146 | pr_debug("[BH] resume.\n"); | ||
147 | if (priv->bh_error) { | ||
148 | wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n"); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | |||
152 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUME); | ||
153 | wake_up(&priv->bh_wq); | ||
154 | return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || | ||
155 | (CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)), | ||
156 | 1 * HZ) ? 0 : -ETIMEDOUT; | ||
157 | } | ||
158 | |||
159 | static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv) | ||
160 | { | ||
161 | ++priv->hw_bufs_used; | ||
162 | } | ||
163 | |||
164 | int wsm_release_tx_buffer(struct cw1200_common *priv, int count) | ||
165 | { | ||
166 | int ret = 0; | ||
167 | int hw_bufs_used = priv->hw_bufs_used; | ||
168 | |||
169 | priv->hw_bufs_used -= count; | ||
170 | if (WARN_ON(priv->hw_bufs_used < 0)) | ||
171 | ret = -1; | ||
172 | else if (hw_bufs_used >= priv->wsm_caps.input_buffers) | ||
173 | ret = 1; | ||
174 | if (!priv->hw_bufs_used) | ||
175 | wake_up(&priv->bh_evt_wq); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv, | ||
180 | u16 *ctrl_reg) | ||
181 | { | ||
182 | int ret; | ||
183 | |||
184 | ret = cw1200_reg_read_16(priv, | ||
185 | ST90TDS_CONTROL_REG_ID, ctrl_reg); | ||
186 | if (ret) { | ||
187 | ret = cw1200_reg_read_16(priv, | ||
188 | ST90TDS_CONTROL_REG_ID, ctrl_reg); | ||
189 | if (ret) | ||
190 | pr_err("[BH] Failed to read control register.\n"); | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static int cw1200_device_wakeup(struct cw1200_common *priv) | ||
197 | { | ||
198 | u16 ctrl_reg; | ||
199 | int ret; | ||
200 | |||
201 | pr_debug("[BH] Device wakeup.\n"); | ||
202 | |||
203 | /* First, set the dpll register */ | ||
204 | ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, | ||
205 | cw1200_dpll_from_clk(priv->hw_refclk)); | ||
206 | if (WARN_ON(ret)) | ||
207 | return ret; | ||
208 | |||
209 | /* To force the device to be always-on, the host sets WLAN_UP to 1 */ | ||
210 | ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, | ||
211 | ST90TDS_CONT_WUP_BIT); | ||
212 | if (WARN_ON(ret)) | ||
213 | return ret; | ||
214 | |||
215 | ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg); | ||
216 | if (WARN_ON(ret)) | ||
217 | return ret; | ||
218 | |||
219 | /* If the device returns WLAN_RDY as 1, the device is active and will | ||
220 | * remain active. */ | ||
221 | if (ctrl_reg & ST90TDS_CONT_RDY_BIT) { | ||
222 | pr_debug("[BH] Device awake.\n"); | ||
223 | return 1; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /* Must be called from BH thraed. */ | ||
230 | void cw1200_enable_powersave(struct cw1200_common *priv, | ||
231 | bool enable) | ||
232 | { | ||
233 | pr_debug("[BH] Powerave is %s.\n", | ||
234 | enable ? "enabled" : "disabled"); | ||
235 | priv->powersave_enabled = enable; | ||
236 | } | ||
237 | |||
238 | static int cw1200_bh_rx_helper(struct cw1200_common *priv, | ||
239 | uint16_t *ctrl_reg, | ||
240 | int *tx) | ||
241 | { | ||
242 | size_t read_len = 0; | ||
243 | struct sk_buff *skb_rx = NULL; | ||
244 | struct wsm_hdr *wsm; | ||
245 | size_t wsm_len; | ||
246 | u16 wsm_id; | ||
247 | u8 wsm_seq; | ||
248 | int rx_resync = 1; | ||
249 | |||
250 | size_t alloc_len; | ||
251 | u8 *data; | ||
252 | |||
253 | read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2; | ||
254 | if (!read_len) | ||
255 | return 0; /* No more work */ | ||
256 | |||
257 | if (WARN_ON((read_len < sizeof(struct wsm_hdr)) || | ||
258 | (read_len > EFFECTIVE_BUF_SIZE))) { | ||
259 | pr_debug("Invalid read len: %zu (%04x)", | ||
260 | read_len, *ctrl_reg); | ||
261 | goto err; | ||
262 | } | ||
263 | |||
264 | /* Add SIZE of PIGGYBACK reg (CONTROL Reg) | ||
265 | * to the NEXT Message length + 2 Bytes for SKB */ | ||
266 | read_len = read_len + 2; | ||
267 | |||
268 | alloc_len = priv->hwbus_ops->align_size( | ||
269 | priv->hwbus_priv, read_len); | ||
270 | |||
271 | /* Check if not exceeding CW1200 capabilities */ | ||
272 | if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { | ||
273 | pr_debug("Read aligned len: %zu\n", | ||
274 | alloc_len); | ||
275 | } | ||
276 | |||
277 | skb_rx = dev_alloc_skb(alloc_len); | ||
278 | if (WARN_ON(!skb_rx)) | ||
279 | goto err; | ||
280 | |||
281 | skb_trim(skb_rx, 0); | ||
282 | skb_put(skb_rx, read_len); | ||
283 | data = skb_rx->data; | ||
284 | if (WARN_ON(!data)) | ||
285 | goto err; | ||
286 | |||
287 | if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) { | ||
288 | pr_err("rx blew up, len %zu\n", alloc_len); | ||
289 | goto err; | ||
290 | } | ||
291 | |||
292 | /* Piggyback */ | ||
293 | *ctrl_reg = __le16_to_cpu( | ||
294 | ((__le16 *)data)[alloc_len / 2 - 1]); | ||
295 | |||
296 | wsm = (struct wsm_hdr *)data; | ||
297 | wsm_len = __le16_to_cpu(wsm->len); | ||
298 | if (WARN_ON(wsm_len > read_len)) | ||
299 | goto err; | ||
300 | |||
301 | if (priv->wsm_enable_wsm_dumps) | ||
302 | print_hex_dump_bytes("<-- ", | ||
303 | DUMP_PREFIX_NONE, | ||
304 | data, wsm_len); | ||
305 | |||
306 | wsm_id = __le16_to_cpu(wsm->id) & 0xFFF; | ||
307 | wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7; | ||
308 | |||
309 | skb_trim(skb_rx, wsm_len); | ||
310 | |||
311 | if (wsm_id == 0x0800) { | ||
312 | wsm_handle_exception(priv, | ||
313 | &data[sizeof(*wsm)], | ||
314 | wsm_len - sizeof(*wsm)); | ||
315 | goto err; | ||
316 | } else if (!rx_resync) { | ||
317 | if (WARN_ON(wsm_seq != priv->wsm_rx_seq)) | ||
318 | goto err; | ||
319 | } | ||
320 | priv->wsm_rx_seq = (wsm_seq + 1) & 7; | ||
321 | rx_resync = 0; | ||
322 | |||
323 | if (wsm_id & 0x0400) { | ||
324 | int rc = wsm_release_tx_buffer(priv, 1); | ||
325 | if (WARN_ON(rc < 0)) | ||
326 | return rc; | ||
327 | else if (rc > 0) | ||
328 | *tx = 1; | ||
329 | } | ||
330 | |||
331 | /* cw1200_wsm_rx takes care on SKB livetime */ | ||
332 | if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx))) | ||
333 | goto err; | ||
334 | |||
335 | if (skb_rx) { | ||
336 | dev_kfree_skb(skb_rx); | ||
337 | skb_rx = NULL; | ||
338 | } | ||
339 | |||
340 | return 0; | ||
341 | |||
342 | err: | ||
343 | if (skb_rx) { | ||
344 | dev_kfree_skb(skb_rx); | ||
345 | skb_rx = NULL; | ||
346 | } | ||
347 | return -1; | ||
348 | } | ||
349 | |||
350 | static int cw1200_bh_tx_helper(struct cw1200_common *priv, | ||
351 | int *pending_tx, | ||
352 | int *tx_burst) | ||
353 | { | ||
354 | size_t tx_len; | ||
355 | u8 *data; | ||
356 | int ret; | ||
357 | struct wsm_hdr *wsm; | ||
358 | |||
359 | if (priv->device_can_sleep) { | ||
360 | ret = cw1200_device_wakeup(priv); | ||
361 | if (WARN_ON(ret < 0)) { /* Error in wakeup */ | ||
362 | *pending_tx = 1; | ||
363 | return 0; | ||
364 | } else if (ret) { /* Woke up */ | ||
365 | priv->device_can_sleep = false; | ||
366 | } else { /* Did not awake */ | ||
367 | *pending_tx = 1; | ||
368 | return 0; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | wsm_alloc_tx_buffer(priv); | ||
373 | ret = wsm_get_tx(priv, &data, &tx_len, tx_burst); | ||
374 | if (ret <= 0) { | ||
375 | wsm_release_tx_buffer(priv, 1); | ||
376 | if (WARN_ON(ret < 0)) | ||
377 | return ret; /* Error */ | ||
378 | return 0; /* No work */ | ||
379 | } | ||
380 | |||
381 | wsm = (struct wsm_hdr *)data; | ||
382 | BUG_ON(tx_len < sizeof(*wsm)); | ||
383 | BUG_ON(__le16_to_cpu(wsm->len) != tx_len); | ||
384 | |||
385 | atomic_add(1, &priv->bh_tx); | ||
386 | |||
387 | tx_len = priv->hwbus_ops->align_size( | ||
388 | priv->hwbus_priv, tx_len); | ||
389 | |||
390 | /* Check if not exceeding CW1200 capabilities */ | ||
391 | if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE)) | ||
392 | pr_debug("Write aligned len: %zu\n", tx_len); | ||
393 | |||
394 | wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX)); | ||
395 | wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq)); | ||
396 | |||
397 | if (WARN_ON(cw1200_data_write(priv, data, tx_len))) { | ||
398 | pr_err("tx blew up, len %zu\n", tx_len); | ||
399 | wsm_release_tx_buffer(priv, 1); | ||
400 | return -1; /* Error */ | ||
401 | } | ||
402 | |||
403 | if (priv->wsm_enable_wsm_dumps) | ||
404 | print_hex_dump_bytes("--> ", | ||
405 | DUMP_PREFIX_NONE, | ||
406 | data, | ||
407 | __le16_to_cpu(wsm->len)); | ||
408 | |||
409 | wsm_txed(priv, data); | ||
410 | priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; | ||
411 | |||
412 | if (*tx_burst > 1) { | ||
413 | cw1200_debug_tx_burst(priv); | ||
414 | return 1; /* Work remains */ | ||
415 | } | ||
416 | |||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | static int cw1200_bh(void *arg) | ||
421 | { | ||
422 | struct cw1200_common *priv = arg; | ||
423 | int rx, tx, term, suspend; | ||
424 | u16 ctrl_reg = 0; | ||
425 | int tx_allowed; | ||
426 | int pending_tx = 0; | ||
427 | int tx_burst; | ||
428 | long status; | ||
429 | u32 dummy; | ||
430 | int ret; | ||
431 | |||
432 | for (;;) { | ||
433 | if (!priv->hw_bufs_used && | ||
434 | priv->powersave_enabled && | ||
435 | !priv->device_can_sleep && | ||
436 | !atomic_read(&priv->recent_scan)) { | ||
437 | status = 1 * HZ; | ||
438 | pr_debug("[BH] Device wakedown. No data.\n"); | ||
439 | cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0); | ||
440 | priv->device_can_sleep = true; | ||
441 | } else if (priv->hw_bufs_used) { | ||
442 | /* Interrupt loss detection */ | ||
443 | status = 1 * HZ; | ||
444 | } else { | ||
445 | status = MAX_SCHEDULE_TIMEOUT; | ||
446 | } | ||
447 | |||
448 | /* Dummy Read for SDIO retry mechanism*/ | ||
449 | if ((priv->hw_type != -1) && | ||
450 | (atomic_read(&priv->bh_rx) == 0) && | ||
451 | (atomic_read(&priv->bh_tx) == 0)) | ||
452 | cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID, | ||
453 | &dummy, sizeof(dummy)); | ||
454 | |||
455 | pr_debug("[BH] waiting ...\n"); | ||
456 | status = wait_event_interruptible_timeout(priv->bh_wq, ({ | ||
457 | rx = atomic_xchg(&priv->bh_rx, 0); | ||
458 | tx = atomic_xchg(&priv->bh_tx, 0); | ||
459 | term = atomic_xchg(&priv->bh_term, 0); | ||
460 | suspend = pending_tx ? | ||
461 | 0 : atomic_read(&priv->bh_suspend); | ||
462 | (rx || tx || term || suspend || priv->bh_error); | ||
463 | }), status); | ||
464 | |||
465 | pr_debug("[BH] - rx: %d, tx: %d, term: %d, suspend: %d, status: %ld\n", | ||
466 | rx, tx, term, suspend, status); | ||
467 | |||
468 | /* Did an error occur? */ | ||
469 | if ((status < 0 && status != -ERESTARTSYS) || | ||
470 | term || priv->bh_error) { | ||
471 | break; | ||
472 | } | ||
473 | if (!status) { /* wait_event timed out */ | ||
474 | unsigned long timestamp = jiffies; | ||
475 | long timeout; | ||
476 | int pending = 0; | ||
477 | int i; | ||
478 | |||
479 | /* Check to see if we have any outstanding frames */ | ||
480 | if (priv->hw_bufs_used && (!rx || !tx)) { | ||
481 | wiphy_warn(priv->hw->wiphy, | ||
482 | "Missed interrupt? (%d frames outstanding)\n", | ||
483 | priv->hw_bufs_used); | ||
484 | rx = 1; | ||
485 | |||
486 | /* Get a timestamp of "oldest" frame */ | ||
487 | for (i = 0; i < 4; ++i) | ||
488 | pending += cw1200_queue_get_xmit_timestamp( | ||
489 | &priv->tx_queue[i], | ||
490 | ×tamp, | ||
491 | priv->pending_frame_id); | ||
492 | |||
493 | /* Check if frame transmission is timed out. | ||
494 | * Add an extra second with respect to possible | ||
495 | * interrupt loss. | ||
496 | */ | ||
497 | timeout = timestamp + | ||
498 | WSM_CMD_LAST_CHANCE_TIMEOUT + | ||
499 | 1 * HZ - | ||
500 | jiffies; | ||
501 | |||
502 | /* And terminate BH thread if the frame is "stuck" */ | ||
503 | if (pending && timeout < 0) { | ||
504 | wiphy_warn(priv->hw->wiphy, | ||
505 | "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n", | ||
506 | priv->hw_bufs_used, pending, | ||
507 | timestamp, jiffies); | ||
508 | break; | ||
509 | } | ||
510 | } else if (!priv->device_can_sleep && | ||
511 | !atomic_read(&priv->recent_scan)) { | ||
512 | pr_debug("[BH] Device wakedown. Timeout.\n"); | ||
513 | cw1200_reg_write_16(priv, | ||
514 | ST90TDS_CONTROL_REG_ID, 0); | ||
515 | priv->device_can_sleep = true; | ||
516 | } | ||
517 | goto done; | ||
518 | } else if (suspend) { | ||
519 | pr_debug("[BH] Device suspend.\n"); | ||
520 | if (priv->powersave_enabled) { | ||
521 | pr_debug("[BH] Device wakedown. Suspend.\n"); | ||
522 | cw1200_reg_write_16(priv, | ||
523 | ST90TDS_CONTROL_REG_ID, 0); | ||
524 | priv->device_can_sleep = true; | ||
525 | } | ||
526 | |||
527 | atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED); | ||
528 | wake_up(&priv->bh_evt_wq); | ||
529 | status = wait_event_interruptible(priv->bh_wq, | ||
530 | CW1200_BH_RESUME == atomic_read(&priv->bh_suspend)); | ||
531 | if (status < 0) { | ||
532 | wiphy_err(priv->hw->wiphy, | ||
533 | "Failed to wait for resume: %ld.\n", | ||
534 | status); | ||
535 | break; | ||
536 | } | ||
537 | pr_debug("[BH] Device resume.\n"); | ||
538 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); | ||
539 | wake_up(&priv->bh_evt_wq); | ||
540 | atomic_add(1, &priv->bh_rx); | ||
541 | goto done; | ||
542 | } | ||
543 | |||
544 | rx: | ||
545 | tx += pending_tx; | ||
546 | pending_tx = 0; | ||
547 | |||
548 | if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) | ||
549 | break; | ||
550 | |||
551 | /* Don't bother trying to rx unless we have data to read */ | ||
552 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { | ||
553 | ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); | ||
554 | if (ret < 0) | ||
555 | break; | ||
556 | /* Double up here if there's more data.. */ | ||
557 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { | ||
558 | ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); | ||
559 | if (ret < 0) | ||
560 | break; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | tx: | ||
565 | if (tx) { | ||
566 | tx = 0; | ||
567 | |||
568 | BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers); | ||
569 | tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used; | ||
570 | tx_allowed = tx_burst > 0; | ||
571 | |||
572 | if (!tx_allowed) { | ||
573 | /* Buffers full. Ensure we process tx | ||
574 | * after we handle rx.. | ||
575 | */ | ||
576 | pending_tx = tx; | ||
577 | goto done_rx; | ||
578 | } | ||
579 | ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst); | ||
580 | if (ret < 0) | ||
581 | break; | ||
582 | if (ret > 0) /* More to transmit */ | ||
583 | tx = ret; | ||
584 | |||
585 | /* Re-read ctrl reg */ | ||
586 | if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | done_rx: | ||
591 | if (priv->bh_error) | ||
592 | break; | ||
593 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) | ||
594 | goto rx; | ||
595 | if (tx) | ||
596 | goto tx; | ||
597 | |||
598 | done: | ||
599 | /* Re-enable device interrupts */ | ||
600 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
601 | __cw1200_irq_enable(priv, 1); | ||
602 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
603 | } | ||
604 | |||
605 | /* Explicitly disable device interrupts */ | ||
606 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
607 | __cw1200_irq_enable(priv, 0); | ||
608 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
609 | |||
610 | if (!term) { | ||
611 | pr_err("[BH] Fatal error, exiting.\n"); | ||
612 | priv->bh_error = 1; | ||
613 | /* TODO: schedule_work(recovery) */ | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
diff --git a/drivers/net/wireless/cw1200/bh.h b/drivers/net/wireless/cw1200/bh.h new file mode 100644 index 000000000000..af6a4853728f --- /dev/null +++ b/drivers/net/wireless/cw1200/bh.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Device handling thread interface for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_BH_H | ||
13 | #define CW1200_BH_H | ||
14 | |||
15 | /* extern */ struct cw1200_common; | ||
16 | |||
17 | int cw1200_register_bh(struct cw1200_common *priv); | ||
18 | void cw1200_unregister_bh(struct cw1200_common *priv); | ||
19 | void cw1200_irq_handler(struct cw1200_common *priv); | ||
20 | void cw1200_bh_wakeup(struct cw1200_common *priv); | ||
21 | int cw1200_bh_suspend(struct cw1200_common *priv); | ||
22 | int cw1200_bh_resume(struct cw1200_common *priv); | ||
23 | /* Must be called from BH thread. */ | ||
24 | void cw1200_enable_powersave(struct cw1200_common *priv, | ||
25 | bool enable); | ||
26 | int wsm_release_tx_buffer(struct cw1200_common *priv, int count); | ||
27 | |||
28 | #endif /* CW1200_BH_H */ | ||
diff --git a/drivers/net/wireless/cw1200/cw1200.h b/drivers/net/wireless/cw1200/cw1200.h new file mode 100644 index 000000000000..95320f2b25eb --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200.h | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * Common private data for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on the mac80211 Prism54 code, which is | ||
8 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> | ||
9 | * | ||
10 | * Based on the islsm (softmac prism54) driver, which is: | ||
11 | * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #ifndef CW1200_H | ||
19 | #define CW1200_H | ||
20 | |||
21 | #include <linux/wait.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <net/mac80211.h> | ||
25 | |||
26 | #include "queue.h" | ||
27 | #include "wsm.h" | ||
28 | #include "scan.h" | ||
29 | #include "txrx.h" | ||
30 | #include "pm.h" | ||
31 | |||
32 | /* Forward declarations */ | ||
33 | struct hwbus_ops; | ||
34 | struct task_struct; | ||
35 | struct cw1200_debug_priv; | ||
36 | struct firmware; | ||
37 | |||
38 | #ifdef CONFIG_CW1200_ETF | ||
39 | extern int etf_mode; | ||
40 | extern char *etf_firmware; | ||
41 | #endif | ||
42 | |||
43 | #define CW1200_MAX_CTRL_FRAME_LEN (0x1000) | ||
44 | |||
45 | #define CW1200_MAX_STA_IN_AP_MODE (5) | ||
46 | #define CW1200_LINK_ID_AFTER_DTIM (CW1200_MAX_STA_IN_AP_MODE + 1) | ||
47 | #define CW1200_LINK_ID_UAPSD (CW1200_MAX_STA_IN_AP_MODE + 2) | ||
48 | #define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3) | ||
49 | #define CW1200_MAX_REQUEUE_ATTEMPTS (5) | ||
50 | |||
51 | #define CW1200_MAX_TID (8) | ||
52 | |||
53 | #define CW1200_BLOCK_ACK_CNT (30) | ||
54 | #define CW1200_BLOCK_ACK_THLD (800) | ||
55 | #define CW1200_BLOCK_ACK_HIST (3) | ||
56 | #define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST) | ||
57 | |||
58 | #define CW1200_JOIN_TIMEOUT (1 * HZ) | ||
59 | #define CW1200_AUTH_TIMEOUT (5 * HZ) | ||
60 | |||
61 | struct cw1200_ht_info { | ||
62 | struct ieee80211_sta_ht_cap ht_cap; | ||
63 | enum nl80211_channel_type channel_type; | ||
64 | u16 operation_mode; | ||
65 | }; | ||
66 | |||
67 | /* Please keep order */ | ||
68 | enum cw1200_join_status { | ||
69 | CW1200_JOIN_STATUS_PASSIVE = 0, | ||
70 | CW1200_JOIN_STATUS_MONITOR, | ||
71 | CW1200_JOIN_STATUS_JOINING, | ||
72 | CW1200_JOIN_STATUS_PRE_STA, | ||
73 | CW1200_JOIN_STATUS_STA, | ||
74 | CW1200_JOIN_STATUS_IBSS, | ||
75 | CW1200_JOIN_STATUS_AP, | ||
76 | }; | ||
77 | |||
78 | enum cw1200_link_status { | ||
79 | CW1200_LINK_OFF, | ||
80 | CW1200_LINK_RESERVE, | ||
81 | CW1200_LINK_SOFT, | ||
82 | CW1200_LINK_HARD, | ||
83 | CW1200_LINK_RESET, | ||
84 | CW1200_LINK_RESET_REMAP, | ||
85 | }; | ||
86 | |||
87 | extern int cw1200_power_mode; | ||
88 | extern const char * const cw1200_fw_types[]; | ||
89 | |||
90 | struct cw1200_link_entry { | ||
91 | unsigned long timestamp; | ||
92 | enum cw1200_link_status status; | ||
93 | enum cw1200_link_status prev_status; | ||
94 | u8 mac[ETH_ALEN]; | ||
95 | u8 buffered[CW1200_MAX_TID]; | ||
96 | struct sk_buff_head rx_queue; | ||
97 | }; | ||
98 | |||
99 | struct cw1200_common { | ||
100 | /* interfaces to the rest of the stack */ | ||
101 | struct ieee80211_hw *hw; | ||
102 | struct ieee80211_vif *vif; | ||
103 | struct device *pdev; | ||
104 | |||
105 | /* Statistics */ | ||
106 | struct ieee80211_low_level_stats stats; | ||
107 | |||
108 | /* Our macaddr */ | ||
109 | u8 mac_addr[ETH_ALEN]; | ||
110 | |||
111 | /* Hardware interface */ | ||
112 | const struct hwbus_ops *hwbus_ops; | ||
113 | struct hwbus_priv *hwbus_priv; | ||
114 | |||
115 | /* Hardware information */ | ||
116 | enum { | ||
117 | HIF_9000_SILICON_VERSATILE = 0, | ||
118 | HIF_8601_VERSATILE, | ||
119 | HIF_8601_SILICON, | ||
120 | } hw_type; | ||
121 | enum { | ||
122 | CW1200_HW_REV_CUT10 = 10, | ||
123 | CW1200_HW_REV_CUT11 = 11, | ||
124 | CW1200_HW_REV_CUT20 = 20, | ||
125 | CW1200_HW_REV_CUT22 = 22, | ||
126 | CW1X60_HW_REV = 40, | ||
127 | } hw_revision; | ||
128 | int hw_refclk; | ||
129 | bool hw_have_5ghz; | ||
130 | const struct firmware *sdd; | ||
131 | char *sdd_path; | ||
132 | |||
133 | struct cw1200_debug_priv *debug; | ||
134 | |||
135 | struct workqueue_struct *workqueue; | ||
136 | struct mutex conf_mutex; | ||
137 | |||
138 | struct cw1200_queue tx_queue[4]; | ||
139 | struct cw1200_queue_stats tx_queue_stats; | ||
140 | int tx_burst_idx; | ||
141 | |||
142 | /* firmware/hardware info */ | ||
143 | unsigned int tx_hdr_len; | ||
144 | |||
145 | /* Radio data */ | ||
146 | int output_power; | ||
147 | |||
148 | /* BBP/MAC state */ | ||
149 | struct ieee80211_rate *rates; | ||
150 | struct ieee80211_rate *mcs_rates; | ||
151 | struct ieee80211_channel *channel; | ||
152 | struct wsm_edca_params edca; | ||
153 | struct wsm_tx_queue_params tx_queue_params; | ||
154 | struct wsm_mib_association_mode association_mode; | ||
155 | struct wsm_set_bss_params bss_params; | ||
156 | struct cw1200_ht_info ht_info; | ||
157 | struct wsm_set_pm powersave_mode; | ||
158 | struct wsm_set_pm firmware_ps_mode; | ||
159 | int cqm_rssi_thold; | ||
160 | unsigned cqm_rssi_hyst; | ||
161 | bool cqm_use_rssi; | ||
162 | int cqm_beacon_loss_count; | ||
163 | int channel_switch_in_progress; | ||
164 | wait_queue_head_t channel_switch_done; | ||
165 | u8 long_frame_max_tx_count; | ||
166 | u8 short_frame_max_tx_count; | ||
167 | int mode; | ||
168 | bool enable_beacon; | ||
169 | int beacon_int; | ||
170 | bool listening; | ||
171 | struct wsm_rx_filter rx_filter; | ||
172 | struct wsm_mib_multicast_filter multicast_filter; | ||
173 | bool has_multicast_subscription; | ||
174 | bool disable_beacon_filter; | ||
175 | struct work_struct update_filtering_work; | ||
176 | struct work_struct set_beacon_wakeup_period_work; | ||
177 | |||
178 | u8 ba_rx_tid_mask; | ||
179 | u8 ba_tx_tid_mask; | ||
180 | |||
181 | struct cw1200_pm_state pm_state; | ||
182 | |||
183 | struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; | ||
184 | struct wsm_uapsd_info uapsd_info; | ||
185 | bool setbssparams_done; | ||
186 | bool bt_present; | ||
187 | u8 conf_listen_interval; | ||
188 | u32 listen_interval; | ||
189 | u32 erp_info; | ||
190 | u32 rts_threshold; | ||
191 | |||
192 | /* BH */ | ||
193 | atomic_t bh_rx; | ||
194 | atomic_t bh_tx; | ||
195 | atomic_t bh_term; | ||
196 | atomic_t bh_suspend; | ||
197 | |||
198 | struct workqueue_struct *bh_workqueue; | ||
199 | struct work_struct bh_work; | ||
200 | |||
201 | int bh_error; | ||
202 | wait_queue_head_t bh_wq; | ||
203 | wait_queue_head_t bh_evt_wq; | ||
204 | u8 buf_id_tx; | ||
205 | u8 buf_id_rx; | ||
206 | u8 wsm_rx_seq; | ||
207 | u8 wsm_tx_seq; | ||
208 | int hw_bufs_used; | ||
209 | bool powersave_enabled; | ||
210 | bool device_can_sleep; | ||
211 | |||
212 | /* Scan status */ | ||
213 | struct cw1200_scan scan; | ||
214 | /* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid | ||
215 | * FW issue with sleeping/waking up. */ | ||
216 | atomic_t recent_scan; | ||
217 | struct delayed_work clear_recent_scan_work; | ||
218 | |||
219 | /* WSM */ | ||
220 | struct wsm_startup_ind wsm_caps; | ||
221 | struct mutex wsm_cmd_mux; | ||
222 | struct wsm_buf wsm_cmd_buf; | ||
223 | struct wsm_cmd wsm_cmd; | ||
224 | wait_queue_head_t wsm_cmd_wq; | ||
225 | wait_queue_head_t wsm_startup_done; | ||
226 | int firmware_ready; | ||
227 | atomic_t tx_lock; | ||
228 | |||
229 | /* WSM debug */ | ||
230 | int wsm_enable_wsm_dumps; | ||
231 | |||
232 | /* WSM Join */ | ||
233 | enum cw1200_join_status join_status; | ||
234 | u32 pending_frame_id; | ||
235 | bool join_pending; | ||
236 | struct delayed_work join_timeout; | ||
237 | struct work_struct unjoin_work; | ||
238 | struct work_struct join_complete_work; | ||
239 | int join_complete_status; | ||
240 | int join_dtim_period; | ||
241 | bool delayed_unjoin; | ||
242 | |||
243 | /* TX/RX and security */ | ||
244 | s8 wep_default_key_id; | ||
245 | struct work_struct wep_key_work; | ||
246 | u32 key_map; | ||
247 | struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; | ||
248 | |||
249 | /* AP powersave */ | ||
250 | u32 link_id_map; | ||
251 | struct cw1200_link_entry link_id_db[CW1200_MAX_STA_IN_AP_MODE]; | ||
252 | struct work_struct link_id_work; | ||
253 | struct delayed_work link_id_gc_work; | ||
254 | u32 sta_asleep_mask; | ||
255 | u32 pspoll_mask; | ||
256 | bool aid0_bit_set; | ||
257 | spinlock_t ps_state_lock; /* Protect power save state */ | ||
258 | bool buffered_multicasts; | ||
259 | bool tx_multicast; | ||
260 | struct work_struct set_tim_work; | ||
261 | struct work_struct set_cts_work; | ||
262 | struct work_struct multicast_start_work; | ||
263 | struct work_struct multicast_stop_work; | ||
264 | struct timer_list mcast_timeout; | ||
265 | |||
266 | /* WSM events and CQM implementation */ | ||
267 | spinlock_t event_queue_lock; /* Protect event queue */ | ||
268 | struct list_head event_queue; | ||
269 | struct work_struct event_handler; | ||
270 | |||
271 | struct delayed_work bss_loss_work; | ||
272 | spinlock_t bss_loss_lock; /* Protect BSS loss state */ | ||
273 | int bss_loss_state; | ||
274 | int bss_loss_confirm_id; | ||
275 | int delayed_link_loss; | ||
276 | struct work_struct bss_params_work; | ||
277 | |||
278 | /* TX rate policy cache */ | ||
279 | struct tx_policy_cache tx_policy_cache; | ||
280 | struct work_struct tx_policy_upload_work; | ||
281 | |||
282 | /* legacy PS mode switch in suspend */ | ||
283 | int ps_mode_switch_in_progress; | ||
284 | wait_queue_head_t ps_mode_switch_done; | ||
285 | |||
286 | /* Workaround for WFD testcase 6.1.10*/ | ||
287 | struct work_struct linkid_reset_work; | ||
288 | u8 action_frame_sa[ETH_ALEN]; | ||
289 | u8 action_linkid; | ||
290 | |||
291 | #ifdef CONFIG_CW1200_ETF | ||
292 | struct sk_buff_head etf_q; | ||
293 | #endif | ||
294 | }; | ||
295 | |||
296 | struct cw1200_sta_priv { | ||
297 | int link_id; | ||
298 | }; | ||
299 | |||
300 | /* interfaces for the drivers */ | ||
301 | int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, | ||
302 | struct hwbus_priv *hwbus, | ||
303 | struct device *pdev, | ||
304 | struct cw1200_common **pself, | ||
305 | int ref_clk, const u8 *macaddr, | ||
306 | const char *sdd_path, bool have_5ghz); | ||
307 | void cw1200_core_release(struct cw1200_common *self); | ||
308 | |||
309 | #define FWLOAD_BLOCK_SIZE (1024) | ||
310 | |||
311 | static inline int cw1200_is_ht(const struct cw1200_ht_info *ht_info) | ||
312 | { | ||
313 | return ht_info->channel_type != NL80211_CHAN_NO_HT; | ||
314 | } | ||
315 | |||
316 | static inline int cw1200_ht_greenfield(const struct cw1200_ht_info *ht_info) | ||
317 | { | ||
318 | return cw1200_is_ht(ht_info) && | ||
319 | (ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && | ||
320 | !(ht_info->operation_mode & | ||
321 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||
322 | } | ||
323 | |||
324 | static inline int cw1200_ht_ampdu_density(const struct cw1200_ht_info *ht_info) | ||
325 | { | ||
326 | if (!cw1200_is_ht(ht_info)) | ||
327 | return 0; | ||
328 | return ht_info->ht_cap.ampdu_density; | ||
329 | } | ||
330 | |||
331 | #endif /* CW1200_H */ | ||
diff --git a/drivers/net/wireless/cw1200/cw1200_sdio.c b/drivers/net/wireless/cw1200/cw1200_sdio.c new file mode 100644 index 000000000000..bb1f405315e4 --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200_sdio.c | |||
@@ -0,0 +1,424 @@ | |||
1 | /* | ||
2 | * Mac80211 SDIO driver for ST-Ericsson CW1200 device | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/mmc/host.h> | ||
16 | #include <linux/mmc/sdio_func.h> | ||
17 | #include <linux/mmc/card.h> | ||
18 | #include <linux/mmc/sdio.h> | ||
19 | #include <net/mac80211.h> | ||
20 | |||
21 | #include "cw1200.h" | ||
22 | #include "hwbus.h" | ||
23 | #include <linux/platform_data/net-cw1200.h> | ||
24 | #include "hwio.h" | ||
25 | |||
26 | MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>"); | ||
27 | MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SDIO driver"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | #define SDIO_BLOCK_SIZE (512) | ||
31 | |||
32 | /* Default platform data for Sagrad modules */ | ||
33 | static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = { | ||
34 | .ref_clk = 38400, | ||
35 | .have_5ghz = false, | ||
36 | .sdd_file = "sdd_sagrad_1091_1098.bin", | ||
37 | }; | ||
38 | |||
39 | /* Allow platform data to be overridden */ | ||
40 | static struct cw1200_platform_data_sdio *global_plat_data = &sagrad_109x_evk_platform_data; | ||
41 | |||
42 | void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata) | ||
43 | { | ||
44 | global_plat_data = pdata; | ||
45 | } | ||
46 | |||
47 | struct hwbus_priv { | ||
48 | struct sdio_func *func; | ||
49 | struct cw1200_common *core; | ||
50 | const struct cw1200_platform_data_sdio *pdata; | ||
51 | }; | ||
52 | |||
53 | #ifndef SDIO_VENDOR_ID_STE | ||
54 | #define SDIO_VENDOR_ID_STE 0x0020 | ||
55 | #endif | ||
56 | |||
57 | #ifndef SDIO_DEVICE_ID_STE_CW1200 | ||
58 | #define SDIO_DEVICE_ID_STE_CW1200 0x2280 | ||
59 | #endif | ||
60 | |||
61 | static const struct sdio_device_id cw1200_sdio_ids[] = { | ||
62 | { SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) }, | ||
63 | { /* end: all zeroes */ }, | ||
64 | }; | ||
65 | |||
66 | /* hwbus_ops implemetation */ | ||
67 | |||
68 | static int cw1200_sdio_memcpy_fromio(struct hwbus_priv *self, | ||
69 | unsigned int addr, | ||
70 | void *dst, int count) | ||
71 | { | ||
72 | return sdio_memcpy_fromio(self->func, dst, addr, count); | ||
73 | } | ||
74 | |||
75 | static int cw1200_sdio_memcpy_toio(struct hwbus_priv *self, | ||
76 | unsigned int addr, | ||
77 | const void *src, int count) | ||
78 | { | ||
79 | return sdio_memcpy_toio(self->func, addr, (void *)src, count); | ||
80 | } | ||
81 | |||
82 | static void cw1200_sdio_lock(struct hwbus_priv *self) | ||
83 | { | ||
84 | sdio_claim_host(self->func); | ||
85 | } | ||
86 | |||
87 | static void cw1200_sdio_unlock(struct hwbus_priv *self) | ||
88 | { | ||
89 | sdio_release_host(self->func); | ||
90 | } | ||
91 | |||
92 | static void cw1200_sdio_irq_handler(struct sdio_func *func) | ||
93 | { | ||
94 | struct hwbus_priv *self = sdio_get_drvdata(func); | ||
95 | |||
96 | /* note: sdio_host already claimed here. */ | ||
97 | if (self->core) | ||
98 | cw1200_irq_handler(self->core); | ||
99 | } | ||
100 | |||
101 | static irqreturn_t cw1200_gpio_hardirq(int irq, void *dev_id) | ||
102 | { | ||
103 | return IRQ_WAKE_THREAD; | ||
104 | } | ||
105 | |||
106 | static irqreturn_t cw1200_gpio_irq(int irq, void *dev_id) | ||
107 | { | ||
108 | struct hwbus_priv *self = dev_id; | ||
109 | |||
110 | if (self->core) { | ||
111 | sdio_claim_host(self->func); | ||
112 | cw1200_irq_handler(self->core); | ||
113 | sdio_release_host(self->func); | ||
114 | return IRQ_HANDLED; | ||
115 | } else { | ||
116 | return IRQ_NONE; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static int cw1200_request_irq(struct hwbus_priv *self) | ||
121 | { | ||
122 | int ret; | ||
123 | u8 cccr; | ||
124 | |||
125 | cccr = sdio_f0_readb(self->func, SDIO_CCCR_IENx, &ret); | ||
126 | if (WARN_ON(ret)) | ||
127 | goto err; | ||
128 | |||
129 | /* Master interrupt enable ... */ | ||
130 | cccr |= BIT(0); | ||
131 | |||
132 | /* ... for our function */ | ||
133 | cccr |= BIT(self->func->num); | ||
134 | |||
135 | sdio_f0_writeb(self->func, cccr, SDIO_CCCR_IENx, &ret); | ||
136 | if (WARN_ON(ret)) | ||
137 | goto err; | ||
138 | |||
139 | ret = enable_irq_wake(self->pdata->irq); | ||
140 | if (WARN_ON(ret)) | ||
141 | goto err; | ||
142 | |||
143 | /* Request the IRQ */ | ||
144 | ret = request_threaded_irq(self->pdata->irq, cw1200_gpio_hardirq, | ||
145 | cw1200_gpio_irq, | ||
146 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | ||
147 | "cw1200_wlan_irq", self); | ||
148 | if (WARN_ON(ret)) | ||
149 | goto err; | ||
150 | |||
151 | return 0; | ||
152 | |||
153 | err: | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | static int cw1200_sdio_irq_subscribe(struct hwbus_priv *self) | ||
158 | { | ||
159 | int ret = 0; | ||
160 | |||
161 | pr_debug("SW IRQ subscribe\n"); | ||
162 | sdio_claim_host(self->func); | ||
163 | if (self->pdata->irq) | ||
164 | ret = cw1200_request_irq(self); | ||
165 | else | ||
166 | ret = sdio_claim_irq(self->func, cw1200_sdio_irq_handler); | ||
167 | |||
168 | sdio_release_host(self->func); | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int cw1200_sdio_irq_unsubscribe(struct hwbus_priv *self) | ||
173 | { | ||
174 | int ret = 0; | ||
175 | |||
176 | pr_debug("SW IRQ unsubscribe\n"); | ||
177 | |||
178 | if (self->pdata->irq) { | ||
179 | disable_irq_wake(self->pdata->irq); | ||
180 | free_irq(self->pdata->irq, self); | ||
181 | } else { | ||
182 | sdio_claim_host(self->func); | ||
183 | ret = sdio_release_irq(self->func); | ||
184 | sdio_release_host(self->func); | ||
185 | } | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int cw1200_sdio_off(const struct cw1200_platform_data_sdio *pdata) | ||
190 | { | ||
191 | if (pdata->reset) { | ||
192 | gpio_set_value(pdata->reset, 0); | ||
193 | msleep(30); /* Min is 2 * CLK32K cycles */ | ||
194 | gpio_free(pdata->reset); | ||
195 | } | ||
196 | |||
197 | if (pdata->power_ctrl) | ||
198 | pdata->power_ctrl(pdata, false); | ||
199 | if (pdata->clk_ctrl) | ||
200 | pdata->clk_ctrl(pdata, false); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int cw1200_sdio_on(const struct cw1200_platform_data_sdio *pdata) | ||
206 | { | ||
207 | /* Ensure I/Os are pulled low */ | ||
208 | if (pdata->reset) { | ||
209 | gpio_request(pdata->reset, "cw1200_wlan_reset"); | ||
210 | gpio_direction_output(pdata->reset, 0); | ||
211 | } | ||
212 | if (pdata->powerup) { | ||
213 | gpio_request(pdata->powerup, "cw1200_wlan_powerup"); | ||
214 | gpio_direction_output(pdata->powerup, 0); | ||
215 | } | ||
216 | if (pdata->reset || pdata->powerup) | ||
217 | msleep(10); /* Settle time? */ | ||
218 | |||
219 | /* Enable 3v3 and 1v8 to hardware */ | ||
220 | if (pdata->power_ctrl) { | ||
221 | if (pdata->power_ctrl(pdata, true)) { | ||
222 | pr_err("power_ctrl() failed!\n"); | ||
223 | return -1; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* Enable CLK32K */ | ||
228 | if (pdata->clk_ctrl) { | ||
229 | if (pdata->clk_ctrl(pdata, true)) { | ||
230 | pr_err("clk_ctrl() failed!\n"); | ||
231 | return -1; | ||
232 | } | ||
233 | msleep(10); /* Delay until clock is stable for 2 cycles */ | ||
234 | } | ||
235 | |||
236 | /* Enable POWERUP signal */ | ||
237 | if (pdata->powerup) { | ||
238 | gpio_set_value(pdata->powerup, 1); | ||
239 | msleep(250); /* or more..? */ | ||
240 | } | ||
241 | /* Enable RSTn signal */ | ||
242 | if (pdata->reset) { | ||
243 | gpio_set_value(pdata->reset, 1); | ||
244 | msleep(50); /* Or more..? */ | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static size_t cw1200_sdio_align_size(struct hwbus_priv *self, size_t size) | ||
250 | { | ||
251 | if (self->pdata->no_nptb) | ||
252 | size = round_up(size, SDIO_BLOCK_SIZE); | ||
253 | else | ||
254 | size = sdio_align_size(self->func, size); | ||
255 | |||
256 | return size; | ||
257 | } | ||
258 | |||
259 | static int cw1200_sdio_pm(struct hwbus_priv *self, bool suspend) | ||
260 | { | ||
261 | int ret = 0; | ||
262 | |||
263 | if (self->pdata->irq) | ||
264 | ret = irq_set_irq_wake(self->pdata->irq, suspend); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | static struct hwbus_ops cw1200_sdio_hwbus_ops = { | ||
269 | .hwbus_memcpy_fromio = cw1200_sdio_memcpy_fromio, | ||
270 | .hwbus_memcpy_toio = cw1200_sdio_memcpy_toio, | ||
271 | .lock = cw1200_sdio_lock, | ||
272 | .unlock = cw1200_sdio_unlock, | ||
273 | .align_size = cw1200_sdio_align_size, | ||
274 | .power_mgmt = cw1200_sdio_pm, | ||
275 | }; | ||
276 | |||
277 | /* Probe Function to be called by SDIO stack when device is discovered */ | ||
278 | static int cw1200_sdio_probe(struct sdio_func *func, | ||
279 | const struct sdio_device_id *id) | ||
280 | { | ||
281 | struct hwbus_priv *self; | ||
282 | int status; | ||
283 | |||
284 | pr_info("cw1200_wlan_sdio: Probe called\n"); | ||
285 | |||
286 | /* We are only able to handle the wlan function */ | ||
287 | if (func->num != 0x01) | ||
288 | return -ENODEV; | ||
289 | |||
290 | self = kzalloc(sizeof(*self), GFP_KERNEL); | ||
291 | if (!self) { | ||
292 | pr_err("Can't allocate SDIO hwbus_priv.\n"); | ||
293 | return -ENOMEM; | ||
294 | } | ||
295 | |||
296 | func->card->quirks |= MMC_QUIRK_LENIENT_FN0; | ||
297 | |||
298 | self->pdata = global_plat_data; /* FIXME */ | ||
299 | self->func = func; | ||
300 | sdio_set_drvdata(func, self); | ||
301 | sdio_claim_host(func); | ||
302 | sdio_enable_func(func); | ||
303 | sdio_release_host(func); | ||
304 | |||
305 | status = cw1200_sdio_irq_subscribe(self); | ||
306 | |||
307 | status = cw1200_core_probe(&cw1200_sdio_hwbus_ops, | ||
308 | self, &func->dev, &self->core, | ||
309 | self->pdata->ref_clk, | ||
310 | self->pdata->macaddr, | ||
311 | self->pdata->sdd_file, | ||
312 | self->pdata->have_5ghz); | ||
313 | if (status) { | ||
314 | cw1200_sdio_irq_unsubscribe(self); | ||
315 | sdio_claim_host(func); | ||
316 | sdio_disable_func(func); | ||
317 | sdio_release_host(func); | ||
318 | sdio_set_drvdata(func, NULL); | ||
319 | kfree(self); | ||
320 | } | ||
321 | |||
322 | return status; | ||
323 | } | ||
324 | |||
325 | /* Disconnect Function to be called by SDIO stack when | ||
326 | * device is disconnected */ | ||
327 | static void cw1200_sdio_disconnect(struct sdio_func *func) | ||
328 | { | ||
329 | struct hwbus_priv *self = sdio_get_drvdata(func); | ||
330 | |||
331 | if (self) { | ||
332 | cw1200_sdio_irq_unsubscribe(self); | ||
333 | if (self->core) { | ||
334 | cw1200_core_release(self->core); | ||
335 | self->core = NULL; | ||
336 | } | ||
337 | sdio_claim_host(func); | ||
338 | sdio_disable_func(func); | ||
339 | sdio_release_host(func); | ||
340 | sdio_set_drvdata(func, NULL); | ||
341 | kfree(self); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | #ifdef CONFIG_PM | ||
346 | static int cw1200_sdio_suspend(struct device *dev) | ||
347 | { | ||
348 | int ret; | ||
349 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
350 | struct hwbus_priv *self = sdio_get_drvdata(func); | ||
351 | |||
352 | if (!cw1200_can_suspend(self->core)) | ||
353 | return -EAGAIN; | ||
354 | |||
355 | /* Notify SDIO that CW1200 will remain powered during suspend */ | ||
356 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
357 | if (ret) | ||
358 | pr_err("Error setting SDIO pm flags: %i\n", ret); | ||
359 | |||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static int cw1200_sdio_resume(struct device *dev) | ||
364 | { | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static const struct dev_pm_ops cw1200_pm_ops = { | ||
369 | .suspend = cw1200_sdio_suspend, | ||
370 | .resume = cw1200_sdio_resume, | ||
371 | }; | ||
372 | #endif | ||
373 | |||
374 | static struct sdio_driver sdio_driver = { | ||
375 | .name = "cw1200_wlan_sdio", | ||
376 | .id_table = cw1200_sdio_ids, | ||
377 | .probe = cw1200_sdio_probe, | ||
378 | .remove = cw1200_sdio_disconnect, | ||
379 | #ifdef CONFIG_PM | ||
380 | .drv = { | ||
381 | .pm = &cw1200_pm_ops, | ||
382 | } | ||
383 | #endif | ||
384 | }; | ||
385 | |||
386 | /* Init Module function -> Called by insmod */ | ||
387 | static int __init cw1200_sdio_init(void) | ||
388 | { | ||
389 | const struct cw1200_platform_data_sdio *pdata; | ||
390 | int ret; | ||
391 | |||
392 | /* FIXME -- this won't support multiple devices */ | ||
393 | pdata = global_plat_data; | ||
394 | |||
395 | if (cw1200_sdio_on(pdata)) { | ||
396 | ret = -1; | ||
397 | goto err; | ||
398 | } | ||
399 | |||
400 | ret = sdio_register_driver(&sdio_driver); | ||
401 | if (ret) | ||
402 | goto err; | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err: | ||
407 | cw1200_sdio_off(pdata); | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | /* Called at Driver Unloading */ | ||
412 | static void __exit cw1200_sdio_exit(void) | ||
413 | { | ||
414 | const struct cw1200_platform_data_sdio *pdata; | ||
415 | |||
416 | /* FIXME -- this won't support multiple devices */ | ||
417 | pdata = global_plat_data; | ||
418 | sdio_unregister_driver(&sdio_driver); | ||
419 | cw1200_sdio_off(pdata); | ||
420 | } | ||
421 | |||
422 | |||
423 | module_init(cw1200_sdio_init); | ||
424 | module_exit(cw1200_sdio_exit); | ||
diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c new file mode 100644 index 000000000000..e58f0a5bafa9 --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200_spi.c | |||
@@ -0,0 +1,465 @@ | |||
1 | /* | ||
2 | * Mac80211 SPI driver for ST-Ericsson CW1200 device | ||
3 | * | ||
4 | * Copyright (c) 2011, Sagrad Inc. | ||
5 | * Author: Solomon Peachy <speachy@sagrad.com> | ||
6 | * | ||
7 | * Based on cw1200_sdio.c | ||
8 | * Copyright (c) 2010, ST-Ericsson | ||
9 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <net/mac80211.h> | ||
22 | |||
23 | #include <linux/spi/spi.h> | ||
24 | #include <linux/device.h> | ||
25 | |||
26 | #include "cw1200.h" | ||
27 | #include "hwbus.h" | ||
28 | #include <linux/platform_data/net-cw1200.h> | ||
29 | #include "hwio.h" | ||
30 | |||
31 | MODULE_AUTHOR("Solomon Peachy <speachy@sagrad.com>"); | ||
32 | MODULE_DESCRIPTION("mac80211 ST-Ericsson CW1200 SPI driver"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_ALIAS("spi:cw1200_wlan_spi"); | ||
35 | |||
36 | /* #define SPI_DEBUG */ | ||
37 | |||
38 | struct hwbus_priv { | ||
39 | struct spi_device *func; | ||
40 | struct cw1200_common *core; | ||
41 | const struct cw1200_platform_data_spi *pdata; | ||
42 | spinlock_t lock; /* Serialize all bus operations */ | ||
43 | int claimed; | ||
44 | }; | ||
45 | |||
46 | #define SDIO_TO_SPI_ADDR(addr) ((addr & 0x1f)>>2) | ||
47 | #define SET_WRITE 0x7FFF /* usage: and operation */ | ||
48 | #define SET_READ 0x8000 /* usage: or operation */ | ||
49 | |||
50 | /* | ||
51 | Notes on byte ordering: | ||
52 | LE: B0 B1 B2 B3 | ||
53 | BE: B3 B2 B1 B0 | ||
54 | |||
55 | Hardware expects 32-bit data to be written as 16-bit BE words: | ||
56 | |||
57 | B1 B0 B3 B2 | ||
58 | |||
59 | */ | ||
60 | |||
61 | static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self, | ||
62 | unsigned int addr, | ||
63 | void *dst, int count) | ||
64 | { | ||
65 | int ret, i; | ||
66 | uint16_t regaddr; | ||
67 | struct spi_message m; | ||
68 | |||
69 | struct spi_transfer t_addr = { | ||
70 | .tx_buf = ®addr, | ||
71 | .len = sizeof(regaddr), | ||
72 | }; | ||
73 | struct spi_transfer t_msg = { | ||
74 | .rx_buf = dst, | ||
75 | .len = count, | ||
76 | }; | ||
77 | |||
78 | regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; | ||
79 | regaddr |= SET_READ; | ||
80 | regaddr |= (count>>1); | ||
81 | regaddr = cpu_to_le16(regaddr); | ||
82 | |||
83 | #ifdef SPI_DEBUG | ||
84 | pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, | ||
85 | le16_to_cpu(regaddr)); | ||
86 | #endif | ||
87 | |||
88 | #if defined(__LITTLE_ENDIAN) | ||
89 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
90 | if (self->func->bits_per_word == 8) | ||
91 | #endif | ||
92 | regaddr = swab16(regaddr); | ||
93 | |||
94 | spi_message_init(&m); | ||
95 | spi_message_add_tail(&t_addr, &m); | ||
96 | spi_message_add_tail(&t_msg, &m); | ||
97 | ret = spi_sync(self->func, &m); | ||
98 | |||
99 | #ifdef SPI_DEBUG | ||
100 | pr_info("READ : "); | ||
101 | for (i = 0; i < t_addr.len; i++) | ||
102 | printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); | ||
103 | printk(" : "); | ||
104 | for (i = 0; i < t_msg.len; i++) | ||
105 | printk("%02x ", ((u8 *)t_msg.rx_buf)[i]); | ||
106 | printk("\n"); | ||
107 | #endif | ||
108 | |||
109 | #if defined(__LITTLE_ENDIAN) | ||
110 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
111 | if (self->func->bits_per_word == 8) | ||
112 | #endif | ||
113 | { | ||
114 | uint16_t *buf = (uint16_t *)dst; | ||
115 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
116 | buf[i] = swab16(buf[i]); | ||
117 | } | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int cw1200_spi_memcpy_toio(struct hwbus_priv *self, | ||
123 | unsigned int addr, | ||
124 | const void *src, int count) | ||
125 | { | ||
126 | int rval, i; | ||
127 | uint16_t regaddr; | ||
128 | struct spi_transfer t_addr = { | ||
129 | .tx_buf = ®addr, | ||
130 | .len = sizeof(regaddr), | ||
131 | }; | ||
132 | struct spi_transfer t_msg = { | ||
133 | .tx_buf = src, | ||
134 | .len = count, | ||
135 | }; | ||
136 | struct spi_message m; | ||
137 | |||
138 | regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; | ||
139 | regaddr &= SET_WRITE; | ||
140 | regaddr |= (count>>1); | ||
141 | regaddr = cpu_to_le16(regaddr); | ||
142 | |||
143 | #ifdef SPI_DEBUG | ||
144 | pr_info("WRITE: %04d to 0x%02x (%04x)\n", count, addr, | ||
145 | le16_to_cpu(regaddr)); | ||
146 | #endif | ||
147 | |||
148 | #if defined(__LITTLE_ENDIAN) | ||
149 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
150 | if (self->func->bits_per_word == 8) | ||
151 | #endif | ||
152 | { | ||
153 | uint16_t *buf = (uint16_t *)src; | ||
154 | regaddr = swab16(regaddr); | ||
155 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
156 | buf[i] = swab16(buf[i]); | ||
157 | } | ||
158 | |||
159 | #ifdef SPI_DEBUG | ||
160 | pr_info("WRITE: "); | ||
161 | for (i = 0; i < t_addr.len; i++) | ||
162 | printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); | ||
163 | printk(" : "); | ||
164 | for (i = 0; i < t_msg.len; i++) | ||
165 | printk("%02x ", ((u8 *)t_msg.tx_buf)[i]); | ||
166 | printk("\n"); | ||
167 | #endif | ||
168 | |||
169 | spi_message_init(&m); | ||
170 | spi_message_add_tail(&t_addr, &m); | ||
171 | spi_message_add_tail(&t_msg, &m); | ||
172 | rval = spi_sync(self->func, &m); | ||
173 | |||
174 | #ifdef SPI_DEBUG | ||
175 | pr_info("WROTE: %d\n", m.actual_length); | ||
176 | #endif | ||
177 | |||
178 | #if defined(__LITTLE_ENDIAN) | ||
179 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
180 | if (self->func->bits_per_word == 8) | ||
181 | #endif | ||
182 | { | ||
183 | uint16_t *buf = (uint16_t *)src; | ||
184 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
185 | buf[i] = swab16(buf[i]); | ||
186 | } | ||
187 | return rval; | ||
188 | } | ||
189 | |||
190 | static void cw1200_spi_lock(struct hwbus_priv *self) | ||
191 | { | ||
192 | unsigned long flags; | ||
193 | |||
194 | might_sleep(); | ||
195 | |||
196 | spin_lock_irqsave(&self->lock, flags); | ||
197 | while (1) { | ||
198 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
199 | if (!self->claimed) | ||
200 | break; | ||
201 | spin_unlock_irqrestore(&self->lock, flags); | ||
202 | schedule(); | ||
203 | spin_lock_irqsave(&self->lock, flags); | ||
204 | } | ||
205 | set_current_state(TASK_RUNNING); | ||
206 | self->claimed = 1; | ||
207 | spin_unlock_irqrestore(&self->lock, flags); | ||
208 | |||
209 | return; | ||
210 | } | ||
211 | |||
212 | static void cw1200_spi_unlock(struct hwbus_priv *self) | ||
213 | { | ||
214 | unsigned long flags; | ||
215 | |||
216 | spin_lock_irqsave(&self->lock, flags); | ||
217 | self->claimed = 0; | ||
218 | spin_unlock_irqrestore(&self->lock, flags); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) | ||
223 | { | ||
224 | struct hwbus_priv *self = dev_id; | ||
225 | |||
226 | if (self->core) { | ||
227 | cw1200_irq_handler(self->core); | ||
228 | return IRQ_HANDLED; | ||
229 | } else { | ||
230 | return IRQ_NONE; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static int cw1200_spi_irq_subscribe(struct hwbus_priv *self) | ||
235 | { | ||
236 | int ret; | ||
237 | |||
238 | pr_debug("SW IRQ subscribe\n"); | ||
239 | |||
240 | ret = request_any_context_irq(self->func->irq, cw1200_spi_irq_handler, | ||
241 | IRQF_TRIGGER_HIGH, | ||
242 | "cw1200_wlan_irq", self); | ||
243 | if (WARN_ON(ret < 0)) | ||
244 | goto exit; | ||
245 | |||
246 | ret = enable_irq_wake(self->func->irq); | ||
247 | if (WARN_ON(ret)) | ||
248 | goto free_irq; | ||
249 | |||
250 | return 0; | ||
251 | |||
252 | free_irq: | ||
253 | free_irq(self->func->irq, self); | ||
254 | exit: | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) | ||
259 | { | ||
260 | int ret = 0; | ||
261 | |||
262 | pr_debug("SW IRQ unsubscribe\n"); | ||
263 | disable_irq_wake(self->func->irq); | ||
264 | free_irq(self->func->irq, self); | ||
265 | |||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) | ||
270 | { | ||
271 | if (pdata->reset) { | ||
272 | gpio_set_value(pdata->reset, 0); | ||
273 | msleep(30); /* Min is 2 * CLK32K cycles */ | ||
274 | gpio_free(pdata->reset); | ||
275 | } | ||
276 | |||
277 | if (pdata->power_ctrl) | ||
278 | pdata->power_ctrl(pdata, false); | ||
279 | if (pdata->clk_ctrl) | ||
280 | pdata->clk_ctrl(pdata, false); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) | ||
286 | { | ||
287 | /* Ensure I/Os are pulled low */ | ||
288 | if (pdata->reset) { | ||
289 | gpio_request(pdata->reset, "cw1200_wlan_reset"); | ||
290 | gpio_direction_output(pdata->reset, 0); | ||
291 | } | ||
292 | if (pdata->powerup) { | ||
293 | gpio_request(pdata->powerup, "cw1200_wlan_powerup"); | ||
294 | gpio_direction_output(pdata->powerup, 0); | ||
295 | } | ||
296 | if (pdata->reset || pdata->powerup) | ||
297 | msleep(10); /* Settle time? */ | ||
298 | |||
299 | /* Enable 3v3 and 1v8 to hardware */ | ||
300 | if (pdata->power_ctrl) { | ||
301 | if (pdata->power_ctrl(pdata, true)) { | ||
302 | pr_err("power_ctrl() failed!\n"); | ||
303 | return -1; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* Enable CLK32K */ | ||
308 | if (pdata->clk_ctrl) { | ||
309 | if (pdata->clk_ctrl(pdata, true)) { | ||
310 | pr_err("clk_ctrl() failed!\n"); | ||
311 | return -1; | ||
312 | } | ||
313 | msleep(10); /* Delay until clock is stable for 2 cycles */ | ||
314 | } | ||
315 | |||
316 | /* Enable POWERUP signal */ | ||
317 | if (pdata->powerup) { | ||
318 | gpio_set_value(pdata->powerup, 1); | ||
319 | msleep(250); /* or more..? */ | ||
320 | } | ||
321 | /* Enable RSTn signal */ | ||
322 | if (pdata->reset) { | ||
323 | gpio_set_value(pdata->reset, 1); | ||
324 | msleep(50); /* Or more..? */ | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size) | ||
330 | { | ||
331 | return size & 1 ? size + 1 : size; | ||
332 | } | ||
333 | |||
334 | static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend) | ||
335 | { | ||
336 | return irq_set_irq_wake(self->func->irq, suspend); | ||
337 | } | ||
338 | |||
339 | static struct hwbus_ops cw1200_spi_hwbus_ops = { | ||
340 | .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio, | ||
341 | .hwbus_memcpy_toio = cw1200_spi_memcpy_toio, | ||
342 | .lock = cw1200_spi_lock, | ||
343 | .unlock = cw1200_spi_unlock, | ||
344 | .align_size = cw1200_spi_align_size, | ||
345 | .power_mgmt = cw1200_spi_pm, | ||
346 | }; | ||
347 | |||
348 | /* Probe Function to be called by SPI stack when device is discovered */ | ||
349 | static int cw1200_spi_probe(struct spi_device *func) | ||
350 | { | ||
351 | const struct cw1200_platform_data_spi *plat_data = | ||
352 | func->dev.platform_data; | ||
353 | struct hwbus_priv *self; | ||
354 | int status; | ||
355 | |||
356 | /* Sanity check speed */ | ||
357 | if (func->max_speed_hz > 52000000) | ||
358 | func->max_speed_hz = 52000000; | ||
359 | if (func->max_speed_hz < 1000000) | ||
360 | func->max_speed_hz = 1000000; | ||
361 | |||
362 | /* Fix up transfer size */ | ||
363 | if (plat_data->spi_bits_per_word) | ||
364 | func->bits_per_word = plat_data->spi_bits_per_word; | ||
365 | if (!func->bits_per_word) | ||
366 | func->bits_per_word = 16; | ||
367 | |||
368 | /* And finally.. */ | ||
369 | func->mode = SPI_MODE_0; | ||
370 | |||
371 | pr_info("cw1200_wlan_spi: Probe called (CS %d M %d BPW %d CLK %d)\n", | ||
372 | func->chip_select, func->mode, func->bits_per_word, | ||
373 | func->max_speed_hz); | ||
374 | |||
375 | if (cw1200_spi_on(plat_data)) { | ||
376 | pr_err("spi_on() failed!\n"); | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | if (spi_setup(func)) { | ||
381 | pr_err("spi_setup() failed!\n"); | ||
382 | return -1; | ||
383 | } | ||
384 | |||
385 | self = kzalloc(sizeof(*self), GFP_KERNEL); | ||
386 | if (!self) { | ||
387 | pr_err("Can't allocate SPI hwbus_priv."); | ||
388 | return -ENOMEM; | ||
389 | } | ||
390 | |||
391 | self->pdata = plat_data; | ||
392 | self->func = func; | ||
393 | spin_lock_init(&self->lock); | ||
394 | |||
395 | spi_set_drvdata(func, self); | ||
396 | |||
397 | status = cw1200_spi_irq_subscribe(self); | ||
398 | |||
399 | status = cw1200_core_probe(&cw1200_spi_hwbus_ops, | ||
400 | self, &func->dev, &self->core, | ||
401 | self->pdata->ref_clk, | ||
402 | self->pdata->macaddr, | ||
403 | self->pdata->sdd_file, | ||
404 | self->pdata->have_5ghz); | ||
405 | |||
406 | if (status) { | ||
407 | cw1200_spi_irq_unsubscribe(self); | ||
408 | cw1200_spi_off(plat_data); | ||
409 | kfree(self); | ||
410 | } | ||
411 | |||
412 | return status; | ||
413 | } | ||
414 | |||
415 | /* Disconnect Function to be called by SPI stack when device is disconnected */ | ||
416 | static int cw1200_spi_disconnect(struct spi_device *func) | ||
417 | { | ||
418 | struct hwbus_priv *self = spi_get_drvdata(func); | ||
419 | |||
420 | if (self) { | ||
421 | cw1200_spi_irq_unsubscribe(self); | ||
422 | if (self->core) { | ||
423 | cw1200_core_release(self->core); | ||
424 | self->core = NULL; | ||
425 | } | ||
426 | kfree(self); | ||
427 | } | ||
428 | cw1200_spi_off(func->dev.platform_data); | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | #ifdef CONFIG_PM | ||
434 | static int cw1200_spi_suspend(struct device *dev, pm_message_t state) | ||
435 | { | ||
436 | struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); | ||
437 | |||
438 | if (!cw1200_can_suspend(self->core)) | ||
439 | return -EAGAIN; | ||
440 | |||
441 | /* XXX notify host that we have to keep CW1200 powered on? */ | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int cw1200_spi_resume(struct device *dev) | ||
446 | { | ||
447 | return 0; | ||
448 | } | ||
449 | #endif | ||
450 | |||
451 | static struct spi_driver spi_driver = { | ||
452 | .probe = cw1200_spi_probe, | ||
453 | .remove = cw1200_spi_disconnect, | ||
454 | .driver = { | ||
455 | .name = "cw1200_wlan_spi", | ||
456 | .bus = &spi_bus_type, | ||
457 | .owner = THIS_MODULE, | ||
458 | #ifdef CONFIG_PM | ||
459 | .suspend = cw1200_spi_suspend, | ||
460 | .resume = cw1200_spi_resume, | ||
461 | #endif | ||
462 | }, | ||
463 | }; | ||
464 | |||
465 | module_spi_driver(spi_driver); | ||
diff --git a/drivers/net/wireless/cw1200/debug.c b/drivers/net/wireless/cw1200/debug.c new file mode 100644 index 000000000000..eb40c9c61a51 --- /dev/null +++ b/drivers/net/wireless/cw1200/debug.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * DebugFS code | ||
4 | * | ||
5 | * Copyright (c) 2010, ST-Ericsson | ||
6 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/debugfs.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include "cw1200.h" | ||
17 | #include "debug.h" | ||
18 | #include "fwio.h" | ||
19 | |||
20 | /* join_status */ | ||
21 | static const char * const cw1200_debug_join_status[] = { | ||
22 | "passive", | ||
23 | "monitor", | ||
24 | "station (joining)", | ||
25 | "station (not authenticated yet)", | ||
26 | "station", | ||
27 | "adhoc", | ||
28 | "access point", | ||
29 | }; | ||
30 | |||
31 | /* WSM_JOIN_PREAMBLE_... */ | ||
32 | static const char * const cw1200_debug_preamble[] = { | ||
33 | "long", | ||
34 | "short", | ||
35 | "long on 1 and 2 Mbps", | ||
36 | }; | ||
37 | |||
38 | |||
39 | static const char * const cw1200_debug_link_id[] = { | ||
40 | "OFF", | ||
41 | "REQ", | ||
42 | "SOFT", | ||
43 | "HARD", | ||
44 | }; | ||
45 | |||
46 | static const char *cw1200_debug_mode(int mode) | ||
47 | { | ||
48 | switch (mode) { | ||
49 | case NL80211_IFTYPE_UNSPECIFIED: | ||
50 | return "unspecified"; | ||
51 | case NL80211_IFTYPE_MONITOR: | ||
52 | return "monitor"; | ||
53 | case NL80211_IFTYPE_STATION: | ||
54 | return "station"; | ||
55 | case NL80211_IFTYPE_ADHOC: | ||
56 | return "adhoc"; | ||
57 | case NL80211_IFTYPE_MESH_POINT: | ||
58 | return "mesh point"; | ||
59 | case NL80211_IFTYPE_AP: | ||
60 | return "access point"; | ||
61 | case NL80211_IFTYPE_P2P_CLIENT: | ||
62 | return "p2p client"; | ||
63 | case NL80211_IFTYPE_P2P_GO: | ||
64 | return "p2p go"; | ||
65 | default: | ||
66 | return "unsupported"; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static void cw1200_queue_status_show(struct seq_file *seq, | ||
71 | struct cw1200_queue *q) | ||
72 | { | ||
73 | int i; | ||
74 | seq_printf(seq, "Queue %d:\n", q->queue_id); | ||
75 | seq_printf(seq, " capacity: %zu\n", q->capacity); | ||
76 | seq_printf(seq, " queued: %zu\n", q->num_queued); | ||
77 | seq_printf(seq, " pending: %zu\n", q->num_pending); | ||
78 | seq_printf(seq, " sent: %zu\n", q->num_sent); | ||
79 | seq_printf(seq, " locked: %s\n", q->tx_locked_cnt ? "yes" : "no"); | ||
80 | seq_printf(seq, " overfull: %s\n", q->overfull ? "yes" : "no"); | ||
81 | seq_puts(seq, " link map: 0-> "); | ||
82 | for (i = 0; i < q->stats->map_capacity; ++i) | ||
83 | seq_printf(seq, "%.2d ", q->link_map_cache[i]); | ||
84 | seq_printf(seq, "<-%zu\n", q->stats->map_capacity); | ||
85 | } | ||
86 | |||
87 | static void cw1200_debug_print_map(struct seq_file *seq, | ||
88 | struct cw1200_common *priv, | ||
89 | const char *label, | ||
90 | u32 map) | ||
91 | { | ||
92 | int i; | ||
93 | seq_printf(seq, "%s0-> ", label); | ||
94 | for (i = 0; i < priv->tx_queue_stats.map_capacity; ++i) | ||
95 | seq_printf(seq, "%s ", (map & BIT(i)) ? "**" : ".."); | ||
96 | seq_printf(seq, "<-%zu\n", priv->tx_queue_stats.map_capacity - 1); | ||
97 | } | ||
98 | |||
99 | static int cw1200_status_show(struct seq_file *seq, void *v) | ||
100 | { | ||
101 | int i; | ||
102 | struct list_head *item; | ||
103 | struct cw1200_common *priv = seq->private; | ||
104 | struct cw1200_debug_priv *d = priv->debug; | ||
105 | |||
106 | seq_puts(seq, "CW1200 Wireless LAN driver status\n"); | ||
107 | seq_printf(seq, "Hardware: %d.%d\n", | ||
108 | priv->wsm_caps.hw_id, | ||
109 | priv->wsm_caps.hw_subid); | ||
110 | seq_printf(seq, "Firmware: %s %d.%d\n", | ||
111 | cw1200_fw_types[priv->wsm_caps.fw_type], | ||
112 | priv->wsm_caps.fw_ver, | ||
113 | priv->wsm_caps.fw_build); | ||
114 | seq_printf(seq, "FW API: %d\n", | ||
115 | priv->wsm_caps.fw_api); | ||
116 | seq_printf(seq, "FW caps: 0x%.4X\n", | ||
117 | priv->wsm_caps.fw_cap); | ||
118 | seq_printf(seq, "FW label: '%s'\n", | ||
119 | priv->wsm_caps.fw_label); | ||
120 | seq_printf(seq, "Mode: %s%s\n", | ||
121 | cw1200_debug_mode(priv->mode), | ||
122 | priv->listening ? " (listening)" : ""); | ||
123 | seq_printf(seq, "Join state: %s\n", | ||
124 | cw1200_debug_join_status[priv->join_status]); | ||
125 | if (priv->channel) | ||
126 | seq_printf(seq, "Channel: %d%s\n", | ||
127 | priv->channel->hw_value, | ||
128 | priv->channel_switch_in_progress ? | ||
129 | " (switching)" : ""); | ||
130 | if (priv->rx_filter.promiscuous) | ||
131 | seq_puts(seq, "Filter: promisc\n"); | ||
132 | else if (priv->rx_filter.fcs) | ||
133 | seq_puts(seq, "Filter: fcs\n"); | ||
134 | if (priv->rx_filter.bssid) | ||
135 | seq_puts(seq, "Filter: bssid\n"); | ||
136 | if (!priv->disable_beacon_filter) | ||
137 | seq_puts(seq, "Filter: beacons\n"); | ||
138 | |||
139 | if (priv->enable_beacon || | ||
140 | priv->mode == NL80211_IFTYPE_AP || | ||
141 | priv->mode == NL80211_IFTYPE_ADHOC || | ||
142 | priv->mode == NL80211_IFTYPE_MESH_POINT || | ||
143 | priv->mode == NL80211_IFTYPE_P2P_GO) | ||
144 | seq_printf(seq, "Beaconing: %s\n", | ||
145 | priv->enable_beacon ? | ||
146 | "enabled" : "disabled"); | ||
147 | |||
148 | for (i = 0; i < 4; ++i) | ||
149 | seq_printf(seq, "EDCA(%d): %d, %d, %d, %d, %d\n", i, | ||
150 | priv->edca.params[i].cwmin, | ||
151 | priv->edca.params[i].cwmax, | ||
152 | priv->edca.params[i].aifns, | ||
153 | priv->edca.params[i].txop_limit, | ||
154 | priv->edca.params[i].max_rx_lifetime); | ||
155 | |||
156 | if (priv->join_status == CW1200_JOIN_STATUS_STA) { | ||
157 | static const char *pm_mode = "unknown"; | ||
158 | switch (priv->powersave_mode.mode) { | ||
159 | case WSM_PSM_ACTIVE: | ||
160 | pm_mode = "off"; | ||
161 | break; | ||
162 | case WSM_PSM_PS: | ||
163 | pm_mode = "on"; | ||
164 | break; | ||
165 | case WSM_PSM_FAST_PS: | ||
166 | pm_mode = "dynamic"; | ||
167 | break; | ||
168 | } | ||
169 | seq_printf(seq, "Preamble: %s\n", | ||
170 | cw1200_debug_preamble[priv->association_mode.preamble]); | ||
171 | seq_printf(seq, "AMPDU spcn: %d\n", | ||
172 | priv->association_mode.mpdu_start_spacing); | ||
173 | seq_printf(seq, "Basic rate: 0x%.8X\n", | ||
174 | le32_to_cpu(priv->association_mode.basic_rate_set)); | ||
175 | seq_printf(seq, "Bss lost: %d beacons\n", | ||
176 | priv->bss_params.beacon_lost_count); | ||
177 | seq_printf(seq, "AID: %d\n", | ||
178 | priv->bss_params.aid); | ||
179 | seq_printf(seq, "Rates: 0x%.8X\n", | ||
180 | priv->bss_params.operational_rate_set); | ||
181 | seq_printf(seq, "Powersave: %s\n", pm_mode); | ||
182 | } | ||
183 | seq_printf(seq, "HT: %s\n", | ||
184 | cw1200_is_ht(&priv->ht_info) ? "on" : "off"); | ||
185 | if (cw1200_is_ht(&priv->ht_info)) { | ||
186 | seq_printf(seq, "Greenfield: %s\n", | ||
187 | cw1200_ht_greenfield(&priv->ht_info) ? "yes" : "no"); | ||
188 | seq_printf(seq, "AMPDU dens: %d\n", | ||
189 | cw1200_ht_ampdu_density(&priv->ht_info)); | ||
190 | } | ||
191 | seq_printf(seq, "RSSI thold: %d\n", | ||
192 | priv->cqm_rssi_thold); | ||
193 | seq_printf(seq, "RSSI hyst: %d\n", | ||
194 | priv->cqm_rssi_hyst); | ||
195 | seq_printf(seq, "Long retr: %d\n", | ||
196 | priv->long_frame_max_tx_count); | ||
197 | seq_printf(seq, "Short retr: %d\n", | ||
198 | priv->short_frame_max_tx_count); | ||
199 | spin_lock_bh(&priv->tx_policy_cache.lock); | ||
200 | i = 0; | ||
201 | list_for_each(item, &priv->tx_policy_cache.used) | ||
202 | ++i; | ||
203 | spin_unlock_bh(&priv->tx_policy_cache.lock); | ||
204 | seq_printf(seq, "RC in use: %d\n", i); | ||
205 | |||
206 | seq_puts(seq, "\n"); | ||
207 | for (i = 0; i < 4; ++i) { | ||
208 | cw1200_queue_status_show(seq, &priv->tx_queue[i]); | ||
209 | seq_puts(seq, "\n"); | ||
210 | } | ||
211 | |||
212 | cw1200_debug_print_map(seq, priv, "Link map: ", | ||
213 | priv->link_id_map); | ||
214 | cw1200_debug_print_map(seq, priv, "Asleep map: ", | ||
215 | priv->sta_asleep_mask); | ||
216 | cw1200_debug_print_map(seq, priv, "PSPOLL map: ", | ||
217 | priv->pspoll_mask); | ||
218 | |||
219 | seq_puts(seq, "\n"); | ||
220 | |||
221 | for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { | ||
222 | if (priv->link_id_db[i].status) { | ||
223 | seq_printf(seq, "Link %d: %s, %pM\n", | ||
224 | i + 1, | ||
225 | cw1200_debug_link_id[priv->link_id_db[i].status], | ||
226 | priv->link_id_db[i].mac); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | seq_puts(seq, "\n"); | ||
231 | |||
232 | seq_printf(seq, "BH status: %s\n", | ||
233 | atomic_read(&priv->bh_term) ? "terminated" : "alive"); | ||
234 | seq_printf(seq, "Pending RX: %d\n", | ||
235 | atomic_read(&priv->bh_rx)); | ||
236 | seq_printf(seq, "Pending TX: %d\n", | ||
237 | atomic_read(&priv->bh_tx)); | ||
238 | if (priv->bh_error) | ||
239 | seq_printf(seq, "BH errcode: %d\n", | ||
240 | priv->bh_error); | ||
241 | seq_printf(seq, "TX bufs: %d x %d bytes\n", | ||
242 | priv->wsm_caps.input_buffers, | ||
243 | priv->wsm_caps.input_buffer_size); | ||
244 | seq_printf(seq, "Used bufs: %d\n", | ||
245 | priv->hw_bufs_used); | ||
246 | seq_printf(seq, "Powermgmt: %s\n", | ||
247 | priv->powersave_enabled ? "on" : "off"); | ||
248 | seq_printf(seq, "Device: %s\n", | ||
249 | priv->device_can_sleep ? "asleep" : "awake"); | ||
250 | |||
251 | spin_lock(&priv->wsm_cmd.lock); | ||
252 | seq_printf(seq, "WSM status: %s\n", | ||
253 | priv->wsm_cmd.done ? "idle" : "active"); | ||
254 | seq_printf(seq, "WSM cmd: 0x%.4X (%td bytes)\n", | ||
255 | priv->wsm_cmd.cmd, priv->wsm_cmd.len); | ||
256 | seq_printf(seq, "WSM retval: %d\n", | ||
257 | priv->wsm_cmd.ret); | ||
258 | spin_unlock(&priv->wsm_cmd.lock); | ||
259 | |||
260 | seq_printf(seq, "Datapath: %s\n", | ||
261 | atomic_read(&priv->tx_lock) ? "locked" : "unlocked"); | ||
262 | if (atomic_read(&priv->tx_lock)) | ||
263 | seq_printf(seq, "TXlock cnt: %d\n", | ||
264 | atomic_read(&priv->tx_lock)); | ||
265 | |||
266 | seq_printf(seq, "TXed: %d\n", | ||
267 | d->tx); | ||
268 | seq_printf(seq, "AGG TXed: %d\n", | ||
269 | d->tx_agg); | ||
270 | seq_printf(seq, "MULTI TXed: %d (%d)\n", | ||
271 | d->tx_multi, d->tx_multi_frames); | ||
272 | seq_printf(seq, "RXed: %d\n", | ||
273 | d->rx); | ||
274 | seq_printf(seq, "AGG RXed: %d\n", | ||
275 | d->rx_agg); | ||
276 | seq_printf(seq, "TX miss: %d\n", | ||
277 | d->tx_cache_miss); | ||
278 | seq_printf(seq, "TX align: %d\n", | ||
279 | d->tx_align); | ||
280 | seq_printf(seq, "TX burst: %d\n", | ||
281 | d->tx_burst); | ||
282 | seq_printf(seq, "TX TTL: %d\n", | ||
283 | d->tx_ttl); | ||
284 | seq_printf(seq, "Scan: %s\n", | ||
285 | atomic_read(&priv->scan.in_progress) ? "active" : "idle"); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static int cw1200_status_open(struct inode *inode, struct file *file) | ||
291 | { | ||
292 | return single_open(file, &cw1200_status_show, | ||
293 | inode->i_private); | ||
294 | } | ||
295 | |||
296 | static const struct file_operations fops_status = { | ||
297 | .open = cw1200_status_open, | ||
298 | .read = seq_read, | ||
299 | .llseek = seq_lseek, | ||
300 | .release = single_release, | ||
301 | .owner = THIS_MODULE, | ||
302 | }; | ||
303 | |||
304 | static int cw1200_counters_show(struct seq_file *seq, void *v) | ||
305 | { | ||
306 | int ret; | ||
307 | struct cw1200_common *priv = seq->private; | ||
308 | struct wsm_mib_counters_table counters; | ||
309 | |||
310 | ret = wsm_get_counters_table(priv, &counters); | ||
311 | if (ret) | ||
312 | return ret; | ||
313 | |||
314 | #define PUT_COUNTER(tab, name) \ | ||
315 | seq_printf(seq, "%s:" tab "%d\n", #name, \ | ||
316 | __le32_to_cpu(counters.name)) | ||
317 | |||
318 | PUT_COUNTER("\t\t", plcp_errors); | ||
319 | PUT_COUNTER("\t\t", fcs_errors); | ||
320 | PUT_COUNTER("\t\t", tx_packets); | ||
321 | PUT_COUNTER("\t\t", rx_packets); | ||
322 | PUT_COUNTER("\t\t", rx_packet_errors); | ||
323 | PUT_COUNTER("\t", rx_decryption_failures); | ||
324 | PUT_COUNTER("\t\t", rx_mic_failures); | ||
325 | PUT_COUNTER("\t", rx_no_key_failures); | ||
326 | PUT_COUNTER("\t", tx_multicast_frames); | ||
327 | PUT_COUNTER("\t", tx_frames_success); | ||
328 | PUT_COUNTER("\t", tx_frame_failures); | ||
329 | PUT_COUNTER("\t", tx_frames_retried); | ||
330 | PUT_COUNTER("\t", tx_frames_multi_retried); | ||
331 | PUT_COUNTER("\t", rx_frame_duplicates); | ||
332 | PUT_COUNTER("\t\t", rts_success); | ||
333 | PUT_COUNTER("\t\t", rts_failures); | ||
334 | PUT_COUNTER("\t\t", ack_failures); | ||
335 | PUT_COUNTER("\t", rx_multicast_frames); | ||
336 | PUT_COUNTER("\t", rx_frames_success); | ||
337 | PUT_COUNTER("\t", rx_cmac_icv_errors); | ||
338 | PUT_COUNTER("\t\t", rx_cmac_replays); | ||
339 | PUT_COUNTER("\t", rx_mgmt_ccmp_replays); | ||
340 | |||
341 | #undef PUT_COUNTER | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int cw1200_counters_open(struct inode *inode, struct file *file) | ||
347 | { | ||
348 | return single_open(file, &cw1200_counters_show, | ||
349 | inode->i_private); | ||
350 | } | ||
351 | |||
352 | static const struct file_operations fops_counters = { | ||
353 | .open = cw1200_counters_open, | ||
354 | .read = seq_read, | ||
355 | .llseek = seq_lseek, | ||
356 | .release = single_release, | ||
357 | .owner = THIS_MODULE, | ||
358 | }; | ||
359 | |||
360 | #ifdef CONFIG_CW1200_ETF | ||
361 | static int cw1200_etf_out_show(struct seq_file *seq, void *v) | ||
362 | { | ||
363 | struct cw1200_common *priv = seq->private; | ||
364 | struct sk_buff *skb; | ||
365 | u32 len = 0; | ||
366 | |||
367 | skb = skb_dequeue(&priv->etf_q); | ||
368 | |||
369 | if (skb) | ||
370 | len = skb->len; | ||
371 | |||
372 | seq_write(seq, &len, sizeof(len)); | ||
373 | |||
374 | if (skb) { | ||
375 | seq_write(seq, skb->data, len); | ||
376 | kfree_skb(skb); | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int cw1200_etf_out_open(struct inode *inode, struct file *file) | ||
383 | { | ||
384 | return single_open(file, &cw1200_etf_out_show, | ||
385 | inode->i_private); | ||
386 | } | ||
387 | |||
388 | static const struct file_operations fops_etf_out = { | ||
389 | .open = cw1200_etf_out_open, | ||
390 | .read = seq_read, | ||
391 | .llseek = seq_lseek, | ||
392 | .release = single_release, | ||
393 | .owner = THIS_MODULE, | ||
394 | }; | ||
395 | |||
396 | struct etf_req_msg; | ||
397 | static int etf_request(struct cw1200_common *priv, | ||
398 | struct etf_req_msg *msg, u32 len); | ||
399 | |||
400 | #define MAX_RX_SZE 2600 | ||
401 | |||
402 | struct etf_in_state { | ||
403 | struct cw1200_common *priv; | ||
404 | u32 total_len; | ||
405 | u8 buf[MAX_RX_SZE]; | ||
406 | u32 written; | ||
407 | }; | ||
408 | |||
409 | static int cw1200_etf_in_open(struct inode *inode, struct file *file) | ||
410 | { | ||
411 | struct etf_in_state *etf = kmalloc(sizeof(struct etf_in_state), | ||
412 | GFP_KERNEL); | ||
413 | |||
414 | if (!etf) | ||
415 | return -ENOMEM; | ||
416 | |||
417 | etf->written = 0; | ||
418 | etf->total_len = 0; | ||
419 | etf->priv = inode->i_private; | ||
420 | |||
421 | file->private_data = etf; | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int cw1200_etf_in_release(struct inode *inode, struct file *file) | ||
427 | { | ||
428 | kfree(file->private_data); | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static ssize_t cw1200_etf_in_write(struct file *file, | ||
433 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
434 | { | ||
435 | struct etf_in_state *etf = file->private_data; | ||
436 | |||
437 | ssize_t written = 0; | ||
438 | |||
439 | if (!etf->total_len) { | ||
440 | if (count < sizeof(etf->total_len)) { | ||
441 | pr_err("count < sizeof(total_len)\n"); | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | if (copy_from_user(&etf->total_len, user_buf, | ||
446 | sizeof(etf->total_len))) { | ||
447 | pr_err("copy_from_user (len) failed\n"); | ||
448 | return -EFAULT; | ||
449 | } | ||
450 | |||
451 | written += sizeof(etf->total_len); | ||
452 | count -= sizeof(etf->total_len); | ||
453 | } | ||
454 | |||
455 | if (!count) | ||
456 | goto done; | ||
457 | |||
458 | if (copy_from_user(etf->buf + etf->written, user_buf + written, | ||
459 | count)) { | ||
460 | pr_err("copy_from_user (payload %zu) failed\n", count); | ||
461 | return -EFAULT; | ||
462 | } | ||
463 | |||
464 | written += count; | ||
465 | etf->written += count; | ||
466 | |||
467 | if (etf->written >= etf->total_len) { | ||
468 | if (etf_request(etf->priv, (struct etf_req_msg *)etf->buf, | ||
469 | etf->total_len)) { | ||
470 | pr_err("etf_request failed\n"); | ||
471 | return -EIO; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | done: | ||
476 | return written; | ||
477 | } | ||
478 | |||
479 | static const struct file_operations fops_etf_in = { | ||
480 | .open = cw1200_etf_in_open, | ||
481 | .release = cw1200_etf_in_release, | ||
482 | .write = cw1200_etf_in_write, | ||
483 | .llseek = default_llseek, | ||
484 | .owner = THIS_MODULE, | ||
485 | }; | ||
486 | #endif /* CONFIG_CW1200_ETF */ | ||
487 | |||
488 | static ssize_t cw1200_wsm_dumps(struct file *file, | ||
489 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
490 | { | ||
491 | struct cw1200_common *priv = file->private_data; | ||
492 | char buf[1]; | ||
493 | |||
494 | if (!count) | ||
495 | return -EINVAL; | ||
496 | if (copy_from_user(buf, user_buf, 1)) | ||
497 | return -EFAULT; | ||
498 | |||
499 | if (buf[0] == '1') | ||
500 | priv->wsm_enable_wsm_dumps = 1; | ||
501 | else | ||
502 | priv->wsm_enable_wsm_dumps = 0; | ||
503 | |||
504 | return count; | ||
505 | } | ||
506 | |||
507 | static const struct file_operations fops_wsm_dumps = { | ||
508 | .open = simple_open, | ||
509 | .write = cw1200_wsm_dumps, | ||
510 | .llseek = default_llseek, | ||
511 | }; | ||
512 | |||
513 | int cw1200_debug_init(struct cw1200_common *priv) | ||
514 | { | ||
515 | int ret = -ENOMEM; | ||
516 | struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv), | ||
517 | GFP_KERNEL); | ||
518 | priv->debug = d; | ||
519 | if (!d) | ||
520 | return ret; | ||
521 | |||
522 | d->debugfs_phy = debugfs_create_dir("cw1200", | ||
523 | priv->hw->wiphy->debugfsdir); | ||
524 | if (!d->debugfs_phy) | ||
525 | goto err; | ||
526 | |||
527 | if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy, | ||
528 | priv, &fops_status)) | ||
529 | goto err; | ||
530 | |||
531 | if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy, | ||
532 | priv, &fops_counters)) | ||
533 | goto err; | ||
534 | |||
535 | #ifdef CONFIG_CW1200_ETF | ||
536 | if (etf_mode) { | ||
537 | skb_queue_head_init(&priv->etf_q); | ||
538 | |||
539 | if (!debugfs_create_file("etf_out", S_IRUSR, d->debugfs_phy, | ||
540 | priv, &fops_etf_out)) | ||
541 | goto err; | ||
542 | if (!debugfs_create_file("etf_in", S_IWUSR, d->debugfs_phy, | ||
543 | priv, &fops_etf_in)) | ||
544 | goto err; | ||
545 | } | ||
546 | #endif /* CONFIG_CW1200_ETF */ | ||
547 | |||
548 | if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy, | ||
549 | priv, &fops_wsm_dumps)) | ||
550 | goto err; | ||
551 | |||
552 | ret = cw1200_itp_init(priv); | ||
553 | if (ret) | ||
554 | goto err; | ||
555 | |||
556 | return 0; | ||
557 | |||
558 | err: | ||
559 | priv->debug = NULL; | ||
560 | debugfs_remove_recursive(d->debugfs_phy); | ||
561 | kfree(d); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | void cw1200_debug_release(struct cw1200_common *priv) | ||
566 | { | ||
567 | struct cw1200_debug_priv *d = priv->debug; | ||
568 | if (d) { | ||
569 | cw1200_itp_release(priv); | ||
570 | priv->debug = NULL; | ||
571 | kfree(d); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | #ifdef CONFIG_CW1200_ETF | ||
576 | struct cw1200_sdd { | ||
577 | u8 id; | ||
578 | u8 len; | ||
579 | u8 data[]; | ||
580 | }; | ||
581 | |||
582 | struct etf_req_msg { | ||
583 | u32 id; | ||
584 | u32 len; | ||
585 | u8 data[]; | ||
586 | }; | ||
587 | |||
588 | static int parse_sdd_file(struct cw1200_common *priv, u8 *data, u32 length) | ||
589 | { | ||
590 | struct cw1200_sdd *ie; | ||
591 | |||
592 | while (length > 0) { | ||
593 | ie = (struct cw1200_sdd *)data; | ||
594 | if (ie->id == SDD_REFERENCE_FREQUENCY_ELT_ID) { | ||
595 | priv->hw_refclk = cpu_to_le16(*((u16 *)ie->data)); | ||
596 | pr_info("Using Reference clock frequency %d KHz\n", | ||
597 | priv->hw_refclk); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | length -= ie->len + sizeof(*ie); | ||
602 | data += ie->len + sizeof(*ie); | ||
603 | } | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | char *etf_firmware; | ||
608 | |||
609 | #define ST90TDS_START_ADAPTER 0x09 /* Loads firmware too */ | ||
610 | #define ST90TDS_STOP_ADAPTER 0x0A | ||
611 | #define ST90TDS_CONFIG_ADAPTER 0x0E /* Send configuration params */ | ||
612 | #define ST90TDS_SBUS_READ 0x13 | ||
613 | #define ST90TDS_SBUS_WRITE 0x14 | ||
614 | #define ST90TDS_GET_DEVICE_OPTION 0x19 | ||
615 | #define ST90TDS_SET_DEVICE_OPTION 0x1A | ||
616 | #define ST90TDS_SEND_SDD 0x1D /* SDD File used to find DPLL */ | ||
617 | |||
618 | #include "fwio.h" | ||
619 | |||
620 | static int etf_request(struct cw1200_common *priv, | ||
621 | struct etf_req_msg *msg, | ||
622 | u32 len) | ||
623 | { | ||
624 | int rval = -1; | ||
625 | switch (msg->id) { | ||
626 | case ST90TDS_START_ADAPTER: | ||
627 | etf_firmware = "cw1200_etf.bin"; | ||
628 | pr_info("ETF_START (len %d, '%s')\n", len, etf_firmware); | ||
629 | rval = cw1200_load_firmware(priv); | ||
630 | break; | ||
631 | case ST90TDS_STOP_ADAPTER: | ||
632 | pr_info("ETF_STOP (unhandled)\n"); | ||
633 | break; | ||
634 | case ST90TDS_SEND_SDD: | ||
635 | pr_info("ETF_SDD\n"); | ||
636 | rval = parse_sdd_file(priv, msg->data, msg->len); | ||
637 | break; | ||
638 | case ST90TDS_CONFIG_ADAPTER: | ||
639 | pr_info("ETF_CONFIG_ADAP (unhandled)\n"); | ||
640 | break; | ||
641 | case ST90TDS_SBUS_READ: | ||
642 | pr_info("ETF_SBUS_READ (unhandled)\n"); | ||
643 | break; | ||
644 | case ST90TDS_SBUS_WRITE: | ||
645 | pr_info("ETF_SBUS_WRITE (unhandled)\n"); | ||
646 | break; | ||
647 | case ST90TDS_SET_DEVICE_OPTION: | ||
648 | pr_info("ETF_SET_DEV_OPT (unhandled)\n"); | ||
649 | break; | ||
650 | default: | ||
651 | pr_info("ETF_PASSTHRU (0x%08x)\n", msg->id); | ||
652 | rval = wsm_raw_cmd(priv, (u8 *)msg, len); | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | return rval; | ||
657 | } | ||
658 | #endif /* CONFIG_CW1200_ETF */ | ||
diff --git a/drivers/net/wireless/cw1200/debug.h b/drivers/net/wireless/cw1200/debug.h new file mode 100644 index 000000000000..1fea5b29a819 --- /dev/null +++ b/drivers/net/wireless/cw1200/debug.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * DebugFS code for ST-Ericsson CW1200 mac80211 driver | ||
3 | * | ||
4 | * Copyright (c) 2011, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_DEBUG_H_INCLUDED | ||
13 | #define CW1200_DEBUG_H_INCLUDED | ||
14 | |||
15 | #include "itp.h" | ||
16 | |||
17 | struct cw1200_debug_priv { | ||
18 | struct dentry *debugfs_phy; | ||
19 | int tx; | ||
20 | int tx_agg; | ||
21 | int rx; | ||
22 | int rx_agg; | ||
23 | int tx_multi; | ||
24 | int tx_multi_frames; | ||
25 | int tx_cache_miss; | ||
26 | int tx_align; | ||
27 | int tx_ttl; | ||
28 | int tx_burst; | ||
29 | int ba_cnt; | ||
30 | int ba_acc; | ||
31 | int ba_cnt_rx; | ||
32 | int ba_acc_rx; | ||
33 | #ifdef CONFIG_CW1200_ITP | ||
34 | struct cw1200_itp itp; | ||
35 | #endif /* CONFIG_CW1200_ITP */ | ||
36 | }; | ||
37 | |||
38 | int cw1200_debug_init(struct cw1200_common *priv); | ||
39 | void cw1200_debug_release(struct cw1200_common *priv); | ||
40 | |||
41 | static inline void cw1200_debug_txed(struct cw1200_common *priv) | ||
42 | { | ||
43 | ++priv->debug->tx; | ||
44 | } | ||
45 | |||
46 | static inline void cw1200_debug_txed_agg(struct cw1200_common *priv) | ||
47 | { | ||
48 | ++priv->debug->tx_agg; | ||
49 | } | ||
50 | |||
51 | static inline void cw1200_debug_txed_multi(struct cw1200_common *priv, | ||
52 | int count) | ||
53 | { | ||
54 | ++priv->debug->tx_multi; | ||
55 | priv->debug->tx_multi_frames += count; | ||
56 | } | ||
57 | |||
58 | static inline void cw1200_debug_rxed(struct cw1200_common *priv) | ||
59 | { | ||
60 | ++priv->debug->rx; | ||
61 | } | ||
62 | |||
63 | static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv) | ||
64 | { | ||
65 | ++priv->debug->rx_agg; | ||
66 | } | ||
67 | |||
68 | static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv) | ||
69 | { | ||
70 | ++priv->debug->tx_cache_miss; | ||
71 | } | ||
72 | |||
73 | static inline void cw1200_debug_tx_align(struct cw1200_common *priv) | ||
74 | { | ||
75 | ++priv->debug->tx_align; | ||
76 | } | ||
77 | |||
78 | static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv) | ||
79 | { | ||
80 | ++priv->debug->tx_ttl; | ||
81 | } | ||
82 | |||
83 | static inline void cw1200_debug_tx_burst(struct cw1200_common *priv) | ||
84 | { | ||
85 | ++priv->debug->tx_burst; | ||
86 | } | ||
87 | |||
88 | static inline void cw1200_debug_ba(struct cw1200_common *priv, | ||
89 | int ba_cnt, int ba_acc, | ||
90 | int ba_cnt_rx, int ba_acc_rx) | ||
91 | { | ||
92 | priv->debug->ba_cnt = ba_cnt; | ||
93 | priv->debug->ba_acc = ba_acc; | ||
94 | priv->debug->ba_cnt_rx = ba_cnt_rx; | ||
95 | priv->debug->ba_acc_rx = ba_acc_rx; | ||
96 | } | ||
97 | |||
98 | #endif /* CW1200_DEBUG_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c new file mode 100644 index 000000000000..427c9f24b94e --- /dev/null +++ b/drivers/net/wireless/cw1200/fwio.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /* | ||
2 | * Firmware I/O code for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * ST-Ericsson UMAC CW1200 driver which is | ||
9 | * Copyright (c) 2010, ST-Ericsson | ||
10 | * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/vmalloc.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/firmware.h> | ||
21 | |||
22 | #include "cw1200.h" | ||
23 | #include "fwio.h" | ||
24 | #include "hwio.h" | ||
25 | #include "hwbus.h" | ||
26 | #include "bh.h" | ||
27 | |||
28 | static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision) | ||
29 | { | ||
30 | int hw_type = -1; | ||
31 | u32 silicon_type = (config_reg_val >> 24) & 0x7; | ||
32 | u32 silicon_vers = (config_reg_val >> 31) & 0x1; | ||
33 | |||
34 | switch (silicon_type) { | ||
35 | case 0x00: | ||
36 | *major_revision = 1; | ||
37 | hw_type = HIF_9000_SILICON_VERSATILE; | ||
38 | break; | ||
39 | case 0x01: | ||
40 | case 0x02: /* CW1x00 */ | ||
41 | case 0x04: /* CW1x60 */ | ||
42 | *major_revision = silicon_type; | ||
43 | if (silicon_vers) | ||
44 | hw_type = HIF_8601_VERSATILE; | ||
45 | else | ||
46 | hw_type = HIF_8601_SILICON; | ||
47 | break; | ||
48 | default: | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | return hw_type; | ||
53 | } | ||
54 | |||
55 | static int cw1200_load_firmware_cw1200(struct cw1200_common *priv) | ||
56 | { | ||
57 | int ret, block, num_blocks; | ||
58 | unsigned i; | ||
59 | u32 val32; | ||
60 | u32 put = 0, get = 0; | ||
61 | u8 *buf = NULL; | ||
62 | const char *fw_path; | ||
63 | const struct firmware *firmware = NULL; | ||
64 | |||
65 | /* Macroses are local. */ | ||
66 | #define APB_WRITE(reg, val) \ | ||
67 | do { \ | ||
68 | ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \ | ||
69 | if (ret < 0) \ | ||
70 | goto error; \ | ||
71 | } while (0) | ||
72 | #define APB_READ(reg, val) \ | ||
73 | do { \ | ||
74 | ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \ | ||
75 | if (ret < 0) \ | ||
76 | goto error; \ | ||
77 | } while (0) | ||
78 | #define REG_WRITE(reg, val) \ | ||
79 | do { \ | ||
80 | ret = cw1200_reg_write_32(priv, (reg), (val)); \ | ||
81 | if (ret < 0) \ | ||
82 | goto error; \ | ||
83 | } while (0) | ||
84 | #define REG_READ(reg, val) \ | ||
85 | do { \ | ||
86 | ret = cw1200_reg_read_32(priv, (reg), &(val)); \ | ||
87 | if (ret < 0) \ | ||
88 | goto error; \ | ||
89 | } while (0) | ||
90 | |||
91 | switch (priv->hw_revision) { | ||
92 | case CW1200_HW_REV_CUT10: | ||
93 | fw_path = FIRMWARE_CUT10; | ||
94 | if (!priv->sdd_path) | ||
95 | priv->sdd_path = SDD_FILE_10; | ||
96 | break; | ||
97 | case CW1200_HW_REV_CUT11: | ||
98 | fw_path = FIRMWARE_CUT11; | ||
99 | if (!priv->sdd_path) | ||
100 | priv->sdd_path = SDD_FILE_11; | ||
101 | break; | ||
102 | case CW1200_HW_REV_CUT20: | ||
103 | fw_path = FIRMWARE_CUT20; | ||
104 | if (!priv->sdd_path) | ||
105 | priv->sdd_path = SDD_FILE_20; | ||
106 | break; | ||
107 | case CW1200_HW_REV_CUT22: | ||
108 | fw_path = FIRMWARE_CUT22; | ||
109 | if (!priv->sdd_path) | ||
110 | priv->sdd_path = SDD_FILE_22; | ||
111 | break; | ||
112 | case CW1X60_HW_REV: | ||
113 | fw_path = FIRMWARE_CW1X60; | ||
114 | if (!priv->sdd_path) | ||
115 | priv->sdd_path = SDD_FILE_CW1X60; | ||
116 | break; | ||
117 | default: | ||
118 | pr_err("Invalid silicon revision %d.\n", priv->hw_revision); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | |||
122 | /* Initialize common registers */ | ||
123 | APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); | ||
124 | APB_WRITE(DOWNLOAD_PUT_REG, 0); | ||
125 | APB_WRITE(DOWNLOAD_GET_REG, 0); | ||
126 | APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); | ||
127 | APB_WRITE(DOWNLOAD_FLAGS_REG, 0); | ||
128 | |||
129 | /* Write the NOP Instruction */ | ||
130 | REG_WRITE(ST90TDS_SRAM_BASE_ADDR_REG_ID, 0xFFF20000); | ||
131 | REG_WRITE(ST90TDS_AHB_DPORT_REG_ID, 0xEAFFFFFE); | ||
132 | |||
133 | /* Release CPU from RESET */ | ||
134 | REG_READ(ST90TDS_CONFIG_REG_ID, val32); | ||
135 | val32 &= ~ST90TDS_CONFIG_CPU_RESET_BIT; | ||
136 | REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); | ||
137 | |||
138 | /* Enable Clock */ | ||
139 | val32 &= ~ST90TDS_CONFIG_CPU_CLK_DIS_BIT; | ||
140 | REG_WRITE(ST90TDS_CONFIG_REG_ID, val32); | ||
141 | |||
142 | #ifdef CONFIG_CW1200_ETF | ||
143 | if (etf_mode) | ||
144 | fw_path = etf_firmware; | ||
145 | #endif | ||
146 | |||
147 | /* Load a firmware file */ | ||
148 | ret = request_firmware(&firmware, fw_path, priv->pdev); | ||
149 | if (ret) { | ||
150 | pr_err("Can't load firmware file %s.\n", fw_path); | ||
151 | goto error; | ||
152 | } | ||
153 | |||
154 | buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); | ||
155 | if (!buf) { | ||
156 | pr_err("Can't allocate firmware load buffer.\n"); | ||
157 | ret = -ENOMEM; | ||
158 | goto error; | ||
159 | } | ||
160 | |||
161 | /* Check if the bootloader is ready */ | ||
162 | for (i = 0; i < 100; i += 1 + i / 2) { | ||
163 | APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); | ||
164 | if (val32 == DOWNLOAD_I_AM_HERE) | ||
165 | break; | ||
166 | mdelay(i); | ||
167 | } /* End of for loop */ | ||
168 | |||
169 | if (val32 != DOWNLOAD_I_AM_HERE) { | ||
170 | pr_err("Bootloader is not ready.\n"); | ||
171 | ret = -ETIMEDOUT; | ||
172 | goto error; | ||
173 | } | ||
174 | |||
175 | /* Calculcate number of download blocks */ | ||
176 | num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; | ||
177 | |||
178 | /* Updating the length in Download Ctrl Area */ | ||
179 | val32 = firmware->size; /* Explicit cast from size_t to u32 */ | ||
180 | APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); | ||
181 | |||
182 | /* Firmware downloading loop */ | ||
183 | for (block = 0; block < num_blocks; block++) { | ||
184 | size_t tx_size; | ||
185 | size_t block_size; | ||
186 | |||
187 | /* check the download status */ | ||
188 | APB_READ(DOWNLOAD_STATUS_REG, val32); | ||
189 | if (val32 != DOWNLOAD_PENDING) { | ||
190 | pr_err("Bootloader reported error %d.\n", val32); | ||
191 | ret = -EIO; | ||
192 | goto error; | ||
193 | } | ||
194 | |||
195 | /* loop until put - get <= 24K */ | ||
196 | for (i = 0; i < 100; i++) { | ||
197 | APB_READ(DOWNLOAD_GET_REG, get); | ||
198 | if ((put - get) <= | ||
199 | (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) | ||
200 | break; | ||
201 | mdelay(i); | ||
202 | } | ||
203 | |||
204 | if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { | ||
205 | pr_err("Timeout waiting for FIFO.\n"); | ||
206 | ret = -ETIMEDOUT; | ||
207 | goto error; | ||
208 | } | ||
209 | |||
210 | /* calculate the block size */ | ||
211 | tx_size = block_size = min((size_t)(firmware->size - put), | ||
212 | (size_t)DOWNLOAD_BLOCK_SIZE); | ||
213 | |||
214 | memcpy(buf, &firmware->data[put], block_size); | ||
215 | if (block_size < DOWNLOAD_BLOCK_SIZE) { | ||
216 | memset(&buf[block_size], 0, | ||
217 | DOWNLOAD_BLOCK_SIZE - block_size); | ||
218 | tx_size = DOWNLOAD_BLOCK_SIZE; | ||
219 | } | ||
220 | |||
221 | /* send the block to sram */ | ||
222 | ret = cw1200_apb_write(priv, | ||
223 | CW1200_APB(DOWNLOAD_FIFO_OFFSET + | ||
224 | (put & (DOWNLOAD_FIFO_SIZE - 1))), | ||
225 | buf, tx_size); | ||
226 | if (ret < 0) { | ||
227 | pr_err("Can't write firmware block @ %d!\n", | ||
228 | put & (DOWNLOAD_FIFO_SIZE - 1)); | ||
229 | goto error; | ||
230 | } | ||
231 | |||
232 | /* update the put register */ | ||
233 | put += block_size; | ||
234 | APB_WRITE(DOWNLOAD_PUT_REG, put); | ||
235 | } /* End of firmware download loop */ | ||
236 | |||
237 | /* Wait for the download completion */ | ||
238 | for (i = 0; i < 300; i += 1 + i / 2) { | ||
239 | APB_READ(DOWNLOAD_STATUS_REG, val32); | ||
240 | if (val32 != DOWNLOAD_PENDING) | ||
241 | break; | ||
242 | mdelay(i); | ||
243 | } | ||
244 | if (val32 != DOWNLOAD_SUCCESS) { | ||
245 | pr_err("Wait for download completion failed: 0x%.8X\n", val32); | ||
246 | ret = -ETIMEDOUT; | ||
247 | goto error; | ||
248 | } else { | ||
249 | pr_info("Firmware download completed.\n"); | ||
250 | ret = 0; | ||
251 | } | ||
252 | |||
253 | error: | ||
254 | kfree(buf); | ||
255 | if (firmware) | ||
256 | release_firmware(firmware); | ||
257 | return ret; | ||
258 | |||
259 | #undef APB_WRITE | ||
260 | #undef APB_READ | ||
261 | #undef REG_WRITE | ||
262 | #undef REG_READ | ||
263 | } | ||
264 | |||
265 | |||
266 | static int config_reg_read(struct cw1200_common *priv, u32 *val) | ||
267 | { | ||
268 | switch (priv->hw_type) { | ||
269 | case HIF_9000_SILICON_VERSATILE: { | ||
270 | u16 val16; | ||
271 | int ret = cw1200_reg_read_16(priv, | ||
272 | ST90TDS_CONFIG_REG_ID, | ||
273 | &val16); | ||
274 | if (ret < 0) | ||
275 | return ret; | ||
276 | *val = val16; | ||
277 | return 0; | ||
278 | } | ||
279 | case HIF_8601_VERSATILE: | ||
280 | case HIF_8601_SILICON: | ||
281 | default: | ||
282 | cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, val); | ||
283 | break; | ||
284 | } | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int config_reg_write(struct cw1200_common *priv, u32 val) | ||
289 | { | ||
290 | switch (priv->hw_type) { | ||
291 | case HIF_9000_SILICON_VERSATILE: | ||
292 | return cw1200_reg_write_16(priv, | ||
293 | ST90TDS_CONFIG_REG_ID, | ||
294 | (u16)val); | ||
295 | case HIF_8601_VERSATILE: | ||
296 | case HIF_8601_SILICON: | ||
297 | default: | ||
298 | return cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val); | ||
299 | break; | ||
300 | } | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | int cw1200_load_firmware(struct cw1200_common *priv) | ||
305 | { | ||
306 | int ret; | ||
307 | int i; | ||
308 | u32 val32; | ||
309 | u16 val16; | ||
310 | int major_revision = -1; | ||
311 | |||
312 | /* Read CONFIG Register */ | ||
313 | ret = cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
314 | if (ret < 0) { | ||
315 | pr_err("Can't read config register.\n"); | ||
316 | goto out; | ||
317 | } | ||
318 | |||
319 | if (val32 == 0 || val32 == 0xffffffff) { | ||
320 | pr_err("Bad config register value (0x%08x)\n", val32); | ||
321 | ret = -EIO; | ||
322 | goto out; | ||
323 | } | ||
324 | |||
325 | priv->hw_type = cw1200_get_hw_type(val32, &major_revision); | ||
326 | if (priv->hw_type < 0) { | ||
327 | pr_err("Can't deduce hardware type.\n"); | ||
328 | ret = -ENOTSUPP; | ||
329 | goto out; | ||
330 | } | ||
331 | |||
332 | /* Set DPLL Reg value, and read back to confirm writes work */ | ||
333 | ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, | ||
334 | cw1200_dpll_from_clk(priv->hw_refclk)); | ||
335 | if (ret < 0) { | ||
336 | pr_err("Can't write DPLL register.\n"); | ||
337 | goto out; | ||
338 | } | ||
339 | |||
340 | msleep(20); | ||
341 | |||
342 | ret = cw1200_reg_read_32(priv, | ||
343 | ST90TDS_TSET_GEN_R_W_REG_ID, &val32); | ||
344 | if (ret < 0) { | ||
345 | pr_err("Can't read DPLL register.\n"); | ||
346 | goto out; | ||
347 | } | ||
348 | |||
349 | if (val32 != cw1200_dpll_from_clk(priv->hw_refclk)) { | ||
350 | pr_err("Unable to initialise DPLL register. Wrote 0x%.8X, Read 0x%.8X.\n", | ||
351 | cw1200_dpll_from_clk(priv->hw_refclk), val32); | ||
352 | ret = -EIO; | ||
353 | goto out; | ||
354 | } | ||
355 | |||
356 | /* Set wakeup bit in device */ | ||
357 | ret = cw1200_reg_read_16(priv, ST90TDS_CONTROL_REG_ID, &val16); | ||
358 | if (ret < 0) { | ||
359 | pr_err("set_wakeup: can't read control register.\n"); | ||
360 | goto out; | ||
361 | } | ||
362 | |||
363 | ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, | ||
364 | val16 | ST90TDS_CONT_WUP_BIT); | ||
365 | if (ret < 0) { | ||
366 | pr_err("set_wakeup: can't write control register.\n"); | ||
367 | goto out; | ||
368 | } | ||
369 | |||
370 | /* Wait for wakeup */ | ||
371 | for (i = 0; i < 300; i += (1 + i / 2)) { | ||
372 | ret = cw1200_reg_read_16(priv, | ||
373 | ST90TDS_CONTROL_REG_ID, &val16); | ||
374 | if (ret < 0) { | ||
375 | pr_err("wait_for_wakeup: can't read control register.\n"); | ||
376 | goto out; | ||
377 | } | ||
378 | |||
379 | if (val16 & ST90TDS_CONT_RDY_BIT) | ||
380 | break; | ||
381 | |||
382 | msleep(i); | ||
383 | } | ||
384 | |||
385 | if ((val16 & ST90TDS_CONT_RDY_BIT) == 0) { | ||
386 | pr_err("wait_for_wakeup: device is not responding.\n"); | ||
387 | ret = -ETIMEDOUT; | ||
388 | goto out; | ||
389 | } | ||
390 | |||
391 | switch (major_revision) { | ||
392 | case 1: | ||
393 | /* CW1200 Hardware detection logic : Check for CUT1.1 */ | ||
394 | ret = cw1200_ahb_read_32(priv, CW1200_CUT_ID_ADDR, &val32); | ||
395 | if (ret) { | ||
396 | pr_err("HW detection: can't read CUT ID.\n"); | ||
397 | goto out; | ||
398 | } | ||
399 | |||
400 | switch (val32) { | ||
401 | case CW1200_CUT_11_ID_STR: | ||
402 | pr_info("CW1x00 Cut 1.1 silicon detected.\n"); | ||
403 | priv->hw_revision = CW1200_HW_REV_CUT11; | ||
404 | break; | ||
405 | default: | ||
406 | pr_info("CW1x00 Cut 1.0 silicon detected.\n"); | ||
407 | priv->hw_revision = CW1200_HW_REV_CUT10; | ||
408 | break; | ||
409 | } | ||
410 | |||
411 | /* According to ST-E, CUT<2.0 has busted BA TID0-3. | ||
412 | Just disable it entirely... | ||
413 | */ | ||
414 | priv->ba_rx_tid_mask = 0; | ||
415 | priv->ba_tx_tid_mask = 0; | ||
416 | break; | ||
417 | case 2: { | ||
418 | u32 ar1, ar2, ar3; | ||
419 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR, &ar1); | ||
420 | if (ret) { | ||
421 | pr_err("(1) HW detection: can't read CUT ID\n"); | ||
422 | goto out; | ||
423 | } | ||
424 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 4, &ar2); | ||
425 | if (ret) { | ||
426 | pr_err("(2) HW detection: can't read CUT ID.\n"); | ||
427 | goto out; | ||
428 | } | ||
429 | |||
430 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 8, &ar3); | ||
431 | if (ret) { | ||
432 | pr_err("(3) HW detection: can't read CUT ID.\n"); | ||
433 | goto out; | ||
434 | } | ||
435 | |||
436 | if (ar1 == CW1200_CUT_22_ID_STR1 && | ||
437 | ar2 == CW1200_CUT_22_ID_STR2 && | ||
438 | ar3 == CW1200_CUT_22_ID_STR3) { | ||
439 | pr_info("CW1x00 Cut 2.2 silicon detected.\n"); | ||
440 | priv->hw_revision = CW1200_HW_REV_CUT22; | ||
441 | } else { | ||
442 | pr_info("CW1x00 Cut 2.0 silicon detected.\n"); | ||
443 | priv->hw_revision = CW1200_HW_REV_CUT20; | ||
444 | } | ||
445 | break; | ||
446 | } | ||
447 | case 4: | ||
448 | pr_info("CW1x60 silicon detected.\n"); | ||
449 | priv->hw_revision = CW1X60_HW_REV; | ||
450 | break; | ||
451 | default: | ||
452 | pr_err("Unsupported silicon major revision %d.\n", | ||
453 | major_revision); | ||
454 | ret = -ENOTSUPP; | ||
455 | goto out; | ||
456 | } | ||
457 | |||
458 | /* Checking for access mode */ | ||
459 | ret = config_reg_read(priv, &val32); | ||
460 | if (ret < 0) { | ||
461 | pr_err("Can't read config register.\n"); | ||
462 | goto out; | ||
463 | } | ||
464 | |||
465 | if (!(val32 & ST90TDS_CONFIG_ACCESS_MODE_BIT)) { | ||
466 | pr_err("Device is already in QUEUE mode!\n"); | ||
467 | ret = -EINVAL; | ||
468 | goto out; | ||
469 | } | ||
470 | |||
471 | switch (priv->hw_type) { | ||
472 | case HIF_8601_SILICON: | ||
473 | if (priv->hw_revision == CW1X60_HW_REV) { | ||
474 | pr_err("Can't handle CW1160/1260 firmware load yet.\n"); | ||
475 | ret = -ENOTSUPP; | ||
476 | goto out; | ||
477 | } | ||
478 | ret = cw1200_load_firmware_cw1200(priv); | ||
479 | break; | ||
480 | default: | ||
481 | pr_err("Can't perform firmware load for hw type %d.\n", | ||
482 | priv->hw_type); | ||
483 | ret = -ENOTSUPP; | ||
484 | goto out; | ||
485 | } | ||
486 | if (ret < 0) { | ||
487 | pr_err("Firmware load error.\n"); | ||
488 | goto out; | ||
489 | } | ||
490 | |||
491 | /* Enable interrupt signalling */ | ||
492 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
493 | ret = __cw1200_irq_enable(priv, 1); | ||
494 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
495 | if (ret < 0) | ||
496 | goto unsubscribe; | ||
497 | |||
498 | /* Configure device for MESSSAGE MODE */ | ||
499 | ret = config_reg_read(priv, &val32); | ||
500 | if (ret < 0) { | ||
501 | pr_err("Can't read config register.\n"); | ||
502 | goto unsubscribe; | ||
503 | } | ||
504 | ret = config_reg_write(priv, val32 & ~ST90TDS_CONFIG_ACCESS_MODE_BIT); | ||
505 | if (ret < 0) { | ||
506 | pr_err("Can't write config register.\n"); | ||
507 | goto unsubscribe; | ||
508 | } | ||
509 | |||
510 | /* Unless we read the CONFIG Register we are | ||
511 | * not able to get an interrupt | ||
512 | */ | ||
513 | mdelay(10); | ||
514 | config_reg_read(priv, &val32); | ||
515 | |||
516 | out: | ||
517 | return ret; | ||
518 | |||
519 | unsubscribe: | ||
520 | /* Disable interrupt signalling */ | ||
521 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
522 | ret = __cw1200_irq_enable(priv, 0); | ||
523 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
524 | return ret; | ||
525 | } | ||
diff --git a/drivers/net/wireless/cw1200/fwio.h b/drivers/net/wireless/cw1200/fwio.h new file mode 100644 index 000000000000..ea3099362cdf --- /dev/null +++ b/drivers/net/wireless/cw1200/fwio.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Firmware API for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * ST-Ericsson UMAC CW1200 driver which is | ||
9 | * Copyright (c) 2010, ST-Ericsson | ||
10 | * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #ifndef FWIO_H_INCLUDED | ||
18 | #define FWIO_H_INCLUDED | ||
19 | |||
20 | #define BOOTLOADER_CW1X60 "boot_cw1x60.bin" | ||
21 | #define FIRMWARE_CW1X60 "wsm_cw1x60.bin" | ||
22 | #define FIRMWARE_CUT22 "wsm_22.bin" | ||
23 | #define FIRMWARE_CUT20 "wsm_20.bin" | ||
24 | #define FIRMWARE_CUT11 "wsm_11.bin" | ||
25 | #define FIRMWARE_CUT10 "wsm_10.bin" | ||
26 | #define SDD_FILE_CW1X60 "sdd_cw1x60.bin" | ||
27 | #define SDD_FILE_22 "sdd_22.bin" | ||
28 | #define SDD_FILE_20 "sdd_20.bin" | ||
29 | #define SDD_FILE_11 "sdd_11.bin" | ||
30 | #define SDD_FILE_10 "sdd_10.bin" | ||
31 | |||
32 | int cw1200_load_firmware(struct cw1200_common *priv); | ||
33 | |||
34 | /* SDD definitions */ | ||
35 | #define SDD_PTA_CFG_ELT_ID 0xEB | ||
36 | #define SDD_REFERENCE_FREQUENCY_ELT_ID 0xc5 | ||
37 | u32 cw1200_dpll_from_clk(u16 clk); | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/net/wireless/cw1200/hwbus.h b/drivers/net/wireless/cw1200/hwbus.h new file mode 100644 index 000000000000..8b2fc831c3de --- /dev/null +++ b/drivers/net/wireless/cw1200/hwbus.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Common hwbus abstraction layer interface for cw1200 wireless driver | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_HWBUS_H | ||
13 | #define CW1200_HWBUS_H | ||
14 | |||
15 | struct hwbus_priv; | ||
16 | |||
17 | void cw1200_irq_handler(struct cw1200_common *priv); | ||
18 | |||
19 | /* This MUST be wrapped with hwbus_ops->lock/unlock! */ | ||
20 | int __cw1200_irq_enable(struct cw1200_common *priv, int enable); | ||
21 | |||
22 | struct hwbus_ops { | ||
23 | int (*hwbus_memcpy_fromio)(struct hwbus_priv *self, unsigned int addr, | ||
24 | void *dst, int count); | ||
25 | int (*hwbus_memcpy_toio)(struct hwbus_priv *self, unsigned int addr, | ||
26 | const void *src, int count); | ||
27 | void (*lock)(struct hwbus_priv *self); | ||
28 | void (*unlock)(struct hwbus_priv *self); | ||
29 | size_t (*align_size)(struct hwbus_priv *self, size_t size); | ||
30 | int (*power_mgmt)(struct hwbus_priv *self, bool suspend); | ||
31 | }; | ||
32 | |||
33 | #endif /* CW1200_HWBUS_H */ | ||
diff --git a/drivers/net/wireless/cw1200/hwio.c b/drivers/net/wireless/cw1200/hwio.c new file mode 100644 index 000000000000..142f45efa204 --- /dev/null +++ b/drivers/net/wireless/cw1200/hwio.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Low-level device IO routines for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * ST-Ericsson UMAC CW1200 driver, which is | ||
9 | * Copyright (c) 2010, ST-Ericsson | ||
10 | * Author: Ajitpal Singh <ajitpal.singh@lockless.no> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | |||
19 | #include "cw1200.h" | ||
20 | #include "hwio.h" | ||
21 | #include "hwbus.h" | ||
22 | |||
23 | /* Sdio addr is 4*spi_addr */ | ||
24 | #define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) | ||
25 | #define SDIO_ADDR17BIT(buf_id, mpf, rfu, reg_id_ofs) \ | ||
26 | ((((buf_id) & 0x1F) << 7) \ | ||
27 | | (((mpf) & 1) << 6) \ | ||
28 | | (((rfu) & 1) << 5) \ | ||
29 | | (((reg_id_ofs) & 0x1F) << 0)) | ||
30 | #define MAX_RETRY 3 | ||
31 | |||
32 | |||
33 | static int __cw1200_reg_read(struct cw1200_common *priv, u16 addr, | ||
34 | void *buf, size_t buf_len, int buf_id) | ||
35 | { | ||
36 | u16 addr_sdio; | ||
37 | u32 sdio_reg_addr_17bit; | ||
38 | |||
39 | /* Check if buffer is aligned to 4 byte boundary */ | ||
40 | if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { | ||
41 | pr_err("buffer is not aligned.\n"); | ||
42 | return -EINVAL; | ||
43 | } | ||
44 | |||
45 | /* Convert to SDIO Register Address */ | ||
46 | addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); | ||
47 | sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); | ||
48 | |||
49 | return priv->hwbus_ops->hwbus_memcpy_fromio(priv->hwbus_priv, | ||
50 | sdio_reg_addr_17bit, | ||
51 | buf, buf_len); | ||
52 | } | ||
53 | |||
54 | static int __cw1200_reg_write(struct cw1200_common *priv, u16 addr, | ||
55 | const void *buf, size_t buf_len, int buf_id) | ||
56 | { | ||
57 | u16 addr_sdio; | ||
58 | u32 sdio_reg_addr_17bit; | ||
59 | |||
60 | /* Convert to SDIO Register Address */ | ||
61 | addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); | ||
62 | sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); | ||
63 | |||
64 | return priv->hwbus_ops->hwbus_memcpy_toio(priv->hwbus_priv, | ||
65 | sdio_reg_addr_17bit, | ||
66 | buf, buf_len); | ||
67 | } | ||
68 | |||
69 | static inline int __cw1200_reg_read_32(struct cw1200_common *priv, | ||
70 | u16 addr, u32 *val) | ||
71 | { | ||
72 | int i = __cw1200_reg_read(priv, addr, val, sizeof(*val), 0); | ||
73 | *val = le32_to_cpu(*val); | ||
74 | return i; | ||
75 | } | ||
76 | |||
77 | static inline int __cw1200_reg_write_32(struct cw1200_common *priv, | ||
78 | u16 addr, u32 val) | ||
79 | { | ||
80 | val = cpu_to_le32(val); | ||
81 | return __cw1200_reg_write(priv, addr, &val, sizeof(val), 0); | ||
82 | } | ||
83 | |||
84 | static inline int __cw1200_reg_read_16(struct cw1200_common *priv, | ||
85 | u16 addr, u16 *val) | ||
86 | { | ||
87 | int i = __cw1200_reg_read(priv, addr, val, sizeof(*val), 0); | ||
88 | *val = le16_to_cpu(*val); | ||
89 | return i; | ||
90 | } | ||
91 | |||
92 | static inline int __cw1200_reg_write_16(struct cw1200_common *priv, | ||
93 | u16 addr, u16 val) | ||
94 | { | ||
95 | val = cpu_to_le16(val); | ||
96 | return __cw1200_reg_write(priv, addr, &val, sizeof(val), 0); | ||
97 | } | ||
98 | |||
99 | int cw1200_reg_read(struct cw1200_common *priv, u16 addr, void *buf, | ||
100 | size_t buf_len) | ||
101 | { | ||
102 | int ret; | ||
103 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
104 | ret = __cw1200_reg_read(priv, addr, buf, buf_len, 0); | ||
105 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | int cw1200_reg_write(struct cw1200_common *priv, u16 addr, const void *buf, | ||
110 | size_t buf_len) | ||
111 | { | ||
112 | int ret; | ||
113 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
114 | ret = __cw1200_reg_write(priv, addr, buf, buf_len, 0); | ||
115 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | int cw1200_data_read(struct cw1200_common *priv, void *buf, size_t buf_len) | ||
120 | { | ||
121 | int ret, retry = 1; | ||
122 | int buf_id_rx = priv->buf_id_rx; | ||
123 | |||
124 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
125 | |||
126 | while (retry <= MAX_RETRY) { | ||
127 | ret = __cw1200_reg_read(priv, | ||
128 | ST90TDS_IN_OUT_QUEUE_REG_ID, buf, | ||
129 | buf_len, buf_id_rx + 1); | ||
130 | if (!ret) { | ||
131 | buf_id_rx = (buf_id_rx + 1) & 3; | ||
132 | priv->buf_id_rx = buf_id_rx; | ||
133 | break; | ||
134 | } else { | ||
135 | retry++; | ||
136 | mdelay(1); | ||
137 | pr_err("error :[%d]\n", ret); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | int cw1200_data_write(struct cw1200_common *priv, const void *buf, | ||
146 | size_t buf_len) | ||
147 | { | ||
148 | int ret, retry = 1; | ||
149 | int buf_id_tx = priv->buf_id_tx; | ||
150 | |||
151 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
152 | |||
153 | while (retry <= MAX_RETRY) { | ||
154 | ret = __cw1200_reg_write(priv, | ||
155 | ST90TDS_IN_OUT_QUEUE_REG_ID, buf, | ||
156 | buf_len, buf_id_tx); | ||
157 | if (!ret) { | ||
158 | buf_id_tx = (buf_id_tx + 1) & 31; | ||
159 | priv->buf_id_tx = buf_id_tx; | ||
160 | break; | ||
161 | } else { | ||
162 | retry++; | ||
163 | mdelay(1); | ||
164 | pr_err("error :[%d]\n", ret); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, | ||
173 | size_t buf_len, u32 prefetch, u16 port_addr) | ||
174 | { | ||
175 | u32 val32 = 0; | ||
176 | int i, ret; | ||
177 | |||
178 | if ((buf_len / 2) >= 0x1000) { | ||
179 | pr_err("Can't read more than 0xfff words.\n"); | ||
180 | return -EINVAL; | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
185 | /* Write address */ | ||
186 | ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); | ||
187 | if (ret < 0) { | ||
188 | pr_err("Can't write address register.\n"); | ||
189 | goto out; | ||
190 | } | ||
191 | |||
192 | /* Read CONFIG Register Value - We will read 32 bits */ | ||
193 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
194 | if (ret < 0) { | ||
195 | pr_err("Can't read config register.\n"); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | /* Set PREFETCH bit */ | ||
200 | ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, | ||
201 | val32 | prefetch); | ||
202 | if (ret < 0) { | ||
203 | pr_err("Can't write prefetch bit.\n"); | ||
204 | goto out; | ||
205 | } | ||
206 | |||
207 | /* Check for PRE-FETCH bit to be cleared */ | ||
208 | for (i = 0; i < 20; i++) { | ||
209 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
210 | if (ret < 0) { | ||
211 | pr_err("Can't check prefetch bit.\n"); | ||
212 | goto out; | ||
213 | } | ||
214 | if (!(val32 & prefetch)) | ||
215 | break; | ||
216 | |||
217 | mdelay(i); | ||
218 | } | ||
219 | |||
220 | if (val32 & prefetch) { | ||
221 | pr_err("Prefetch bit is not cleared.\n"); | ||
222 | goto out; | ||
223 | } | ||
224 | |||
225 | /* Read data port */ | ||
226 | ret = __cw1200_reg_read(priv, port_addr, buf, buf_len, 0); | ||
227 | if (ret < 0) { | ||
228 | pr_err("Can't read data port.\n"); | ||
229 | goto out; | ||
230 | } | ||
231 | |||
232 | out: | ||
233 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, | ||
238 | size_t buf_len) | ||
239 | { | ||
240 | int ret; | ||
241 | |||
242 | if ((buf_len / 2) >= 0x1000) { | ||
243 | pr_err("Can't write more than 0xfff words.\n"); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
248 | |||
249 | /* Write address */ | ||
250 | ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); | ||
251 | if (ret < 0) { | ||
252 | pr_err("Can't write address register.\n"); | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | /* Write data port */ | ||
257 | ret = __cw1200_reg_write(priv, ST90TDS_SRAM_DPORT_REG_ID, | ||
258 | buf, buf_len, 0); | ||
259 | if (ret < 0) { | ||
260 | pr_err("Can't write data port.\n"); | ||
261 | goto out; | ||
262 | } | ||
263 | |||
264 | out: | ||
265 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | int __cw1200_irq_enable(struct cw1200_common *priv, int enable) | ||
270 | { | ||
271 | u32 val32; | ||
272 | u16 val16; | ||
273 | int ret; | ||
274 | |||
275 | if (HIF_8601_SILICON == priv->hw_type) { | ||
276 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
277 | if (ret < 0) { | ||
278 | pr_err("Can't read config register.\n"); | ||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | if (enable) | ||
283 | val32 |= ST90TDS_CONF_IRQ_RDY_ENABLE; | ||
284 | else | ||
285 | val32 &= ~ST90TDS_CONF_IRQ_RDY_ENABLE; | ||
286 | |||
287 | ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val32); | ||
288 | if (ret < 0) { | ||
289 | pr_err("Can't write config register.\n"); | ||
290 | return ret; | ||
291 | } | ||
292 | } else { | ||
293 | ret = __cw1200_reg_read_16(priv, ST90TDS_CONFIG_REG_ID, &val16); | ||
294 | if (ret < 0) { | ||
295 | pr_err("Can't read control register.\n"); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | if (enable) | ||
300 | val16 |= ST90TDS_CONT_IRQ_RDY_ENABLE; | ||
301 | else | ||
302 | val16 &= ~ST90TDS_CONT_IRQ_RDY_ENABLE; | ||
303 | |||
304 | ret = __cw1200_reg_write_16(priv, ST90TDS_CONFIG_REG_ID, val16); | ||
305 | if (ret < 0) { | ||
306 | pr_err("Can't write control register.\n"); | ||
307 | return ret; | ||
308 | } | ||
309 | } | ||
310 | return 0; | ||
311 | } | ||
diff --git a/drivers/net/wireless/cw1200/hwio.h b/drivers/net/wireless/cw1200/hwio.h new file mode 100644 index 000000000000..7ee73fe32ccf --- /dev/null +++ b/drivers/net/wireless/cw1200/hwio.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Low-level API for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * ST-Ericsson UMAC CW1200 driver which is | ||
9 | * Copyright (c) 2010, ST-Ericsson | ||
10 | * Author: Ajitpal Singh <ajitpal.singh@stericsson.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #ifndef CW1200_HWIO_H_INCLUDED | ||
18 | #define CW1200_HWIO_H_INCLUDED | ||
19 | |||
20 | /* extern */ struct cw1200_common; | ||
21 | |||
22 | #define CW1200_CUT_11_ID_STR (0x302E3830) | ||
23 | #define CW1200_CUT_22_ID_STR1 (0x302e3132) | ||
24 | #define CW1200_CUT_22_ID_STR2 (0x32302e30) | ||
25 | #define CW1200_CUT_22_ID_STR3 (0x3335) | ||
26 | #define CW1200_CUT_ID_ADDR (0xFFF17F90) | ||
27 | #define CW1200_CUT2_ID_ADDR (0xFFF1FF90) | ||
28 | |||
29 | /* Download control area */ | ||
30 | /* boot loader start address in SRAM */ | ||
31 | #define DOWNLOAD_BOOT_LOADER_OFFSET (0x00000000) | ||
32 | /* 32K, 0x4000 to 0xDFFF */ | ||
33 | #define DOWNLOAD_FIFO_OFFSET (0x00004000) | ||
34 | /* 32K */ | ||
35 | #define DOWNLOAD_FIFO_SIZE (0x00008000) | ||
36 | /* 128 bytes, 0xFF80 to 0xFFFF */ | ||
37 | #define DOWNLOAD_CTRL_OFFSET (0x0000FF80) | ||
38 | #define DOWNLOAD_CTRL_DATA_DWORDS (32-6) | ||
39 | |||
40 | struct download_cntl_t { | ||
41 | /* size of whole firmware file (including Cheksum), host init */ | ||
42 | u32 image_size; | ||
43 | /* downloading flags */ | ||
44 | u32 flags; | ||
45 | /* No. of bytes put into the download, init & updated by host */ | ||
46 | u32 put; | ||
47 | /* last traced program counter, last ARM reg_pc */ | ||
48 | u32 trace_pc; | ||
49 | /* No. of bytes read from the download, host init, device updates */ | ||
50 | u32 get; | ||
51 | /* r0, boot losader status, host init to pending, device updates */ | ||
52 | u32 status; | ||
53 | /* Extra debug info, r1 to r14 if status=r0=DOWNLOAD_EXCEPTION */ | ||
54 | u32 debug_data[DOWNLOAD_CTRL_DATA_DWORDS]; | ||
55 | }; | ||
56 | |||
57 | #define DOWNLOAD_IMAGE_SIZE_REG \ | ||
58 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, image_size)) | ||
59 | #define DOWNLOAD_FLAGS_REG \ | ||
60 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, flags)) | ||
61 | #define DOWNLOAD_PUT_REG \ | ||
62 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, put)) | ||
63 | #define DOWNLOAD_TRACE_PC_REG \ | ||
64 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, trace_pc)) | ||
65 | #define DOWNLOAD_GET_REG \ | ||
66 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, get)) | ||
67 | #define DOWNLOAD_STATUS_REG \ | ||
68 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, status)) | ||
69 | #define DOWNLOAD_DEBUG_DATA_REG \ | ||
70 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, debug_data)) | ||
71 | #define DOWNLOAD_DEBUG_DATA_LEN (108) | ||
72 | |||
73 | #define DOWNLOAD_BLOCK_SIZE (1024) | ||
74 | |||
75 | /* For boot loader detection */ | ||
76 | #define DOWNLOAD_ARE_YOU_HERE (0x87654321) | ||
77 | #define DOWNLOAD_I_AM_HERE (0x12345678) | ||
78 | |||
79 | /* Download error code */ | ||
80 | #define DOWNLOAD_PENDING (0xFFFFFFFF) | ||
81 | #define DOWNLOAD_SUCCESS (0) | ||
82 | #define DOWNLOAD_EXCEPTION (1) | ||
83 | #define DOWNLOAD_ERR_MEM_1 (2) | ||
84 | #define DOWNLOAD_ERR_MEM_2 (3) | ||
85 | #define DOWNLOAD_ERR_SOFTWARE (4) | ||
86 | #define DOWNLOAD_ERR_FILE_SIZE (5) | ||
87 | #define DOWNLOAD_ERR_CHECKSUM (6) | ||
88 | #define DOWNLOAD_ERR_OVERFLOW (7) | ||
89 | #define DOWNLOAD_ERR_IMAGE (8) | ||
90 | #define DOWNLOAD_ERR_HOST (9) | ||
91 | #define DOWNLOAD_ERR_ABORT (10) | ||
92 | |||
93 | |||
94 | #define SYS_BASE_ADDR_SILICON (0) | ||
95 | #define PAC_BASE_ADDRESS_SILICON (SYS_BASE_ADDR_SILICON + 0x09000000) | ||
96 | #define PAC_SHARED_MEMORY_SILICON (PAC_BASE_ADDRESS_SILICON) | ||
97 | |||
98 | #define CW1200_APB(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) | ||
99 | |||
100 | /* *************************************************************** | ||
101 | *Device register definitions | ||
102 | *************************************************************** */ | ||
103 | /* WBF - SPI Register Addresses */ | ||
104 | #define ST90TDS_ADDR_ID_BASE (0x0000) | ||
105 | /* 16/32 bits */ | ||
106 | #define ST90TDS_CONFIG_REG_ID (0x0000) | ||
107 | /* 16/32 bits */ | ||
108 | #define ST90TDS_CONTROL_REG_ID (0x0001) | ||
109 | /* 16 bits, Q mode W/R */ | ||
110 | #define ST90TDS_IN_OUT_QUEUE_REG_ID (0x0002) | ||
111 | /* 32 bits, AHB bus R/W */ | ||
112 | #define ST90TDS_AHB_DPORT_REG_ID (0x0003) | ||
113 | /* 16/32 bits */ | ||
114 | #define ST90TDS_SRAM_BASE_ADDR_REG_ID (0x0004) | ||
115 | /* 32 bits, APB bus R/W */ | ||
116 | #define ST90TDS_SRAM_DPORT_REG_ID (0x0005) | ||
117 | /* 32 bits, t_settle/general */ | ||
118 | #define ST90TDS_TSET_GEN_R_W_REG_ID (0x0006) | ||
119 | /* 16 bits, Q mode read, no length */ | ||
120 | #define ST90TDS_FRAME_OUT_REG_ID (0x0007) | ||
121 | #define ST90TDS_ADDR_ID_MAX (ST90TDS_FRAME_OUT_REG_ID) | ||
122 | |||
123 | /* WBF - Control register bit set */ | ||
124 | /* next o/p length, bit 11 to 0 */ | ||
125 | #define ST90TDS_CONT_NEXT_LEN_MASK (0x0FFF) | ||
126 | #define ST90TDS_CONT_WUP_BIT (BIT(12)) | ||
127 | #define ST90TDS_CONT_RDY_BIT (BIT(13)) | ||
128 | #define ST90TDS_CONT_IRQ_ENABLE (BIT(14)) | ||
129 | #define ST90TDS_CONT_RDY_ENABLE (BIT(15)) | ||
130 | #define ST90TDS_CONT_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) | ||
131 | |||
132 | /* SPI Config register bit set */ | ||
133 | #define ST90TDS_CONFIG_FRAME_BIT (BIT(2)) | ||
134 | #define ST90TDS_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) | ||
135 | #define ST90TDS_CONFIG_WORD_MODE_1 (BIT(3)) | ||
136 | #define ST90TDS_CONFIG_WORD_MODE_2 (BIT(4)) | ||
137 | #define ST90TDS_CONFIG_ERROR_0_BIT (BIT(5)) | ||
138 | #define ST90TDS_CONFIG_ERROR_1_BIT (BIT(6)) | ||
139 | #define ST90TDS_CONFIG_ERROR_2_BIT (BIT(7)) | ||
140 | /* TBD: Sure??? */ | ||
141 | #define ST90TDS_CONFIG_CSN_FRAME_BIT (BIT(7)) | ||
142 | #define ST90TDS_CONFIG_ERROR_3_BIT (BIT(8)) | ||
143 | #define ST90TDS_CONFIG_ERROR_4_BIT (BIT(9)) | ||
144 | /* QueueM */ | ||
145 | #define ST90TDS_CONFIG_ACCESS_MODE_BIT (BIT(10)) | ||
146 | /* AHB bus */ | ||
147 | #define ST90TDS_CONFIG_AHB_PRFETCH_BIT (BIT(11)) | ||
148 | #define ST90TDS_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) | ||
149 | /* APB bus */ | ||
150 | #define ST90TDS_CONFIG_PRFETCH_BIT (BIT(13)) | ||
151 | /* cpu reset */ | ||
152 | #define ST90TDS_CONFIG_CPU_RESET_BIT (BIT(14)) | ||
153 | #define ST90TDS_CONFIG_CLEAR_INT_BIT (BIT(15)) | ||
154 | |||
155 | /* For CW1200 the IRQ Enable and Ready Bits are in CONFIG register */ | ||
156 | #define ST90TDS_CONF_IRQ_ENABLE (BIT(16)) | ||
157 | #define ST90TDS_CONF_RDY_ENABLE (BIT(17)) | ||
158 | #define ST90TDS_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) | ||
159 | |||
160 | int cw1200_data_read(struct cw1200_common *priv, | ||
161 | void *buf, size_t buf_len); | ||
162 | int cw1200_data_write(struct cw1200_common *priv, | ||
163 | const void *buf, size_t buf_len); | ||
164 | |||
165 | int cw1200_reg_read(struct cw1200_common *priv, u16 addr, | ||
166 | void *buf, size_t buf_len); | ||
167 | int cw1200_reg_write(struct cw1200_common *priv, u16 addr, | ||
168 | const void *buf, size_t buf_len); | ||
169 | |||
170 | static inline int cw1200_reg_read_16(struct cw1200_common *priv, | ||
171 | u16 addr, u16 *val) | ||
172 | { | ||
173 | u32 tmp; | ||
174 | int i; | ||
175 | i = cw1200_reg_read(priv, addr, &tmp, sizeof(tmp)); | ||
176 | tmp = le32_to_cpu(tmp); | ||
177 | *val = tmp & 0xffff; | ||
178 | return i; | ||
179 | } | ||
180 | |||
181 | static inline int cw1200_reg_write_16(struct cw1200_common *priv, | ||
182 | u16 addr, u16 val) | ||
183 | { | ||
184 | u32 tmp = val; | ||
185 | tmp = cpu_to_le32(tmp); | ||
186 | return cw1200_reg_write(priv, addr, &tmp, sizeof(tmp)); | ||
187 | } | ||
188 | |||
189 | static inline int cw1200_reg_read_32(struct cw1200_common *priv, | ||
190 | u16 addr, u32 *val) | ||
191 | { | ||
192 | int i = cw1200_reg_read(priv, addr, val, sizeof(*val)); | ||
193 | *val = le32_to_cpu(*val); | ||
194 | return i; | ||
195 | } | ||
196 | |||
197 | static inline int cw1200_reg_write_32(struct cw1200_common *priv, | ||
198 | u16 addr, u32 val) | ||
199 | { | ||
200 | val = cpu_to_le32(val); | ||
201 | return cw1200_reg_write(priv, addr, &val, sizeof(val)); | ||
202 | } | ||
203 | |||
204 | int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, | ||
205 | size_t buf_len, u32 prefetch, u16 port_addr); | ||
206 | int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, | ||
207 | size_t buf_len); | ||
208 | |||
209 | static inline int cw1200_apb_read(struct cw1200_common *priv, u32 addr, | ||
210 | void *buf, size_t buf_len) | ||
211 | { | ||
212 | return cw1200_indirect_read(priv, addr, buf, buf_len, | ||
213 | ST90TDS_CONFIG_PRFETCH_BIT, | ||
214 | ST90TDS_SRAM_DPORT_REG_ID); | ||
215 | } | ||
216 | |||
217 | static inline int cw1200_ahb_read(struct cw1200_common *priv, u32 addr, | ||
218 | void *buf, size_t buf_len) | ||
219 | { | ||
220 | return cw1200_indirect_read(priv, addr, buf, buf_len, | ||
221 | ST90TDS_CONFIG_AHB_PRFETCH_BIT, | ||
222 | ST90TDS_AHB_DPORT_REG_ID); | ||
223 | } | ||
224 | |||
225 | static inline int cw1200_apb_read_32(struct cw1200_common *priv, | ||
226 | u32 addr, u32 *val) | ||
227 | { | ||
228 | int i = cw1200_apb_read(priv, addr, val, sizeof(*val)); | ||
229 | *val = le32_to_cpu(*val); | ||
230 | return i; | ||
231 | } | ||
232 | |||
233 | static inline int cw1200_apb_write_32(struct cw1200_common *priv, | ||
234 | u32 addr, u32 val) | ||
235 | { | ||
236 | val = cpu_to_le32(val); | ||
237 | return cw1200_apb_write(priv, addr, &val, sizeof(val)); | ||
238 | } | ||
239 | static inline int cw1200_ahb_read_32(struct cw1200_common *priv, | ||
240 | u32 addr, u32 *val) | ||
241 | { | ||
242 | int i = cw1200_ahb_read(priv, addr, val, sizeof(*val)); | ||
243 | *val = le32_to_cpu(*val); | ||
244 | return i; | ||
245 | } | ||
246 | |||
247 | #endif /* CW1200_HWIO_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/cw1200/itp.c b/drivers/net/wireless/cw1200/itp.c new file mode 100644 index 000000000000..c0730bb49b75 --- /dev/null +++ b/drivers/net/wireless/cw1200/itp.c | |||
@@ -0,0 +1,730 @@ | |||
1 | /* | ||
2 | * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * ITP code | ||
4 | * | ||
5 | * Copyright (c) 2010, ST-Ericsson | ||
6 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/debugfs.h> | ||
15 | #include <linux/poll.h> | ||
16 | #include <linux/time.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/kallsyms.h> | ||
19 | #include <net/mac80211.h> | ||
20 | #include "cw1200.h" | ||
21 | #include "debug.h" | ||
22 | #include "itp.h" | ||
23 | #include "sta.h" | ||
24 | |||
25 | static int __cw1200_itp_open(struct cw1200_common *priv); | ||
26 | static int __cw1200_itp_close(struct cw1200_common *priv); | ||
27 | static void cw1200_itp_rx_start(struct cw1200_common *priv); | ||
28 | static void cw1200_itp_rx_stop(struct cw1200_common *priv); | ||
29 | static void cw1200_itp_rx_stats(struct cw1200_common *priv); | ||
30 | static void cw1200_itp_rx_reset(struct cw1200_common *priv); | ||
31 | static void cw1200_itp_tx_stop(struct cw1200_common *priv); | ||
32 | static void cw1200_itp_handle(struct cw1200_common *priv, | ||
33 | struct sk_buff *skb); | ||
34 | static void cw1200_itp_err(struct cw1200_common *priv, | ||
35 | int err, | ||
36 | int arg); | ||
37 | static void __cw1200_itp_tx_stop(struct cw1200_common *priv); | ||
38 | |||
39 | static ssize_t cw1200_itp_read(struct file *file, | ||
40 | char __user *user_buf, size_t count, loff_t *ppos) | ||
41 | { | ||
42 | struct cw1200_common *priv = file->private_data; | ||
43 | struct cw1200_itp *itp = &priv->debug->itp; | ||
44 | struct sk_buff *skb; | ||
45 | int ret; | ||
46 | |||
47 | if (skb_queue_empty(&itp->log_queue)) | ||
48 | return 0; | ||
49 | |||
50 | skb = skb_dequeue(&itp->log_queue); | ||
51 | ret = copy_to_user(user_buf, skb->data, skb->len); | ||
52 | *ppos += skb->len; | ||
53 | skb->data[skb->len] = 0; | ||
54 | pr_debug("[ITP] >>> %s", skb->data); | ||
55 | consume_skb(skb); | ||
56 | |||
57 | return skb->len - ret; | ||
58 | } | ||
59 | |||
60 | static ssize_t cw1200_itp_write(struct file *file, | ||
61 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
62 | { | ||
63 | struct cw1200_common *priv = file->private_data; | ||
64 | struct sk_buff *skb; | ||
65 | |||
66 | if (!count || count > 1024) | ||
67 | return -EINVAL; | ||
68 | skb = dev_alloc_skb(count + 1); | ||
69 | if (!skb) | ||
70 | return -ENOMEM; | ||
71 | skb_trim(skb, 0); | ||
72 | skb_put(skb, count + 1); | ||
73 | if (copy_from_user(skb->data, user_buf, count)) { | ||
74 | kfree_skb(skb); | ||
75 | return -EFAULT; | ||
76 | } | ||
77 | skb->data[count] = 0; | ||
78 | |||
79 | cw1200_itp_handle(priv, skb); | ||
80 | consume_skb(skb); | ||
81 | return count; | ||
82 | } | ||
83 | |||
84 | static unsigned int cw1200_itp_poll(struct file *file, poll_table *wait) | ||
85 | { | ||
86 | struct cw1200_common *priv = file->private_data; | ||
87 | struct cw1200_itp *itp = &priv->debug->itp; | ||
88 | unsigned int mask = 0; | ||
89 | |||
90 | poll_wait(file, &itp->read_wait, wait); | ||
91 | |||
92 | if (!skb_queue_empty(&itp->log_queue)) | ||
93 | mask |= POLLIN | POLLRDNORM; | ||
94 | |||
95 | mask |= POLLOUT | POLLWRNORM; | ||
96 | |||
97 | return mask; | ||
98 | } | ||
99 | |||
100 | static int cw1200_itp_open(struct inode *inode, struct file *file) | ||
101 | { | ||
102 | struct cw1200_common *priv = inode->i_private; | ||
103 | struct cw1200_itp *itp = &priv->debug->itp; | ||
104 | int ret = 0; | ||
105 | |||
106 | file->private_data = priv; | ||
107 | if (atomic_inc_return(&itp->open_count) == 1) { | ||
108 | ret = __cw1200_itp_open(priv); | ||
109 | if (ret && !atomic_dec_return(&itp->open_count)) | ||
110 | __cw1200_itp_close(priv); | ||
111 | } else { | ||
112 | atomic_dec(&itp->open_count); | ||
113 | ret = -EBUSY; | ||
114 | } | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int cw1200_itp_close(struct inode *inode, struct file *file) | ||
120 | { | ||
121 | struct cw1200_common *priv = file->private_data; | ||
122 | struct cw1200_itp *itp = &priv->debug->itp; | ||
123 | if (!atomic_dec_return(&itp->open_count)) { | ||
124 | __cw1200_itp_close(priv); | ||
125 | wake_up(&itp->close_wait); | ||
126 | } | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static const struct file_operations fops_itp = { | ||
131 | .open = cw1200_itp_open, | ||
132 | .read = cw1200_itp_read, | ||
133 | .write = cw1200_itp_write, | ||
134 | .poll = cw1200_itp_poll, | ||
135 | .release = cw1200_itp_close, | ||
136 | .llseek = default_llseek, | ||
137 | .owner = THIS_MODULE, | ||
138 | }; | ||
139 | |||
140 | static void cw1200_itp_fill_pattern(u8 *data, int size, | ||
141 | enum cw1200_itp_data_modes mode) | ||
142 | { | ||
143 | if (size <= 0) | ||
144 | return; | ||
145 | |||
146 | switch (mode) { | ||
147 | default: | ||
148 | case ITP_DATA_ZEROS: | ||
149 | memset(data, 0x0, size); | ||
150 | break; | ||
151 | case ITP_DATA_ONES: | ||
152 | memset(data, 0xff, size); | ||
153 | break; | ||
154 | case ITP_DATA_ZERONES: | ||
155 | memset(data, 0x55, size); | ||
156 | break; | ||
157 | case ITP_DATA_RANDOM: | ||
158 | get_random_bytes(data, size); | ||
159 | break; | ||
160 | } | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | static void cw1200_itp_tx_work(struct work_struct *work) | ||
165 | { | ||
166 | struct cw1200_itp *itp = container_of(work, struct cw1200_itp, | ||
167 | tx_work.work); | ||
168 | struct cw1200_common *priv = itp->priv; | ||
169 | atomic_set(&priv->bh_tx, 1); | ||
170 | wake_up(&priv->bh_wq); | ||
171 | } | ||
172 | |||
173 | static void cw1200_itp_tx_finish(struct work_struct *work) | ||
174 | { | ||
175 | struct cw1200_itp *itp = container_of(work, struct cw1200_itp, | ||
176 | tx_finish.work); | ||
177 | __cw1200_itp_tx_stop(itp->priv); | ||
178 | } | ||
179 | |||
180 | int cw1200_itp_init(struct cw1200_common *priv) | ||
181 | { | ||
182 | struct cw1200_itp *itp = &priv->debug->itp; | ||
183 | |||
184 | itp->priv = priv; | ||
185 | atomic_set(&itp->open_count, 0); | ||
186 | atomic_set(&itp->stop_tx, 0); | ||
187 | atomic_set(&itp->awaiting_confirm, 0); | ||
188 | skb_queue_head_init(&itp->log_queue); | ||
189 | spin_lock_init(&itp->tx_lock); | ||
190 | init_waitqueue_head(&itp->read_wait); | ||
191 | init_waitqueue_head(&itp->write_wait); | ||
192 | init_waitqueue_head(&itp->close_wait); | ||
193 | INIT_DELAYED_WORK(&itp->tx_work, cw1200_itp_tx_work); | ||
194 | INIT_DELAYED_WORK(&itp->tx_finish, cw1200_itp_tx_finish); | ||
195 | itp->data = NULL; | ||
196 | itp->hdr_len = WSM_TX_EXTRA_HEADROOM + | ||
197 | sizeof(struct ieee80211_hdr_3addr); | ||
198 | |||
199 | if (!debugfs_create_file("itp", S_IRUSR | S_IWUSR, | ||
200 | priv->debug->debugfs_phy, priv, &fops_itp)) | ||
201 | return -ENOMEM; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | void cw1200_itp_release(struct cw1200_common *priv) | ||
207 | { | ||
208 | struct cw1200_itp *itp = &priv->debug->itp; | ||
209 | |||
210 | wait_event_interruptible(itp->close_wait, | ||
211 | !atomic_read(&itp->open_count)); | ||
212 | |||
213 | WARN_ON(atomic_read(&itp->open_count)); | ||
214 | |||
215 | skb_queue_purge(&itp->log_queue); | ||
216 | cw1200_itp_tx_stop(priv); | ||
217 | } | ||
218 | |||
219 | static int __cw1200_itp_open(struct cw1200_common *priv) | ||
220 | { | ||
221 | struct cw1200_itp *itp = &priv->debug->itp; | ||
222 | |||
223 | if (!priv->vif) | ||
224 | return -EINVAL; | ||
225 | if (priv->join_status) | ||
226 | return -EINVAL; | ||
227 | itp->saved_channel = priv->channel; | ||
228 | if (!priv->channel) | ||
229 | priv->channel = &priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; | ||
230 | wsm_set_bssid_filtering(priv, false); | ||
231 | cw1200_itp_rx_reset(priv); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int __cw1200_itp_close(struct cw1200_common *priv) | ||
236 | { | ||
237 | struct cw1200_itp *itp = &priv->debug->itp; | ||
238 | if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST) | ||
239 | cw1200_itp_rx_stop(priv); | ||
240 | cw1200_itp_tx_stop(priv); | ||
241 | cw1200_disable_listening(priv); | ||
242 | cw1200_update_filtering(priv); | ||
243 | priv->channel = itp->saved_channel; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | bool cw1200_is_itp(struct cw1200_common *priv) | ||
248 | { | ||
249 | struct cw1200_itp *itp = &priv->debug->itp; | ||
250 | return atomic_read(&itp->open_count) != 0; | ||
251 | } | ||
252 | |||
253 | static void cw1200_itp_rx_reset(struct cw1200_common *priv) | ||
254 | { | ||
255 | struct cw1200_itp *itp = &priv->debug->itp; | ||
256 | itp->rx_cnt = 0; | ||
257 | itp->rx_rssi = 0; | ||
258 | itp->rx_rssi_max = -1000; | ||
259 | itp->rx_rssi_min = 1000; | ||
260 | } | ||
261 | |||
262 | static void cw1200_itp_rx_start(struct cw1200_common *priv) | ||
263 | { | ||
264 | struct cw1200_itp *itp = &priv->debug->itp; | ||
265 | |||
266 | pr_debug("[ITP] RX start, band = %d, ch = %d\n", | ||
267 | itp->band, itp->ch); | ||
268 | atomic_set(&itp->test_mode, TEST_MODE_RX_TEST); | ||
269 | cw1200_update_listening(priv, false); | ||
270 | priv->channel = &priv->hw-> | ||
271 | wiphy->bands[itp->band]->channels[itp->ch]; | ||
272 | cw1200_update_listening(priv, true); | ||
273 | wsm_set_bssid_filtering(priv, false); | ||
274 | } | ||
275 | |||
276 | static void cw1200_itp_rx_stop(struct cw1200_common *priv) | ||
277 | { | ||
278 | struct cw1200_itp *itp = &priv->debug->itp; | ||
279 | pr_debug("[ITP] RX stop\n"); | ||
280 | atomic_set(&itp->test_mode, TEST_MODE_NO_TEST); | ||
281 | cw1200_itp_rx_reset(priv); | ||
282 | } | ||
283 | |||
284 | static void cw1200_itp_rx_stats(struct cw1200_common *priv) | ||
285 | { | ||
286 | struct cw1200_itp *itp = &priv->debug->itp; | ||
287 | struct sk_buff *skb; | ||
288 | char buf[128]; | ||
289 | int len, ret; | ||
290 | struct wsm_mib_counters_table counters; | ||
291 | |||
292 | ret = wsm_get_counters_table(priv, &counters); | ||
293 | |||
294 | if (ret) | ||
295 | cw1200_itp_err(priv, -EBUSY, 20); | ||
296 | |||
297 | if (!itp->rx_cnt) | ||
298 | len = snprintf(buf, sizeof(buf), "1,0,0,0,0,%d\n", | ||
299 | counters.rx_packet_errors); | ||
300 | else | ||
301 | len = snprintf(buf, sizeof(buf), "1,%d,%ld,%d,%d,%d\n", | ||
302 | itp->rx_cnt, | ||
303 | itp->rx_cnt ? itp->rx_rssi / itp->rx_cnt : 0, | ||
304 | itp->rx_rssi_min, itp->rx_rssi_max, | ||
305 | counters.rx_packet_errors); | ||
306 | |||
307 | if (len <= 0) { | ||
308 | cw1200_itp_err(priv, -EBUSY, 21); | ||
309 | return; | ||
310 | } | ||
311 | |||
312 | skb = dev_alloc_skb(len); | ||
313 | if (!skb) { | ||
314 | cw1200_itp_err(priv, -ENOMEM, 22); | ||
315 | return; | ||
316 | } | ||
317 | |||
318 | itp->rx_cnt = 0; | ||
319 | itp->rx_rssi = 0; | ||
320 | itp->rx_rssi_max = -1000; | ||
321 | itp->rx_rssi_min = 1000; | ||
322 | |||
323 | skb_trim(skb, 0); | ||
324 | skb_put(skb, len); | ||
325 | |||
326 | memcpy(skb->data, buf, len); | ||
327 | skb_queue_tail(&itp->log_queue, skb); | ||
328 | wake_up(&itp->read_wait); | ||
329 | } | ||
330 | |||
331 | static void cw1200_itp_tx_start(struct cw1200_common *priv) | ||
332 | { | ||
333 | struct wsm_tx *tx; | ||
334 | struct ieee80211_hdr_3addr *hdr; | ||
335 | struct cw1200_itp *itp = &priv->debug->itp; | ||
336 | struct wsm_mib_association_mode assoc_mode = { | ||
337 | .flags = WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE, | ||
338 | .preamble = itp->preamble, | ||
339 | }; | ||
340 | int len; | ||
341 | u8 da_addr[6] = ITP_DEFAULT_DA_ADDR; | ||
342 | |||
343 | /* Rates index 4 and 5 are not supported */ | ||
344 | if (itp->rate > 3) | ||
345 | itp->rate += 2; | ||
346 | |||
347 | pr_debug("[ITP] TX start: band = %d, ch = %d, rate = %d, preamble = %d, number = %d, data_mode = %d, interval = %d, power = %d, data_len = %d\n", | ||
348 | itp->band, itp->ch, itp->rate, itp->preamble, | ||
349 | itp->number, itp->data_mode, itp->interval_us, | ||
350 | itp->power, itp->data_len); | ||
351 | |||
352 | len = itp->hdr_len + itp->data_len; | ||
353 | |||
354 | itp->data = kmalloc(len, GFP_KERNEL); | ||
355 | tx = (struct wsm_tx *)itp->data; | ||
356 | tx->hdr.len = itp->data_len + itp->hdr_len; | ||
357 | tx->hdr.id = __cpu_to_le16(0x0004 | 1 << 6); | ||
358 | tx->max_tx_rate = itp->rate; | ||
359 | tx->queue_id = 3; | ||
360 | tx->more = 0; | ||
361 | tx->flags = 0xc; | ||
362 | tx->packet_id = 0x55ff55; | ||
363 | tx->reserved = 0; | ||
364 | tx->expire_time = 1; | ||
365 | |||
366 | if (itp->preamble == ITP_PREAMBLE_GREENFIELD) | ||
367 | tx->ht_tx_parameters = WSM_HT_TX_GREENFIELD; | ||
368 | else if (itp->preamble == ITP_PREAMBLE_MIXED) | ||
369 | tx->ht_tx_parameters = WSM_HT_TX_MIXED; | ||
370 | |||
371 | hdr = (struct ieee80211_hdr_3addr *)&itp->data[sizeof(struct wsm_tx)]; | ||
372 | memset(hdr, 0, sizeof(*hdr)); | ||
373 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS); | ||
374 | memcpy(hdr->addr1, da_addr, ETH_ALEN); | ||
375 | memcpy(hdr->addr2, priv->vif->addr, ETH_ALEN); | ||
376 | memcpy(hdr->addr3, da_addr, ETH_ALEN); | ||
377 | |||
378 | cw1200_itp_fill_pattern(&itp->data[itp->hdr_len], | ||
379 | itp->data_len, itp->data_mode); | ||
380 | |||
381 | cw1200_update_listening(priv, false); | ||
382 | priv->channel = &priv->hw->wiphy->bands[itp->band]->channels[itp->ch]; | ||
383 | WARN_ON(wsm_set_output_power(priv, itp->power)); | ||
384 | if (itp->preamble == ITP_PREAMBLE_SHORT || | ||
385 | itp->preamble == ITP_PREAMBLE_LONG) | ||
386 | WARN_ON(wsm_set_association_mode(priv, | ||
387 | &assoc_mode)); | ||
388 | wsm_set_bssid_filtering(priv, false); | ||
389 | cw1200_update_listening(priv, true); | ||
390 | |||
391 | spin_lock_bh(&itp->tx_lock); | ||
392 | atomic_set(&itp->test_mode, TEST_MODE_TX_TEST); | ||
393 | atomic_set(&itp->awaiting_confirm, 0); | ||
394 | atomic_set(&itp->stop_tx, 0); | ||
395 | atomic_set(&priv->bh_tx, 1); | ||
396 | ktime_get_ts(&itp->last_sent); | ||
397 | wake_up(&priv->bh_wq); | ||
398 | spin_unlock_bh(&itp->tx_lock); | ||
399 | } | ||
400 | |||
401 | void __cw1200_itp_tx_stop(struct cw1200_common *priv) | ||
402 | { | ||
403 | struct cw1200_itp *itp = &priv->debug->itp; | ||
404 | spin_lock_bh(&itp->tx_lock); | ||
405 | kfree(itp->data); | ||
406 | itp->data = NULL; | ||
407 | atomic_set(&itp->test_mode, TEST_MODE_NO_TEST); | ||
408 | spin_unlock_bh(&itp->tx_lock); | ||
409 | } | ||
410 | |||
411 | static void cw1200_itp_tx_stop(struct cw1200_common *priv) | ||
412 | { | ||
413 | struct cw1200_itp *itp = &priv->debug->itp; | ||
414 | pr_debug("[ITP] TX stop\n"); | ||
415 | atomic_set(&itp->stop_tx, 1); | ||
416 | flush_workqueue(priv->workqueue); | ||
417 | |||
418 | /* time for FW to confirm all tx requests */ | ||
419 | msleep(500); | ||
420 | |||
421 | __cw1200_itp_tx_stop(priv); | ||
422 | } | ||
423 | |||
424 | static int cw1200_print_fw_version(struct cw1200_common *priv, | ||
425 | u8 *buf, size_t len) | ||
426 | { | ||
427 | return snprintf(buf, len, "%s %d.%d", | ||
428 | cw1200_fw_types[priv->wsm_caps.fw_type], | ||
429 | priv->wsm_caps.fw_ver, | ||
430 | priv->wsm_caps.fw_build); | ||
431 | } | ||
432 | |||
433 | static void cw1200_itp_get_version(struct cw1200_common *priv, | ||
434 | enum cw1200_itp_version_type type) | ||
435 | { | ||
436 | struct cw1200_itp *itp = &priv->debug->itp; | ||
437 | struct sk_buff *skb; | ||
438 | char buf[ITP_BUF_SIZE]; | ||
439 | size_t size = 0; | ||
440 | int len; | ||
441 | pr_debug("[ITP] print %s version\n", | ||
442 | type == ITP_CHIP_ID ? "chip" : "firmware"); | ||
443 | |||
444 | len = snprintf(buf, ITP_BUF_SIZE, "2,"); | ||
445 | if (len <= 0) { | ||
446 | cw1200_itp_err(priv, -EINVAL, 40); | ||
447 | return; | ||
448 | } | ||
449 | size += len; | ||
450 | |||
451 | switch (type) { | ||
452 | case ITP_CHIP_ID: | ||
453 | len = cw1200_print_fw_version(priv, buf+size, | ||
454 | ITP_BUF_SIZE - size); | ||
455 | |||
456 | if (len <= 0) { | ||
457 | cw1200_itp_err(priv, -EINVAL, 41); | ||
458 | return; | ||
459 | } | ||
460 | size += len; | ||
461 | break; | ||
462 | case ITP_FW_VER: | ||
463 | len = snprintf(buf+size, ITP_BUF_SIZE - size, | ||
464 | "%d.%d", priv->wsm_caps.hw_id, | ||
465 | priv->wsm_caps.hw_subid); | ||
466 | if (len <= 0) { | ||
467 | cw1200_itp_err(priv, -EINVAL, 42); | ||
468 | return; | ||
469 | } | ||
470 | size += len; | ||
471 | break; | ||
472 | default: | ||
473 | cw1200_itp_err(priv, -EINVAL, 43); | ||
474 | break; | ||
475 | } | ||
476 | |||
477 | len = snprintf(buf+size, ITP_BUF_SIZE-size, "\n"); | ||
478 | if (len <= 0) { | ||
479 | cw1200_itp_err(priv, -EINVAL, 44); | ||
480 | return; | ||
481 | } | ||
482 | size += len; | ||
483 | |||
484 | skb = dev_alloc_skb(size); | ||
485 | if (!skb) { | ||
486 | cw1200_itp_err(priv, -ENOMEM, 45); | ||
487 | return; | ||
488 | } | ||
489 | |||
490 | skb_trim(skb, 0); | ||
491 | skb_put(skb, size); | ||
492 | |||
493 | memcpy(skb->data, buf, size); | ||
494 | skb_queue_tail(&itp->log_queue, skb); | ||
495 | wake_up(&itp->read_wait); | ||
496 | } | ||
497 | |||
498 | int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data, | ||
499 | size_t *tx_len, int *burst) | ||
500 | { | ||
501 | struct cw1200_itp *itp; | ||
502 | struct timespec now; | ||
503 | int time_left_us; | ||
504 | |||
505 | if (!priv->debug) | ||
506 | return 0; | ||
507 | |||
508 | itp = &priv->debug->itp; | ||
509 | |||
510 | if (!itp) | ||
511 | return 0; | ||
512 | |||
513 | spin_lock_bh(&itp->tx_lock); | ||
514 | if (atomic_read(&itp->test_mode) != TEST_MODE_TX_TEST) | ||
515 | goto out; | ||
516 | |||
517 | if (atomic_read(&itp->stop_tx)) | ||
518 | goto out; | ||
519 | |||
520 | if (itp->number == 0) { | ||
521 | atomic_set(&itp->stop_tx, 1); | ||
522 | queue_delayed_work(priv->workqueue, &itp->tx_finish, HZ/10); | ||
523 | goto out; | ||
524 | } | ||
525 | |||
526 | if (!itp->data) | ||
527 | goto out; | ||
528 | |||
529 | if (priv->hw_bufs_used >= 2) { | ||
530 | if (!atomic_read(&priv->bh_rx)) | ||
531 | atomic_set(&priv->bh_rx, 1); | ||
532 | atomic_set(&priv->bh_tx, 1); | ||
533 | goto out; | ||
534 | } | ||
535 | |||
536 | ktime_get_ts(&now); | ||
537 | time_left_us = (itp->last_sent.tv_sec - now.tv_sec)*1000000 + | ||
538 | (itp->last_sent.tv_nsec - now.tv_nsec)/1000 + | ||
539 | itp->interval_us; | ||
540 | |||
541 | if (time_left_us > ITP_TIME_THRES_US) { | ||
542 | queue_delayed_work(priv->workqueue, &itp->tx_work, | ||
543 | ITP_US_TO_MS(time_left_us)*HZ/1000); | ||
544 | goto out; | ||
545 | } | ||
546 | |||
547 | if (time_left_us > 50) | ||
548 | udelay(time_left_us); | ||
549 | |||
550 | if (itp->number > 0) | ||
551 | itp->number--; | ||
552 | |||
553 | *data = itp->data; | ||
554 | *tx_len = itp->data_len + itp->hdr_len; | ||
555 | |||
556 | if (itp->data_mode == ITP_DATA_RANDOM) | ||
557 | cw1200_itp_fill_pattern(&itp->data[itp->hdr_len], | ||
558 | itp->data_len, itp->data_mode); | ||
559 | *burst = 2; | ||
560 | atomic_set(&priv->bh_tx, 1); | ||
561 | ktime_get_ts(&itp->last_sent); | ||
562 | atomic_add(1, &itp->awaiting_confirm); | ||
563 | spin_unlock_bh(&itp->tx_lock); | ||
564 | return 1; | ||
565 | |||
566 | out: | ||
567 | spin_unlock_bh(&itp->tx_lock); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb) | ||
572 | { | ||
573 | struct cw1200_itp *itp = &priv->debug->itp; | ||
574 | struct ieee80211_rx_status *rx = IEEE80211_SKB_RXCB(skb); | ||
575 | int signal; | ||
576 | |||
577 | if (atomic_read(&itp->test_mode) != TEST_MODE_RX_TEST) | ||
578 | return cw1200_is_itp(priv); | ||
579 | if (rx->freq != priv->channel->center_freq) | ||
580 | return true; | ||
581 | |||
582 | signal = rx->signal; | ||
583 | itp->rx_cnt++; | ||
584 | itp->rx_rssi += signal; | ||
585 | if (itp->rx_rssi_min > rx->signal) | ||
586 | itp->rx_rssi_min = rx->signal; | ||
587 | if (itp->rx_rssi_max < rx->signal) | ||
588 | itp->rx_rssi_max = rx->signal; | ||
589 | |||
590 | return true; | ||
591 | } | ||
592 | |||
593 | void cw1200_itp_wake_up_tx(struct cw1200_common *priv) | ||
594 | { | ||
595 | wake_up(&priv->debug->itp.write_wait); | ||
596 | } | ||
597 | |||
598 | bool cw1200_itp_tx_running(struct cw1200_common *priv) | ||
599 | { | ||
600 | if (atomic_read(&priv->debug->itp.awaiting_confirm) || | ||
601 | atomic_read(&priv->debug->itp.test_mode) == | ||
602 | TEST_MODE_TX_TEST) { | ||
603 | atomic_sub(1, &priv->debug->itp.awaiting_confirm); | ||
604 | return true; | ||
605 | } | ||
606 | return false; | ||
607 | } | ||
608 | |||
609 | static void cw1200_itp_handle(struct cw1200_common *priv, | ||
610 | struct sk_buff *skb) | ||
611 | { | ||
612 | struct cw1200_itp *itp = &priv->debug->itp; | ||
613 | const struct wiphy *wiphy = priv->hw->wiphy; | ||
614 | int cmd; | ||
615 | int ret; | ||
616 | |||
617 | pr_debug("[ITP] <<< %s", skb->data); | ||
618 | if (sscanf(skb->data, "%d", &cmd) != 1) { | ||
619 | cw1200_itp_err(priv, -EINVAL, 1); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | switch (cmd) { | ||
624 | case 1: /* RX test */ | ||
625 | if (atomic_read(&itp->test_mode)) { | ||
626 | cw1200_itp_err(priv, -EBUSY, 0); | ||
627 | return; | ||
628 | } | ||
629 | ret = sscanf(skb->data, "%d,%d,%d", | ||
630 | &cmd, &itp->band, &itp->ch); | ||
631 | if (ret != 3) { | ||
632 | cw1200_itp_err(priv, -EINVAL, ret + 1); | ||
633 | return; | ||
634 | } | ||
635 | if (itp->band >= 2) { | ||
636 | cw1200_itp_err(priv, -EINVAL, 2); | ||
637 | } else if (!wiphy->bands[itp->band]) { | ||
638 | cw1200_itp_err(priv, -EINVAL, 2); | ||
639 | } else if (itp->ch >= wiphy->bands[itp->band]->n_channels) { | ||
640 | cw1200_itp_err(priv, -EINVAL, 3); | ||
641 | } else { | ||
642 | cw1200_itp_rx_stats(priv); | ||
643 | cw1200_itp_rx_start(priv); | ||
644 | } | ||
645 | break; | ||
646 | case 2: /* RX stat */ | ||
647 | cw1200_itp_rx_stats(priv); | ||
648 | break; | ||
649 | case 3: /* RX/TX stop */ | ||
650 | if (atomic_read(&itp->test_mode) == TEST_MODE_RX_TEST) { | ||
651 | cw1200_itp_rx_stats(priv); | ||
652 | cw1200_itp_rx_stop(priv); | ||
653 | } else if (atomic_read(&itp->test_mode) == TEST_MODE_TX_TEST) { | ||
654 | cw1200_itp_tx_stop(priv); | ||
655 | } else { | ||
656 | cw1200_itp_err(priv, -EBUSY, 0); | ||
657 | } | ||
658 | break; | ||
659 | case 4: /* TX start */ | ||
660 | if (atomic_read(&itp->test_mode) != TEST_MODE_NO_TEST) { | ||
661 | cw1200_itp_err(priv, -EBUSY, 0); | ||
662 | return; | ||
663 | } | ||
664 | ret = sscanf(skb->data, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", | ||
665 | &cmd, &itp->band, &itp->ch, &itp->rate, | ||
666 | &itp->preamble, &itp->number, &itp->data_mode, | ||
667 | &itp->interval_us, &itp->power, &itp->data_len); | ||
668 | if (ret != 10) { | ||
669 | cw1200_itp_err(priv, -EINVAL, ret + 1); | ||
670 | return; | ||
671 | } | ||
672 | if (itp->band >= 2) { | ||
673 | cw1200_itp_err(priv, -EINVAL, 2); | ||
674 | } else if (!wiphy->bands[itp->band]) { | ||
675 | cw1200_itp_err(priv, -EINVAL, 2); | ||
676 | } else if (itp->ch >= wiphy->bands[itp->band]->n_channels) { | ||
677 | cw1200_itp_err(priv, -EINVAL, 3); | ||
678 | } else if (itp->rate >= 20) { | ||
679 | cw1200_itp_err(priv, -EINVAL, 4); | ||
680 | } else if (itp->preamble >= ITP_PREAMBLE_MAX) { | ||
681 | cw1200_itp_err(priv, -EINVAL, 5); | ||
682 | } else if (itp->data_mode >= ITP_DATA_MAX_MODE) { | ||
683 | cw1200_itp_err(priv, -EINVAL, 7); | ||
684 | } else if (itp->data_len < ITP_MIN_DATA_SIZE || | ||
685 | itp->data_len > (priv->wsm_caps.input_buffer_size - itp->hdr_len)) { | ||
686 | cw1200_itp_err(priv, -EINVAL, 8); | ||
687 | } else { | ||
688 | cw1200_itp_tx_start(priv); | ||
689 | } | ||
690 | break; | ||
691 | case 5: | ||
692 | cw1200_itp_get_version(priv, ITP_CHIP_ID); | ||
693 | break; | ||
694 | case 6: | ||
695 | cw1200_itp_get_version(priv, ITP_FW_VER); | ||
696 | break; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | static void cw1200_itp_err(struct cw1200_common *priv, | ||
701 | int err, int arg) | ||
702 | { | ||
703 | struct cw1200_itp *itp = &priv->debug->itp; | ||
704 | struct sk_buff *skb; | ||
705 | static char buf[255]; | ||
706 | int len; | ||
707 | |||
708 | len = snprintf(buf, sizeof(buf), "%d,%d\n", | ||
709 | err, arg); | ||
710 | if (len <= 0) | ||
711 | return; | ||
712 | |||
713 | skb = dev_alloc_skb(len); | ||
714 | if (!skb) | ||
715 | return; | ||
716 | |||
717 | skb_trim(skb, 0); | ||
718 | skb_put(skb, len); | ||
719 | |||
720 | memcpy(skb->data, buf, len); | ||
721 | skb_queue_tail(&itp->log_queue, skb); | ||
722 | wake_up(&itp->read_wait); | ||
723 | |||
724 | len = sprint_symbol(buf, | ||
725 | (unsigned long)__builtin_return_address(0)); | ||
726 | if (len <= 0) | ||
727 | return; | ||
728 | pr_debug("[ITP] error %d,%d from %s\n", | ||
729 | err, arg, buf); | ||
730 | } | ||
diff --git a/drivers/net/wireless/cw1200/itp.h b/drivers/net/wireless/cw1200/itp.h new file mode 100644 index 000000000000..1e9dfb7fcadc --- /dev/null +++ b/drivers/net/wireless/cw1200/itp.h | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * ITP code for ST-Ericsson CW1200 mac80211 driver | ||
3 | * | ||
4 | * Copyright (c) 2011, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_ITP_H_INCLUDED | ||
13 | #define CW1200_ITP_H_INCLUDED | ||
14 | |||
15 | struct cw200_common; | ||
16 | struct wsm_tx_confirm; | ||
17 | struct dentry; | ||
18 | |||
19 | #ifdef CONFIG_CW1200_ITP | ||
20 | |||
21 | /*extern*/ struct ieee80211_channel; | ||
22 | |||
23 | #define TEST_MODE_NO_TEST (0) | ||
24 | #define TEST_MODE_RX_TEST (1) | ||
25 | #define TEST_MODE_TX_TEST (2) | ||
26 | #define ITP_DEFAULT_DA_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} | ||
27 | #define ITP_MIN_DATA_SIZE 6 | ||
28 | #define ITP_MAX_DATA_SIZE 1600 | ||
29 | #define ITP_TIME_THRES_US 10000 | ||
30 | #define ITP_US_TO_MS(x) ((x)/1000) | ||
31 | #define ITP_MS_TO_US(x) ((x)*1000) | ||
32 | #define ITP_BUF_SIZE 255 | ||
33 | |||
34 | |||
35 | enum cw1200_itp_data_modes { | ||
36 | ITP_DATA_ZEROS, | ||
37 | ITP_DATA_ONES, | ||
38 | ITP_DATA_ZERONES, | ||
39 | ITP_DATA_RANDOM, | ||
40 | ITP_DATA_MAX_MODE, | ||
41 | }; | ||
42 | |||
43 | enum cw1200_itp_version_type { | ||
44 | ITP_CHIP_ID, | ||
45 | ITP_FW_VER, | ||
46 | }; | ||
47 | |||
48 | enum cw1200_itp_preamble_type { | ||
49 | ITP_PREAMBLE_LONG, | ||
50 | ITP_PREAMBLE_SHORT, | ||
51 | ITP_PREAMBLE_OFDM, | ||
52 | ITP_PREAMBLE_MIXED, | ||
53 | ITP_PREAMBLE_GREENFIELD, | ||
54 | ITP_PREAMBLE_MAX, | ||
55 | }; | ||
56 | |||
57 | |||
58 | struct cw1200_itp { | ||
59 | struct cw1200_common *priv; | ||
60 | atomic_t open_count; | ||
61 | atomic_t awaiting_confirm; | ||
62 | struct sk_buff_head log_queue; | ||
63 | wait_queue_head_t read_wait; | ||
64 | wait_queue_head_t write_wait; | ||
65 | wait_queue_head_t close_wait; | ||
66 | struct ieee80211_channel *saved_channel; | ||
67 | atomic_t stop_tx; | ||
68 | struct delayed_work tx_work; | ||
69 | struct delayed_work tx_finish; | ||
70 | spinlock_t tx_lock; | ||
71 | struct timespec last_sent; | ||
72 | atomic_t test_mode; | ||
73 | int rx_cnt; | ||
74 | long rx_rssi; | ||
75 | int rx_rssi_max; | ||
76 | int rx_rssi_min; | ||
77 | unsigned band; | ||
78 | unsigned ch; | ||
79 | unsigned rate; | ||
80 | unsigned preamble; | ||
81 | unsigned int number; | ||
82 | unsigned data_mode; | ||
83 | int interval_us; | ||
84 | int power; | ||
85 | u8 *data; | ||
86 | int hdr_len; | ||
87 | int data_len; | ||
88 | }; | ||
89 | |||
90 | int cw1200_itp_init(struct cw1200_common *priv); | ||
91 | void cw1200_itp_release(struct cw1200_common *priv); | ||
92 | |||
93 | bool cw1200_is_itp(struct cw1200_common *priv); | ||
94 | bool cw1200_itp_rxed(struct cw1200_common *priv, struct sk_buff *skb); | ||
95 | void cw1200_itp_wake_up_tx(struct cw1200_common *priv); | ||
96 | int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data, | ||
97 | size_t *tx_len, int *burst); | ||
98 | bool cw1200_itp_tx_running(struct cw1200_common *priv); | ||
99 | |||
100 | #else /* CONFIG_CW1200_ITP */ | ||
101 | |||
102 | static inline int cw1200_itp_init(struct cw1200_common *priv) | ||
103 | { | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static inline void cw1200_itp_release(struct cw1200_common *priv) | ||
108 | { | ||
109 | } | ||
110 | |||
111 | static inline bool cw1200_is_itp(struct cw1200_common *priv) | ||
112 | { | ||
113 | return false; | ||
114 | } | ||
115 | |||
116 | static inline bool cw1200_itp_rxed(struct cw1200_common *priv, | ||
117 | struct sk_buff *skb) | ||
118 | { | ||
119 | return false; | ||
120 | } | ||
121 | |||
122 | |||
123 | static inline void cw1200_itp_consume_txed(struct cw1200_common *priv) | ||
124 | { | ||
125 | } | ||
126 | |||
127 | static inline void cw1200_itp_wake_up_tx(struct cw1200_common *priv) | ||
128 | { | ||
129 | } | ||
130 | |||
131 | static inline int cw1200_itp_get_tx(struct cw1200_common *priv, u8 **data, | ||
132 | size_t *tx_len, int *burst) | ||
133 | { | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static inline bool cw1200_itp_tx_running(struct cw1200_common *priv) | ||
138 | { | ||
139 | return false; | ||
140 | } | ||
141 | |||
142 | #endif /* CONFIG_CW1200_ITP */ | ||
143 | |||
144 | #endif /* CW1200_ITP_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c new file mode 100644 index 000000000000..c934ec52d129 --- /dev/null +++ b/drivers/net/wireless/cw1200/main.c | |||
@@ -0,0 +1,633 @@ | |||
1 | /* | ||
2 | * mac80211 glue code for mac80211 ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on: | ||
8 | * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> | ||
9 | * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de> | ||
10 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
11 | * | ||
12 | * Based on: | ||
13 | * - the islsm (softmac prism54) driver, which is: | ||
14 | * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. | ||
15 | * - stlc45xx driver | ||
16 | * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License version 2 as | ||
20 | * published by the Free Software Foundation. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/vmalloc.h> | ||
28 | #include <linux/random.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <net/mac80211.h> | ||
31 | |||
32 | #include "cw1200.h" | ||
33 | #include "txrx.h" | ||
34 | #include "hwbus.h" | ||
35 | #include "fwio.h" | ||
36 | #include "hwio.h" | ||
37 | #include "bh.h" | ||
38 | #include "sta.h" | ||
39 | #include "scan.h" | ||
40 | #include "debug.h" | ||
41 | #include "pm.h" | ||
42 | |||
43 | MODULE_AUTHOR("Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>"); | ||
44 | MODULE_DESCRIPTION("Softmac ST-Ericsson CW1200 common code"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_ALIAS("cw1200_core"); | ||
47 | |||
48 | /* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */ | ||
49 | static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00}; | ||
50 | module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO); | ||
51 | MODULE_PARM_DESC(macaddr, "Override platform_data MAC address"); | ||
52 | |||
53 | static char *cw1200_sdd_path; | ||
54 | module_param(cw1200_sdd_path, charp, 0644); | ||
55 | MODULE_PARM_DESC(cw1200_sdd_path, "Override platform_data SDD file"); | ||
56 | static int cw1200_refclk; | ||
57 | module_param(cw1200_refclk, int, 0644); | ||
58 | MODULE_PARM_DESC(cw1200_refclk, "Override platform_data reference clock"); | ||
59 | |||
60 | int cw1200_power_mode = wsm_power_mode_quiescent; | ||
61 | module_param(cw1200_power_mode, int, 0644); | ||
62 | MODULE_PARM_DESC(cw1200_power_mode, "WSM power mode. 0 == active, 1 == doze, 2 == quiescent (default)"); | ||
63 | |||
64 | #ifdef CONFIG_CW1200_ETF | ||
65 | int etf_mode; | ||
66 | module_param(etf_mode, int, 0644); | ||
67 | MODULE_PARM_DESC(etf_mode, "Enable EngineeringTestingFramework operation"); | ||
68 | #endif | ||
69 | |||
70 | #define RATETAB_ENT(_rate, _rateid, _flags) \ | ||
71 | { \ | ||
72 | .bitrate = (_rate), \ | ||
73 | .hw_value = (_rateid), \ | ||
74 | .flags = (_flags), \ | ||
75 | } | ||
76 | |||
77 | static struct ieee80211_rate cw1200_rates[] = { | ||
78 | RATETAB_ENT(10, 0, 0), | ||
79 | RATETAB_ENT(20, 1, 0), | ||
80 | RATETAB_ENT(55, 2, 0), | ||
81 | RATETAB_ENT(110, 3, 0), | ||
82 | RATETAB_ENT(60, 6, 0), | ||
83 | RATETAB_ENT(90, 7, 0), | ||
84 | RATETAB_ENT(120, 8, 0), | ||
85 | RATETAB_ENT(180, 9, 0), | ||
86 | RATETAB_ENT(240, 10, 0), | ||
87 | RATETAB_ENT(360, 11, 0), | ||
88 | RATETAB_ENT(480, 12, 0), | ||
89 | RATETAB_ENT(540, 13, 0), | ||
90 | }; | ||
91 | |||
92 | static struct ieee80211_rate cw1200_mcs_rates[] = { | ||
93 | RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), | ||
94 | RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), | ||
95 | RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), | ||
96 | RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), | ||
97 | RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), | ||
98 | RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), | ||
99 | RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), | ||
100 | RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), | ||
101 | }; | ||
102 | |||
103 | #define cw1200_a_rates (cw1200_rates + 4) | ||
104 | #define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4) | ||
105 | #define cw1200_g_rates (cw1200_rates + 0) | ||
106 | #define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates)) | ||
107 | #define cw1200_n_rates (cw1200_mcs_rates) | ||
108 | #define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates)) | ||
109 | |||
110 | |||
111 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
112 | .band = IEEE80211_BAND_2GHZ, \ | ||
113 | .center_freq = (_freq), \ | ||
114 | .hw_value = (_channel), \ | ||
115 | .flags = (_flags), \ | ||
116 | .max_antenna_gain = 0, \ | ||
117 | .max_power = 30, \ | ||
118 | } | ||
119 | |||
120 | #define CHAN5G(_channel, _flags) { \ | ||
121 | .band = IEEE80211_BAND_5GHZ, \ | ||
122 | .center_freq = 5000 + (5 * (_channel)), \ | ||
123 | .hw_value = (_channel), \ | ||
124 | .flags = (_flags), \ | ||
125 | .max_antenna_gain = 0, \ | ||
126 | .max_power = 30, \ | ||
127 | } | ||
128 | |||
129 | static struct ieee80211_channel cw1200_2ghz_chantable[] = { | ||
130 | CHAN2G(1, 2412, 0), | ||
131 | CHAN2G(2, 2417, 0), | ||
132 | CHAN2G(3, 2422, 0), | ||
133 | CHAN2G(4, 2427, 0), | ||
134 | CHAN2G(5, 2432, 0), | ||
135 | CHAN2G(6, 2437, 0), | ||
136 | CHAN2G(7, 2442, 0), | ||
137 | CHAN2G(8, 2447, 0), | ||
138 | CHAN2G(9, 2452, 0), | ||
139 | CHAN2G(10, 2457, 0), | ||
140 | CHAN2G(11, 2462, 0), | ||
141 | CHAN2G(12, 2467, 0), | ||
142 | CHAN2G(13, 2472, 0), | ||
143 | CHAN2G(14, 2484, 0), | ||
144 | }; | ||
145 | |||
146 | static struct ieee80211_channel cw1200_5ghz_chantable[] = { | ||
147 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
148 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
149 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
150 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
151 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
152 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
153 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
154 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
155 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
156 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
157 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
158 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
159 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
160 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
161 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
162 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
163 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
164 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
165 | CHAN5G(216, 0), | ||
166 | }; | ||
167 | |||
168 | static struct ieee80211_supported_band cw1200_band_2ghz = { | ||
169 | .channels = cw1200_2ghz_chantable, | ||
170 | .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable), | ||
171 | .bitrates = cw1200_g_rates, | ||
172 | .n_bitrates = cw1200_g_rates_size, | ||
173 | .ht_cap = { | ||
174 | .cap = IEEE80211_HT_CAP_GRN_FLD | | ||
175 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | | ||
176 | IEEE80211_HT_CAP_MAX_AMSDU, | ||
177 | .ht_supported = 1, | ||
178 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, | ||
179 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, | ||
180 | .mcs = { | ||
181 | .rx_mask[0] = 0xFF, | ||
182 | .rx_highest = __cpu_to_le16(0x41), | ||
183 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
184 | }, | ||
185 | }, | ||
186 | }; | ||
187 | |||
188 | static struct ieee80211_supported_band cw1200_band_5ghz = { | ||
189 | .channels = cw1200_5ghz_chantable, | ||
190 | .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable), | ||
191 | .bitrates = cw1200_a_rates, | ||
192 | .n_bitrates = cw1200_a_rates_size, | ||
193 | .ht_cap = { | ||
194 | .cap = IEEE80211_HT_CAP_GRN_FLD | | ||
195 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | | ||
196 | IEEE80211_HT_CAP_MAX_AMSDU, | ||
197 | .ht_supported = 1, | ||
198 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, | ||
199 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, | ||
200 | .mcs = { | ||
201 | .rx_mask[0] = 0xFF, | ||
202 | .rx_highest = __cpu_to_le16(0x41), | ||
203 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
204 | }, | ||
205 | }, | ||
206 | }; | ||
207 | |||
208 | static const unsigned long cw1200_ttl[] = { | ||
209 | 1 * HZ, /* VO */ | ||
210 | 2 * HZ, /* VI */ | ||
211 | 5 * HZ, /* BE */ | ||
212 | 10 * HZ /* BK */ | ||
213 | }; | ||
214 | |||
215 | static const struct ieee80211_ops cw1200_ops = { | ||
216 | .start = cw1200_start, | ||
217 | .stop = cw1200_stop, | ||
218 | .add_interface = cw1200_add_interface, | ||
219 | .remove_interface = cw1200_remove_interface, | ||
220 | .change_interface = cw1200_change_interface, | ||
221 | .tx = cw1200_tx, | ||
222 | .hw_scan = cw1200_hw_scan, | ||
223 | .set_tim = cw1200_set_tim, | ||
224 | .sta_notify = cw1200_sta_notify, | ||
225 | .sta_add = cw1200_sta_add, | ||
226 | .sta_remove = cw1200_sta_remove, | ||
227 | .set_key = cw1200_set_key, | ||
228 | .set_rts_threshold = cw1200_set_rts_threshold, | ||
229 | .config = cw1200_config, | ||
230 | .bss_info_changed = cw1200_bss_info_changed, | ||
231 | .prepare_multicast = cw1200_prepare_multicast, | ||
232 | .configure_filter = cw1200_configure_filter, | ||
233 | .conf_tx = cw1200_conf_tx, | ||
234 | .get_stats = cw1200_get_stats, | ||
235 | .ampdu_action = cw1200_ampdu_action, | ||
236 | .flush = cw1200_flush, | ||
237 | #ifdef CONFIG_PM | ||
238 | .suspend = cw1200_wow_suspend, | ||
239 | .resume = cw1200_wow_resume, | ||
240 | #endif | ||
241 | /* Intentionally not offloaded: */ | ||
242 | /*.channel_switch = cw1200_channel_switch, */ | ||
243 | /*.remain_on_channel = cw1200_remain_on_channel, */ | ||
244 | /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */ | ||
245 | }; | ||
246 | |||
247 | int cw1200_ba_rx_tids = -1; | ||
248 | int cw1200_ba_tx_tids = -1; | ||
249 | module_param(cw1200_ba_rx_tids, int, 0644); | ||
250 | module_param(cw1200_ba_tx_tids, int, 0644); | ||
251 | MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs"); | ||
252 | MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs"); | ||
253 | |||
254 | #ifdef CONFIG_PM | ||
255 | static const struct wiphy_wowlan_support cw1200_wowlan_support = { | ||
256 | /* Support only for limited wowlan functionalities */ | ||
257 | .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT, | ||
258 | }; | ||
259 | #endif | ||
260 | |||
261 | |||
262 | static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, | ||
263 | const bool have_5ghz) | ||
264 | { | ||
265 | int i, band; | ||
266 | struct ieee80211_hw *hw; | ||
267 | struct cw1200_common *priv; | ||
268 | |||
269 | hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops); | ||
270 | if (!hw) | ||
271 | return NULL; | ||
272 | |||
273 | priv = hw->priv; | ||
274 | priv->hw = hw; | ||
275 | priv->hw_type = -1; | ||
276 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||
277 | priv->rates = cw1200_rates; /* TODO: fetch from FW */ | ||
278 | priv->mcs_rates = cw1200_n_rates; | ||
279 | if (cw1200_ba_rx_tids != -1) | ||
280 | priv->ba_rx_tid_mask = cw1200_ba_rx_tids; | ||
281 | else | ||
282 | priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */ | ||
283 | if (cw1200_ba_tx_tids != -1) | ||
284 | priv->ba_tx_tid_mask = cw1200_ba_tx_tids; | ||
285 | else | ||
286 | priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */ | ||
287 | |||
288 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
289 | IEEE80211_HW_SUPPORTS_PS | | ||
290 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||
291 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||
292 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
293 | IEEE80211_HW_CONNECTION_MONITOR | | ||
294 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
295 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | | ||
296 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC; | ||
297 | |||
298 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
299 | BIT(NL80211_IFTYPE_ADHOC) | | ||
300 | BIT(NL80211_IFTYPE_AP) | | ||
301 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
302 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
303 | BIT(NL80211_IFTYPE_P2P_GO); | ||
304 | |||
305 | #ifdef CONFIG_PM | ||
306 | hw->wiphy->wowlan = &cw1200_wowlan_support; | ||
307 | #endif | ||
308 | |||
309 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | ||
310 | |||
311 | hw->channel_change_time = 1000; /* TODO: find actual value */ | ||
312 | hw->queues = 4; | ||
313 | |||
314 | priv->rts_threshold = -1; | ||
315 | |||
316 | hw->max_rates = 8; | ||
317 | hw->max_rate_tries = 15; | ||
318 | hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + | ||
319 | 8; /* TKIP IV */ | ||
320 | |||
321 | hw->sta_data_size = sizeof(struct cw1200_sta_priv); | ||
322 | |||
323 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz; | ||
324 | if (have_5ghz) | ||
325 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz; | ||
326 | |||
327 | /* Channel params have to be cleared before registering wiphy again */ | ||
328 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
329 | struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; | ||
330 | if (!sband) | ||
331 | continue; | ||
332 | for (i = 0; i < sband->n_channels; i++) { | ||
333 | sband->channels[i].flags = 0; | ||
334 | sband->channels[i].max_antenna_gain = 0; | ||
335 | sband->channels[i].max_power = 30; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | hw->wiphy->max_scan_ssids = 2; | ||
340 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
341 | |||
342 | if (macaddr) | ||
343 | SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr); | ||
344 | else | ||
345 | SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template); | ||
346 | |||
347 | /* Fix up mac address if necessary */ | ||
348 | if (hw->wiphy->perm_addr[3] == 0 && | ||
349 | hw->wiphy->perm_addr[4] == 0 && | ||
350 | hw->wiphy->perm_addr[5] == 0) { | ||
351 | get_random_bytes(&hw->wiphy->perm_addr[3], 3); | ||
352 | } | ||
353 | |||
354 | mutex_init(&priv->wsm_cmd_mux); | ||
355 | mutex_init(&priv->conf_mutex); | ||
356 | priv->workqueue = create_singlethread_workqueue("cw1200_wq"); | ||
357 | sema_init(&priv->scan.lock, 1); | ||
358 | INIT_WORK(&priv->scan.work, cw1200_scan_work); | ||
359 | INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); | ||
360 | INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); | ||
361 | INIT_DELAYED_WORK(&priv->clear_recent_scan_work, | ||
362 | cw1200_clear_recent_scan_work); | ||
363 | INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); | ||
364 | INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); | ||
365 | INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work); | ||
366 | INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); | ||
367 | INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); | ||
368 | spin_lock_init(&priv->event_queue_lock); | ||
369 | INIT_LIST_HEAD(&priv->event_queue); | ||
370 | INIT_WORK(&priv->event_handler, cw1200_event_handler); | ||
371 | INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); | ||
372 | INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work); | ||
373 | spin_lock_init(&priv->bss_loss_lock); | ||
374 | spin_lock_init(&priv->ps_state_lock); | ||
375 | INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work); | ||
376 | INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); | ||
377 | INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); | ||
378 | INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); | ||
379 | INIT_WORK(&priv->link_id_work, cw1200_link_id_work); | ||
380 | INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); | ||
381 | INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); | ||
382 | INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); | ||
383 | INIT_WORK(&priv->set_beacon_wakeup_period_work, | ||
384 | cw1200_set_beacon_wakeup_period_work); | ||
385 | init_timer(&priv->mcast_timeout); | ||
386 | priv->mcast_timeout.data = (unsigned long)priv; | ||
387 | priv->mcast_timeout.function = cw1200_mcast_timeout; | ||
388 | |||
389 | if (cw1200_queue_stats_init(&priv->tx_queue_stats, | ||
390 | CW1200_LINK_ID_MAX, | ||
391 | cw1200_skb_dtor, | ||
392 | priv)) { | ||
393 | ieee80211_free_hw(hw); | ||
394 | return NULL; | ||
395 | } | ||
396 | |||
397 | for (i = 0; i < 4; ++i) { | ||
398 | if (cw1200_queue_init(&priv->tx_queue[i], | ||
399 | &priv->tx_queue_stats, i, 16, | ||
400 | cw1200_ttl[i])) { | ||
401 | for (; i > 0; i--) | ||
402 | cw1200_queue_deinit(&priv->tx_queue[i - 1]); | ||
403 | cw1200_queue_stats_deinit(&priv->tx_queue_stats); | ||
404 | ieee80211_free_hw(hw); | ||
405 | return NULL; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | init_waitqueue_head(&priv->channel_switch_done); | ||
410 | init_waitqueue_head(&priv->wsm_cmd_wq); | ||
411 | init_waitqueue_head(&priv->wsm_startup_done); | ||
412 | init_waitqueue_head(&priv->ps_mode_switch_done); | ||
413 | wsm_buf_init(&priv->wsm_cmd_buf); | ||
414 | spin_lock_init(&priv->wsm_cmd.lock); | ||
415 | priv->wsm_cmd.done = 1; | ||
416 | tx_policy_init(priv); | ||
417 | |||
418 | return hw; | ||
419 | } | ||
420 | |||
421 | static int cw1200_register_common(struct ieee80211_hw *dev) | ||
422 | { | ||
423 | struct cw1200_common *priv = dev->priv; | ||
424 | int err; | ||
425 | |||
426 | #ifdef CONFIG_CW1200_ETF | ||
427 | if (etf_mode) | ||
428 | goto done; | ||
429 | #endif | ||
430 | |||
431 | #ifdef CONFIG_PM | ||
432 | err = cw1200_pm_init(&priv->pm_state, priv); | ||
433 | if (err) { | ||
434 | pr_err("Cannot init PM. (%d).\n", | ||
435 | err); | ||
436 | return err; | ||
437 | } | ||
438 | #endif | ||
439 | |||
440 | err = ieee80211_register_hw(dev); | ||
441 | if (err) { | ||
442 | pr_err("Cannot register device (%d).\n", | ||
443 | err); | ||
444 | #ifdef CONFIG_PM | ||
445 | cw1200_pm_deinit(&priv->pm_state); | ||
446 | #endif | ||
447 | return err; | ||
448 | } | ||
449 | |||
450 | #ifdef CONFIG_CW1200_ETF | ||
451 | done: | ||
452 | #endif | ||
453 | cw1200_debug_init(priv); | ||
454 | |||
455 | pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy)); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void cw1200_free_common(struct ieee80211_hw *dev) | ||
460 | { | ||
461 | ieee80211_free_hw(dev); | ||
462 | } | ||
463 | |||
464 | static void cw1200_unregister_common(struct ieee80211_hw *dev) | ||
465 | { | ||
466 | struct cw1200_common *priv = dev->priv; | ||
467 | int i; | ||
468 | |||
469 | #ifdef CONFIG_CW1200_ETF | ||
470 | if (!etf_mode) { | ||
471 | #endif | ||
472 | ieee80211_unregister_hw(dev); | ||
473 | #ifdef CONFIG_CW1200_ETF | ||
474 | } | ||
475 | #endif | ||
476 | |||
477 | del_timer_sync(&priv->mcast_timeout); | ||
478 | cw1200_unregister_bh(priv); | ||
479 | |||
480 | cw1200_debug_release(priv); | ||
481 | |||
482 | mutex_destroy(&priv->conf_mutex); | ||
483 | |||
484 | wsm_buf_deinit(&priv->wsm_cmd_buf); | ||
485 | |||
486 | destroy_workqueue(priv->workqueue); | ||
487 | priv->workqueue = NULL; | ||
488 | |||
489 | if (priv->sdd) { | ||
490 | release_firmware(priv->sdd); | ||
491 | priv->sdd = NULL; | ||
492 | } | ||
493 | |||
494 | for (i = 0; i < 4; ++i) | ||
495 | cw1200_queue_deinit(&priv->tx_queue[i]); | ||
496 | |||
497 | cw1200_queue_stats_deinit(&priv->tx_queue_stats); | ||
498 | #ifdef CONFIG_PM | ||
499 | cw1200_pm_deinit(&priv->pm_state); | ||
500 | #endif | ||
501 | } | ||
502 | |||
503 | /* Clock is in KHz */ | ||
504 | u32 cw1200_dpll_from_clk(u16 clk_khz) | ||
505 | { | ||
506 | switch (clk_khz) { | ||
507 | case 0x32C8: /* 13000 KHz */ | ||
508 | return 0x1D89D241; | ||
509 | case 0x3E80: /* 16000 KHz */ | ||
510 | return 0x000001E1; | ||
511 | case 0x41A0: /* 16800 KHz */ | ||
512 | return 0x124931C1; | ||
513 | case 0x4B00: /* 19200 KHz */ | ||
514 | return 0x00000191; | ||
515 | case 0x5DC0: /* 24000 KHz */ | ||
516 | return 0x00000141; | ||
517 | case 0x6590: /* 26000 KHz */ | ||
518 | return 0x0EC4F121; | ||
519 | case 0x8340: /* 33600 KHz */ | ||
520 | return 0x092490E1; | ||
521 | case 0x9600: /* 38400 KHz */ | ||
522 | return 0x100010C1; | ||
523 | case 0x9C40: /* 40000 KHz */ | ||
524 | return 0x000000C1; | ||
525 | case 0xBB80: /* 48000 KHz */ | ||
526 | return 0x000000A1; | ||
527 | case 0xCB20: /* 52000 KHz */ | ||
528 | return 0x07627091; | ||
529 | default: | ||
530 | pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n", | ||
531 | clk_khz); | ||
532 | return 0x0EC4F121; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, | ||
537 | struct hwbus_priv *hwbus, | ||
538 | struct device *pdev, | ||
539 | struct cw1200_common **core, | ||
540 | int ref_clk, const u8 *macaddr, | ||
541 | const char *sdd_path, bool have_5ghz) | ||
542 | { | ||
543 | int err = -EINVAL; | ||
544 | struct ieee80211_hw *dev; | ||
545 | struct cw1200_common *priv; | ||
546 | struct wsm_operational_mode mode = { | ||
547 | .power_mode = cw1200_power_mode, | ||
548 | .disable_more_flag_usage = true, | ||
549 | }; | ||
550 | |||
551 | dev = cw1200_init_common(macaddr, have_5ghz); | ||
552 | if (!dev) | ||
553 | goto err; | ||
554 | |||
555 | priv = dev->priv; | ||
556 | priv->hw_refclk = ref_clk; | ||
557 | if (cw1200_refclk) | ||
558 | priv->hw_refclk = cw1200_refclk; | ||
559 | |||
560 | priv->sdd_path = (char *)sdd_path; | ||
561 | if (cw1200_sdd_path) | ||
562 | priv->sdd_path = cw1200_sdd_path; | ||
563 | |||
564 | priv->hwbus_ops = hwbus_ops; | ||
565 | priv->hwbus_priv = hwbus; | ||
566 | priv->pdev = pdev; | ||
567 | SET_IEEE80211_DEV(priv->hw, pdev); | ||
568 | |||
569 | /* Pass struct cw1200_common back up */ | ||
570 | *core = priv; | ||
571 | |||
572 | err = cw1200_register_bh(priv); | ||
573 | if (err) | ||
574 | goto err1; | ||
575 | |||
576 | #ifdef CONFIG_CW1200_ETF | ||
577 | if (etf_mode) | ||
578 | goto skip_fw; | ||
579 | #endif | ||
580 | |||
581 | err = cw1200_load_firmware(priv); | ||
582 | if (err) | ||
583 | goto err2; | ||
584 | |||
585 | if (wait_event_interruptible_timeout(priv->wsm_startup_done, | ||
586 | priv->firmware_ready, | ||
587 | 3*HZ) <= 0) { | ||
588 | /* TODO: Need to find how to reset device | ||
589 | in QUEUE mode properly. | ||
590 | */ | ||
591 | pr_err("Timeout waiting on device startup\n"); | ||
592 | err = -ETIMEDOUT; | ||
593 | goto err2; | ||
594 | } | ||
595 | |||
596 | /* Set low-power mode. */ | ||
597 | wsm_set_operational_mode(priv, &mode); | ||
598 | |||
599 | /* Enable multi-TX confirmation */ | ||
600 | wsm_use_multi_tx_conf(priv, true); | ||
601 | |||
602 | #ifdef CONFIG_CW1200_ETF | ||
603 | skip_fw: | ||
604 | #endif | ||
605 | err = cw1200_register_common(dev); | ||
606 | if (err) | ||
607 | goto err2; | ||
608 | |||
609 | return err; | ||
610 | |||
611 | err2: | ||
612 | cw1200_unregister_bh(priv); | ||
613 | err1: | ||
614 | cw1200_free_common(dev); | ||
615 | err: | ||
616 | *core = NULL; | ||
617 | return err; | ||
618 | } | ||
619 | EXPORT_SYMBOL_GPL(cw1200_core_probe); | ||
620 | |||
621 | void cw1200_core_release(struct cw1200_common *self) | ||
622 | { | ||
623 | /* Disable device interrupts */ | ||
624 | self->hwbus_ops->lock(self->hwbus_priv); | ||
625 | __cw1200_irq_enable(self, 0); | ||
626 | self->hwbus_ops->unlock(self->hwbus_priv); | ||
627 | |||
628 | /* And then clean up */ | ||
629 | cw1200_unregister_common(self->hw); | ||
630 | cw1200_free_common(self->hw); | ||
631 | return; | ||
632 | } | ||
633 | EXPORT_SYMBOL_GPL(cw1200_core_release); | ||
diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c new file mode 100644 index 000000000000..b37abb9f0453 --- /dev/null +++ b/drivers/net/wireless/cw1200/pm.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * Mac80211 power management API for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2011, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/if_ether.h> | ||
14 | #include "cw1200.h" | ||
15 | #include "pm.h" | ||
16 | #include "sta.h" | ||
17 | #include "bh.h" | ||
18 | #include "hwbus.h" | ||
19 | |||
20 | #define CW1200_BEACON_SKIPPING_MULTIPLIER 3 | ||
21 | |||
22 | struct cw1200_udp_port_filter { | ||
23 | struct wsm_udp_port_filter_hdr hdr; | ||
24 | /* Up to 4 filters are allowed. */ | ||
25 | struct wsm_udp_port_filter filters[WSM_MAX_FILTER_ELEMENTS]; | ||
26 | } __packed; | ||
27 | |||
28 | struct cw1200_ether_type_filter { | ||
29 | struct wsm_ether_type_filter_hdr hdr; | ||
30 | /* Up to 4 filters are allowed. */ | ||
31 | struct wsm_ether_type_filter filters[WSM_MAX_FILTER_ELEMENTS]; | ||
32 | } __packed; | ||
33 | |||
34 | static struct cw1200_udp_port_filter cw1200_udp_port_filter_on = { | ||
35 | .hdr.num = 2, | ||
36 | .filters = { | ||
37 | [0] = { | ||
38 | .action = WSM_FILTER_ACTION_FILTER_OUT, | ||
39 | .type = WSM_FILTER_PORT_TYPE_DST, | ||
40 | .port = __cpu_to_le16(67), /* DHCP Bootps */ | ||
41 | }, | ||
42 | [1] = { | ||
43 | .action = WSM_FILTER_ACTION_FILTER_OUT, | ||
44 | .type = WSM_FILTER_PORT_TYPE_DST, | ||
45 | .port = __cpu_to_le16(68), /* DHCP Bootpc */ | ||
46 | }, | ||
47 | } | ||
48 | }; | ||
49 | |||
50 | static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off = { | ||
51 | .num = 0, | ||
52 | }; | ||
53 | |||
54 | #ifndef ETH_P_WAPI | ||
55 | #define ETH_P_WAPI 0x88B4 | ||
56 | #endif | ||
57 | |||
58 | static struct cw1200_ether_type_filter cw1200_ether_type_filter_on = { | ||
59 | .hdr.num = 4, | ||
60 | .filters = { | ||
61 | [0] = { | ||
62 | .action = WSM_FILTER_ACTION_FILTER_IN, | ||
63 | .type = __cpu_to_le16(ETH_P_IP), | ||
64 | }, | ||
65 | [1] = { | ||
66 | .action = WSM_FILTER_ACTION_FILTER_IN, | ||
67 | .type = __cpu_to_le16(ETH_P_PAE), | ||
68 | }, | ||
69 | [2] = { | ||
70 | .action = WSM_FILTER_ACTION_FILTER_IN, | ||
71 | .type = __cpu_to_le16(ETH_P_WAPI), | ||
72 | }, | ||
73 | [3] = { | ||
74 | .action = WSM_FILTER_ACTION_FILTER_IN, | ||
75 | .type = __cpu_to_le16(ETH_P_ARP), | ||
76 | }, | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off = { | ||
81 | .num = 0, | ||
82 | }; | ||
83 | |||
84 | /* private */ | ||
85 | struct cw1200_suspend_state { | ||
86 | unsigned long bss_loss_tmo; | ||
87 | unsigned long join_tmo; | ||
88 | unsigned long direct_probe; | ||
89 | unsigned long link_id_gc; | ||
90 | bool beacon_skipping; | ||
91 | u8 prev_ps_mode; | ||
92 | }; | ||
93 | |||
94 | static void cw1200_pm_stay_awake_tmo(unsigned long arg) | ||
95 | { | ||
96 | /* XXX what's the point of this ? */ | ||
97 | } | ||
98 | |||
99 | int cw1200_pm_init(struct cw1200_pm_state *pm, | ||
100 | struct cw1200_common *priv) | ||
101 | { | ||
102 | spin_lock_init(&pm->lock); | ||
103 | |||
104 | init_timer(&pm->stay_awake); | ||
105 | pm->stay_awake.data = (unsigned long)pm; | ||
106 | pm->stay_awake.function = cw1200_pm_stay_awake_tmo; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | void cw1200_pm_deinit(struct cw1200_pm_state *pm) | ||
112 | { | ||
113 | del_timer_sync(&pm->stay_awake); | ||
114 | } | ||
115 | |||
116 | void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, | ||
117 | unsigned long tmo) | ||
118 | { | ||
119 | long cur_tmo; | ||
120 | spin_lock_bh(&pm->lock); | ||
121 | cur_tmo = pm->stay_awake.expires - jiffies; | ||
122 | if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) | ||
123 | mod_timer(&pm->stay_awake, jiffies + tmo); | ||
124 | spin_unlock_bh(&pm->lock); | ||
125 | } | ||
126 | |||
127 | static long cw1200_suspend_work(struct delayed_work *work) | ||
128 | { | ||
129 | int ret = cancel_delayed_work(work); | ||
130 | long tmo; | ||
131 | if (ret > 0) { | ||
132 | /* Timer is pending */ | ||
133 | tmo = work->timer.expires - jiffies; | ||
134 | if (tmo < 0) | ||
135 | tmo = 0; | ||
136 | } else { | ||
137 | tmo = -1; | ||
138 | } | ||
139 | return tmo; | ||
140 | } | ||
141 | |||
142 | static int cw1200_resume_work(struct cw1200_common *priv, | ||
143 | struct delayed_work *work, | ||
144 | unsigned long tmo) | ||
145 | { | ||
146 | if ((long)tmo < 0) | ||
147 | return 1; | ||
148 | |||
149 | return queue_delayed_work(priv->workqueue, work, tmo); | ||
150 | } | ||
151 | |||
152 | int cw1200_can_suspend(struct cw1200_common *priv) | ||
153 | { | ||
154 | if (atomic_read(&priv->bh_rx)) { | ||
155 | wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n"); | ||
156 | return 0; | ||
157 | } | ||
158 | return 1; | ||
159 | } | ||
160 | EXPORT_SYMBOL_GPL(cw1200_can_suspend); | ||
161 | |||
162 | int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | ||
163 | { | ||
164 | struct cw1200_common *priv = hw->priv; | ||
165 | struct cw1200_pm_state *pm_state = &priv->pm_state; | ||
166 | struct cw1200_suspend_state *state; | ||
167 | int ret; | ||
168 | |||
169 | spin_lock_bh(&pm_state->lock); | ||
170 | ret = timer_pending(&pm_state->stay_awake); | ||
171 | spin_unlock_bh(&pm_state->lock); | ||
172 | if (ret) | ||
173 | return -EAGAIN; | ||
174 | |||
175 | /* Do not suspend when datapath is not idle */ | ||
176 | if (priv->tx_queue_stats.num_queued) | ||
177 | return -EBUSY; | ||
178 | |||
179 | /* Make sure there is no configuration requests in progress. */ | ||
180 | if (!mutex_trylock(&priv->conf_mutex)) | ||
181 | return -EBUSY; | ||
182 | |||
183 | /* Ensure pending operations are done. | ||
184 | * Note also that wow_suspend must return in ~2.5sec, before | ||
185 | * watchdog is triggered. | ||
186 | */ | ||
187 | if (priv->channel_switch_in_progress) | ||
188 | goto revert1; | ||
189 | |||
190 | /* Do not suspend when join is pending */ | ||
191 | if (priv->join_pending) | ||
192 | goto revert1; | ||
193 | |||
194 | /* Do not suspend when scanning */ | ||
195 | if (down_trylock(&priv->scan.lock)) | ||
196 | goto revert1; | ||
197 | |||
198 | /* Lock TX. */ | ||
199 | wsm_lock_tx_async(priv); | ||
200 | |||
201 | /* Wait to avoid possible race with bh code. | ||
202 | * But do not wait too long... | ||
203 | */ | ||
204 | if (wait_event_timeout(priv->bh_evt_wq, | ||
205 | !priv->hw_bufs_used, HZ / 10) <= 0) | ||
206 | goto revert2; | ||
207 | |||
208 | /* Set UDP filter */ | ||
209 | wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr); | ||
210 | |||
211 | /* Set ethernet frame type filter */ | ||
212 | wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr); | ||
213 | |||
214 | /* Allocate state */ | ||
215 | state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); | ||
216 | if (!state) | ||
217 | goto revert3; | ||
218 | |||
219 | /* Change to legacy PS while going to suspend */ | ||
220 | if (!priv->vif->p2p && | ||
221 | priv->join_status == CW1200_JOIN_STATUS_STA && | ||
222 | priv->powersave_mode.mode != WSM_PSM_PS) { | ||
223 | state->prev_ps_mode = priv->powersave_mode.mode; | ||
224 | priv->powersave_mode.mode = WSM_PSM_PS; | ||
225 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
226 | if (wait_event_interruptible_timeout(priv->ps_mode_switch_done, | ||
227 | !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) { | ||
228 | goto revert3; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* Store delayed work states. */ | ||
233 | state->bss_loss_tmo = | ||
234 | cw1200_suspend_work(&priv->bss_loss_work); | ||
235 | state->join_tmo = | ||
236 | cw1200_suspend_work(&priv->join_timeout); | ||
237 | state->direct_probe = | ||
238 | cw1200_suspend_work(&priv->scan.probe_work); | ||
239 | state->link_id_gc = | ||
240 | cw1200_suspend_work(&priv->link_id_gc_work); | ||
241 | |||
242 | cancel_delayed_work_sync(&priv->clear_recent_scan_work); | ||
243 | atomic_set(&priv->recent_scan, 0); | ||
244 | |||
245 | /* Enable beacon skipping */ | ||
246 | if (priv->join_status == CW1200_JOIN_STATUS_STA && | ||
247 | priv->join_dtim_period && | ||
248 | !priv->has_multicast_subscription) { | ||
249 | state->beacon_skipping = true; | ||
250 | wsm_set_beacon_wakeup_period(priv, | ||
251 | priv->join_dtim_period, | ||
252 | CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period); | ||
253 | } | ||
254 | |||
255 | /* Stop serving thread */ | ||
256 | if (cw1200_bh_suspend(priv)) | ||
257 | goto revert4; | ||
258 | |||
259 | ret = timer_pending(&priv->mcast_timeout); | ||
260 | if (ret) | ||
261 | goto revert5; | ||
262 | |||
263 | /* Store suspend state */ | ||
264 | pm_state->suspend_state = state; | ||
265 | |||
266 | /* Enable IRQ wake */ | ||
267 | ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true); | ||
268 | if (ret) { | ||
269 | wiphy_err(priv->hw->wiphy, | ||
270 | "PM request failed: %d. WoW is disabled.\n", ret); | ||
271 | cw1200_wow_resume(hw); | ||
272 | return -EBUSY; | ||
273 | } | ||
274 | |||
275 | /* Force resume if event is coming from the device. */ | ||
276 | if (atomic_read(&priv->bh_rx)) { | ||
277 | cw1200_wow_resume(hw); | ||
278 | return -EAGAIN; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | |||
283 | revert5: | ||
284 | WARN_ON(cw1200_bh_resume(priv)); | ||
285 | revert4: | ||
286 | cw1200_resume_work(priv, &priv->bss_loss_work, | ||
287 | state->bss_loss_tmo); | ||
288 | cw1200_resume_work(priv, &priv->join_timeout, | ||
289 | state->join_tmo); | ||
290 | cw1200_resume_work(priv, &priv->scan.probe_work, | ||
291 | state->direct_probe); | ||
292 | cw1200_resume_work(priv, &priv->link_id_gc_work, | ||
293 | state->link_id_gc); | ||
294 | kfree(state); | ||
295 | revert3: | ||
296 | wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); | ||
297 | wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); | ||
298 | revert2: | ||
299 | wsm_unlock_tx(priv); | ||
300 | up(&priv->scan.lock); | ||
301 | revert1: | ||
302 | mutex_unlock(&priv->conf_mutex); | ||
303 | return -EBUSY; | ||
304 | } | ||
305 | |||
306 | int cw1200_wow_resume(struct ieee80211_hw *hw) | ||
307 | { | ||
308 | struct cw1200_common *priv = hw->priv; | ||
309 | struct cw1200_pm_state *pm_state = &priv->pm_state; | ||
310 | struct cw1200_suspend_state *state; | ||
311 | |||
312 | state = pm_state->suspend_state; | ||
313 | pm_state->suspend_state = NULL; | ||
314 | |||
315 | /* Disable IRQ wake */ | ||
316 | priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false); | ||
317 | |||
318 | /* Scan.lock must be released before BH is resumed other way | ||
319 | * in case when BSS_LOST command arrived the processing of the | ||
320 | * command will be delayed. | ||
321 | */ | ||
322 | up(&priv->scan.lock); | ||
323 | |||
324 | /* Resume BH thread */ | ||
325 | WARN_ON(cw1200_bh_resume(priv)); | ||
326 | |||
327 | /* Restores previous PS mode */ | ||
328 | if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) { | ||
329 | priv->powersave_mode.mode = state->prev_ps_mode; | ||
330 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
331 | } | ||
332 | |||
333 | if (state->beacon_skipping) { | ||
334 | wsm_set_beacon_wakeup_period(priv, priv->beacon_int * | ||
335 | priv->join_dtim_period > | ||
336 | MAX_BEACON_SKIP_TIME_MS ? 1 : | ||
337 | priv->join_dtim_period, 0); | ||
338 | state->beacon_skipping = false; | ||
339 | } | ||
340 | |||
341 | /* Resume delayed work */ | ||
342 | cw1200_resume_work(priv, &priv->bss_loss_work, | ||
343 | state->bss_loss_tmo); | ||
344 | cw1200_resume_work(priv, &priv->join_timeout, | ||
345 | state->join_tmo); | ||
346 | cw1200_resume_work(priv, &priv->scan.probe_work, | ||
347 | state->direct_probe); | ||
348 | cw1200_resume_work(priv, &priv->link_id_gc_work, | ||
349 | state->link_id_gc); | ||
350 | |||
351 | /* Remove UDP port filter */ | ||
352 | wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); | ||
353 | |||
354 | /* Remove ethernet frame type filter */ | ||
355 | wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); | ||
356 | |||
357 | /* Unlock datapath */ | ||
358 | wsm_unlock_tx(priv); | ||
359 | |||
360 | /* Unlock configuration mutex */ | ||
361 | mutex_unlock(&priv->conf_mutex); | ||
362 | |||
363 | /* Free memory */ | ||
364 | kfree(state); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
diff --git a/drivers/net/wireless/cw1200/pm.h b/drivers/net/wireless/cw1200/pm.h new file mode 100644 index 000000000000..3ed90ff22bb8 --- /dev/null +++ b/drivers/net/wireless/cw1200/pm.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Mac80211 power management interface for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2011, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef PM_H_INCLUDED | ||
13 | #define PM_H_INCLUDED | ||
14 | |||
15 | /* ******************************************************************** */ | ||
16 | /* mac80211 API */ | ||
17 | |||
18 | /* extern */ struct cw1200_common; | ||
19 | /* private */ struct cw1200_suspend_state; | ||
20 | |||
21 | struct cw1200_pm_state { | ||
22 | struct cw1200_suspend_state *suspend_state; | ||
23 | struct timer_list stay_awake; | ||
24 | struct platform_device *pm_dev; | ||
25 | spinlock_t lock; /* Protect access */ | ||
26 | }; | ||
27 | |||
28 | #ifdef CONFIG_PM | ||
29 | int cw1200_pm_init(struct cw1200_pm_state *pm, | ||
30 | struct cw1200_common *priv); | ||
31 | void cw1200_pm_deinit(struct cw1200_pm_state *pm); | ||
32 | int cw1200_wow_suspend(struct ieee80211_hw *hw, | ||
33 | struct cfg80211_wowlan *wowlan); | ||
34 | int cw1200_wow_resume(struct ieee80211_hw *hw); | ||
35 | int cw1200_can_suspend(struct cw1200_common *priv); | ||
36 | void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, | ||
37 | unsigned long tmo); | ||
38 | #else | ||
39 | static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, | ||
40 | unsigned long tmo) { | ||
41 | } | ||
42 | #endif | ||
43 | #endif | ||
diff --git a/drivers/net/wireless/cw1200/queue.c b/drivers/net/wireless/cw1200/queue.c new file mode 100644 index 000000000000..8510454d5db1 --- /dev/null +++ b/drivers/net/wireless/cw1200/queue.c | |||
@@ -0,0 +1,583 @@ | |||
1 | /* | ||
2 | * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <net/mac80211.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include "queue.h" | ||
15 | #include "cw1200.h" | ||
16 | #include "debug.h" | ||
17 | |||
18 | /* private */ struct cw1200_queue_item | ||
19 | { | ||
20 | struct list_head head; | ||
21 | struct sk_buff *skb; | ||
22 | u32 packet_id; | ||
23 | unsigned long queue_timestamp; | ||
24 | unsigned long xmit_timestamp; | ||
25 | struct cw1200_txpriv txpriv; | ||
26 | u8 generation; | ||
27 | }; | ||
28 | |||
29 | static inline void __cw1200_queue_lock(struct cw1200_queue *queue) | ||
30 | { | ||
31 | struct cw1200_queue_stats *stats = queue->stats; | ||
32 | if (queue->tx_locked_cnt++ == 0) { | ||
33 | pr_debug("[TX] Queue %d is locked.\n", | ||
34 | queue->queue_id); | ||
35 | ieee80211_stop_queue(stats->priv->hw, queue->queue_id); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static inline void __cw1200_queue_unlock(struct cw1200_queue *queue) | ||
40 | { | ||
41 | struct cw1200_queue_stats *stats = queue->stats; | ||
42 | BUG_ON(!queue->tx_locked_cnt); | ||
43 | if (--queue->tx_locked_cnt == 0) { | ||
44 | pr_debug("[TX] Queue %d is unlocked.\n", | ||
45 | queue->queue_id); | ||
46 | ieee80211_wake_queue(stats->priv->hw, queue->queue_id); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | static inline void cw1200_queue_parse_id(u32 packet_id, u8 *queue_generation, | ||
51 | u8 *queue_id, u8 *item_generation, | ||
52 | u8 *item_id) | ||
53 | { | ||
54 | *item_id = (packet_id >> 0) & 0xFF; | ||
55 | *item_generation = (packet_id >> 8) & 0xFF; | ||
56 | *queue_id = (packet_id >> 16) & 0xFF; | ||
57 | *queue_generation = (packet_id >> 24) & 0xFF; | ||
58 | } | ||
59 | |||
60 | static inline u32 cw1200_queue_mk_packet_id(u8 queue_generation, u8 queue_id, | ||
61 | u8 item_generation, u8 item_id) | ||
62 | { | ||
63 | return ((u32)item_id << 0) | | ||
64 | ((u32)item_generation << 8) | | ||
65 | ((u32)queue_id << 16) | | ||
66 | ((u32)queue_generation << 24); | ||
67 | } | ||
68 | |||
69 | static void cw1200_queue_post_gc(struct cw1200_queue_stats *stats, | ||
70 | struct list_head *gc_list) | ||
71 | { | ||
72 | struct cw1200_queue_item *item, *tmp; | ||
73 | |||
74 | list_for_each_entry_safe(item, tmp, gc_list, head) { | ||
75 | list_del(&item->head); | ||
76 | stats->skb_dtor(stats->priv, item->skb, &item->txpriv); | ||
77 | kfree(item); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static void cw1200_queue_register_post_gc(struct list_head *gc_list, | ||
82 | struct cw1200_queue_item *item) | ||
83 | { | ||
84 | struct cw1200_queue_item *gc_item; | ||
85 | gc_item = kmalloc(sizeof(struct cw1200_queue_item), | ||
86 | GFP_ATOMIC); | ||
87 | BUG_ON(!gc_item); | ||
88 | memcpy(gc_item, item, sizeof(struct cw1200_queue_item)); | ||
89 | list_add_tail(&gc_item->head, gc_list); | ||
90 | } | ||
91 | |||
92 | static void __cw1200_queue_gc(struct cw1200_queue *queue, | ||
93 | struct list_head *head, | ||
94 | bool unlock) | ||
95 | { | ||
96 | struct cw1200_queue_stats *stats = queue->stats; | ||
97 | struct cw1200_queue_item *item = NULL, *tmp; | ||
98 | bool wakeup_stats = false; | ||
99 | |||
100 | list_for_each_entry_safe(item, tmp, &queue->queue, head) { | ||
101 | if (jiffies - item->queue_timestamp < queue->ttl) | ||
102 | break; | ||
103 | --queue->num_queued; | ||
104 | --queue->link_map_cache[item->txpriv.link_id]; | ||
105 | spin_lock_bh(&stats->lock); | ||
106 | --stats->num_queued; | ||
107 | if (!--stats->link_map_cache[item->txpriv.link_id]) | ||
108 | wakeup_stats = true; | ||
109 | spin_unlock_bh(&stats->lock); | ||
110 | cw1200_debug_tx_ttl(stats->priv); | ||
111 | cw1200_queue_register_post_gc(head, item); | ||
112 | item->skb = NULL; | ||
113 | list_move_tail(&item->head, &queue->free_pool); | ||
114 | } | ||
115 | |||
116 | if (wakeup_stats) | ||
117 | wake_up(&stats->wait_link_id_empty); | ||
118 | |||
119 | if (queue->overfull) { | ||
120 | if (queue->num_queued <= (queue->capacity >> 1)) { | ||
121 | queue->overfull = false; | ||
122 | if (unlock) | ||
123 | __cw1200_queue_unlock(queue); | ||
124 | } else if (item) { | ||
125 | unsigned long tmo = item->queue_timestamp + queue->ttl; | ||
126 | mod_timer(&queue->gc, tmo); | ||
127 | cw1200_pm_stay_awake(&stats->priv->pm_state, | ||
128 | tmo - jiffies); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void cw1200_queue_gc(unsigned long arg) | ||
134 | { | ||
135 | LIST_HEAD(list); | ||
136 | struct cw1200_queue *queue = | ||
137 | (struct cw1200_queue *)arg; | ||
138 | |||
139 | spin_lock_bh(&queue->lock); | ||
140 | __cw1200_queue_gc(queue, &list, true); | ||
141 | spin_unlock_bh(&queue->lock); | ||
142 | cw1200_queue_post_gc(queue->stats, &list); | ||
143 | } | ||
144 | |||
145 | int cw1200_queue_stats_init(struct cw1200_queue_stats *stats, | ||
146 | size_t map_capacity, | ||
147 | cw1200_queue_skb_dtor_t skb_dtor, | ||
148 | struct cw1200_common *priv) | ||
149 | { | ||
150 | memset(stats, 0, sizeof(*stats)); | ||
151 | stats->map_capacity = map_capacity; | ||
152 | stats->skb_dtor = skb_dtor; | ||
153 | stats->priv = priv; | ||
154 | spin_lock_init(&stats->lock); | ||
155 | init_waitqueue_head(&stats->wait_link_id_empty); | ||
156 | |||
157 | stats->link_map_cache = kzalloc(sizeof(int) * map_capacity, | ||
158 | GFP_KERNEL); | ||
159 | if (!stats->link_map_cache) | ||
160 | return -ENOMEM; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | int cw1200_queue_init(struct cw1200_queue *queue, | ||
166 | struct cw1200_queue_stats *stats, | ||
167 | u8 queue_id, | ||
168 | size_t capacity, | ||
169 | unsigned long ttl) | ||
170 | { | ||
171 | size_t i; | ||
172 | |||
173 | memset(queue, 0, sizeof(*queue)); | ||
174 | queue->stats = stats; | ||
175 | queue->capacity = capacity; | ||
176 | queue->queue_id = queue_id; | ||
177 | queue->ttl = ttl; | ||
178 | INIT_LIST_HEAD(&queue->queue); | ||
179 | INIT_LIST_HEAD(&queue->pending); | ||
180 | INIT_LIST_HEAD(&queue->free_pool); | ||
181 | spin_lock_init(&queue->lock); | ||
182 | init_timer(&queue->gc); | ||
183 | queue->gc.data = (unsigned long)queue; | ||
184 | queue->gc.function = cw1200_queue_gc; | ||
185 | |||
186 | queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity, | ||
187 | GFP_KERNEL); | ||
188 | if (!queue->pool) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | queue->link_map_cache = kzalloc(sizeof(int) * stats->map_capacity, | ||
192 | GFP_KERNEL); | ||
193 | if (!queue->link_map_cache) { | ||
194 | kfree(queue->pool); | ||
195 | queue->pool = NULL; | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | |||
199 | for (i = 0; i < capacity; ++i) | ||
200 | list_add_tail(&queue->pool[i].head, &queue->free_pool); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | int cw1200_queue_clear(struct cw1200_queue *queue) | ||
206 | { | ||
207 | int i; | ||
208 | LIST_HEAD(gc_list); | ||
209 | struct cw1200_queue_stats *stats = queue->stats; | ||
210 | struct cw1200_queue_item *item, *tmp; | ||
211 | |||
212 | spin_lock_bh(&queue->lock); | ||
213 | queue->generation++; | ||
214 | list_splice_tail_init(&queue->queue, &queue->pending); | ||
215 | list_for_each_entry_safe(item, tmp, &queue->pending, head) { | ||
216 | WARN_ON(!item->skb); | ||
217 | cw1200_queue_register_post_gc(&gc_list, item); | ||
218 | item->skb = NULL; | ||
219 | list_move_tail(&item->head, &queue->free_pool); | ||
220 | } | ||
221 | queue->num_queued = 0; | ||
222 | queue->num_pending = 0; | ||
223 | |||
224 | spin_lock_bh(&stats->lock); | ||
225 | for (i = 0; i < stats->map_capacity; ++i) { | ||
226 | stats->num_queued -= queue->link_map_cache[i]; | ||
227 | stats->link_map_cache[i] -= queue->link_map_cache[i]; | ||
228 | queue->link_map_cache[i] = 0; | ||
229 | } | ||
230 | spin_unlock_bh(&stats->lock); | ||
231 | if (queue->overfull) { | ||
232 | queue->overfull = false; | ||
233 | __cw1200_queue_unlock(queue); | ||
234 | } | ||
235 | spin_unlock_bh(&queue->lock); | ||
236 | wake_up(&stats->wait_link_id_empty); | ||
237 | cw1200_queue_post_gc(stats, &gc_list); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | void cw1200_queue_stats_deinit(struct cw1200_queue_stats *stats) | ||
242 | { | ||
243 | kfree(stats->link_map_cache); | ||
244 | stats->link_map_cache = NULL; | ||
245 | } | ||
246 | |||
247 | void cw1200_queue_deinit(struct cw1200_queue *queue) | ||
248 | { | ||
249 | cw1200_queue_clear(queue); | ||
250 | del_timer_sync(&queue->gc); | ||
251 | INIT_LIST_HEAD(&queue->free_pool); | ||
252 | kfree(queue->pool); | ||
253 | kfree(queue->link_map_cache); | ||
254 | queue->pool = NULL; | ||
255 | queue->link_map_cache = NULL; | ||
256 | queue->capacity = 0; | ||
257 | } | ||
258 | |||
259 | size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue, | ||
260 | u32 link_id_map) | ||
261 | { | ||
262 | size_t ret; | ||
263 | int i, bit; | ||
264 | size_t map_capacity = queue->stats->map_capacity; | ||
265 | |||
266 | if (!link_id_map) | ||
267 | return 0; | ||
268 | |||
269 | spin_lock_bh(&queue->lock); | ||
270 | if (link_id_map == (u32)-1) { | ||
271 | ret = queue->num_queued - queue->num_pending; | ||
272 | } else { | ||
273 | ret = 0; | ||
274 | for (i = 0, bit = 1; i < map_capacity; ++i, bit <<= 1) { | ||
275 | if (link_id_map & bit) | ||
276 | ret += queue->link_map_cache[i]; | ||
277 | } | ||
278 | } | ||
279 | spin_unlock_bh(&queue->lock); | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | int cw1200_queue_put(struct cw1200_queue *queue, | ||
284 | struct sk_buff *skb, | ||
285 | struct cw1200_txpriv *txpriv) | ||
286 | { | ||
287 | int ret = 0; | ||
288 | LIST_HEAD(gc_list); | ||
289 | struct cw1200_queue_stats *stats = queue->stats; | ||
290 | |||
291 | if (txpriv->link_id >= queue->stats->map_capacity) | ||
292 | return -EINVAL; | ||
293 | |||
294 | spin_lock_bh(&queue->lock); | ||
295 | if (!WARN_ON(list_empty(&queue->free_pool))) { | ||
296 | struct cw1200_queue_item *item = list_first_entry( | ||
297 | &queue->free_pool, struct cw1200_queue_item, head); | ||
298 | BUG_ON(item->skb); | ||
299 | |||
300 | list_move_tail(&item->head, &queue->queue); | ||
301 | item->skb = skb; | ||
302 | item->txpriv = *txpriv; | ||
303 | item->generation = 0; | ||
304 | item->packet_id = cw1200_queue_mk_packet_id(queue->generation, | ||
305 | queue->queue_id, | ||
306 | item->generation, | ||
307 | item - queue->pool); | ||
308 | item->queue_timestamp = jiffies; | ||
309 | |||
310 | ++queue->num_queued; | ||
311 | ++queue->link_map_cache[txpriv->link_id]; | ||
312 | |||
313 | spin_lock_bh(&stats->lock); | ||
314 | ++stats->num_queued; | ||
315 | ++stats->link_map_cache[txpriv->link_id]; | ||
316 | spin_unlock_bh(&stats->lock); | ||
317 | |||
318 | /* TX may happen in parallel sometimes. | ||
319 | * Leave extra queue slots so we don't overflow. | ||
320 | */ | ||
321 | if (queue->overfull == false && | ||
322 | queue->num_queued >= | ||
323 | (queue->capacity - (num_present_cpus() - 1))) { | ||
324 | queue->overfull = true; | ||
325 | __cw1200_queue_lock(queue); | ||
326 | mod_timer(&queue->gc, jiffies); | ||
327 | } | ||
328 | } else { | ||
329 | ret = -ENOENT; | ||
330 | } | ||
331 | spin_unlock_bh(&queue->lock); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | int cw1200_queue_get(struct cw1200_queue *queue, | ||
336 | u32 link_id_map, | ||
337 | struct wsm_tx **tx, | ||
338 | struct ieee80211_tx_info **tx_info, | ||
339 | const struct cw1200_txpriv **txpriv) | ||
340 | { | ||
341 | int ret = -ENOENT; | ||
342 | struct cw1200_queue_item *item; | ||
343 | struct cw1200_queue_stats *stats = queue->stats; | ||
344 | bool wakeup_stats = false; | ||
345 | |||
346 | spin_lock_bh(&queue->lock); | ||
347 | list_for_each_entry(item, &queue->queue, head) { | ||
348 | if (link_id_map & BIT(item->txpriv.link_id)) { | ||
349 | ret = 0; | ||
350 | break; | ||
351 | } | ||
352 | } | ||
353 | |||
354 | if (!WARN_ON(ret)) { | ||
355 | *tx = (struct wsm_tx *)item->skb->data; | ||
356 | *tx_info = IEEE80211_SKB_CB(item->skb); | ||
357 | *txpriv = &item->txpriv; | ||
358 | (*tx)->packet_id = __cpu_to_le32(item->packet_id); | ||
359 | list_move_tail(&item->head, &queue->pending); | ||
360 | ++queue->num_pending; | ||
361 | --queue->link_map_cache[item->txpriv.link_id]; | ||
362 | item->xmit_timestamp = jiffies; | ||
363 | |||
364 | spin_lock_bh(&stats->lock); | ||
365 | --stats->num_queued; | ||
366 | if (!--stats->link_map_cache[item->txpriv.link_id]) | ||
367 | wakeup_stats = true; | ||
368 | spin_unlock_bh(&stats->lock); | ||
369 | } | ||
370 | spin_unlock_bh(&queue->lock); | ||
371 | if (wakeup_stats) | ||
372 | wake_up(&stats->wait_link_id_empty); | ||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id) | ||
377 | { | ||
378 | int ret = 0; | ||
379 | u8 queue_generation, queue_id, item_generation, item_id; | ||
380 | struct cw1200_queue_item *item; | ||
381 | struct cw1200_queue_stats *stats = queue->stats; | ||
382 | |||
383 | cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, | ||
384 | &item_generation, &item_id); | ||
385 | |||
386 | item = &queue->pool[item_id]; | ||
387 | |||
388 | spin_lock_bh(&queue->lock); | ||
389 | BUG_ON(queue_id != queue->queue_id); | ||
390 | if (queue_generation != queue->generation) { | ||
391 | ret = -ENOENT; | ||
392 | } else if (item_id >= (unsigned) queue->capacity) { | ||
393 | WARN_ON(1); | ||
394 | ret = -EINVAL; | ||
395 | } else if (item->generation != item_generation) { | ||
396 | WARN_ON(1); | ||
397 | ret = -ENOENT; | ||
398 | } else { | ||
399 | --queue->num_pending; | ||
400 | ++queue->link_map_cache[item->txpriv.link_id]; | ||
401 | |||
402 | spin_lock_bh(&stats->lock); | ||
403 | ++stats->num_queued; | ||
404 | ++stats->link_map_cache[item->txpriv.link_id]; | ||
405 | spin_unlock_bh(&stats->lock); | ||
406 | |||
407 | item->generation = ++item_generation; | ||
408 | item->packet_id = cw1200_queue_mk_packet_id(queue_generation, | ||
409 | queue_id, | ||
410 | item_generation, | ||
411 | item_id); | ||
412 | list_move(&item->head, &queue->queue); | ||
413 | } | ||
414 | spin_unlock_bh(&queue->lock); | ||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | int cw1200_queue_requeue_all(struct cw1200_queue *queue) | ||
419 | { | ||
420 | struct cw1200_queue_item *item, *tmp; | ||
421 | struct cw1200_queue_stats *stats = queue->stats; | ||
422 | spin_lock_bh(&queue->lock); | ||
423 | |||
424 | list_for_each_entry_safe_reverse(item, tmp, &queue->pending, head) { | ||
425 | --queue->num_pending; | ||
426 | ++queue->link_map_cache[item->txpriv.link_id]; | ||
427 | |||
428 | spin_lock_bh(&stats->lock); | ||
429 | ++stats->num_queued; | ||
430 | ++stats->link_map_cache[item->txpriv.link_id]; | ||
431 | spin_unlock_bh(&stats->lock); | ||
432 | |||
433 | ++item->generation; | ||
434 | item->packet_id = cw1200_queue_mk_packet_id(queue->generation, | ||
435 | queue->queue_id, | ||
436 | item->generation, | ||
437 | item - queue->pool); | ||
438 | list_move(&item->head, &queue->queue); | ||
439 | } | ||
440 | spin_unlock_bh(&queue->lock); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id) | ||
446 | { | ||
447 | int ret = 0; | ||
448 | u8 queue_generation, queue_id, item_generation, item_id; | ||
449 | struct cw1200_queue_item *item; | ||
450 | struct cw1200_queue_stats *stats = queue->stats; | ||
451 | struct sk_buff *gc_skb = NULL; | ||
452 | struct cw1200_txpriv gc_txpriv; | ||
453 | |||
454 | cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, | ||
455 | &item_generation, &item_id); | ||
456 | |||
457 | item = &queue->pool[item_id]; | ||
458 | |||
459 | spin_lock_bh(&queue->lock); | ||
460 | BUG_ON(queue_id != queue->queue_id); | ||
461 | if (queue_generation != queue->generation) { | ||
462 | ret = -ENOENT; | ||
463 | } else if (item_id >= (unsigned) queue->capacity) { | ||
464 | WARN_ON(1); | ||
465 | ret = -EINVAL; | ||
466 | } else if (item->generation != item_generation) { | ||
467 | WARN_ON(1); | ||
468 | ret = -ENOENT; | ||
469 | } else { | ||
470 | gc_txpriv = item->txpriv; | ||
471 | gc_skb = item->skb; | ||
472 | item->skb = NULL; | ||
473 | --queue->num_pending; | ||
474 | --queue->num_queued; | ||
475 | ++queue->num_sent; | ||
476 | ++item->generation; | ||
477 | /* Do not use list_move_tail here, but list_move: | ||
478 | * try to utilize cache row. | ||
479 | */ | ||
480 | list_move(&item->head, &queue->free_pool); | ||
481 | |||
482 | if (queue->overfull && | ||
483 | (queue->num_queued <= (queue->capacity >> 1))) { | ||
484 | queue->overfull = false; | ||
485 | __cw1200_queue_unlock(queue); | ||
486 | } | ||
487 | } | ||
488 | spin_unlock_bh(&queue->lock); | ||
489 | |||
490 | if (gc_skb) | ||
491 | stats->skb_dtor(stats->priv, gc_skb, &gc_txpriv); | ||
492 | |||
493 | return ret; | ||
494 | } | ||
495 | |||
496 | int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, | ||
497 | struct sk_buff **skb, | ||
498 | const struct cw1200_txpriv **txpriv) | ||
499 | { | ||
500 | int ret = 0; | ||
501 | u8 queue_generation, queue_id, item_generation, item_id; | ||
502 | struct cw1200_queue_item *item; | ||
503 | cw1200_queue_parse_id(packet_id, &queue_generation, &queue_id, | ||
504 | &item_generation, &item_id); | ||
505 | |||
506 | item = &queue->pool[item_id]; | ||
507 | |||
508 | spin_lock_bh(&queue->lock); | ||
509 | BUG_ON(queue_id != queue->queue_id); | ||
510 | if (queue_generation != queue->generation) { | ||
511 | ret = -ENOENT; | ||
512 | } else if (item_id >= (unsigned) queue->capacity) { | ||
513 | WARN_ON(1); | ||
514 | ret = -EINVAL; | ||
515 | } else if (item->generation != item_generation) { | ||
516 | WARN_ON(1); | ||
517 | ret = -ENOENT; | ||
518 | } else { | ||
519 | *skb = item->skb; | ||
520 | *txpriv = &item->txpriv; | ||
521 | } | ||
522 | spin_unlock_bh(&queue->lock); | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | void cw1200_queue_lock(struct cw1200_queue *queue) | ||
527 | { | ||
528 | spin_lock_bh(&queue->lock); | ||
529 | __cw1200_queue_lock(queue); | ||
530 | spin_unlock_bh(&queue->lock); | ||
531 | } | ||
532 | |||
533 | void cw1200_queue_unlock(struct cw1200_queue *queue) | ||
534 | { | ||
535 | spin_lock_bh(&queue->lock); | ||
536 | __cw1200_queue_unlock(queue); | ||
537 | spin_unlock_bh(&queue->lock); | ||
538 | } | ||
539 | |||
540 | bool cw1200_queue_get_xmit_timestamp(struct cw1200_queue *queue, | ||
541 | unsigned long *timestamp, | ||
542 | u32 pending_frame_id) | ||
543 | { | ||
544 | struct cw1200_queue_item *item; | ||
545 | bool ret; | ||
546 | |||
547 | spin_lock_bh(&queue->lock); | ||
548 | ret = !list_empty(&queue->pending); | ||
549 | if (ret) { | ||
550 | list_for_each_entry(item, &queue->pending, head) { | ||
551 | if (item->packet_id != pending_frame_id) | ||
552 | if (time_before(item->xmit_timestamp, | ||
553 | *timestamp)) | ||
554 | *timestamp = item->xmit_timestamp; | ||
555 | } | ||
556 | } | ||
557 | spin_unlock_bh(&queue->lock); | ||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | bool cw1200_queue_stats_is_empty(struct cw1200_queue_stats *stats, | ||
562 | u32 link_id_map) | ||
563 | { | ||
564 | bool empty = true; | ||
565 | |||
566 | spin_lock_bh(&stats->lock); | ||
567 | if (link_id_map == (u32)-1) { | ||
568 | empty = stats->num_queued == 0; | ||
569 | } else { | ||
570 | int i; | ||
571 | for (i = 0; i < stats->map_capacity; ++i) { | ||
572 | if (link_id_map & BIT(i)) { | ||
573 | if (stats->link_map_cache[i]) { | ||
574 | empty = false; | ||
575 | break; | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | spin_unlock_bh(&stats->lock); | ||
581 | |||
582 | return empty; | ||
583 | } | ||
diff --git a/drivers/net/wireless/cw1200/queue.h b/drivers/net/wireless/cw1200/queue.h new file mode 100644 index 000000000000..119f9c79c14e --- /dev/null +++ b/drivers/net/wireless/cw1200/queue.h | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * O(1) TX queue with built-in allocator for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_QUEUE_H_INCLUDED | ||
13 | #define CW1200_QUEUE_H_INCLUDED | ||
14 | |||
15 | /* private */ struct cw1200_queue_item; | ||
16 | |||
17 | /* extern */ struct sk_buff; | ||
18 | /* extern */ struct wsm_tx; | ||
19 | /* extern */ struct cw1200_common; | ||
20 | /* extern */ struct ieee80211_tx_queue_stats; | ||
21 | /* extern */ struct cw1200_txpriv; | ||
22 | |||
23 | /* forward */ struct cw1200_queue_stats; | ||
24 | |||
25 | typedef void (*cw1200_queue_skb_dtor_t)(struct cw1200_common *priv, | ||
26 | struct sk_buff *skb, | ||
27 | const struct cw1200_txpriv *txpriv); | ||
28 | |||
29 | struct cw1200_queue { | ||
30 | struct cw1200_queue_stats *stats; | ||
31 | size_t capacity; | ||
32 | size_t num_queued; | ||
33 | size_t num_pending; | ||
34 | size_t num_sent; | ||
35 | struct cw1200_queue_item *pool; | ||
36 | struct list_head queue; | ||
37 | struct list_head free_pool; | ||
38 | struct list_head pending; | ||
39 | int tx_locked_cnt; | ||
40 | int *link_map_cache; | ||
41 | bool overfull; | ||
42 | spinlock_t lock; /* Protect queue entry */ | ||
43 | u8 queue_id; | ||
44 | u8 generation; | ||
45 | struct timer_list gc; | ||
46 | unsigned long ttl; | ||
47 | }; | ||
48 | |||
49 | struct cw1200_queue_stats { | ||
50 | spinlock_t lock; /* Protect stats entry */ | ||
51 | int *link_map_cache; | ||
52 | int num_queued; | ||
53 | size_t map_capacity; | ||
54 | wait_queue_head_t wait_link_id_empty; | ||
55 | cw1200_queue_skb_dtor_t skb_dtor; | ||
56 | struct cw1200_common *priv; | ||
57 | }; | ||
58 | |||
59 | struct cw1200_txpriv { | ||
60 | u8 link_id; | ||
61 | u8 raw_link_id; | ||
62 | u8 tid; | ||
63 | u8 rate_id; | ||
64 | u8 offset; | ||
65 | }; | ||
66 | |||
67 | int cw1200_queue_stats_init(struct cw1200_queue_stats *stats, | ||
68 | size_t map_capacity, | ||
69 | cw1200_queue_skb_dtor_t skb_dtor, | ||
70 | struct cw1200_common *priv); | ||
71 | int cw1200_queue_init(struct cw1200_queue *queue, | ||
72 | struct cw1200_queue_stats *stats, | ||
73 | u8 queue_id, | ||
74 | size_t capacity, | ||
75 | unsigned long ttl); | ||
76 | int cw1200_queue_clear(struct cw1200_queue *queue); | ||
77 | void cw1200_queue_stats_deinit(struct cw1200_queue_stats *stats); | ||
78 | void cw1200_queue_deinit(struct cw1200_queue *queue); | ||
79 | |||
80 | size_t cw1200_queue_get_num_queued(struct cw1200_queue *queue, | ||
81 | u32 link_id_map); | ||
82 | int cw1200_queue_put(struct cw1200_queue *queue, | ||
83 | struct sk_buff *skb, | ||
84 | struct cw1200_txpriv *txpriv); | ||
85 | int cw1200_queue_get(struct cw1200_queue *queue, | ||
86 | u32 link_id_map, | ||
87 | struct wsm_tx **tx, | ||
88 | struct ieee80211_tx_info **tx_info, | ||
89 | const struct cw1200_txpriv **txpriv); | ||
90 | int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id); | ||
91 | int cw1200_queue_requeue_all(struct cw1200_queue *queue); | ||
92 | int cw1200_queue_remove(struct cw1200_queue *queue, | ||
93 | u32 packet_id); | ||
94 | int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, | ||
95 | struct sk_buff **skb, | ||
96 | const struct cw1200_txpriv **txpriv); | ||
97 | void cw1200_queue_lock(struct cw1200_queue *queue); | ||
98 | void cw1200_queue_unlock(struct cw1200_queue *queue); | ||
99 | bool cw1200_queue_get_xmit_timestamp(struct cw1200_queue *queue, | ||
100 | unsigned long *timestamp, | ||
101 | u32 pending_frame_id); | ||
102 | |||
103 | bool cw1200_queue_stats_is_empty(struct cw1200_queue_stats *stats, | ||
104 | u32 link_id_map); | ||
105 | |||
106 | static inline u8 cw1200_queue_get_queue_id(u32 packet_id) | ||
107 | { | ||
108 | return (packet_id >> 16) & 0xFF; | ||
109 | } | ||
110 | |||
111 | static inline u8 cw1200_queue_get_generation(u32 packet_id) | ||
112 | { | ||
113 | return (packet_id >> 8) & 0xFF; | ||
114 | } | ||
115 | |||
116 | #endif /* CW1200_QUEUE_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c new file mode 100644 index 000000000000..ee3c19037aac --- /dev/null +++ b/drivers/net/wireless/cw1200/scan.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * Scan implementation for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | #include "cw1200.h" | ||
14 | #include "scan.h" | ||
15 | #include "sta.h" | ||
16 | #include "pm.h" | ||
17 | |||
18 | static void cw1200_scan_restart_delayed(struct cw1200_common *priv); | ||
19 | |||
20 | static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan) | ||
21 | { | ||
22 | int ret, i; | ||
23 | int tmo = 2000; | ||
24 | |||
25 | switch (priv->join_status) { | ||
26 | case CW1200_JOIN_STATUS_PRE_STA: | ||
27 | case CW1200_JOIN_STATUS_JOINING: | ||
28 | return -EBUSY; | ||
29 | default: | ||
30 | break; | ||
31 | } | ||
32 | |||
33 | wiphy_dbg(priv->hw->wiphy, "[SCAN] hw req, type %d, %d channels, flags: 0x%x.\n", | ||
34 | scan->type, scan->num_channels, scan->flags); | ||
35 | |||
36 | for (i = 0; i < scan->num_channels; ++i) | ||
37 | tmo += scan->ch[i].max_chan_time + 10; | ||
38 | |||
39 | cancel_delayed_work_sync(&priv->clear_recent_scan_work); | ||
40 | atomic_set(&priv->scan.in_progress, 1); | ||
41 | atomic_set(&priv->recent_scan, 1); | ||
42 | cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000); | ||
43 | queue_delayed_work(priv->workqueue, &priv->scan.timeout, | ||
44 | tmo * HZ / 1000); | ||
45 | ret = wsm_scan(priv, scan); | ||
46 | if (ret) { | ||
47 | atomic_set(&priv->scan.in_progress, 0); | ||
48 | cancel_delayed_work_sync(&priv->scan.timeout); | ||
49 | cw1200_scan_restart_delayed(priv); | ||
50 | } | ||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | int cw1200_hw_scan(struct ieee80211_hw *hw, | ||
55 | struct ieee80211_vif *vif, | ||
56 | struct cfg80211_scan_request *req) | ||
57 | { | ||
58 | struct cw1200_common *priv = hw->priv; | ||
59 | struct wsm_template_frame frame = { | ||
60 | .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, | ||
61 | }; | ||
62 | int i, ret; | ||
63 | |||
64 | if (!priv->vif) | ||
65 | return -EINVAL; | ||
66 | |||
67 | /* Scan when P2P_GO corrupt firmware MiniAP mode */ | ||
68 | if (priv->join_status == CW1200_JOIN_STATUS_AP) | ||
69 | return -EOPNOTSUPP; | ||
70 | |||
71 | if (req->n_ssids == 1 && !req->ssids[0].ssid_len) | ||
72 | req->n_ssids = 0; | ||
73 | |||
74 | wiphy_dbg(hw->wiphy, "[SCAN] Scan request for %d SSIDs.\n", | ||
75 | req->n_ssids); | ||
76 | |||
77 | if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS) | ||
78 | return -EINVAL; | ||
79 | |||
80 | frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, | ||
81 | req->ie_len); | ||
82 | if (!frame.skb) | ||
83 | return -ENOMEM; | ||
84 | |||
85 | if (req->ie_len) | ||
86 | memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); | ||
87 | |||
88 | /* will be unlocked in cw1200_scan_work() */ | ||
89 | down(&priv->scan.lock); | ||
90 | mutex_lock(&priv->conf_mutex); | ||
91 | |||
92 | ret = wsm_set_template_frame(priv, &frame); | ||
93 | if (!ret) { | ||
94 | /* Host want to be the probe responder. */ | ||
95 | ret = wsm_set_probe_responder(priv, true); | ||
96 | } | ||
97 | if (ret) { | ||
98 | mutex_unlock(&priv->conf_mutex); | ||
99 | up(&priv->scan.lock); | ||
100 | dev_kfree_skb(frame.skb); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | wsm_lock_tx(priv); | ||
105 | |||
106 | BUG_ON(priv->scan.req); | ||
107 | priv->scan.req = req; | ||
108 | priv->scan.n_ssids = 0; | ||
109 | priv->scan.status = 0; | ||
110 | priv->scan.begin = &req->channels[0]; | ||
111 | priv->scan.curr = priv->scan.begin; | ||
112 | priv->scan.end = &req->channels[req->n_channels]; | ||
113 | priv->scan.output_power = priv->output_power; | ||
114 | |||
115 | for (i = 0; i < req->n_ssids; ++i) { | ||
116 | struct wsm_ssid *dst = &priv->scan.ssids[priv->scan.n_ssids]; | ||
117 | memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); | ||
118 | dst->length = req->ssids[i].ssid_len; | ||
119 | ++priv->scan.n_ssids; | ||
120 | } | ||
121 | |||
122 | mutex_unlock(&priv->conf_mutex); | ||
123 | |||
124 | if (frame.skb) | ||
125 | dev_kfree_skb(frame.skb); | ||
126 | queue_work(priv->workqueue, &priv->scan.work); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | void cw1200_scan_work(struct work_struct *work) | ||
131 | { | ||
132 | struct cw1200_common *priv = container_of(work, struct cw1200_common, | ||
133 | scan.work); | ||
134 | struct ieee80211_channel **it; | ||
135 | struct wsm_scan scan = { | ||
136 | .type = WSM_SCAN_TYPE_FOREGROUND, | ||
137 | .flags = WSM_SCAN_FLAG_SPLIT_METHOD, | ||
138 | }; | ||
139 | bool first_run = (priv->scan.begin == priv->scan.curr && | ||
140 | priv->scan.begin != priv->scan.end); | ||
141 | int i; | ||
142 | |||
143 | if (first_run) { | ||
144 | /* Firmware gets crazy if scan request is sent | ||
145 | * when STA is joined but not yet associated. | ||
146 | * Force unjoin in this case. | ||
147 | */ | ||
148 | if (cancel_delayed_work_sync(&priv->join_timeout) > 0) | ||
149 | cw1200_join_timeout(&priv->join_timeout.work); | ||
150 | } | ||
151 | |||
152 | mutex_lock(&priv->conf_mutex); | ||
153 | |||
154 | if (first_run) { | ||
155 | if (priv->join_status == CW1200_JOIN_STATUS_STA && | ||
156 | !(priv->powersave_mode.mode & WSM_PSM_PS)) { | ||
157 | struct wsm_set_pm pm = priv->powersave_mode; | ||
158 | pm.mode = WSM_PSM_PS; | ||
159 | cw1200_set_pm(priv, &pm); | ||
160 | } else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { | ||
161 | /* FW bug: driver has to restart p2p-dev mode | ||
162 | * after scan | ||
163 | */ | ||
164 | cw1200_disable_listening(priv); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { | ||
169 | if (priv->scan.output_power != priv->output_power) | ||
170 | wsm_set_output_power(priv, priv->output_power * 10); | ||
171 | if (priv->join_status == CW1200_JOIN_STATUS_STA && | ||
172 | !(priv->powersave_mode.mode & WSM_PSM_PS)) | ||
173 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
174 | |||
175 | if (priv->scan.status < 0) | ||
176 | wiphy_dbg(priv->hw->wiphy, "[SCAN] Scan failed (%d).\n", | ||
177 | priv->scan.status); | ||
178 | else if (priv->scan.req) | ||
179 | wiphy_dbg(priv->hw->wiphy, | ||
180 | "[SCAN] Scan completed.\n"); | ||
181 | else | ||
182 | wiphy_dbg(priv->hw->wiphy, | ||
183 | "[SCAN] Scan canceled.\n"); | ||
184 | |||
185 | priv->scan.req = NULL; | ||
186 | cw1200_scan_restart_delayed(priv); | ||
187 | wsm_unlock_tx(priv); | ||
188 | mutex_unlock(&priv->conf_mutex); | ||
189 | ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); | ||
190 | up(&priv->scan.lock); | ||
191 | return; | ||
192 | } else { | ||
193 | struct ieee80211_channel *first = *priv->scan.curr; | ||
194 | for (it = priv->scan.curr + 1, i = 1; | ||
195 | it != priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; | ||
196 | ++it, ++i) { | ||
197 | if ((*it)->band != first->band) | ||
198 | break; | ||
199 | if (((*it)->flags ^ first->flags) & | ||
200 | IEEE80211_CHAN_PASSIVE_SCAN) | ||
201 | break; | ||
202 | if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && | ||
203 | (*it)->max_power != first->max_power) | ||
204 | break; | ||
205 | } | ||
206 | scan.band = first->band; | ||
207 | |||
208 | if (priv->scan.req->no_cck) | ||
209 | scan.max_tx_rate = WSM_TRANSMIT_RATE_6; | ||
210 | else | ||
211 | scan.max_tx_rate = WSM_TRANSMIT_RATE_1; | ||
212 | scan.num_probes = | ||
213 | (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2; | ||
214 | scan.num_ssids = priv->scan.n_ssids; | ||
215 | scan.ssids = &priv->scan.ssids[0]; | ||
216 | scan.num_channels = it - priv->scan.curr; | ||
217 | /* TODO: Is it optimal? */ | ||
218 | scan.probe_delay = 100; | ||
219 | /* It is not stated in WSM specification, however | ||
220 | * FW team says that driver may not use FG scan | ||
221 | * when joined. | ||
222 | */ | ||
223 | if (priv->join_status == CW1200_JOIN_STATUS_STA) { | ||
224 | scan.type = WSM_SCAN_TYPE_BACKGROUND; | ||
225 | scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; | ||
226 | } | ||
227 | scan.ch = kzalloc( | ||
228 | sizeof(struct wsm_scan_ch) * (it - priv->scan.curr), | ||
229 | GFP_KERNEL); | ||
230 | if (!scan.ch) { | ||
231 | priv->scan.status = -ENOMEM; | ||
232 | goto fail; | ||
233 | } | ||
234 | for (i = 0; i < scan.num_channels; ++i) { | ||
235 | scan.ch[i].number = priv->scan.curr[i]->hw_value; | ||
236 | if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { | ||
237 | scan.ch[i].min_chan_time = 50; | ||
238 | scan.ch[i].max_chan_time = 100; | ||
239 | } else { | ||
240 | scan.ch[i].min_chan_time = 10; | ||
241 | scan.ch[i].max_chan_time = 25; | ||
242 | } | ||
243 | } | ||
244 | if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && | ||
245 | priv->scan.output_power != first->max_power) { | ||
246 | priv->scan.output_power = first->max_power; | ||
247 | wsm_set_output_power(priv, | ||
248 | priv->scan.output_power * 10); | ||
249 | } | ||
250 | priv->scan.status = cw1200_scan_start(priv, &scan); | ||
251 | kfree(scan.ch); | ||
252 | if (priv->scan.status) | ||
253 | goto fail; | ||
254 | priv->scan.curr = it; | ||
255 | } | ||
256 | mutex_unlock(&priv->conf_mutex); | ||
257 | return; | ||
258 | |||
259 | fail: | ||
260 | priv->scan.curr = priv->scan.end; | ||
261 | mutex_unlock(&priv->conf_mutex); | ||
262 | queue_work(priv->workqueue, &priv->scan.work); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | static void cw1200_scan_restart_delayed(struct cw1200_common *priv) | ||
267 | { | ||
268 | /* FW bug: driver has to restart p2p-dev mode after scan. */ | ||
269 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { | ||
270 | cw1200_enable_listening(priv); | ||
271 | cw1200_update_filtering(priv); | ||
272 | } | ||
273 | |||
274 | if (priv->delayed_unjoin) { | ||
275 | priv->delayed_unjoin = false; | ||
276 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
277 | wsm_unlock_tx(priv); | ||
278 | } else if (priv->delayed_link_loss) { | ||
279 | wiphy_dbg(priv->hw->wiphy, "[CQM] Requeue BSS loss.\n"); | ||
280 | priv->delayed_link_loss = 0; | ||
281 | cw1200_cqm_bssloss_sm(priv, 1, 0, 0); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void cw1200_scan_complete(struct cw1200_common *priv) | ||
286 | { | ||
287 | queue_delayed_work(priv->workqueue, &priv->clear_recent_scan_work, HZ); | ||
288 | if (priv->scan.direct_probe) { | ||
289 | wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe complete.\n"); | ||
290 | cw1200_scan_restart_delayed(priv); | ||
291 | priv->scan.direct_probe = 0; | ||
292 | up(&priv->scan.lock); | ||
293 | wsm_unlock_tx(priv); | ||
294 | } else { | ||
295 | cw1200_scan_work(&priv->scan.work); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | void cw1200_scan_failed_cb(struct cw1200_common *priv) | ||
300 | { | ||
301 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
302 | /* STA is stopped. */ | ||
303 | return; | ||
304 | |||
305 | if (cancel_delayed_work_sync(&priv->scan.timeout) > 0) { | ||
306 | priv->scan.status = -EIO; | ||
307 | queue_delayed_work(priv->workqueue, &priv->scan.timeout, 0); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | |||
312 | void cw1200_scan_complete_cb(struct cw1200_common *priv, | ||
313 | struct wsm_scan_complete *arg) | ||
314 | { | ||
315 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
316 | /* STA is stopped. */ | ||
317 | return; | ||
318 | |||
319 | if (cancel_delayed_work_sync(&priv->scan.timeout) > 0) { | ||
320 | priv->scan.status = 1; | ||
321 | queue_delayed_work(priv->workqueue, &priv->scan.timeout, 0); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | void cw1200_clear_recent_scan_work(struct work_struct *work) | ||
326 | { | ||
327 | struct cw1200_common *priv = | ||
328 | container_of(work, struct cw1200_common, | ||
329 | clear_recent_scan_work.work); | ||
330 | atomic_xchg(&priv->recent_scan, 0); | ||
331 | } | ||
332 | |||
333 | void cw1200_scan_timeout(struct work_struct *work) | ||
334 | { | ||
335 | struct cw1200_common *priv = | ||
336 | container_of(work, struct cw1200_common, scan.timeout.work); | ||
337 | if (atomic_xchg(&priv->scan.in_progress, 0)) { | ||
338 | if (priv->scan.status > 0) { | ||
339 | priv->scan.status = 0; | ||
340 | } else if (!priv->scan.status) { | ||
341 | wiphy_warn(priv->hw->wiphy, | ||
342 | "Timeout waiting for scan complete notification.\n"); | ||
343 | priv->scan.status = -ETIMEDOUT; | ||
344 | priv->scan.curr = priv->scan.end; | ||
345 | wsm_stop_scan(priv); | ||
346 | } | ||
347 | cw1200_scan_complete(priv); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | void cw1200_probe_work(struct work_struct *work) | ||
352 | { | ||
353 | struct cw1200_common *priv = | ||
354 | container_of(work, struct cw1200_common, scan.probe_work.work); | ||
355 | u8 queue_id = cw1200_queue_get_queue_id(priv->pending_frame_id); | ||
356 | struct cw1200_queue *queue = &priv->tx_queue[queue_id]; | ||
357 | const struct cw1200_txpriv *txpriv; | ||
358 | struct wsm_tx *wsm; | ||
359 | struct wsm_template_frame frame = { | ||
360 | .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, | ||
361 | }; | ||
362 | struct wsm_ssid ssids[1] = {{ | ||
363 | .length = 0, | ||
364 | } }; | ||
365 | struct wsm_scan_ch ch[1] = {{ | ||
366 | .min_chan_time = 0, | ||
367 | .max_chan_time = 10, | ||
368 | } }; | ||
369 | struct wsm_scan scan = { | ||
370 | .type = WSM_SCAN_TYPE_FOREGROUND, | ||
371 | .num_probes = 1, | ||
372 | .probe_delay = 0, | ||
373 | .num_channels = 1, | ||
374 | .ssids = ssids, | ||
375 | .ch = ch, | ||
376 | }; | ||
377 | u8 *ies; | ||
378 | size_t ies_len; | ||
379 | int ret; | ||
380 | |||
381 | wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe work.\n"); | ||
382 | |||
383 | mutex_lock(&priv->conf_mutex); | ||
384 | if (down_trylock(&priv->scan.lock)) { | ||
385 | /* Scan is already in progress. Requeue self. */ | ||
386 | schedule(); | ||
387 | queue_delayed_work(priv->workqueue, | ||
388 | &priv->scan.probe_work, HZ / 10); | ||
389 | mutex_unlock(&priv->conf_mutex); | ||
390 | return; | ||
391 | } | ||
392 | |||
393 | /* Make sure we still have a pending probe req */ | ||
394 | if (cw1200_queue_get_skb(queue, priv->pending_frame_id, | ||
395 | &frame.skb, &txpriv)) { | ||
396 | up(&priv->scan.lock); | ||
397 | mutex_unlock(&priv->conf_mutex); | ||
398 | wsm_unlock_tx(priv); | ||
399 | return; | ||
400 | } | ||
401 | wsm = (struct wsm_tx *)frame.skb->data; | ||
402 | scan.max_tx_rate = wsm->max_tx_rate; | ||
403 | scan.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? | ||
404 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; | ||
405 | if (priv->join_status == CW1200_JOIN_STATUS_STA || | ||
406 | priv->join_status == CW1200_JOIN_STATUS_IBSS) { | ||
407 | scan.type = WSM_SCAN_TYPE_BACKGROUND; | ||
408 | scan.flags = WSM_SCAN_FLAG_FORCE_BACKGROUND; | ||
409 | } | ||
410 | ch[0].number = priv->channel->hw_value; | ||
411 | |||
412 | skb_pull(frame.skb, txpriv->offset); | ||
413 | |||
414 | ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)]; | ||
415 | ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr); | ||
416 | |||
417 | if (ies_len) { | ||
418 | u8 *ssidie = | ||
419 | (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); | ||
420 | if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) { | ||
421 | u8 *nextie = &ssidie[2 + ssidie[1]]; | ||
422 | /* Remove SSID from the IE list. It has to be provided | ||
423 | * as a separate argument in cw1200_scan_start call | ||
424 | */ | ||
425 | |||
426 | /* Store SSID localy */ | ||
427 | ssids[0].length = ssidie[1]; | ||
428 | memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length); | ||
429 | scan.num_ssids = 1; | ||
430 | |||
431 | /* Remove SSID from IE list */ | ||
432 | ssidie[1] = 0; | ||
433 | memmove(&ssidie[2], nextie, &ies[ies_len] - nextie); | ||
434 | skb_trim(frame.skb, frame.skb->len - ssids[0].length); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /* FW bug: driver has to restart p2p-dev mode after scan */ | ||
439 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) | ||
440 | cw1200_disable_listening(priv); | ||
441 | ret = wsm_set_template_frame(priv, &frame); | ||
442 | priv->scan.direct_probe = 1; | ||
443 | if (!ret) { | ||
444 | wsm_flush_tx(priv); | ||
445 | ret = cw1200_scan_start(priv, &scan); | ||
446 | } | ||
447 | mutex_unlock(&priv->conf_mutex); | ||
448 | |||
449 | skb_push(frame.skb, txpriv->offset); | ||
450 | if (!ret) | ||
451 | IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK; | ||
452 | BUG_ON(cw1200_queue_remove(queue, priv->pending_frame_id)); | ||
453 | |||
454 | if (ret) { | ||
455 | priv->scan.direct_probe = 0; | ||
456 | up(&priv->scan.lock); | ||
457 | wsm_unlock_tx(priv); | ||
458 | } | ||
459 | |||
460 | return; | ||
461 | } | ||
diff --git a/drivers/net/wireless/cw1200/scan.h b/drivers/net/wireless/cw1200/scan.h new file mode 100644 index 000000000000..5a8296ccfa82 --- /dev/null +++ b/drivers/net/wireless/cw1200/scan.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Scan interface for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef SCAN_H_INCLUDED | ||
13 | #define SCAN_H_INCLUDED | ||
14 | |||
15 | #include <linux/semaphore.h> | ||
16 | #include "wsm.h" | ||
17 | |||
18 | /* external */ struct sk_buff; | ||
19 | /* external */ struct cfg80211_scan_request; | ||
20 | /* external */ struct ieee80211_channel; | ||
21 | /* external */ struct ieee80211_hw; | ||
22 | /* external */ struct work_struct; | ||
23 | |||
24 | struct cw1200_scan { | ||
25 | struct semaphore lock; | ||
26 | struct work_struct work; | ||
27 | struct delayed_work timeout; | ||
28 | struct cfg80211_scan_request *req; | ||
29 | struct ieee80211_channel **begin; | ||
30 | struct ieee80211_channel **curr; | ||
31 | struct ieee80211_channel **end; | ||
32 | struct wsm_ssid ssids[WSM_SCAN_MAX_NUM_OF_SSIDS]; | ||
33 | int output_power; | ||
34 | int n_ssids; | ||
35 | int status; | ||
36 | atomic_t in_progress; | ||
37 | /* Direct probe requests workaround */ | ||
38 | struct delayed_work probe_work; | ||
39 | int direct_probe; | ||
40 | }; | ||
41 | |||
42 | int cw1200_hw_scan(struct ieee80211_hw *hw, | ||
43 | struct ieee80211_vif *vif, | ||
44 | struct cfg80211_scan_request *req); | ||
45 | void cw1200_scan_work(struct work_struct *work); | ||
46 | void cw1200_scan_timeout(struct work_struct *work); | ||
47 | void cw1200_clear_recent_scan_work(struct work_struct *work); | ||
48 | void cw1200_scan_complete_cb(struct cw1200_common *priv, | ||
49 | struct wsm_scan_complete *arg); | ||
50 | void cw1200_scan_failed_cb(struct cw1200_common *priv); | ||
51 | |||
52 | /* ******************************************************************** */ | ||
53 | /* Raw probe requests TX workaround */ | ||
54 | void cw1200_probe_work(struct work_struct *work); | ||
55 | |||
56 | #endif | ||
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c new file mode 100644 index 000000000000..679c55f15c67 --- /dev/null +++ b/drivers/net/wireless/cw1200/sta.c | |||
@@ -0,0 +1,2406 @@ | |||
1 | /* | ||
2 | * Mac80211 STA API for ST-Ericsson CW1200 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/vmalloc.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/firmware.h> | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include "cw1200.h" | ||
18 | #include "sta.h" | ||
19 | #include "fwio.h" | ||
20 | #include "bh.h" | ||
21 | #include "debug.h" | ||
22 | |||
23 | #ifndef ERP_INFO_BYTE_OFFSET | ||
24 | #define ERP_INFO_BYTE_OFFSET 2 | ||
25 | #endif | ||
26 | |||
27 | static void cw1200_do_join(struct cw1200_common *priv); | ||
28 | static void cw1200_do_unjoin(struct cw1200_common *priv); | ||
29 | |||
30 | static int cw1200_upload_beacon(struct cw1200_common *priv); | ||
31 | static int cw1200_upload_pspoll(struct cw1200_common *priv); | ||
32 | static int cw1200_upload_null(struct cw1200_common *priv); | ||
33 | static int cw1200_upload_qosnull(struct cw1200_common *priv); | ||
34 | static int cw1200_start_ap(struct cw1200_common *priv); | ||
35 | static int cw1200_update_beaconing(struct cw1200_common *priv); | ||
36 | static int cw1200_enable_beaconing(struct cw1200_common *priv, | ||
37 | bool enable); | ||
38 | static void __cw1200_sta_notify(struct ieee80211_hw *dev, | ||
39 | struct ieee80211_vif *vif, | ||
40 | enum sta_notify_cmd notify_cmd, | ||
41 | int link_id); | ||
42 | static int __cw1200_flush(struct cw1200_common *priv, bool drop); | ||
43 | |||
44 | static inline void __cw1200_free_event_queue(struct list_head *list) | ||
45 | { | ||
46 | struct cw1200_wsm_event *event, *tmp; | ||
47 | list_for_each_entry_safe(event, tmp, list, link) { | ||
48 | list_del(&event->link); | ||
49 | kfree(event); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /* ******************************************************************** */ | ||
54 | /* STA API */ | ||
55 | |||
56 | int cw1200_start(struct ieee80211_hw *dev) | ||
57 | { | ||
58 | struct cw1200_common *priv = dev->priv; | ||
59 | int ret = 0; | ||
60 | |||
61 | cw1200_pm_stay_awake(&priv->pm_state, HZ); | ||
62 | |||
63 | mutex_lock(&priv->conf_mutex); | ||
64 | |||
65 | /* default EDCA */ | ||
66 | WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, 47, 0xc8, false); | ||
67 | WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, 94, 0xc8, false); | ||
68 | WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, 0, 0xc8, false); | ||
69 | WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, 0, 0xc8, false); | ||
70 | ret = wsm_set_edca_params(priv, &priv->edca); | ||
71 | if (ret) | ||
72 | goto out; | ||
73 | |||
74 | ret = cw1200_set_uapsd_param(priv, &priv->edca); | ||
75 | if (ret) | ||
76 | goto out; | ||
77 | |||
78 | priv->setbssparams_done = false; | ||
79 | |||
80 | memcpy(priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN); | ||
81 | priv->mode = NL80211_IFTYPE_MONITOR; | ||
82 | priv->wep_default_key_id = -1; | ||
83 | |||
84 | priv->cqm_beacon_loss_count = 10; | ||
85 | |||
86 | ret = cw1200_setup_mac(priv); | ||
87 | if (ret) | ||
88 | goto out; | ||
89 | |||
90 | out: | ||
91 | mutex_unlock(&priv->conf_mutex); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | void cw1200_stop(struct ieee80211_hw *dev) | ||
96 | { | ||
97 | struct cw1200_common *priv = dev->priv; | ||
98 | LIST_HEAD(list); | ||
99 | int i; | ||
100 | |||
101 | wsm_lock_tx(priv); | ||
102 | |||
103 | while (down_trylock(&priv->scan.lock)) { | ||
104 | /* Scan is in progress. Force it to stop. */ | ||
105 | priv->scan.req = NULL; | ||
106 | schedule(); | ||
107 | } | ||
108 | up(&priv->scan.lock); | ||
109 | |||
110 | cancel_delayed_work_sync(&priv->scan.probe_work); | ||
111 | cancel_delayed_work_sync(&priv->scan.timeout); | ||
112 | cancel_delayed_work_sync(&priv->clear_recent_scan_work); | ||
113 | cancel_delayed_work_sync(&priv->join_timeout); | ||
114 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
115 | cancel_work_sync(&priv->unjoin_work); | ||
116 | cancel_delayed_work_sync(&priv->link_id_gc_work); | ||
117 | flush_workqueue(priv->workqueue); | ||
118 | del_timer_sync(&priv->mcast_timeout); | ||
119 | mutex_lock(&priv->conf_mutex); | ||
120 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||
121 | priv->listening = false; | ||
122 | |||
123 | spin_lock(&priv->event_queue_lock); | ||
124 | list_splice_init(&priv->event_queue, &list); | ||
125 | spin_unlock(&priv->event_queue_lock); | ||
126 | __cw1200_free_event_queue(&list); | ||
127 | |||
128 | |||
129 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
130 | priv->join_pending = false; | ||
131 | |||
132 | for (i = 0; i < 4; i++) | ||
133 | cw1200_queue_clear(&priv->tx_queue[i]); | ||
134 | mutex_unlock(&priv->conf_mutex); | ||
135 | tx_policy_clean(priv); | ||
136 | |||
137 | /* HACK! */ | ||
138 | if (atomic_xchg(&priv->tx_lock, 1) != 1) | ||
139 | pr_debug("[STA] TX is force-unlocked due to stop request.\n"); | ||
140 | |||
141 | wsm_unlock_tx(priv); | ||
142 | atomic_xchg(&priv->tx_lock, 0); /* for recovery to work */ | ||
143 | } | ||
144 | |||
145 | static int cw1200_bssloss_mitigation = 1; | ||
146 | module_param(cw1200_bssloss_mitigation, int, 0644); | ||
147 | MODULE_PARM_DESC(cw1200_bssloss_mitigation, "BSS Loss mitigation. 0 == disabled, 1 == enabled (default)"); | ||
148 | |||
149 | |||
150 | void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv, | ||
151 | int init, int good, int bad) | ||
152 | { | ||
153 | int tx = 0; | ||
154 | |||
155 | priv->delayed_link_loss = 0; | ||
156 | cancel_work_sync(&priv->bss_params_work); | ||
157 | |||
158 | pr_debug("[STA] CQM BSSLOSS_SM: state: %d init %d good %d bad: %d txlock: %d uj: %d\n", | ||
159 | priv->bss_loss_state, | ||
160 | init, good, bad, | ||
161 | atomic_read(&priv->tx_lock), | ||
162 | priv->delayed_unjoin); | ||
163 | |||
164 | /* If we have a pending unjoin */ | ||
165 | if (priv->delayed_unjoin) | ||
166 | return; | ||
167 | |||
168 | if (init) { | ||
169 | queue_delayed_work(priv->workqueue, | ||
170 | &priv->bss_loss_work, | ||
171 | HZ); | ||
172 | priv->bss_loss_state = 0; | ||
173 | |||
174 | /* Skip the confimration procedure in P2P case */ | ||
175 | if (!priv->vif->p2p && !atomic_read(&priv->tx_lock)) | ||
176 | tx = 1; | ||
177 | } else if (good) { | ||
178 | cancel_delayed_work_sync(&priv->bss_loss_work); | ||
179 | priv->bss_loss_state = 0; | ||
180 | queue_work(priv->workqueue, &priv->bss_params_work); | ||
181 | } else if (bad) { | ||
182 | /* XXX Should we just keep going until we time out? */ | ||
183 | if (priv->bss_loss_state < 3) | ||
184 | tx = 1; | ||
185 | } else { | ||
186 | cancel_delayed_work_sync(&priv->bss_loss_work); | ||
187 | priv->bss_loss_state = 0; | ||
188 | } | ||
189 | |||
190 | /* Bypass mitigation if it's disabled */ | ||
191 | if (!cw1200_bssloss_mitigation) | ||
192 | tx = 0; | ||
193 | |||
194 | /* Spit out a NULL packet to our AP if necessary */ | ||
195 | if (tx) { | ||
196 | struct sk_buff *skb; | ||
197 | |||
198 | priv->bss_loss_state++; | ||
199 | |||
200 | skb = ieee80211_nullfunc_get(priv->hw, priv->vif); | ||
201 | WARN_ON(!skb); | ||
202 | if (skb) | ||
203 | cw1200_tx(priv->hw, NULL, skb); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | int cw1200_add_interface(struct ieee80211_hw *dev, | ||
208 | struct ieee80211_vif *vif) | ||
209 | { | ||
210 | int ret; | ||
211 | struct cw1200_common *priv = dev->priv; | ||
212 | /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ | ||
213 | |||
214 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | | ||
215 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; | ||
216 | |||
217 | mutex_lock(&priv->conf_mutex); | ||
218 | |||
219 | if (priv->mode != NL80211_IFTYPE_MONITOR) { | ||
220 | mutex_unlock(&priv->conf_mutex); | ||
221 | return -EOPNOTSUPP; | ||
222 | } | ||
223 | |||
224 | switch (vif->type) { | ||
225 | case NL80211_IFTYPE_STATION: | ||
226 | case NL80211_IFTYPE_ADHOC: | ||
227 | case NL80211_IFTYPE_MESH_POINT: | ||
228 | case NL80211_IFTYPE_AP: | ||
229 | priv->mode = vif->type; | ||
230 | break; | ||
231 | default: | ||
232 | mutex_unlock(&priv->conf_mutex); | ||
233 | return -EOPNOTSUPP; | ||
234 | } | ||
235 | |||
236 | priv->vif = vif; | ||
237 | memcpy(priv->mac_addr, vif->addr, ETH_ALEN); | ||
238 | ret = cw1200_setup_mac(priv); | ||
239 | /* Enable auto-calibration */ | ||
240 | /* Exception in subsequent channel switch; disabled. | ||
241 | * wsm_write_mib(priv, WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE, | ||
242 | * &auto_calibration_mode, sizeof(auto_calibration_mode)); | ||
243 | */ | ||
244 | |||
245 | mutex_unlock(&priv->conf_mutex); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | void cw1200_remove_interface(struct ieee80211_hw *dev, | ||
250 | struct ieee80211_vif *vif) | ||
251 | { | ||
252 | struct cw1200_common *priv = dev->priv; | ||
253 | struct wsm_reset reset = { | ||
254 | .reset_statistics = true, | ||
255 | }; | ||
256 | int i; | ||
257 | |||
258 | mutex_lock(&priv->conf_mutex); | ||
259 | switch (priv->join_status) { | ||
260 | case CW1200_JOIN_STATUS_JOINING: | ||
261 | case CW1200_JOIN_STATUS_PRE_STA: | ||
262 | case CW1200_JOIN_STATUS_STA: | ||
263 | case CW1200_JOIN_STATUS_IBSS: | ||
264 | wsm_lock_tx(priv); | ||
265 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
266 | wsm_unlock_tx(priv); | ||
267 | break; | ||
268 | case CW1200_JOIN_STATUS_AP: | ||
269 | for (i = 0; priv->link_id_map; ++i) { | ||
270 | if (priv->link_id_map & BIT(i)) { | ||
271 | reset.link_id = i; | ||
272 | wsm_reset(priv, &reset); | ||
273 | priv->link_id_map &= ~BIT(i); | ||
274 | } | ||
275 | } | ||
276 | memset(priv->link_id_db, 0, sizeof(priv->link_id_db)); | ||
277 | priv->sta_asleep_mask = 0; | ||
278 | priv->enable_beacon = false; | ||
279 | priv->tx_multicast = false; | ||
280 | priv->aid0_bit_set = false; | ||
281 | priv->buffered_multicasts = false; | ||
282 | priv->pspoll_mask = 0; | ||
283 | reset.link_id = 0; | ||
284 | wsm_reset(priv, &reset); | ||
285 | break; | ||
286 | case CW1200_JOIN_STATUS_MONITOR: | ||
287 | cw1200_update_listening(priv, false); | ||
288 | break; | ||
289 | default: | ||
290 | break; | ||
291 | } | ||
292 | priv->vif = NULL; | ||
293 | priv->mode = NL80211_IFTYPE_MONITOR; | ||
294 | memset(priv->mac_addr, 0, ETH_ALEN); | ||
295 | memset(&priv->p2p_ps_modeinfo, 0, sizeof(priv->p2p_ps_modeinfo)); | ||
296 | cw1200_free_keys(priv); | ||
297 | cw1200_setup_mac(priv); | ||
298 | priv->listening = false; | ||
299 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
300 | if (!__cw1200_flush(priv, true)) | ||
301 | wsm_unlock_tx(priv); | ||
302 | |||
303 | mutex_unlock(&priv->conf_mutex); | ||
304 | } | ||
305 | |||
306 | int cw1200_change_interface(struct ieee80211_hw *dev, | ||
307 | struct ieee80211_vif *vif, | ||
308 | enum nl80211_iftype new_type, | ||
309 | bool p2p) | ||
310 | { | ||
311 | int ret = 0; | ||
312 | pr_debug("change_interface new: %d (%d), old: %d (%d)\n", new_type, | ||
313 | p2p, vif->type, vif->p2p); | ||
314 | |||
315 | if (new_type != vif->type || vif->p2p != p2p) { | ||
316 | cw1200_remove_interface(dev, vif); | ||
317 | vif->type = new_type; | ||
318 | vif->p2p = p2p; | ||
319 | ret = cw1200_add_interface(dev, vif); | ||
320 | } | ||
321 | |||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | int cw1200_config(struct ieee80211_hw *dev, u32 changed) | ||
326 | { | ||
327 | int ret = 0; | ||
328 | struct cw1200_common *priv = dev->priv; | ||
329 | struct ieee80211_conf *conf = &dev->conf; | ||
330 | |||
331 | pr_debug("CONFIG CHANGED: %08x\n", changed); | ||
332 | |||
333 | down(&priv->scan.lock); | ||
334 | mutex_lock(&priv->conf_mutex); | ||
335 | /* TODO: IEEE80211_CONF_CHANGE_QOS */ | ||
336 | /* TODO: IEEE80211_CONF_CHANGE_LISTEN_INTERVAL */ | ||
337 | |||
338 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | ||
339 | priv->output_power = conf->power_level; | ||
340 | pr_debug("[STA] TX power: %d\n", priv->output_power); | ||
341 | wsm_set_output_power(priv, priv->output_power * 10); | ||
342 | } | ||
343 | |||
344 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) && | ||
345 | (priv->channel != conf->chandef.chan)) { | ||
346 | struct ieee80211_channel *ch = conf->chandef.chan; | ||
347 | struct wsm_switch_channel channel = { | ||
348 | .channel_number = ch->hw_value, | ||
349 | }; | ||
350 | pr_debug("[STA] Freq %d (wsm ch: %d).\n", | ||
351 | ch->center_freq, ch->hw_value); | ||
352 | |||
353 | /* __cw1200_flush() implicitly locks tx, if successful */ | ||
354 | if (!__cw1200_flush(priv, false)) { | ||
355 | if (!wsm_switch_channel(priv, &channel)) { | ||
356 | ret = wait_event_timeout(priv->channel_switch_done, | ||
357 | !priv->channel_switch_in_progress, | ||
358 | 3 * HZ); | ||
359 | if (ret) { | ||
360 | /* Already unlocks if successful */ | ||
361 | priv->channel = ch; | ||
362 | ret = 0; | ||
363 | } else { | ||
364 | ret = -ETIMEDOUT; | ||
365 | } | ||
366 | } else { | ||
367 | /* Unlock if switch channel fails */ | ||
368 | wsm_unlock_tx(priv); | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | |||
373 | if (changed & IEEE80211_CONF_CHANGE_PS) { | ||
374 | if (!(conf->flags & IEEE80211_CONF_PS)) | ||
375 | priv->powersave_mode.mode = WSM_PSM_ACTIVE; | ||
376 | else if (conf->dynamic_ps_timeout <= 0) | ||
377 | priv->powersave_mode.mode = WSM_PSM_PS; | ||
378 | else | ||
379 | priv->powersave_mode.mode = WSM_PSM_FAST_PS; | ||
380 | |||
381 | /* Firmware requires that value for this 1-byte field must | ||
382 | * be specified in units of 500us. Values above the 128ms | ||
383 | * threshold are not supported. | ||
384 | */ | ||
385 | if (conf->dynamic_ps_timeout >= 0x80) | ||
386 | priv->powersave_mode.fast_psm_idle_period = 0xFF; | ||
387 | else | ||
388 | priv->powersave_mode.fast_psm_idle_period = | ||
389 | conf->dynamic_ps_timeout << 1; | ||
390 | |||
391 | if (priv->join_status == CW1200_JOIN_STATUS_STA && | ||
392 | priv->bss_params.aid) | ||
393 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
394 | } | ||
395 | |||
396 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { | ||
397 | /* TBD: It looks like it's transparent | ||
398 | * there's a monitor interface present -- use this | ||
399 | * to determine for example whether to calculate | ||
400 | * timestamps for packets or not, do not use instead | ||
401 | * of filter flags! | ||
402 | */ | ||
403 | } | ||
404 | |||
405 | if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||
406 | struct wsm_operational_mode mode = { | ||
407 | .power_mode = cw1200_power_mode, | ||
408 | .disable_more_flag_usage = true, | ||
409 | }; | ||
410 | |||
411 | wsm_lock_tx(priv); | ||
412 | /* Disable p2p-dev mode forced by TX request */ | ||
413 | if ((priv->join_status == CW1200_JOIN_STATUS_MONITOR) && | ||
414 | (conf->flags & IEEE80211_CONF_IDLE) && | ||
415 | !priv->listening) { | ||
416 | cw1200_disable_listening(priv); | ||
417 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
418 | } | ||
419 | wsm_set_operational_mode(priv, &mode); | ||
420 | wsm_unlock_tx(priv); | ||
421 | } | ||
422 | |||
423 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | ||
424 | pr_debug("[STA] Retry limits: %d (long), %d (short).\n", | ||
425 | conf->long_frame_max_tx_count, | ||
426 | conf->short_frame_max_tx_count); | ||
427 | spin_lock_bh(&priv->tx_policy_cache.lock); | ||
428 | priv->long_frame_max_tx_count = conf->long_frame_max_tx_count; | ||
429 | priv->short_frame_max_tx_count = | ||
430 | (conf->short_frame_max_tx_count < 0x0F) ? | ||
431 | conf->short_frame_max_tx_count : 0x0F; | ||
432 | priv->hw->max_rate_tries = priv->short_frame_max_tx_count; | ||
433 | spin_unlock_bh(&priv->tx_policy_cache.lock); | ||
434 | } | ||
435 | mutex_unlock(&priv->conf_mutex); | ||
436 | up(&priv->scan.lock); | ||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | void cw1200_update_filtering(struct cw1200_common *priv) | ||
441 | { | ||
442 | int ret; | ||
443 | bool bssid_filtering = !priv->rx_filter.bssid; | ||
444 | bool is_p2p = priv->vif && priv->vif->p2p; | ||
445 | bool is_sta = priv->vif && NL80211_IFTYPE_STATION == priv->vif->type; | ||
446 | |||
447 | static struct wsm_beacon_filter_control bf_ctrl; | ||
448 | static struct wsm_mib_beacon_filter_table bf_tbl = { | ||
449 | .entry[0].ie_id = WLAN_EID_VENDOR_SPECIFIC, | ||
450 | .entry[0].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | | ||
451 | WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | | ||
452 | WSM_BEACON_FILTER_IE_HAS_APPEARED, | ||
453 | .entry[0].oui[0] = 0x50, | ||
454 | .entry[0].oui[1] = 0x6F, | ||
455 | .entry[0].oui[2] = 0x9A, | ||
456 | .entry[1].ie_id = WLAN_EID_HT_OPERATION, | ||
457 | .entry[1].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | | ||
458 | WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | | ||
459 | WSM_BEACON_FILTER_IE_HAS_APPEARED, | ||
460 | .entry[2].ie_id = WLAN_EID_ERP_INFO, | ||
461 | .entry[2].flags = WSM_BEACON_FILTER_IE_HAS_CHANGED | | ||
462 | WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | | ||
463 | WSM_BEACON_FILTER_IE_HAS_APPEARED, | ||
464 | }; | ||
465 | |||
466 | if (priv->join_status == CW1200_JOIN_STATUS_PASSIVE) | ||
467 | return; | ||
468 | else if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) | ||
469 | bssid_filtering = false; | ||
470 | |||
471 | if (priv->disable_beacon_filter) { | ||
472 | bf_ctrl.enabled = 0; | ||
473 | bf_ctrl.bcn_count = 1; | ||
474 | bf_tbl.num = __cpu_to_le32(0); | ||
475 | } else if (is_p2p || !is_sta) { | ||
476 | bf_ctrl.enabled = WSM_BEACON_FILTER_ENABLE | | ||
477 | WSM_BEACON_FILTER_AUTO_ERP; | ||
478 | bf_ctrl.bcn_count = 0; | ||
479 | bf_tbl.num = __cpu_to_le32(2); | ||
480 | } else { | ||
481 | bf_ctrl.enabled = WSM_BEACON_FILTER_ENABLE; | ||
482 | bf_ctrl.bcn_count = 0; | ||
483 | bf_tbl.num = __cpu_to_le32(3); | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * When acting as p2p client being connected to p2p GO, in order to | ||
488 | * receive frames from a different p2p device, turn off bssid filter. | ||
489 | * | ||
490 | * WARNING: FW dependency! | ||
491 | * This can only be used with FW WSM371 and its successors. | ||
492 | * In that FW version even with bssid filter turned off, | ||
493 | * device will block most of the unwanted frames. | ||
494 | */ | ||
495 | if (is_p2p) | ||
496 | bssid_filtering = false; | ||
497 | |||
498 | ret = wsm_set_rx_filter(priv, &priv->rx_filter); | ||
499 | if (!ret) | ||
500 | ret = wsm_set_beacon_filter_table(priv, &bf_tbl); | ||
501 | if (!ret) | ||
502 | ret = wsm_beacon_filter_control(priv, &bf_ctrl); | ||
503 | if (!ret) | ||
504 | ret = wsm_set_bssid_filtering(priv, bssid_filtering); | ||
505 | if (!ret) | ||
506 | ret = wsm_set_multicast_filter(priv, &priv->multicast_filter); | ||
507 | if (ret) | ||
508 | wiphy_err(priv->hw->wiphy, | ||
509 | "Update filtering failed: %d.\n", ret); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | void cw1200_update_filtering_work(struct work_struct *work) | ||
514 | { | ||
515 | struct cw1200_common *priv = | ||
516 | container_of(work, struct cw1200_common, | ||
517 | update_filtering_work); | ||
518 | |||
519 | cw1200_update_filtering(priv); | ||
520 | } | ||
521 | |||
522 | void cw1200_set_beacon_wakeup_period_work(struct work_struct *work) | ||
523 | { | ||
524 | struct cw1200_common *priv = | ||
525 | container_of(work, struct cw1200_common, | ||
526 | set_beacon_wakeup_period_work); | ||
527 | |||
528 | wsm_set_beacon_wakeup_period(priv, | ||
529 | priv->beacon_int * priv->join_dtim_period > | ||
530 | MAX_BEACON_SKIP_TIME_MS ? 1 : | ||
531 | priv->join_dtim_period, 0); | ||
532 | } | ||
533 | |||
534 | u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, | ||
535 | struct netdev_hw_addr_list *mc_list) | ||
536 | { | ||
537 | static u8 broadcast_ipv6[ETH_ALEN] = { | ||
538 | 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 | ||
539 | }; | ||
540 | static u8 broadcast_ipv4[ETH_ALEN] = { | ||
541 | 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01 | ||
542 | }; | ||
543 | struct cw1200_common *priv = hw->priv; | ||
544 | struct netdev_hw_addr *ha; | ||
545 | int count = 0; | ||
546 | |||
547 | /* Disable multicast filtering */ | ||
548 | priv->has_multicast_subscription = false; | ||
549 | memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter)); | ||
550 | |||
551 | if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES) | ||
552 | return 0; | ||
553 | |||
554 | /* Enable if requested */ | ||
555 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
556 | pr_debug("[STA] multicast: %pM\n", ha->addr); | ||
557 | memcpy(&priv->multicast_filter.macaddrs[count], | ||
558 | ha->addr, ETH_ALEN); | ||
559 | if (memcmp(ha->addr, broadcast_ipv4, ETH_ALEN) && | ||
560 | memcmp(ha->addr, broadcast_ipv6, ETH_ALEN)) | ||
561 | priv->has_multicast_subscription = true; | ||
562 | count++; | ||
563 | } | ||
564 | |||
565 | if (count) { | ||
566 | priv->multicast_filter.enable = __cpu_to_le32(1); | ||
567 | priv->multicast_filter.num_addrs = __cpu_to_le32(count); | ||
568 | } | ||
569 | |||
570 | return netdev_hw_addr_list_count(mc_list); | ||
571 | } | ||
572 | |||
573 | void cw1200_configure_filter(struct ieee80211_hw *dev, | ||
574 | unsigned int changed_flags, | ||
575 | unsigned int *total_flags, | ||
576 | u64 multicast) | ||
577 | { | ||
578 | struct cw1200_common *priv = dev->priv; | ||
579 | bool listening = !!(*total_flags & | ||
580 | (FIF_PROMISC_IN_BSS | | ||
581 | FIF_OTHER_BSS | | ||
582 | FIF_BCN_PRBRESP_PROMISC | | ||
583 | FIF_PROBE_REQ)); | ||
584 | |||
585 | *total_flags &= FIF_PROMISC_IN_BSS | | ||
586 | FIF_OTHER_BSS | | ||
587 | FIF_FCSFAIL | | ||
588 | FIF_BCN_PRBRESP_PROMISC | | ||
589 | FIF_PROBE_REQ; | ||
590 | |||
591 | down(&priv->scan.lock); | ||
592 | mutex_lock(&priv->conf_mutex); | ||
593 | |||
594 | priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS) | ||
595 | ? 1 : 0; | ||
596 | priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS | | ||
597 | FIF_PROBE_REQ)) ? 1 : 0; | ||
598 | priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0; | ||
599 | priv->disable_beacon_filter = !(*total_flags & | ||
600 | (FIF_BCN_PRBRESP_PROMISC | | ||
601 | FIF_PROMISC_IN_BSS | | ||
602 | FIF_PROBE_REQ)); | ||
603 | if (priv->listening != listening) { | ||
604 | priv->listening = listening; | ||
605 | wsm_lock_tx(priv); | ||
606 | cw1200_update_listening(priv, listening); | ||
607 | wsm_unlock_tx(priv); | ||
608 | } | ||
609 | cw1200_update_filtering(priv); | ||
610 | mutex_unlock(&priv->conf_mutex); | ||
611 | up(&priv->scan.lock); | ||
612 | } | ||
613 | |||
614 | int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, | ||
615 | u16 queue, const struct ieee80211_tx_queue_params *params) | ||
616 | { | ||
617 | struct cw1200_common *priv = dev->priv; | ||
618 | int ret = 0; | ||
619 | /* To prevent re-applying PM request OID again and again*/ | ||
620 | bool old_uapsd_flags; | ||
621 | |||
622 | mutex_lock(&priv->conf_mutex); | ||
623 | |||
624 | if (queue < dev->queues) { | ||
625 | old_uapsd_flags = priv->uapsd_info.uapsd_flags; | ||
626 | |||
627 | WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0); | ||
628 | ret = wsm_set_tx_queue_params(priv, | ||
629 | &priv->tx_queue_params.params[queue], queue); | ||
630 | if (ret) { | ||
631 | ret = -EINVAL; | ||
632 | goto out; | ||
633 | } | ||
634 | |||
635 | WSM_EDCA_SET(&priv->edca, queue, params->aifs, | ||
636 | params->cw_min, params->cw_max, | ||
637 | params->txop, 0xc8, | ||
638 | params->uapsd); | ||
639 | ret = wsm_set_edca_params(priv, &priv->edca); | ||
640 | if (ret) { | ||
641 | ret = -EINVAL; | ||
642 | goto out; | ||
643 | } | ||
644 | |||
645 | if (priv->mode == NL80211_IFTYPE_STATION) { | ||
646 | ret = cw1200_set_uapsd_param(priv, &priv->edca); | ||
647 | if (!ret && priv->setbssparams_done && | ||
648 | (priv->join_status == CW1200_JOIN_STATUS_STA) && | ||
649 | (old_uapsd_flags != priv->uapsd_info.uapsd_flags)) | ||
650 | ret = cw1200_set_pm(priv, &priv->powersave_mode); | ||
651 | } | ||
652 | } else { | ||
653 | ret = -EINVAL; | ||
654 | } | ||
655 | |||
656 | out: | ||
657 | mutex_unlock(&priv->conf_mutex); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | int cw1200_get_stats(struct ieee80211_hw *dev, | ||
662 | struct ieee80211_low_level_stats *stats) | ||
663 | { | ||
664 | struct cw1200_common *priv = dev->priv; | ||
665 | |||
666 | memcpy(stats, &priv->stats, sizeof(*stats)); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) | ||
671 | { | ||
672 | struct wsm_set_pm pm = *arg; | ||
673 | |||
674 | if (priv->uapsd_info.uapsd_flags != 0) | ||
675 | pm.mode &= ~WSM_PSM_FAST_PS_FLAG; | ||
676 | |||
677 | if (memcmp(&pm, &priv->firmware_ps_mode, | ||
678 | sizeof(struct wsm_set_pm))) { | ||
679 | priv->firmware_ps_mode = pm; | ||
680 | return wsm_set_pm(priv, &pm); | ||
681 | } else { | ||
682 | return 0; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | ||
687 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
688 | struct ieee80211_key_conf *key) | ||
689 | { | ||
690 | int ret = -EOPNOTSUPP; | ||
691 | struct cw1200_common *priv = dev->priv; | ||
692 | struct ieee80211_key_seq seq; | ||
693 | |||
694 | mutex_lock(&priv->conf_mutex); | ||
695 | |||
696 | if (cmd == SET_KEY) { | ||
697 | u8 *peer_addr = NULL; | ||
698 | int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? | ||
699 | 1 : 0; | ||
700 | int idx = cw1200_alloc_key(priv); | ||
701 | struct wsm_add_key *wsm_key = &priv->keys[idx]; | ||
702 | |||
703 | if (idx < 0) { | ||
704 | ret = -EINVAL; | ||
705 | goto finally; | ||
706 | } | ||
707 | |||
708 | if (sta) | ||
709 | peer_addr = sta->addr; | ||
710 | |||
711 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; | ||
712 | |||
713 | switch (key->cipher) { | ||
714 | case WLAN_CIPHER_SUITE_WEP40: | ||
715 | case WLAN_CIPHER_SUITE_WEP104: | ||
716 | if (key->keylen > 16) { | ||
717 | cw1200_free_key(priv, idx); | ||
718 | ret = -EINVAL; | ||
719 | goto finally; | ||
720 | } | ||
721 | |||
722 | if (pairwise) { | ||
723 | wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; | ||
724 | memcpy(wsm_key->wep_pairwise.peer, | ||
725 | peer_addr, ETH_ALEN); | ||
726 | memcpy(wsm_key->wep_pairwise.keydata, | ||
727 | &key->key[0], key->keylen); | ||
728 | wsm_key->wep_pairwise.keylen = key->keylen; | ||
729 | } else { | ||
730 | wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; | ||
731 | memcpy(wsm_key->wep_group.keydata, | ||
732 | &key->key[0], key->keylen); | ||
733 | wsm_key->wep_group.keylen = key->keylen; | ||
734 | wsm_key->wep_group.keyid = key->keyidx; | ||
735 | } | ||
736 | break; | ||
737 | case WLAN_CIPHER_SUITE_TKIP: | ||
738 | ieee80211_get_key_rx_seq(key, 0, &seq); | ||
739 | if (pairwise) { | ||
740 | wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; | ||
741 | memcpy(wsm_key->tkip_pairwise.peer, | ||
742 | peer_addr, ETH_ALEN); | ||
743 | memcpy(wsm_key->tkip_pairwise.keydata, | ||
744 | &key->key[0], 16); | ||
745 | memcpy(wsm_key->tkip_pairwise.tx_mic_key, | ||
746 | &key->key[16], 8); | ||
747 | memcpy(wsm_key->tkip_pairwise.rx_mic_key, | ||
748 | &key->key[24], 8); | ||
749 | } else { | ||
750 | size_t mic_offset = | ||
751 | (priv->mode == NL80211_IFTYPE_AP) ? | ||
752 | 16 : 24; | ||
753 | wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; | ||
754 | memcpy(wsm_key->tkip_group.keydata, | ||
755 | &key->key[0], 16); | ||
756 | memcpy(wsm_key->tkip_group.rx_mic_key, | ||
757 | &key->key[mic_offset], 8); | ||
758 | |||
759 | wsm_key->tkip_group.rx_seqnum[0] = seq.tkip.iv16 & 0xff; | ||
760 | wsm_key->tkip_group.rx_seqnum[1] = (seq.tkip.iv16 >> 8) & 0xff; | ||
761 | wsm_key->tkip_group.rx_seqnum[2] = seq.tkip.iv32 & 0xff; | ||
762 | wsm_key->tkip_group.rx_seqnum[3] = (seq.tkip.iv32 >> 8) & 0xff; | ||
763 | wsm_key->tkip_group.rx_seqnum[4] = (seq.tkip.iv32 >> 16) & 0xff; | ||
764 | wsm_key->tkip_group.rx_seqnum[5] = (seq.tkip.iv32 >> 24) & 0xff; | ||
765 | wsm_key->tkip_group.rx_seqnum[6] = 0; | ||
766 | wsm_key->tkip_group.rx_seqnum[7] = 0; | ||
767 | |||
768 | wsm_key->tkip_group.keyid = key->keyidx; | ||
769 | } | ||
770 | break; | ||
771 | case WLAN_CIPHER_SUITE_CCMP: | ||
772 | ieee80211_get_key_rx_seq(key, 0, &seq); | ||
773 | if (pairwise) { | ||
774 | wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; | ||
775 | memcpy(wsm_key->aes_pairwise.peer, | ||
776 | peer_addr, ETH_ALEN); | ||
777 | memcpy(wsm_key->aes_pairwise.keydata, | ||
778 | &key->key[0], 16); | ||
779 | } else { | ||
780 | wsm_key->type = WSM_KEY_TYPE_AES_GROUP; | ||
781 | memcpy(wsm_key->aes_group.keydata, | ||
782 | &key->key[0], 16); | ||
783 | |||
784 | wsm_key->aes_group.rx_seqnum[0] = seq.ccmp.pn[5]; | ||
785 | wsm_key->aes_group.rx_seqnum[1] = seq.ccmp.pn[4]; | ||
786 | wsm_key->aes_group.rx_seqnum[2] = seq.ccmp.pn[3]; | ||
787 | wsm_key->aes_group.rx_seqnum[3] = seq.ccmp.pn[2]; | ||
788 | wsm_key->aes_group.rx_seqnum[4] = seq.ccmp.pn[1]; | ||
789 | wsm_key->aes_group.rx_seqnum[5] = seq.ccmp.pn[0]; | ||
790 | wsm_key->aes_group.rx_seqnum[6] = 0; | ||
791 | wsm_key->aes_group.rx_seqnum[7] = 0; | ||
792 | wsm_key->aes_group.keyid = key->keyidx; | ||
793 | } | ||
794 | break; | ||
795 | case WLAN_CIPHER_SUITE_SMS4: | ||
796 | if (pairwise) { | ||
797 | wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; | ||
798 | memcpy(wsm_key->wapi_pairwise.peer, | ||
799 | peer_addr, ETH_ALEN); | ||
800 | memcpy(wsm_key->wapi_pairwise.keydata, | ||
801 | &key->key[0], 16); | ||
802 | memcpy(wsm_key->wapi_pairwise.mic_key, | ||
803 | &key->key[16], 16); | ||
804 | wsm_key->wapi_pairwise.keyid = key->keyidx; | ||
805 | } else { | ||
806 | wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; | ||
807 | memcpy(wsm_key->wapi_group.keydata, | ||
808 | &key->key[0], 16); | ||
809 | memcpy(wsm_key->wapi_group.mic_key, | ||
810 | &key->key[16], 16); | ||
811 | wsm_key->wapi_group.keyid = key->keyidx; | ||
812 | } | ||
813 | break; | ||
814 | default: | ||
815 | pr_warn("Unhandled key type %d\n", key->cipher); | ||
816 | cw1200_free_key(priv, idx); | ||
817 | ret = -EOPNOTSUPP; | ||
818 | goto finally; | ||
819 | } | ||
820 | ret = wsm_add_key(priv, wsm_key); | ||
821 | if (!ret) | ||
822 | key->hw_key_idx = idx; | ||
823 | else | ||
824 | cw1200_free_key(priv, idx); | ||
825 | } else if (cmd == DISABLE_KEY) { | ||
826 | struct wsm_remove_key wsm_key = { | ||
827 | .index = key->hw_key_idx, | ||
828 | }; | ||
829 | |||
830 | if (wsm_key.index > WSM_KEY_MAX_INDEX) { | ||
831 | ret = -EINVAL; | ||
832 | goto finally; | ||
833 | } | ||
834 | |||
835 | cw1200_free_key(priv, wsm_key.index); | ||
836 | ret = wsm_remove_key(priv, &wsm_key); | ||
837 | } else { | ||
838 | pr_warn("Unhandled key command %d\n", cmd); | ||
839 | } | ||
840 | |||
841 | finally: | ||
842 | mutex_unlock(&priv->conf_mutex); | ||
843 | return ret; | ||
844 | } | ||
845 | |||
846 | void cw1200_wep_key_work(struct work_struct *work) | ||
847 | { | ||
848 | struct cw1200_common *priv = | ||
849 | container_of(work, struct cw1200_common, wep_key_work); | ||
850 | u8 queue_id = cw1200_queue_get_queue_id(priv->pending_frame_id); | ||
851 | struct cw1200_queue *queue = &priv->tx_queue[queue_id]; | ||
852 | __le32 wep_default_key_id = __cpu_to_le32( | ||
853 | priv->wep_default_key_id); | ||
854 | |||
855 | pr_debug("[STA] Setting default WEP key: %d\n", | ||
856 | priv->wep_default_key_id); | ||
857 | wsm_flush_tx(priv); | ||
858 | wsm_write_mib(priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, | ||
859 | &wep_default_key_id, sizeof(wep_default_key_id)); | ||
860 | cw1200_queue_requeue(queue, priv->pending_frame_id); | ||
861 | wsm_unlock_tx(priv); | ||
862 | } | ||
863 | |||
864 | int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
865 | { | ||
866 | int ret = 0; | ||
867 | __le32 val32; | ||
868 | struct cw1200_common *priv = hw->priv; | ||
869 | |||
870 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
871 | return 0; | ||
872 | |||
873 | if (value != (u32) -1) | ||
874 | val32 = __cpu_to_le32(value); | ||
875 | else | ||
876 | val32 = 0; /* disabled */ | ||
877 | |||
878 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
879 | /* device is down, can _not_ set threshold */ | ||
880 | ret = -ENODEV; | ||
881 | goto out; | ||
882 | } | ||
883 | |||
884 | if (priv->rts_threshold == value) | ||
885 | goto out; | ||
886 | |||
887 | pr_debug("[STA] Setting RTS threshold: %d\n", | ||
888 | priv->rts_threshold); | ||
889 | |||
890 | /* mutex_lock(&priv->conf_mutex); */ | ||
891 | ret = wsm_write_mib(priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD, | ||
892 | &val32, sizeof(val32)); | ||
893 | if (!ret) | ||
894 | priv->rts_threshold = value; | ||
895 | /* mutex_unlock(&priv->conf_mutex); */ | ||
896 | |||
897 | out: | ||
898 | return ret; | ||
899 | } | ||
900 | |||
901 | /* If successful, LOCKS the TX queue! */ | ||
902 | static int __cw1200_flush(struct cw1200_common *priv, bool drop) | ||
903 | { | ||
904 | int i, ret; | ||
905 | |||
906 | for (;;) { | ||
907 | /* TODO: correct flush handling is required when dev_stop. | ||
908 | * Temporary workaround: 2s | ||
909 | */ | ||
910 | if (drop) { | ||
911 | for (i = 0; i < 4; ++i) | ||
912 | cw1200_queue_clear(&priv->tx_queue[i]); | ||
913 | } else { | ||
914 | ret = wait_event_timeout( | ||
915 | priv->tx_queue_stats.wait_link_id_empty, | ||
916 | cw1200_queue_stats_is_empty( | ||
917 | &priv->tx_queue_stats, -1), | ||
918 | 2 * HZ); | ||
919 | } | ||
920 | |||
921 | if (!drop && ret <= 0) { | ||
922 | ret = -ETIMEDOUT; | ||
923 | break; | ||
924 | } else { | ||
925 | ret = 0; | ||
926 | } | ||
927 | |||
928 | wsm_lock_tx(priv); | ||
929 | if (!cw1200_queue_stats_is_empty(&priv->tx_queue_stats, -1)) { | ||
930 | /* Highly unlikely: WSM requeued frames. */ | ||
931 | wsm_unlock_tx(priv); | ||
932 | continue; | ||
933 | } | ||
934 | break; | ||
935 | } | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop) | ||
940 | { | ||
941 | struct cw1200_common *priv = hw->priv; | ||
942 | |||
943 | switch (priv->mode) { | ||
944 | case NL80211_IFTYPE_MONITOR: | ||
945 | drop = true; | ||
946 | break; | ||
947 | case NL80211_IFTYPE_AP: | ||
948 | if (!priv->enable_beacon) | ||
949 | drop = true; | ||
950 | break; | ||
951 | } | ||
952 | |||
953 | if (!__cw1200_flush(priv, drop)) | ||
954 | wsm_unlock_tx(priv); | ||
955 | |||
956 | return; | ||
957 | } | ||
958 | |||
959 | /* ******************************************************************** */ | ||
960 | /* WSM callbacks */ | ||
961 | |||
962 | void cw1200_free_event_queue(struct cw1200_common *priv) | ||
963 | { | ||
964 | LIST_HEAD(list); | ||
965 | |||
966 | spin_lock(&priv->event_queue_lock); | ||
967 | list_splice_init(&priv->event_queue, &list); | ||
968 | spin_unlock(&priv->event_queue_lock); | ||
969 | |||
970 | __cw1200_free_event_queue(&list); | ||
971 | } | ||
972 | |||
973 | void cw1200_event_handler(struct work_struct *work) | ||
974 | { | ||
975 | struct cw1200_common *priv = | ||
976 | container_of(work, struct cw1200_common, event_handler); | ||
977 | struct cw1200_wsm_event *event; | ||
978 | LIST_HEAD(list); | ||
979 | |||
980 | spin_lock(&priv->event_queue_lock); | ||
981 | list_splice_init(&priv->event_queue, &list); | ||
982 | spin_unlock(&priv->event_queue_lock); | ||
983 | |||
984 | list_for_each_entry(event, &list, link) { | ||
985 | switch (event->evt.id) { | ||
986 | case WSM_EVENT_ERROR: | ||
987 | pr_err("Unhandled WSM Error from LMAC\n"); | ||
988 | break; | ||
989 | case WSM_EVENT_BSS_LOST: | ||
990 | pr_debug("[CQM] BSS lost.\n"); | ||
991 | cancel_work_sync(&priv->unjoin_work); | ||
992 | if (!down_trylock(&priv->scan.lock)) { | ||
993 | cw1200_cqm_bssloss_sm(priv, 1, 0, 0); | ||
994 | up(&priv->scan.lock); | ||
995 | } else { | ||
996 | /* Scan is in progress. Delay reporting. | ||
997 | * Scan complete will trigger bss_loss_work | ||
998 | */ | ||
999 | priv->delayed_link_loss = 1; | ||
1000 | /* Also start a watchdog. */ | ||
1001 | queue_delayed_work(priv->workqueue, | ||
1002 | &priv->bss_loss_work, 5*HZ); | ||
1003 | } | ||
1004 | break; | ||
1005 | case WSM_EVENT_BSS_REGAINED: | ||
1006 | pr_debug("[CQM] BSS regained.\n"); | ||
1007 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1008 | cancel_work_sync(&priv->unjoin_work); | ||
1009 | break; | ||
1010 | case WSM_EVENT_RADAR_DETECTED: | ||
1011 | wiphy_info(priv->hw->wiphy, "radar pulse detected\n"); | ||
1012 | break; | ||
1013 | case WSM_EVENT_RCPI_RSSI: | ||
1014 | { | ||
1015 | /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 | ||
1016 | * RSSI = RCPI / 2 - 110 | ||
1017 | */ | ||
1018 | int rcpiRssi = (int)(event->evt.data & 0xFF); | ||
1019 | int cqm_evt; | ||
1020 | if (priv->cqm_use_rssi) | ||
1021 | rcpiRssi = (s8)rcpiRssi; | ||
1022 | else | ||
1023 | rcpiRssi = rcpiRssi / 2 - 110; | ||
1024 | |||
1025 | cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ? | ||
1026 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : | ||
1027 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | ||
1028 | pr_debug("[CQM] RSSI event: %d.\n", rcpiRssi); | ||
1029 | ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, | ||
1030 | GFP_KERNEL); | ||
1031 | break; | ||
1032 | } | ||
1033 | case WSM_EVENT_BT_INACTIVE: | ||
1034 | pr_warn("Unhandled BT INACTIVE from LMAC\n"); | ||
1035 | break; | ||
1036 | case WSM_EVENT_BT_ACTIVE: | ||
1037 | pr_warn("Unhandled BT ACTIVE from LMAC\n"); | ||
1038 | break; | ||
1039 | } | ||
1040 | } | ||
1041 | __cw1200_free_event_queue(&list); | ||
1042 | } | ||
1043 | |||
1044 | void cw1200_bss_loss_work(struct work_struct *work) | ||
1045 | { | ||
1046 | struct cw1200_common *priv = | ||
1047 | container_of(work, struct cw1200_common, bss_loss_work.work); | ||
1048 | |||
1049 | pr_debug("[CQM] Reporting connection loss.\n"); | ||
1050 | wsm_lock_tx(priv); | ||
1051 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1052 | wsm_unlock_tx(priv); | ||
1053 | } | ||
1054 | |||
1055 | void cw1200_bss_params_work(struct work_struct *work) | ||
1056 | { | ||
1057 | struct cw1200_common *priv = | ||
1058 | container_of(work, struct cw1200_common, bss_params_work); | ||
1059 | mutex_lock(&priv->conf_mutex); | ||
1060 | |||
1061 | priv->bss_params.reset_beacon_loss = 1; | ||
1062 | wsm_set_bss_params(priv, &priv->bss_params); | ||
1063 | priv->bss_params.reset_beacon_loss = 0; | ||
1064 | |||
1065 | mutex_unlock(&priv->conf_mutex); | ||
1066 | } | ||
1067 | |||
1068 | /* ******************************************************************** */ | ||
1069 | /* Internal API */ | ||
1070 | |||
1071 | /* | ||
1072 | * This function is called to Parse the SDD file | ||
1073 | * to extract listen_interval and PTA related information | ||
1074 | * sdd is a TLV: u8 id, u8 len, u8 data[] | ||
1075 | */ | ||
1076 | static int cw1200_parse_sdd_file(struct cw1200_common *priv) | ||
1077 | { | ||
1078 | const u8 *p = priv->sdd->data; | ||
1079 | int ret = 0; | ||
1080 | |||
1081 | while (p + 2 <= priv->sdd->data + priv->sdd->size) { | ||
1082 | if (p + p[1] + 2 > priv->sdd->data + priv->sdd->size) { | ||
1083 | pr_warn("Malformed sdd structure\n"); | ||
1084 | return -1; | ||
1085 | } | ||
1086 | switch (p[0]) { | ||
1087 | case SDD_PTA_CFG_ELT_ID: { | ||
1088 | u16 v; | ||
1089 | if (p[1] < 4) { | ||
1090 | pr_warn("SDD_PTA_CFG_ELT_ID malformed\n"); | ||
1091 | ret = -1; | ||
1092 | break; | ||
1093 | } | ||
1094 | v = le16_to_cpu(*((u16 *)(p + 2))); | ||
1095 | if (!v) /* non-zero means this is enabled */ | ||
1096 | break; | ||
1097 | |||
1098 | v = le16_to_cpu(*((u16 *)(p + 4))); | ||
1099 | priv->conf_listen_interval = (v >> 7) & 0x1F; | ||
1100 | pr_debug("PTA found; Listen Interval %d\n", | ||
1101 | priv->conf_listen_interval); | ||
1102 | break; | ||
1103 | } | ||
1104 | case SDD_REFERENCE_FREQUENCY_ELT_ID: { | ||
1105 | u16 clk = le16_to_cpu(*((u16 *)(p + 2))); | ||
1106 | if (clk != priv->hw_refclk) | ||
1107 | pr_warn("SDD file doesn't match configured refclk (%d vs %d)\n", | ||
1108 | clk, priv->hw_refclk); | ||
1109 | break; | ||
1110 | } | ||
1111 | default: | ||
1112 | break; | ||
1113 | } | ||
1114 | p += p[1] + 2; | ||
1115 | } | ||
1116 | |||
1117 | if (!priv->bt_present) { | ||
1118 | pr_debug("PTA element NOT found.\n"); | ||
1119 | priv->conf_listen_interval = 0; | ||
1120 | } | ||
1121 | return ret; | ||
1122 | } | ||
1123 | |||
1124 | int cw1200_setup_mac(struct cw1200_common *priv) | ||
1125 | { | ||
1126 | int ret = 0; | ||
1127 | |||
1128 | /* NOTE: There is a bug in FW: it reports signal | ||
1129 | * as RSSI if RSSI subscription is enabled. | ||
1130 | * It's not enough to set WSM_RCPI_RSSI_USE_RSSI. | ||
1131 | * | ||
1132 | * NOTE2: RSSI based reports have been switched to RCPI, since | ||
1133 | * FW has a bug and RSSI reported values are not stable, | ||
1134 | * what can leads to signal level oscilations in user-end applications | ||
1135 | */ | ||
1136 | struct wsm_rcpi_rssi_threshold threshold = { | ||
1137 | .rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE | | ||
1138 | WSM_RCPI_RSSI_DONT_USE_UPPER | | ||
1139 | WSM_RCPI_RSSI_DONT_USE_LOWER, | ||
1140 | .rollingAverageCount = 16, | ||
1141 | }; | ||
1142 | |||
1143 | struct wsm_configuration cfg = { | ||
1144 | .dot11StationId = &priv->mac_addr[0], | ||
1145 | }; | ||
1146 | |||
1147 | /* Remember the decission here to make sure, we will handle | ||
1148 | * the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS | ||
1149 | */ | ||
1150 | if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI) | ||
1151 | priv->cqm_use_rssi = true; | ||
1152 | |||
1153 | if (!priv->sdd) { | ||
1154 | ret = request_firmware(&priv->sdd, priv->sdd_path, priv->pdev); | ||
1155 | if (ret) { | ||
1156 | pr_err("Can't load sdd file %s.\n", priv->sdd_path); | ||
1157 | return ret; | ||
1158 | } | ||
1159 | cw1200_parse_sdd_file(priv); | ||
1160 | } | ||
1161 | |||
1162 | cfg.dpdData = priv->sdd->data; | ||
1163 | cfg.dpdData_size = priv->sdd->size; | ||
1164 | ret = wsm_configuration(priv, &cfg); | ||
1165 | if (ret) | ||
1166 | return ret; | ||
1167 | |||
1168 | /* Configure RSSI/SCPI reporting as RSSI. */ | ||
1169 | wsm_set_rcpi_rssi_threshold(priv, &threshold); | ||
1170 | |||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | static void cw1200_join_complete(struct cw1200_common *priv) | ||
1175 | { | ||
1176 | pr_debug("[STA] Join complete (%d)\n", priv->join_complete_status); | ||
1177 | |||
1178 | priv->join_pending = false; | ||
1179 | if (priv->join_complete_status) { | ||
1180 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1181 | cw1200_update_listening(priv, priv->listening); | ||
1182 | cw1200_do_unjoin(priv); | ||
1183 | ieee80211_connection_loss(priv->vif); | ||
1184 | } else { | ||
1185 | if (priv->mode == NL80211_IFTYPE_ADHOC) | ||
1186 | priv->join_status = CW1200_JOIN_STATUS_IBSS; | ||
1187 | else | ||
1188 | priv->join_status = CW1200_JOIN_STATUS_PRE_STA; | ||
1189 | } | ||
1190 | wsm_unlock_tx(priv); /* Clearing the lock held before do_join() */ | ||
1191 | } | ||
1192 | |||
1193 | void cw1200_join_complete_work(struct work_struct *work) | ||
1194 | { | ||
1195 | struct cw1200_common *priv = | ||
1196 | container_of(work, struct cw1200_common, join_complete_work); | ||
1197 | mutex_lock(&priv->conf_mutex); | ||
1198 | cw1200_join_complete(priv); | ||
1199 | mutex_unlock(&priv->conf_mutex); | ||
1200 | } | ||
1201 | |||
1202 | void cw1200_join_complete_cb(struct cw1200_common *priv, | ||
1203 | struct wsm_join_complete *arg) | ||
1204 | { | ||
1205 | pr_debug("[STA] cw1200_join_complete_cb called, status=%d.\n", | ||
1206 | arg->status); | ||
1207 | |||
1208 | if (cancel_delayed_work(&priv->join_timeout)) { | ||
1209 | priv->join_complete_status = arg->status; | ||
1210 | queue_work(priv->workqueue, &priv->join_complete_work); | ||
1211 | } | ||
1212 | } | ||
1213 | |||
1214 | /* MUST be called with tx_lock held! It will be unlocked for us. */ | ||
1215 | static void cw1200_do_join(struct cw1200_common *priv) | ||
1216 | { | ||
1217 | const u8 *bssid; | ||
1218 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
1219 | struct cfg80211_bss *bss = NULL; | ||
1220 | struct wsm_protected_mgmt_policy mgmt_policy; | ||
1221 | struct wsm_join join = { | ||
1222 | .mode = conf->ibss_joined ? | ||
1223 | WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, | ||
1224 | .preamble_type = WSM_JOIN_PREAMBLE_LONG, | ||
1225 | .probe_for_join = 1, | ||
1226 | .atim_window = 0, | ||
1227 | .basic_rate_set = cw1200_rate_mask_to_wsm(priv, | ||
1228 | conf->basic_rates), | ||
1229 | }; | ||
1230 | if (delayed_work_pending(&priv->join_timeout)) { | ||
1231 | pr_warn("[STA] - Join request already pending, skipping..\n"); | ||
1232 | wsm_unlock_tx(priv); | ||
1233 | return; | ||
1234 | } | ||
1235 | |||
1236 | if (priv->join_status) | ||
1237 | cw1200_do_unjoin(priv); | ||
1238 | |||
1239 | bssid = priv->vif->bss_conf.bssid; | ||
1240 | |||
1241 | bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, | ||
1242 | bssid, NULL, 0, 0, 0); | ||
1243 | |||
1244 | if (!bss && !conf->ibss_joined) { | ||
1245 | wsm_unlock_tx(priv); | ||
1246 | return; | ||
1247 | } | ||
1248 | |||
1249 | mutex_lock(&priv->conf_mutex); | ||
1250 | |||
1251 | /* Under the conf lock: check scan status and | ||
1252 | * bail out if it is in progress. | ||
1253 | */ | ||
1254 | if (atomic_read(&priv->scan.in_progress)) { | ||
1255 | wsm_unlock_tx(priv); | ||
1256 | goto done_put; | ||
1257 | } | ||
1258 | |||
1259 | priv->join_pending = true; | ||
1260 | |||
1261 | /* Sanity check basic rates */ | ||
1262 | if (!join.basic_rate_set) | ||
1263 | join.basic_rate_set = 7; | ||
1264 | |||
1265 | /* Sanity check beacon interval */ | ||
1266 | if (!priv->beacon_int) | ||
1267 | priv->beacon_int = 1; | ||
1268 | |||
1269 | join.beacon_interval = priv->beacon_int; | ||
1270 | |||
1271 | /* BT Coex related changes */ | ||
1272 | if (priv->bt_present) { | ||
1273 | if (((priv->conf_listen_interval * 100) % | ||
1274 | priv->beacon_int) == 0) | ||
1275 | priv->listen_interval = | ||
1276 | ((priv->conf_listen_interval * 100) / | ||
1277 | priv->beacon_int); | ||
1278 | else | ||
1279 | priv->listen_interval = | ||
1280 | ((priv->conf_listen_interval * 100) / | ||
1281 | priv->beacon_int + 1); | ||
1282 | } | ||
1283 | |||
1284 | if (priv->hw->conf.ps_dtim_period) | ||
1285 | priv->join_dtim_period = priv->hw->conf.ps_dtim_period; | ||
1286 | join.dtim_period = priv->join_dtim_period; | ||
1287 | |||
1288 | join.channel_number = priv->channel->hw_value; | ||
1289 | join.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? | ||
1290 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; | ||
1291 | |||
1292 | memcpy(join.bssid, bssid, sizeof(join.bssid)); | ||
1293 | |||
1294 | pr_debug("[STA] Join BSSID: %pM DTIM: %d, interval: %d\n", | ||
1295 | join.bssid, | ||
1296 | join.dtim_period, priv->beacon_int); | ||
1297 | |||
1298 | if (!conf->ibss_joined) { | ||
1299 | const u8 *ssidie; | ||
1300 | rcu_read_lock(); | ||
1301 | ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | ||
1302 | if (ssidie) { | ||
1303 | join.ssid_len = ssidie[1]; | ||
1304 | memcpy(join.ssid, &ssidie[2], join.ssid_len); | ||
1305 | } | ||
1306 | rcu_read_unlock(); | ||
1307 | } | ||
1308 | |||
1309 | if (priv->vif->p2p) { | ||
1310 | join.flags |= WSM_JOIN_FLAGS_P2P_GO; | ||
1311 | join.basic_rate_set = | ||
1312 | cw1200_rate_mask_to_wsm(priv, 0xFF0); | ||
1313 | } | ||
1314 | |||
1315 | /* Enable asynchronous join calls */ | ||
1316 | if (!conf->ibss_joined) { | ||
1317 | join.flags |= WSM_JOIN_FLAGS_FORCE; | ||
1318 | join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND; | ||
1319 | } | ||
1320 | |||
1321 | wsm_flush_tx(priv); | ||
1322 | |||
1323 | /* Stay Awake for Join and Auth Timeouts and a bit more */ | ||
1324 | cw1200_pm_stay_awake(&priv->pm_state, | ||
1325 | CW1200_JOIN_TIMEOUT + CW1200_AUTH_TIMEOUT); | ||
1326 | |||
1327 | cw1200_update_listening(priv, false); | ||
1328 | |||
1329 | /* Turn on Block ACKs */ | ||
1330 | wsm_set_block_ack_policy(priv, priv->ba_tx_tid_mask, | ||
1331 | priv->ba_rx_tid_mask); | ||
1332 | |||
1333 | /* Set up timeout */ | ||
1334 | if (join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND) { | ||
1335 | priv->join_status = CW1200_JOIN_STATUS_JOINING; | ||
1336 | queue_delayed_work(priv->workqueue, | ||
1337 | &priv->join_timeout, | ||
1338 | CW1200_JOIN_TIMEOUT); | ||
1339 | } | ||
1340 | |||
1341 | /* 802.11w protected mgmt frames */ | ||
1342 | mgmt_policy.protectedMgmtEnable = 0; | ||
1343 | mgmt_policy.unprotectedMgmtFramesAllowed = 1; | ||
1344 | mgmt_policy.encryptionForAuthFrame = 1; | ||
1345 | wsm_set_protected_mgmt_policy(priv, &mgmt_policy); | ||
1346 | |||
1347 | /* Perform actual join */ | ||
1348 | if (wsm_join(priv, &join)) { | ||
1349 | pr_err("[STA] cw1200_join_work: wsm_join failed!\n"); | ||
1350 | cancel_delayed_work_sync(&priv->join_timeout); | ||
1351 | cw1200_update_listening(priv, priv->listening); | ||
1352 | /* Tx lock still held, unjoin will clear it. */ | ||
1353 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1354 | wsm_unlock_tx(priv); | ||
1355 | } else { | ||
1356 | if (!(join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND)) | ||
1357 | cw1200_join_complete(priv); /* Will clear tx_lock */ | ||
1358 | |||
1359 | /* Upload keys */ | ||
1360 | cw1200_upload_keys(priv); | ||
1361 | |||
1362 | /* Due to beacon filtering it is possible that the | ||
1363 | * AP's beacon is not known for the mac80211 stack. | ||
1364 | * Disable filtering temporary to make sure the stack | ||
1365 | * receives at least one | ||
1366 | */ | ||
1367 | priv->disable_beacon_filter = true; | ||
1368 | } | ||
1369 | cw1200_update_filtering(priv); | ||
1370 | |||
1371 | done_put: | ||
1372 | mutex_unlock(&priv->conf_mutex); | ||
1373 | if (bss) | ||
1374 | cfg80211_put_bss(priv->hw->wiphy, bss); | ||
1375 | } | ||
1376 | |||
1377 | void cw1200_join_timeout(struct work_struct *work) | ||
1378 | { | ||
1379 | struct cw1200_common *priv = | ||
1380 | container_of(work, struct cw1200_common, join_timeout.work); | ||
1381 | pr_debug("[WSM] Join timed out.\n"); | ||
1382 | wsm_lock_tx(priv); | ||
1383 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1384 | wsm_unlock_tx(priv); | ||
1385 | } | ||
1386 | |||
1387 | static void cw1200_do_unjoin(struct cw1200_common *priv) | ||
1388 | { | ||
1389 | struct wsm_reset reset = { | ||
1390 | .reset_statistics = true, | ||
1391 | }; | ||
1392 | |||
1393 | cancel_delayed_work_sync(&priv->join_timeout); | ||
1394 | |||
1395 | mutex_lock(&priv->conf_mutex); | ||
1396 | priv->join_pending = false; | ||
1397 | |||
1398 | if (atomic_read(&priv->scan.in_progress)) { | ||
1399 | if (priv->delayed_unjoin) | ||
1400 | wiphy_dbg(priv->hw->wiphy, "Delayed unjoin is already scheduled.\n"); | ||
1401 | else | ||
1402 | priv->delayed_unjoin = true; | ||
1403 | goto done; | ||
1404 | } | ||
1405 | |||
1406 | priv->delayed_link_loss = false; | ||
1407 | |||
1408 | if (!priv->join_status) | ||
1409 | goto done; | ||
1410 | |||
1411 | if (priv->join_status > CW1200_JOIN_STATUS_IBSS) { | ||
1412 | wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n", | ||
1413 | priv->join_status); | ||
1414 | BUG_ON(1); | ||
1415 | } | ||
1416 | |||
1417 | cancel_work_sync(&priv->update_filtering_work); | ||
1418 | cancel_work_sync(&priv->set_beacon_wakeup_period_work); | ||
1419 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1420 | |||
1421 | /* Unjoin is a reset. */ | ||
1422 | wsm_flush_tx(priv); | ||
1423 | wsm_keep_alive_period(priv, 0); | ||
1424 | wsm_reset(priv, &reset); | ||
1425 | wsm_set_output_power(priv, priv->output_power * 10); | ||
1426 | priv->join_dtim_period = 0; | ||
1427 | cw1200_setup_mac(priv); | ||
1428 | cw1200_free_event_queue(priv); | ||
1429 | cancel_work_sync(&priv->event_handler); | ||
1430 | cw1200_update_listening(priv, priv->listening); | ||
1431 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1432 | |||
1433 | /* Disable Block ACKs */ | ||
1434 | wsm_set_block_ack_policy(priv, 0, 0); | ||
1435 | |||
1436 | priv->disable_beacon_filter = false; | ||
1437 | cw1200_update_filtering(priv); | ||
1438 | memset(&priv->association_mode, 0, | ||
1439 | sizeof(priv->association_mode)); | ||
1440 | memset(&priv->bss_params, 0, sizeof(priv->bss_params)); | ||
1441 | priv->setbssparams_done = false; | ||
1442 | memset(&priv->firmware_ps_mode, 0, | ||
1443 | sizeof(priv->firmware_ps_mode)); | ||
1444 | |||
1445 | pr_debug("[STA] Unjoin completed.\n"); | ||
1446 | |||
1447 | done: | ||
1448 | mutex_unlock(&priv->conf_mutex); | ||
1449 | } | ||
1450 | |||
1451 | void cw1200_unjoin_work(struct work_struct *work) | ||
1452 | { | ||
1453 | struct cw1200_common *priv = | ||
1454 | container_of(work, struct cw1200_common, unjoin_work); | ||
1455 | |||
1456 | cw1200_do_unjoin(priv); | ||
1457 | |||
1458 | /* Tell the stack we're dead */ | ||
1459 | ieee80211_connection_loss(priv->vif); | ||
1460 | |||
1461 | wsm_unlock_tx(priv); | ||
1462 | } | ||
1463 | |||
1464 | int cw1200_enable_listening(struct cw1200_common *priv) | ||
1465 | { | ||
1466 | struct wsm_start start = { | ||
1467 | .mode = WSM_START_MODE_P2P_DEV, | ||
1468 | .band = WSM_PHY_BAND_2_4G, | ||
1469 | .beacon_interval = 100, | ||
1470 | .dtim_period = 1, | ||
1471 | .probe_delay = 0, | ||
1472 | .basic_rate_set = 0x0F, | ||
1473 | }; | ||
1474 | |||
1475 | if (priv->channel) { | ||
1476 | start.band = priv->channel->band == IEEE80211_BAND_5GHZ ? | ||
1477 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; | ||
1478 | start.channel_number = priv->channel->hw_value; | ||
1479 | } else { | ||
1480 | start.band = WSM_PHY_BAND_2_4G; | ||
1481 | start.channel_number = 1; | ||
1482 | } | ||
1483 | |||
1484 | return wsm_start(priv, &start); | ||
1485 | } | ||
1486 | |||
1487 | int cw1200_disable_listening(struct cw1200_common *priv) | ||
1488 | { | ||
1489 | int ret; | ||
1490 | struct wsm_reset reset = { | ||
1491 | .reset_statistics = true, | ||
1492 | }; | ||
1493 | ret = wsm_reset(priv, &reset); | ||
1494 | return ret; | ||
1495 | } | ||
1496 | |||
1497 | void cw1200_update_listening(struct cw1200_common *priv, bool enabled) | ||
1498 | { | ||
1499 | if (enabled) { | ||
1500 | if (priv->join_status == CW1200_JOIN_STATUS_PASSIVE) { | ||
1501 | if (!cw1200_enable_listening(priv)) | ||
1502 | priv->join_status = CW1200_JOIN_STATUS_MONITOR; | ||
1503 | wsm_set_probe_responder(priv, true); | ||
1504 | } | ||
1505 | } else { | ||
1506 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { | ||
1507 | if (!cw1200_disable_listening(priv)) | ||
1508 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1509 | wsm_set_probe_responder(priv, false); | ||
1510 | } | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1514 | int cw1200_set_uapsd_param(struct cw1200_common *priv, | ||
1515 | const struct wsm_edca_params *arg) | ||
1516 | { | ||
1517 | int ret; | ||
1518 | u16 uapsd_flags = 0; | ||
1519 | |||
1520 | /* Here's the mapping AC [queue, bit] | ||
1521 | * VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0] | ||
1522 | */ | ||
1523 | |||
1524 | if (arg->uapsd_enable[0]) | ||
1525 | uapsd_flags |= 1 << 3; | ||
1526 | |||
1527 | if (arg->uapsd_enable[1]) | ||
1528 | uapsd_flags |= 1 << 2; | ||
1529 | |||
1530 | if (arg->uapsd_enable[2]) | ||
1531 | uapsd_flags |= 1 << 1; | ||
1532 | |||
1533 | if (arg->uapsd_enable[3]) | ||
1534 | uapsd_flags |= 1; | ||
1535 | |||
1536 | /* Currently pseudo U-APSD operation is not supported, so setting | ||
1537 | * MinAutoTriggerInterval, MaxAutoTriggerInterval and | ||
1538 | * AutoTriggerStep to 0 | ||
1539 | */ | ||
1540 | |||
1541 | priv->uapsd_info.uapsd_flags = cpu_to_le16(uapsd_flags); | ||
1542 | priv->uapsd_info.min_auto_trigger_interval = 0; | ||
1543 | priv->uapsd_info.max_auto_trigger_interval = 0; | ||
1544 | priv->uapsd_info.auto_trigger_step = 0; | ||
1545 | |||
1546 | ret = wsm_set_uapsd_info(priv, &priv->uapsd_info); | ||
1547 | return ret; | ||
1548 | } | ||
1549 | |||
1550 | /* ******************************************************************** */ | ||
1551 | /* AP API */ | ||
1552 | |||
1553 | int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1554 | struct ieee80211_sta *sta) | ||
1555 | { | ||
1556 | struct cw1200_common *priv = hw->priv; | ||
1557 | struct cw1200_sta_priv *sta_priv = | ||
1558 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1559 | struct cw1200_link_entry *entry; | ||
1560 | struct sk_buff *skb; | ||
1561 | |||
1562 | if (priv->mode != NL80211_IFTYPE_AP) | ||
1563 | return 0; | ||
1564 | |||
1565 | sta_priv->link_id = cw1200_find_link_id(priv, sta->addr); | ||
1566 | if (WARN_ON(!sta_priv->link_id)) { | ||
1567 | wiphy_info(priv->hw->wiphy, | ||
1568 | "[AP] No more link IDs available.\n"); | ||
1569 | return -ENOENT; | ||
1570 | } | ||
1571 | |||
1572 | entry = &priv->link_id_db[sta_priv->link_id - 1]; | ||
1573 | spin_lock_bh(&priv->ps_state_lock); | ||
1574 | if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == | ||
1575 | IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
1576 | priv->sta_asleep_mask |= BIT(sta_priv->link_id); | ||
1577 | entry->status = CW1200_LINK_HARD; | ||
1578 | while ((skb = skb_dequeue(&entry->rx_queue))) | ||
1579 | ieee80211_rx_irqsafe(priv->hw, skb); | ||
1580 | spin_unlock_bh(&priv->ps_state_lock); | ||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1585 | struct ieee80211_sta *sta) | ||
1586 | { | ||
1587 | struct cw1200_common *priv = hw->priv; | ||
1588 | struct cw1200_sta_priv *sta_priv = | ||
1589 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1590 | struct cw1200_link_entry *entry; | ||
1591 | |||
1592 | if (priv->mode != NL80211_IFTYPE_AP || !sta_priv->link_id) | ||
1593 | return 0; | ||
1594 | |||
1595 | entry = &priv->link_id_db[sta_priv->link_id - 1]; | ||
1596 | spin_lock_bh(&priv->ps_state_lock); | ||
1597 | entry->status = CW1200_LINK_RESERVE; | ||
1598 | entry->timestamp = jiffies; | ||
1599 | wsm_lock_tx_async(priv); | ||
1600 | if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) | ||
1601 | wsm_unlock_tx(priv); | ||
1602 | spin_unlock_bh(&priv->ps_state_lock); | ||
1603 | flush_workqueue(priv->workqueue); | ||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | static void __cw1200_sta_notify(struct ieee80211_hw *dev, | ||
1608 | struct ieee80211_vif *vif, | ||
1609 | enum sta_notify_cmd notify_cmd, | ||
1610 | int link_id) | ||
1611 | { | ||
1612 | struct cw1200_common *priv = dev->priv; | ||
1613 | u32 bit, prev; | ||
1614 | |||
1615 | /* Zero link id means "for all link IDs" */ | ||
1616 | if (link_id) | ||
1617 | bit = BIT(link_id); | ||
1618 | else if (WARN_ON_ONCE(notify_cmd != STA_NOTIFY_AWAKE)) | ||
1619 | bit = 0; | ||
1620 | else | ||
1621 | bit = priv->link_id_map; | ||
1622 | prev = priv->sta_asleep_mask & bit; | ||
1623 | |||
1624 | switch (notify_cmd) { | ||
1625 | case STA_NOTIFY_SLEEP: | ||
1626 | if (!prev) { | ||
1627 | if (priv->buffered_multicasts && | ||
1628 | !priv->sta_asleep_mask) | ||
1629 | queue_work(priv->workqueue, | ||
1630 | &priv->multicast_start_work); | ||
1631 | priv->sta_asleep_mask |= bit; | ||
1632 | } | ||
1633 | break; | ||
1634 | case STA_NOTIFY_AWAKE: | ||
1635 | if (prev) { | ||
1636 | priv->sta_asleep_mask &= ~bit; | ||
1637 | priv->pspoll_mask &= ~bit; | ||
1638 | if (priv->tx_multicast && link_id && | ||
1639 | !priv->sta_asleep_mask) | ||
1640 | queue_work(priv->workqueue, | ||
1641 | &priv->multicast_stop_work); | ||
1642 | cw1200_bh_wakeup(priv); | ||
1643 | } | ||
1644 | break; | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | void cw1200_sta_notify(struct ieee80211_hw *dev, | ||
1649 | struct ieee80211_vif *vif, | ||
1650 | enum sta_notify_cmd notify_cmd, | ||
1651 | struct ieee80211_sta *sta) | ||
1652 | { | ||
1653 | struct cw1200_common *priv = dev->priv; | ||
1654 | struct cw1200_sta_priv *sta_priv = | ||
1655 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1656 | |||
1657 | spin_lock_bh(&priv->ps_state_lock); | ||
1658 | __cw1200_sta_notify(dev, vif, notify_cmd, sta_priv->link_id); | ||
1659 | spin_unlock_bh(&priv->ps_state_lock); | ||
1660 | } | ||
1661 | |||
1662 | static void cw1200_ps_notify(struct cw1200_common *priv, | ||
1663 | int link_id, bool ps) | ||
1664 | { | ||
1665 | if (link_id > CW1200_MAX_STA_IN_AP_MODE) | ||
1666 | return; | ||
1667 | |||
1668 | pr_debug("%s for LinkId: %d. STAs asleep: %.8X\n", | ||
1669 | ps ? "Stop" : "Start", | ||
1670 | link_id, priv->sta_asleep_mask); | ||
1671 | |||
1672 | __cw1200_sta_notify(priv->hw, priv->vif, | ||
1673 | ps ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, link_id); | ||
1674 | } | ||
1675 | |||
1676 | static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) | ||
1677 | { | ||
1678 | struct sk_buff *skb; | ||
1679 | struct wsm_update_ie update_ie = { | ||
1680 | .what = WSM_UPDATE_IE_BEACON, | ||
1681 | .count = 1, | ||
1682 | }; | ||
1683 | u16 tim_offset, tim_length; | ||
1684 | |||
1685 | pr_debug("[AP] mcast: %s.\n", aid0_bit_set ? "ena" : "dis"); | ||
1686 | |||
1687 | skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, | ||
1688 | &tim_offset, &tim_length); | ||
1689 | if (!skb) { | ||
1690 | if (!__cw1200_flush(priv, true)) | ||
1691 | wsm_unlock_tx(priv); | ||
1692 | return -ENOENT; | ||
1693 | } | ||
1694 | |||
1695 | if (tim_offset && tim_length >= 6) { | ||
1696 | /* Ignore DTIM count from mac80211: | ||
1697 | * firmware handles DTIM internally. | ||
1698 | */ | ||
1699 | skb->data[tim_offset + 2] = 0; | ||
1700 | |||
1701 | /* Set/reset aid0 bit */ | ||
1702 | if (aid0_bit_set) | ||
1703 | skb->data[tim_offset + 4] |= 1; | ||
1704 | else | ||
1705 | skb->data[tim_offset + 4] &= ~1; | ||
1706 | } | ||
1707 | |||
1708 | update_ie.ies = &skb->data[tim_offset]; | ||
1709 | update_ie.length = tim_length; | ||
1710 | wsm_update_ie(priv, &update_ie); | ||
1711 | |||
1712 | dev_kfree_skb(skb); | ||
1713 | |||
1714 | return 0; | ||
1715 | } | ||
1716 | |||
1717 | void cw1200_set_tim_work(struct work_struct *work) | ||
1718 | { | ||
1719 | struct cw1200_common *priv = | ||
1720 | container_of(work, struct cw1200_common, set_tim_work); | ||
1721 | (void)cw1200_set_tim_impl(priv, priv->aid0_bit_set); | ||
1722 | } | ||
1723 | |||
1724 | int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, | ||
1725 | bool set) | ||
1726 | { | ||
1727 | struct cw1200_common *priv = dev->priv; | ||
1728 | queue_work(priv->workqueue, &priv->set_tim_work); | ||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | void cw1200_set_cts_work(struct work_struct *work) | ||
1733 | { | ||
1734 | struct cw1200_common *priv = | ||
1735 | container_of(work, struct cw1200_common, set_cts_work); | ||
1736 | |||
1737 | u8 erp_ie[3] = {WLAN_EID_ERP_INFO, 0x1, 0}; | ||
1738 | struct wsm_update_ie update_ie = { | ||
1739 | .what = WSM_UPDATE_IE_BEACON, | ||
1740 | .count = 1, | ||
1741 | .ies = erp_ie, | ||
1742 | .length = 3, | ||
1743 | }; | ||
1744 | u32 erp_info; | ||
1745 | __le32 use_cts_prot; | ||
1746 | mutex_lock(&priv->conf_mutex); | ||
1747 | erp_info = priv->erp_info; | ||
1748 | mutex_unlock(&priv->conf_mutex); | ||
1749 | use_cts_prot = | ||
1750 | erp_info & WLAN_ERP_USE_PROTECTION ? | ||
1751 | __cpu_to_le32(1) : 0; | ||
1752 | |||
1753 | erp_ie[ERP_INFO_BYTE_OFFSET] = erp_info; | ||
1754 | |||
1755 | pr_debug("[STA] ERP information 0x%x\n", erp_info); | ||
1756 | |||
1757 | wsm_write_mib(priv, WSM_MIB_ID_NON_ERP_PROTECTION, | ||
1758 | &use_cts_prot, sizeof(use_cts_prot)); | ||
1759 | wsm_update_ie(priv, &update_ie); | ||
1760 | |||
1761 | return; | ||
1762 | } | ||
1763 | |||
1764 | static int cw1200_set_btcoexinfo(struct cw1200_common *priv) | ||
1765 | { | ||
1766 | struct wsm_override_internal_txrate arg; | ||
1767 | int ret = 0; | ||
1768 | |||
1769 | if (priv->mode == NL80211_IFTYPE_STATION) { | ||
1770 | /* Plumb PSPOLL and NULL template */ | ||
1771 | cw1200_upload_pspoll(priv); | ||
1772 | cw1200_upload_null(priv); | ||
1773 | cw1200_upload_qosnull(priv); | ||
1774 | } else { | ||
1775 | return 0; | ||
1776 | } | ||
1777 | |||
1778 | memset(&arg, 0, sizeof(struct wsm_override_internal_txrate)); | ||
1779 | |||
1780 | if (!priv->vif->p2p) { | ||
1781 | /* STATION mode */ | ||
1782 | if (priv->bss_params.operational_rate_set & ~0xF) { | ||
1783 | pr_debug("[STA] STA has ERP rates\n"); | ||
1784 | /* G or BG mode */ | ||
1785 | arg.internalTxRate = (__ffs( | ||
1786 | priv->bss_params.operational_rate_set & ~0xF)); | ||
1787 | } else { | ||
1788 | pr_debug("[STA] STA has non ERP rates\n"); | ||
1789 | /* B only mode */ | ||
1790 | arg.internalTxRate = (__ffs(priv->association_mode.basic_rate_set)); | ||
1791 | } | ||
1792 | arg.nonErpInternalTxRate = (__ffs(priv->association_mode.basic_rate_set)); | ||
1793 | } else { | ||
1794 | /* P2P mode */ | ||
1795 | arg.internalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); | ||
1796 | arg.nonErpInternalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); | ||
1797 | } | ||
1798 | |||
1799 | pr_debug("[STA] BTCOEX_INFO MODE %d, internalTxRate : %x, nonErpInternalTxRate: %x\n", | ||
1800 | priv->mode, | ||
1801 | arg.internalTxRate, | ||
1802 | arg.nonErpInternalTxRate); | ||
1803 | |||
1804 | ret = wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, | ||
1805 | &arg, sizeof(arg)); | ||
1806 | |||
1807 | return ret; | ||
1808 | } | ||
1809 | |||
1810 | void cw1200_bss_info_changed(struct ieee80211_hw *dev, | ||
1811 | struct ieee80211_vif *vif, | ||
1812 | struct ieee80211_bss_conf *info, | ||
1813 | u32 changed) | ||
1814 | { | ||
1815 | struct cw1200_common *priv = dev->priv; | ||
1816 | bool do_join = false; | ||
1817 | |||
1818 | mutex_lock(&priv->conf_mutex); | ||
1819 | |||
1820 | pr_debug("BSS CHANGED: %08x\n", changed); | ||
1821 | |||
1822 | /* TODO: BSS_CHANGED_QOS */ | ||
1823 | /* TODO: BSS_CHANGED_TXPOWER */ | ||
1824 | |||
1825 | if (changed & BSS_CHANGED_ARP_FILTER) { | ||
1826 | struct wsm_mib_arp_ipv4_filter filter = {0}; | ||
1827 | int i; | ||
1828 | |||
1829 | pr_debug("[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", | ||
1830 | info->arp_addr_cnt); | ||
1831 | |||
1832 | /* Currently only one IP address is supported by firmware. | ||
1833 | * In case of more IPs arp filtering will be disabled. | ||
1834 | */ | ||
1835 | if (info->arp_addr_cnt > 0 && | ||
1836 | info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { | ||
1837 | for (i = 0; i < info->arp_addr_cnt; i++) { | ||
1838 | filter.ipv4addrs[i] = info->arp_addr_list[i]; | ||
1839 | pr_debug("[STA] addr[%d]: 0x%X\n", | ||
1840 | i, filter.ipv4addrs[i]); | ||
1841 | } | ||
1842 | filter.enable = __cpu_to_le32(1); | ||
1843 | } | ||
1844 | |||
1845 | pr_debug("[STA] arp ip filter enable: %d\n", | ||
1846 | __le32_to_cpu(filter.enable)); | ||
1847 | |||
1848 | wsm_set_arp_ipv4_filter(priv, &filter); | ||
1849 | } | ||
1850 | |||
1851 | if (changed & | ||
1852 | (BSS_CHANGED_BEACON | | ||
1853 | BSS_CHANGED_AP_PROBE_RESP | | ||
1854 | BSS_CHANGED_BSSID | | ||
1855 | BSS_CHANGED_SSID | | ||
1856 | BSS_CHANGED_IBSS)) { | ||
1857 | pr_debug("BSS_CHANGED_BEACON\n"); | ||
1858 | priv->beacon_int = info->beacon_int; | ||
1859 | cw1200_update_beaconing(priv); | ||
1860 | cw1200_upload_beacon(priv); | ||
1861 | } | ||
1862 | |||
1863 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | ||
1864 | pr_debug("BSS_CHANGED_BEACON_ENABLED (%d)\n", info->enable_beacon); | ||
1865 | |||
1866 | if (priv->enable_beacon != info->enable_beacon) { | ||
1867 | cw1200_enable_beaconing(priv, info->enable_beacon); | ||
1868 | priv->enable_beacon = info->enable_beacon; | ||
1869 | } | ||
1870 | } | ||
1871 | |||
1872 | if (changed & BSS_CHANGED_BEACON_INT) { | ||
1873 | pr_debug("CHANGED_BEACON_INT\n"); | ||
1874 | if (info->ibss_joined) | ||
1875 | do_join = true; | ||
1876 | else if (priv->join_status == CW1200_JOIN_STATUS_AP) | ||
1877 | cw1200_update_beaconing(priv); | ||
1878 | } | ||
1879 | |||
1880 | /* assoc/disassoc, or maybe AID changed */ | ||
1881 | if (changed & BSS_CHANGED_ASSOC) { | ||
1882 | wsm_lock_tx(priv); | ||
1883 | priv->wep_default_key_id = -1; | ||
1884 | wsm_unlock_tx(priv); | ||
1885 | } | ||
1886 | |||
1887 | if (changed & BSS_CHANGED_BSSID) { | ||
1888 | pr_debug("BSS_CHANGED_BSSID\n"); | ||
1889 | do_join = true; | ||
1890 | } | ||
1891 | |||
1892 | if (changed & | ||
1893 | (BSS_CHANGED_ASSOC | | ||
1894 | BSS_CHANGED_BSSID | | ||
1895 | BSS_CHANGED_IBSS | | ||
1896 | BSS_CHANGED_BASIC_RATES | | ||
1897 | BSS_CHANGED_HT)) { | ||
1898 | pr_debug("BSS_CHANGED_ASSOC\n"); | ||
1899 | if (info->assoc) { | ||
1900 | if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) { | ||
1901 | ieee80211_connection_loss(vif); | ||
1902 | mutex_unlock(&priv->conf_mutex); | ||
1903 | return; | ||
1904 | } else if (priv->join_status == CW1200_JOIN_STATUS_PRE_STA) { | ||
1905 | priv->join_status = CW1200_JOIN_STATUS_STA; | ||
1906 | } | ||
1907 | } else { | ||
1908 | do_join = true; | ||
1909 | } | ||
1910 | |||
1911 | if (info->assoc || info->ibss_joined) { | ||
1912 | struct ieee80211_sta *sta = NULL; | ||
1913 | u32 val = 0; | ||
1914 | |||
1915 | if (info->dtim_period) | ||
1916 | priv->join_dtim_period = info->dtim_period; | ||
1917 | priv->beacon_int = info->beacon_int; | ||
1918 | |||
1919 | rcu_read_lock(); | ||
1920 | |||
1921 | if (info->bssid && !info->ibss_joined) | ||
1922 | sta = ieee80211_find_sta(vif, info->bssid); | ||
1923 | if (sta) { | ||
1924 | priv->ht_info.ht_cap = sta->ht_cap; | ||
1925 | priv->bss_params.operational_rate_set = | ||
1926 | cw1200_rate_mask_to_wsm(priv, | ||
1927 | sta->supp_rates[priv->channel->band]); | ||
1928 | priv->ht_info.channel_type = cfg80211_get_chandef_type(&dev->conf.chandef); | ||
1929 | priv->ht_info.operation_mode = info->ht_operation_mode; | ||
1930 | } else { | ||
1931 | memset(&priv->ht_info, 0, | ||
1932 | sizeof(priv->ht_info)); | ||
1933 | priv->bss_params.operational_rate_set = -1; | ||
1934 | } | ||
1935 | rcu_read_unlock(); | ||
1936 | |||
1937 | /* Non Greenfield stations present */ | ||
1938 | if (priv->ht_info.operation_mode & | ||
1939 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) | ||
1940 | val |= WSM_NON_GREENFIELD_STA_PRESENT; | ||
1941 | |||
1942 | /* Set HT protection method */ | ||
1943 | val |= (priv->ht_info.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) << 2; | ||
1944 | |||
1945 | /* TODO: | ||
1946 | * STBC_param.dual_cts | ||
1947 | * STBC_param.LSIG_TXOP_FILL | ||
1948 | */ | ||
1949 | |||
1950 | val = cpu_to_le32(val); | ||
1951 | wsm_write_mib(priv, WSM_MIB_ID_SET_HT_PROTECTION, | ||
1952 | &val, sizeof(val)); | ||
1953 | |||
1954 | priv->association_mode.greenfield = | ||
1955 | cw1200_ht_greenfield(&priv->ht_info); | ||
1956 | priv->association_mode.flags = | ||
1957 | WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES | | ||
1958 | WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE | | ||
1959 | WSM_ASSOCIATION_MODE_USE_HT_MODE | | ||
1960 | WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET | | ||
1961 | WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING; | ||
1962 | priv->association_mode.preamble = | ||
1963 | info->use_short_preamble ? | ||
1964 | WSM_JOIN_PREAMBLE_SHORT : | ||
1965 | WSM_JOIN_PREAMBLE_LONG; | ||
1966 | priv->association_mode.basic_rate_set = __cpu_to_le32( | ||
1967 | cw1200_rate_mask_to_wsm(priv, | ||
1968 | info->basic_rates)); | ||
1969 | priv->association_mode.mpdu_start_spacing = | ||
1970 | cw1200_ht_ampdu_density(&priv->ht_info); | ||
1971 | |||
1972 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1973 | cancel_work_sync(&priv->unjoin_work); | ||
1974 | |||
1975 | priv->bss_params.beacon_lost_count = priv->cqm_beacon_loss_count; | ||
1976 | priv->bss_params.aid = info->aid; | ||
1977 | |||
1978 | if (priv->join_dtim_period < 1) | ||
1979 | priv->join_dtim_period = 1; | ||
1980 | |||
1981 | pr_debug("[STA] DTIM %d, interval: %d\n", | ||
1982 | priv->join_dtim_period, priv->beacon_int); | ||
1983 | pr_debug("[STA] Preamble: %d, Greenfield: %d, Aid: %d, Rates: 0x%.8X, Basic: 0x%.8X\n", | ||
1984 | priv->association_mode.preamble, | ||
1985 | priv->association_mode.greenfield, | ||
1986 | priv->bss_params.aid, | ||
1987 | priv->bss_params.operational_rate_set, | ||
1988 | priv->association_mode.basic_rate_set); | ||
1989 | wsm_set_association_mode(priv, &priv->association_mode); | ||
1990 | |||
1991 | if (!info->ibss_joined) { | ||
1992 | wsm_keep_alive_period(priv, 30 /* sec */); | ||
1993 | wsm_set_bss_params(priv, &priv->bss_params); | ||
1994 | priv->setbssparams_done = true; | ||
1995 | cw1200_set_beacon_wakeup_period_work(&priv->set_beacon_wakeup_period_work); | ||
1996 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
1997 | } | ||
1998 | if (priv->vif->p2p) { | ||
1999 | pr_debug("[STA] Setting p2p powersave configuration.\n"); | ||
2000 | wsm_set_p2p_ps_modeinfo(priv, | ||
2001 | &priv->p2p_ps_modeinfo); | ||
2002 | } | ||
2003 | if (priv->bt_present) | ||
2004 | cw1200_set_btcoexinfo(priv); | ||
2005 | } else { | ||
2006 | memset(&priv->association_mode, 0, | ||
2007 | sizeof(priv->association_mode)); | ||
2008 | memset(&priv->bss_params, 0, sizeof(priv->bss_params)); | ||
2009 | } | ||
2010 | } | ||
2011 | |||
2012 | /* ERP Protection */ | ||
2013 | if (changed & (BSS_CHANGED_ASSOC | | ||
2014 | BSS_CHANGED_ERP_CTS_PROT | | ||
2015 | BSS_CHANGED_ERP_PREAMBLE)) { | ||
2016 | u32 prev_erp_info = priv->erp_info; | ||
2017 | if (info->use_cts_prot) | ||
2018 | priv->erp_info |= WLAN_ERP_USE_PROTECTION; | ||
2019 | else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) | ||
2020 | priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; | ||
2021 | |||
2022 | if (info->use_short_preamble) | ||
2023 | priv->erp_info |= WLAN_ERP_BARKER_PREAMBLE; | ||
2024 | else | ||
2025 | priv->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; | ||
2026 | |||
2027 | pr_debug("[STA] ERP Protection: %x\n", priv->erp_info); | ||
2028 | |||
2029 | if (prev_erp_info != priv->erp_info) | ||
2030 | queue_work(priv->workqueue, &priv->set_cts_work); | ||
2031 | } | ||
2032 | |||
2033 | /* ERP Slottime */ | ||
2034 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) { | ||
2035 | __le32 slot_time = info->use_short_slot ? | ||
2036 | __cpu_to_le32(9) : __cpu_to_le32(20); | ||
2037 | pr_debug("[STA] Slot time: %d us.\n", | ||
2038 | __le32_to_cpu(slot_time)); | ||
2039 | wsm_write_mib(priv, WSM_MIB_ID_DOT11_SLOT_TIME, | ||
2040 | &slot_time, sizeof(slot_time)); | ||
2041 | } | ||
2042 | |||
2043 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { | ||
2044 | struct wsm_rcpi_rssi_threshold threshold = { | ||
2045 | .rollingAverageCount = 8, | ||
2046 | }; | ||
2047 | pr_debug("[CQM] RSSI threshold subscribe: %d +- %d\n", | ||
2048 | info->cqm_rssi_thold, info->cqm_rssi_hyst); | ||
2049 | priv->cqm_rssi_thold = info->cqm_rssi_thold; | ||
2050 | priv->cqm_rssi_hyst = info->cqm_rssi_hyst; | ||
2051 | |||
2052 | if (info->cqm_rssi_thold || info->cqm_rssi_hyst) { | ||
2053 | /* RSSI subscription enabled */ | ||
2054 | /* TODO: It's not a correct way of setting threshold. | ||
2055 | * Upper and lower must be set equal here and adjusted | ||
2056 | * in callback. However current implementation is much | ||
2057 | * more relaible and stable. | ||
2058 | */ | ||
2059 | |||
2060 | /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 | ||
2061 | * RSSI = RCPI / 2 - 110 | ||
2062 | */ | ||
2063 | if (priv->cqm_use_rssi) { | ||
2064 | threshold.upperThreshold = | ||
2065 | info->cqm_rssi_thold + info->cqm_rssi_hyst; | ||
2066 | threshold.lowerThreshold = | ||
2067 | info->cqm_rssi_thold; | ||
2068 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; | ||
2069 | } else { | ||
2070 | threshold.upperThreshold = (info->cqm_rssi_thold + info->cqm_rssi_hyst + 110) * 2; | ||
2071 | threshold.lowerThreshold = (info->cqm_rssi_thold + 110) * 2; | ||
2072 | } | ||
2073 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE; | ||
2074 | } else { | ||
2075 | /* There is a bug in FW, see sta.c. We have to enable | ||
2076 | * dummy subscription to get correct RSSI values. | ||
2077 | */ | ||
2078 | threshold.rssiRcpiMode |= | ||
2079 | WSM_RCPI_RSSI_THRESHOLD_ENABLE | | ||
2080 | WSM_RCPI_RSSI_DONT_USE_UPPER | | ||
2081 | WSM_RCPI_RSSI_DONT_USE_LOWER; | ||
2082 | if (priv->cqm_use_rssi) | ||
2083 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; | ||
2084 | } | ||
2085 | wsm_set_rcpi_rssi_threshold(priv, &threshold); | ||
2086 | } | ||
2087 | mutex_unlock(&priv->conf_mutex); | ||
2088 | |||
2089 | if (do_join) { | ||
2090 | wsm_lock_tx(priv); | ||
2091 | cw1200_do_join(priv); /* Will unlock it for us */ | ||
2092 | } | ||
2093 | } | ||
2094 | |||
2095 | void cw1200_multicast_start_work(struct work_struct *work) | ||
2096 | { | ||
2097 | struct cw1200_common *priv = | ||
2098 | container_of(work, struct cw1200_common, multicast_start_work); | ||
2099 | long tmo = priv->join_dtim_period * | ||
2100 | (priv->beacon_int + 20) * HZ / 1024; | ||
2101 | |||
2102 | cancel_work_sync(&priv->multicast_stop_work); | ||
2103 | |||
2104 | if (!priv->aid0_bit_set) { | ||
2105 | wsm_lock_tx(priv); | ||
2106 | cw1200_set_tim_impl(priv, true); | ||
2107 | priv->aid0_bit_set = true; | ||
2108 | mod_timer(&priv->mcast_timeout, jiffies + tmo); | ||
2109 | wsm_unlock_tx(priv); | ||
2110 | } | ||
2111 | } | ||
2112 | |||
2113 | void cw1200_multicast_stop_work(struct work_struct *work) | ||
2114 | { | ||
2115 | struct cw1200_common *priv = | ||
2116 | container_of(work, struct cw1200_common, multicast_stop_work); | ||
2117 | |||
2118 | if (priv->aid0_bit_set) { | ||
2119 | del_timer_sync(&priv->mcast_timeout); | ||
2120 | wsm_lock_tx(priv); | ||
2121 | priv->aid0_bit_set = false; | ||
2122 | cw1200_set_tim_impl(priv, false); | ||
2123 | wsm_unlock_tx(priv); | ||
2124 | } | ||
2125 | } | ||
2126 | |||
2127 | void cw1200_mcast_timeout(unsigned long arg) | ||
2128 | { | ||
2129 | struct cw1200_common *priv = | ||
2130 | (struct cw1200_common *)arg; | ||
2131 | |||
2132 | wiphy_warn(priv->hw->wiphy, | ||
2133 | "Multicast delivery timeout.\n"); | ||
2134 | spin_lock_bh(&priv->ps_state_lock); | ||
2135 | priv->tx_multicast = priv->aid0_bit_set && | ||
2136 | priv->buffered_multicasts; | ||
2137 | if (priv->tx_multicast) | ||
2138 | cw1200_bh_wakeup(priv); | ||
2139 | spin_unlock_bh(&priv->ps_state_lock); | ||
2140 | } | ||
2141 | |||
2142 | int cw1200_ampdu_action(struct ieee80211_hw *hw, | ||
2143 | struct ieee80211_vif *vif, | ||
2144 | enum ieee80211_ampdu_mlme_action action, | ||
2145 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
2146 | u8 buf_size) | ||
2147 | { | ||
2148 | /* Aggregation is implemented fully in firmware, | ||
2149 | * including block ack negotiation. Do not allow | ||
2150 | * mac80211 stack to do anything: it interferes with | ||
2151 | * the firmware. | ||
2152 | */ | ||
2153 | |||
2154 | /* Note that we still need this function stubbed. */ | ||
2155 | return -ENOTSUPP; | ||
2156 | } | ||
2157 | |||
2158 | /* ******************************************************************** */ | ||
2159 | /* WSM callback */ | ||
2160 | void cw1200_suspend_resume(struct cw1200_common *priv, | ||
2161 | struct wsm_suspend_resume *arg) | ||
2162 | { | ||
2163 | pr_debug("[AP] %s: %s\n", | ||
2164 | arg->stop ? "stop" : "start", | ||
2165 | arg->multicast ? "broadcast" : "unicast"); | ||
2166 | |||
2167 | if (arg->multicast) { | ||
2168 | bool cancel_tmo = false; | ||
2169 | spin_lock_bh(&priv->ps_state_lock); | ||
2170 | if (arg->stop) { | ||
2171 | priv->tx_multicast = false; | ||
2172 | } else { | ||
2173 | /* Firmware sends this indication every DTIM if there | ||
2174 | * is a STA in powersave connected. There is no reason | ||
2175 | * to suspend, following wakeup will consume much more | ||
2176 | * power than it could be saved. | ||
2177 | */ | ||
2178 | cw1200_pm_stay_awake(&priv->pm_state, | ||
2179 | priv->join_dtim_period * | ||
2180 | (priv->beacon_int + 20) * HZ / 1024); | ||
2181 | priv->tx_multicast = (priv->aid0_bit_set && | ||
2182 | priv->buffered_multicasts); | ||
2183 | if (priv->tx_multicast) { | ||
2184 | cancel_tmo = true; | ||
2185 | cw1200_bh_wakeup(priv); | ||
2186 | } | ||
2187 | } | ||
2188 | spin_unlock_bh(&priv->ps_state_lock); | ||
2189 | if (cancel_tmo) | ||
2190 | del_timer_sync(&priv->mcast_timeout); | ||
2191 | } else { | ||
2192 | spin_lock_bh(&priv->ps_state_lock); | ||
2193 | cw1200_ps_notify(priv, arg->link_id, arg->stop); | ||
2194 | spin_unlock_bh(&priv->ps_state_lock); | ||
2195 | if (!arg->stop) | ||
2196 | cw1200_bh_wakeup(priv); | ||
2197 | } | ||
2198 | return; | ||
2199 | } | ||
2200 | |||
2201 | /* ******************************************************************** */ | ||
2202 | /* AP privates */ | ||
2203 | |||
2204 | static int cw1200_upload_beacon(struct cw1200_common *priv) | ||
2205 | { | ||
2206 | int ret = 0; | ||
2207 | struct ieee80211_mgmt *mgmt; | ||
2208 | struct wsm_template_frame frame = { | ||
2209 | .frame_type = WSM_FRAME_TYPE_BEACON, | ||
2210 | }; | ||
2211 | |||
2212 | u16 tim_offset; | ||
2213 | u16 tim_len; | ||
2214 | |||
2215 | if (priv->mode == NL80211_IFTYPE_STATION || | ||
2216 | priv->mode == NL80211_IFTYPE_MONITOR || | ||
2217 | priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
2218 | goto done; | ||
2219 | |||
2220 | if (priv->vif->p2p) | ||
2221 | frame.rate = WSM_TRANSMIT_RATE_6; | ||
2222 | |||
2223 | frame.skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, | ||
2224 | &tim_offset, &tim_len); | ||
2225 | if (!frame.skb) | ||
2226 | return -ENOMEM; | ||
2227 | |||
2228 | ret = wsm_set_template_frame(priv, &frame); | ||
2229 | |||
2230 | if (ret) | ||
2231 | goto done; | ||
2232 | |||
2233 | /* TODO: Distill probe resp; remove TIM | ||
2234 | * and any other beacon-specific IEs | ||
2235 | */ | ||
2236 | mgmt = (void *)frame.skb->data; | ||
2237 | mgmt->frame_control = | ||
2238 | __cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2239 | IEEE80211_STYPE_PROBE_RESP); | ||
2240 | |||
2241 | frame.frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE; | ||
2242 | if (priv->vif->p2p) { | ||
2243 | ret = wsm_set_probe_responder(priv, true); | ||
2244 | } else { | ||
2245 | ret = wsm_set_template_frame(priv, &frame); | ||
2246 | wsm_set_probe_responder(priv, false); | ||
2247 | } | ||
2248 | |||
2249 | done: | ||
2250 | dev_kfree_skb(frame.skb); | ||
2251 | |||
2252 | return ret; | ||
2253 | } | ||
2254 | |||
2255 | static int cw1200_upload_pspoll(struct cw1200_common *priv) | ||
2256 | { | ||
2257 | int ret = 0; | ||
2258 | struct wsm_template_frame frame = { | ||
2259 | .frame_type = WSM_FRAME_TYPE_PS_POLL, | ||
2260 | .rate = 0xFF, | ||
2261 | }; | ||
2262 | |||
2263 | |||
2264 | frame.skb = ieee80211_pspoll_get(priv->hw, priv->vif); | ||
2265 | if (!frame.skb) | ||
2266 | return -ENOMEM; | ||
2267 | |||
2268 | ret = wsm_set_template_frame(priv, &frame); | ||
2269 | |||
2270 | dev_kfree_skb(frame.skb); | ||
2271 | |||
2272 | return ret; | ||
2273 | } | ||
2274 | |||
2275 | static int cw1200_upload_null(struct cw1200_common *priv) | ||
2276 | { | ||
2277 | int ret = 0; | ||
2278 | struct wsm_template_frame frame = { | ||
2279 | .frame_type = WSM_FRAME_TYPE_NULL, | ||
2280 | .rate = 0xFF, | ||
2281 | }; | ||
2282 | |||
2283 | frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif); | ||
2284 | if (!frame.skb) | ||
2285 | return -ENOMEM; | ||
2286 | |||
2287 | ret = wsm_set_template_frame(priv, &frame); | ||
2288 | |||
2289 | dev_kfree_skb(frame.skb); | ||
2290 | |||
2291 | return ret; | ||
2292 | } | ||
2293 | |||
2294 | static int cw1200_upload_qosnull(struct cw1200_common *priv) | ||
2295 | { | ||
2296 | int ret = 0; | ||
2297 | /* TODO: This needs to be implemented | ||
2298 | |||
2299 | struct wsm_template_frame frame = { | ||
2300 | .frame_type = WSM_FRAME_TYPE_QOS_NULL, | ||
2301 | .rate = 0xFF, | ||
2302 | }; | ||
2303 | |||
2304 | frame.skb = ieee80211_qosnullfunc_get(priv->hw, priv->vif); | ||
2305 | if (!frame.skb) | ||
2306 | return -ENOMEM; | ||
2307 | |||
2308 | ret = wsm_set_template_frame(priv, &frame); | ||
2309 | |||
2310 | dev_kfree_skb(frame.skb); | ||
2311 | |||
2312 | */ | ||
2313 | return ret; | ||
2314 | } | ||
2315 | |||
2316 | static int cw1200_enable_beaconing(struct cw1200_common *priv, | ||
2317 | bool enable) | ||
2318 | { | ||
2319 | struct wsm_beacon_transmit transmit = { | ||
2320 | .enable_beaconing = enable, | ||
2321 | }; | ||
2322 | |||
2323 | return wsm_beacon_transmit(priv, &transmit); | ||
2324 | } | ||
2325 | |||
2326 | static int cw1200_start_ap(struct cw1200_common *priv) | ||
2327 | { | ||
2328 | int ret; | ||
2329 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
2330 | struct wsm_start start = { | ||
2331 | .mode = priv->vif->p2p ? | ||
2332 | WSM_START_MODE_P2P_GO : WSM_START_MODE_AP, | ||
2333 | .band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? | ||
2334 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, | ||
2335 | .channel_number = priv->channel->hw_value, | ||
2336 | .beacon_interval = conf->beacon_int, | ||
2337 | .dtim_period = conf->dtim_period, | ||
2338 | .preamble = conf->use_short_preamble ? | ||
2339 | WSM_JOIN_PREAMBLE_SHORT : | ||
2340 | WSM_JOIN_PREAMBLE_LONG, | ||
2341 | .probe_delay = 100, | ||
2342 | .basic_rate_set = cw1200_rate_mask_to_wsm(priv, | ||
2343 | conf->basic_rates), | ||
2344 | }; | ||
2345 | struct wsm_operational_mode mode = { | ||
2346 | .power_mode = cw1200_power_mode, | ||
2347 | .disable_more_flag_usage = true, | ||
2348 | }; | ||
2349 | |||
2350 | memset(start.ssid, 0, sizeof(start.ssid)); | ||
2351 | if (!conf->hidden_ssid) { | ||
2352 | start.ssid_len = conf->ssid_len; | ||
2353 | memcpy(start.ssid, conf->ssid, start.ssid_len); | ||
2354 | } | ||
2355 | |||
2356 | priv->beacon_int = conf->beacon_int; | ||
2357 | priv->join_dtim_period = conf->dtim_period; | ||
2358 | |||
2359 | memset(&priv->link_id_db, 0, sizeof(priv->link_id_db)); | ||
2360 | |||
2361 | pr_debug("[AP] ch: %d(%d), bcn: %d(%d), brt: 0x%.8X, ssid: %.*s.\n", | ||
2362 | start.channel_number, start.band, | ||
2363 | start.beacon_interval, start.dtim_period, | ||
2364 | start.basic_rate_set, | ||
2365 | start.ssid_len, start.ssid); | ||
2366 | ret = wsm_start(priv, &start); | ||
2367 | if (!ret) | ||
2368 | ret = cw1200_upload_keys(priv); | ||
2369 | if (!ret && priv->vif->p2p) { | ||
2370 | pr_debug("[AP] Setting p2p powersave configuration.\n"); | ||
2371 | wsm_set_p2p_ps_modeinfo(priv, &priv->p2p_ps_modeinfo); | ||
2372 | } | ||
2373 | if (!ret) { | ||
2374 | wsm_set_block_ack_policy(priv, 0, 0); | ||
2375 | priv->join_status = CW1200_JOIN_STATUS_AP; | ||
2376 | cw1200_update_filtering(priv); | ||
2377 | } | ||
2378 | wsm_set_operational_mode(priv, &mode); | ||
2379 | return ret; | ||
2380 | } | ||
2381 | |||
2382 | static int cw1200_update_beaconing(struct cw1200_common *priv) | ||
2383 | { | ||
2384 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
2385 | struct wsm_reset reset = { | ||
2386 | .link_id = 0, | ||
2387 | .reset_statistics = true, | ||
2388 | }; | ||
2389 | |||
2390 | if (priv->mode == NL80211_IFTYPE_AP) { | ||
2391 | /* TODO: check if changed channel, band */ | ||
2392 | if (priv->join_status != CW1200_JOIN_STATUS_AP || | ||
2393 | priv->beacon_int != conf->beacon_int) { | ||
2394 | pr_debug("ap restarting\n"); | ||
2395 | wsm_lock_tx(priv); | ||
2396 | if (priv->join_status != CW1200_JOIN_STATUS_PASSIVE) | ||
2397 | wsm_reset(priv, &reset); | ||
2398 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
2399 | cw1200_start_ap(priv); | ||
2400 | wsm_unlock_tx(priv); | ||
2401 | } else | ||
2402 | pr_debug("ap started join_status: %d\n", | ||
2403 | priv->join_status); | ||
2404 | } | ||
2405 | return 0; | ||
2406 | } | ||
diff --git a/drivers/net/wireless/cw1200/sta.h b/drivers/net/wireless/cw1200/sta.h new file mode 100644 index 000000000000..35babb62cc6a --- /dev/null +++ b/drivers/net/wireless/cw1200/sta.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Mac80211 STA interface for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef STA_H_INCLUDED | ||
13 | #define STA_H_INCLUDED | ||
14 | |||
15 | /* ******************************************************************** */ | ||
16 | /* mac80211 API */ | ||
17 | |||
18 | int cw1200_start(struct ieee80211_hw *dev); | ||
19 | void cw1200_stop(struct ieee80211_hw *dev); | ||
20 | int cw1200_add_interface(struct ieee80211_hw *dev, | ||
21 | struct ieee80211_vif *vif); | ||
22 | void cw1200_remove_interface(struct ieee80211_hw *dev, | ||
23 | struct ieee80211_vif *vif); | ||
24 | int cw1200_change_interface(struct ieee80211_hw *dev, | ||
25 | struct ieee80211_vif *vif, | ||
26 | enum nl80211_iftype new_type, | ||
27 | bool p2p); | ||
28 | int cw1200_config(struct ieee80211_hw *dev, u32 changed); | ||
29 | void cw1200_configure_filter(struct ieee80211_hw *dev, | ||
30 | unsigned int changed_flags, | ||
31 | unsigned int *total_flags, | ||
32 | u64 multicast); | ||
33 | int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, | ||
34 | u16 queue, const struct ieee80211_tx_queue_params *params); | ||
35 | int cw1200_get_stats(struct ieee80211_hw *dev, | ||
36 | struct ieee80211_low_level_stats *stats); | ||
37 | int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | ||
38 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
39 | struct ieee80211_key_conf *key); | ||
40 | |||
41 | int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value); | ||
42 | |||
43 | void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop); | ||
44 | |||
45 | u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, | ||
46 | struct netdev_hw_addr_list *mc_list); | ||
47 | |||
48 | int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); | ||
49 | |||
50 | /* ******************************************************************** */ | ||
51 | /* WSM callbacks */ | ||
52 | |||
53 | void cw1200_join_complete_cb(struct cw1200_common *priv, | ||
54 | struct wsm_join_complete *arg); | ||
55 | |||
56 | /* ******************************************************************** */ | ||
57 | /* WSM events */ | ||
58 | |||
59 | void cw1200_free_event_queue(struct cw1200_common *priv); | ||
60 | void cw1200_event_handler(struct work_struct *work); | ||
61 | void cw1200_bss_loss_work(struct work_struct *work); | ||
62 | void cw1200_bss_params_work(struct work_struct *work); | ||
63 | void cw1200_keep_alive_work(struct work_struct *work); | ||
64 | void cw1200_tx_failure_work(struct work_struct *work); | ||
65 | |||
66 | void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv, int init, int good, | ||
67 | int bad); | ||
68 | static inline void cw1200_cqm_bssloss_sm(struct cw1200_common *priv, | ||
69 | int init, int good, int bad) | ||
70 | { | ||
71 | spin_lock(&priv->bss_loss_lock); | ||
72 | __cw1200_cqm_bssloss_sm(priv, init, good, bad); | ||
73 | spin_unlock(&priv->bss_loss_lock); | ||
74 | } | ||
75 | |||
76 | /* ******************************************************************** */ | ||
77 | /* Internal API */ | ||
78 | |||
79 | int cw1200_setup_mac(struct cw1200_common *priv); | ||
80 | void cw1200_join_timeout(struct work_struct *work); | ||
81 | void cw1200_unjoin_work(struct work_struct *work); | ||
82 | void cw1200_join_complete_work(struct work_struct *work); | ||
83 | void cw1200_wep_key_work(struct work_struct *work); | ||
84 | void cw1200_update_listening(struct cw1200_common *priv, bool enabled); | ||
85 | void cw1200_update_filtering(struct cw1200_common *priv); | ||
86 | void cw1200_update_filtering_work(struct work_struct *work); | ||
87 | void cw1200_set_beacon_wakeup_period_work(struct work_struct *work); | ||
88 | int cw1200_enable_listening(struct cw1200_common *priv); | ||
89 | int cw1200_disable_listening(struct cw1200_common *priv); | ||
90 | int cw1200_set_uapsd_param(struct cw1200_common *priv, | ||
91 | const struct wsm_edca_params *arg); | ||
92 | void cw1200_ba_work(struct work_struct *work); | ||
93 | void cw1200_ba_timer(unsigned long arg); | ||
94 | |||
95 | /* AP stuffs */ | ||
96 | int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, | ||
97 | bool set); | ||
98 | int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
99 | struct ieee80211_sta *sta); | ||
100 | int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
101 | struct ieee80211_sta *sta); | ||
102 | void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, | ||
103 | enum sta_notify_cmd notify_cmd, | ||
104 | struct ieee80211_sta *sta); | ||
105 | void cw1200_bss_info_changed(struct ieee80211_hw *dev, | ||
106 | struct ieee80211_vif *vif, | ||
107 | struct ieee80211_bss_conf *info, | ||
108 | u32 changed); | ||
109 | int cw1200_ampdu_action(struct ieee80211_hw *hw, | ||
110 | struct ieee80211_vif *vif, | ||
111 | enum ieee80211_ampdu_mlme_action action, | ||
112 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
113 | u8 buf_size); | ||
114 | |||
115 | void cw1200_suspend_resume(struct cw1200_common *priv, | ||
116 | struct wsm_suspend_resume *arg); | ||
117 | void cw1200_set_tim_work(struct work_struct *work); | ||
118 | void cw1200_set_cts_work(struct work_struct *work); | ||
119 | void cw1200_multicast_start_work(struct work_struct *work); | ||
120 | void cw1200_multicast_stop_work(struct work_struct *work); | ||
121 | void cw1200_mcast_timeout(unsigned long arg); | ||
122 | |||
123 | #endif | ||
diff --git a/drivers/net/wireless/cw1200/txrx.c b/drivers/net/wireless/cw1200/txrx.c new file mode 100644 index 000000000000..0e40890e1993 --- /dev/null +++ b/drivers/net/wireless/cw1200/txrx.c | |||
@@ -0,0 +1,1474 @@ | |||
1 | /* | ||
2 | * Datapath implementation for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <net/mac80211.h> | ||
13 | #include <linux/etherdevice.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | |||
16 | #include "cw1200.h" | ||
17 | #include "wsm.h" | ||
18 | #include "bh.h" | ||
19 | #include "sta.h" | ||
20 | #include "debug.h" | ||
21 | |||
22 | #define CW1200_INVALID_RATE_ID (0xFF) | ||
23 | |||
24 | static int cw1200_handle_action_rx(struct cw1200_common *priv, | ||
25 | struct sk_buff *skb); | ||
26 | static const struct ieee80211_rate * | ||
27 | cw1200_get_tx_rate(const struct cw1200_common *priv, | ||
28 | const struct ieee80211_tx_rate *rate); | ||
29 | |||
30 | /* ******************************************************************** */ | ||
31 | /* TX queue lock / unlock */ | ||
32 | |||
33 | static inline void cw1200_tx_queues_lock(struct cw1200_common *priv) | ||
34 | { | ||
35 | int i; | ||
36 | for (i = 0; i < 4; ++i) | ||
37 | cw1200_queue_lock(&priv->tx_queue[i]); | ||
38 | } | ||
39 | |||
40 | static inline void cw1200_tx_queues_unlock(struct cw1200_common *priv) | ||
41 | { | ||
42 | int i; | ||
43 | for (i = 0; i < 4; ++i) | ||
44 | cw1200_queue_unlock(&priv->tx_queue[i]); | ||
45 | } | ||
46 | |||
47 | /* ******************************************************************** */ | ||
48 | /* TX policy cache implementation */ | ||
49 | |||
50 | static void tx_policy_dump(struct tx_policy *policy) | ||
51 | { | ||
52 | pr_debug("[TX policy] %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X %.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X: %d\n", | ||
53 | policy->raw[0] & 0x0F, policy->raw[0] >> 4, | ||
54 | policy->raw[1] & 0x0F, policy->raw[1] >> 4, | ||
55 | policy->raw[2] & 0x0F, policy->raw[2] >> 4, | ||
56 | policy->raw[3] & 0x0F, policy->raw[3] >> 4, | ||
57 | policy->raw[4] & 0x0F, policy->raw[4] >> 4, | ||
58 | policy->raw[5] & 0x0F, policy->raw[5] >> 4, | ||
59 | policy->raw[6] & 0x0F, policy->raw[6] >> 4, | ||
60 | policy->raw[7] & 0x0F, policy->raw[7] >> 4, | ||
61 | policy->raw[8] & 0x0F, policy->raw[8] >> 4, | ||
62 | policy->raw[9] & 0x0F, policy->raw[9] >> 4, | ||
63 | policy->raw[10] & 0x0F, policy->raw[10] >> 4, | ||
64 | policy->raw[11] & 0x0F, policy->raw[11] >> 4, | ||
65 | policy->defined); | ||
66 | } | ||
67 | |||
68 | static void tx_policy_build(const struct cw1200_common *priv, | ||
69 | /* [out] */ struct tx_policy *policy, | ||
70 | struct ieee80211_tx_rate *rates, size_t count) | ||
71 | { | ||
72 | int i, j; | ||
73 | unsigned limit = priv->short_frame_max_tx_count; | ||
74 | unsigned total = 0; | ||
75 | BUG_ON(rates[0].idx < 0); | ||
76 | memset(policy, 0, sizeof(*policy)); | ||
77 | |||
78 | /* minstrel is buggy a little bit, so distille | ||
79 | * incoming rates first. */ | ||
80 | |||
81 | /* Sort rates in descending order. */ | ||
82 | for (i = 1; i < count; ++i) { | ||
83 | if (rates[i].idx < 0) { | ||
84 | count = i; | ||
85 | break; | ||
86 | } | ||
87 | if (rates[i].idx > rates[i - 1].idx) { | ||
88 | struct ieee80211_tx_rate tmp = rates[i - 1]; | ||
89 | rates[i - 1] = rates[i]; | ||
90 | rates[i] = tmp; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* Eliminate duplicates. */ | ||
95 | total = rates[0].count; | ||
96 | for (i = 0, j = 1; j < count; ++j) { | ||
97 | if (rates[j].idx == rates[i].idx) { | ||
98 | rates[i].count += rates[j].count; | ||
99 | } else if (rates[j].idx > rates[i].idx) { | ||
100 | break; | ||
101 | } else { | ||
102 | ++i; | ||
103 | if (i != j) | ||
104 | rates[i] = rates[j]; | ||
105 | } | ||
106 | total += rates[j].count; | ||
107 | } | ||
108 | count = i + 1; | ||
109 | |||
110 | /* Re-fill policy trying to keep every requested rate and with | ||
111 | * respect to the global max tx retransmission count. */ | ||
112 | if (limit < count) | ||
113 | limit = count; | ||
114 | if (total > limit) { | ||
115 | for (i = 0; i < count; ++i) { | ||
116 | int left = count - i - 1; | ||
117 | if (rates[i].count > limit - left) | ||
118 | rates[i].count = limit - left; | ||
119 | limit -= rates[i].count; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /* HACK!!! Device has problems (at least) switching from | ||
124 | * 54Mbps CTS to 1Mbps. This switch takes enormous amount | ||
125 | * of time (100-200 ms), leading to valuable throughput drop. | ||
126 | * As a workaround, additional g-rates are injected to the | ||
127 | * policy. | ||
128 | */ | ||
129 | if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && | ||
130 | rates[0].idx > 4 && rates[0].count > 2 && | ||
131 | rates[1].idx < 2) { | ||
132 | /* ">> 1" is an equivalent of "/ 2", but faster */ | ||
133 | int mid_rate = (rates[0].idx + 4) >> 1; | ||
134 | |||
135 | /* Decrease number of retries for the initial rate */ | ||
136 | rates[0].count -= 2; | ||
137 | |||
138 | if (mid_rate != 4) { | ||
139 | /* Keep fallback rate at 1Mbps. */ | ||
140 | rates[3] = rates[1]; | ||
141 | |||
142 | /* Inject 1 transmission on lowest g-rate */ | ||
143 | rates[2].idx = 4; | ||
144 | rates[2].count = 1; | ||
145 | rates[2].flags = rates[1].flags; | ||
146 | |||
147 | /* Inject 1 transmission on mid-rate */ | ||
148 | rates[1].idx = mid_rate; | ||
149 | rates[1].count = 1; | ||
150 | |||
151 | /* Fallback to 1 Mbps is a really bad thing, | ||
152 | * so let's try to increase probability of | ||
153 | * successful transmission on the lowest g rate | ||
154 | * even more */ | ||
155 | if (rates[0].count >= 3) { | ||
156 | --rates[0].count; | ||
157 | ++rates[2].count; | ||
158 | } | ||
159 | |||
160 | /* Adjust amount of rates defined */ | ||
161 | count += 2; | ||
162 | } else { | ||
163 | /* Keep fallback rate at 1Mbps. */ | ||
164 | rates[2] = rates[1]; | ||
165 | |||
166 | /* Inject 2 transmissions on lowest g-rate */ | ||
167 | rates[1].idx = 4; | ||
168 | rates[1].count = 2; | ||
169 | |||
170 | /* Adjust amount of rates defined */ | ||
171 | count += 1; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | policy->defined = cw1200_get_tx_rate(priv, &rates[0])->hw_value + 1; | ||
176 | |||
177 | for (i = 0; i < count; ++i) { | ||
178 | register unsigned rateid, off, shift, retries; | ||
179 | |||
180 | rateid = cw1200_get_tx_rate(priv, &rates[i])->hw_value; | ||
181 | off = rateid >> 3; /* eq. rateid / 8 */ | ||
182 | shift = (rateid & 0x07) << 2; /* eq. (rateid % 8) * 4 */ | ||
183 | |||
184 | retries = rates[i].count; | ||
185 | if (retries > 0x0F) { | ||
186 | rates[i].count = 0x0f; | ||
187 | retries = 0x0F; | ||
188 | } | ||
189 | policy->tbl[off] |= __cpu_to_le32(retries << shift); | ||
190 | policy->retry_count += retries; | ||
191 | } | ||
192 | |||
193 | pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", | ||
194 | count, | ||
195 | rates[0].idx, rates[0].count, | ||
196 | rates[1].idx, rates[1].count, | ||
197 | rates[2].idx, rates[2].count, | ||
198 | rates[3].idx, rates[3].count, | ||
199 | rates[4].idx, rates[4].count); | ||
200 | } | ||
201 | |||
202 | static inline bool tx_policy_is_equal(const struct tx_policy *wanted, | ||
203 | const struct tx_policy *cached) | ||
204 | { | ||
205 | size_t count = wanted->defined >> 1; | ||
206 | if (wanted->defined > cached->defined) | ||
207 | return false; | ||
208 | if (count) { | ||
209 | if (memcmp(wanted->raw, cached->raw, count)) | ||
210 | return false; | ||
211 | } | ||
212 | if (wanted->defined & 1) { | ||
213 | if ((wanted->raw[count] & 0x0F) != (cached->raw[count] & 0x0F)) | ||
214 | return false; | ||
215 | } | ||
216 | return true; | ||
217 | } | ||
218 | |||
219 | static int tx_policy_find(struct tx_policy_cache *cache, | ||
220 | const struct tx_policy *wanted) | ||
221 | { | ||
222 | /* O(n) complexity. Not so good, but there's only 8 entries in | ||
223 | * the cache. | ||
224 | * Also lru helps to reduce search time. */ | ||
225 | struct tx_policy_cache_entry *it; | ||
226 | /* First search for policy in "used" list */ | ||
227 | list_for_each_entry(it, &cache->used, link) { | ||
228 | if (tx_policy_is_equal(wanted, &it->policy)) | ||
229 | return it - cache->cache; | ||
230 | } | ||
231 | /* Then - in "free list" */ | ||
232 | list_for_each_entry(it, &cache->free, link) { | ||
233 | if (tx_policy_is_equal(wanted, &it->policy)) | ||
234 | return it - cache->cache; | ||
235 | } | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | static inline void tx_policy_use(struct tx_policy_cache *cache, | ||
240 | struct tx_policy_cache_entry *entry) | ||
241 | { | ||
242 | ++entry->policy.usage_count; | ||
243 | list_move(&entry->link, &cache->used); | ||
244 | } | ||
245 | |||
246 | static inline int tx_policy_release(struct tx_policy_cache *cache, | ||
247 | struct tx_policy_cache_entry *entry) | ||
248 | { | ||
249 | int ret = --entry->policy.usage_count; | ||
250 | if (!ret) | ||
251 | list_move(&entry->link, &cache->free); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | void tx_policy_clean(struct cw1200_common *priv) | ||
256 | { | ||
257 | int idx, locked; | ||
258 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
259 | struct tx_policy_cache_entry *entry; | ||
260 | |||
261 | cw1200_tx_queues_lock(priv); | ||
262 | spin_lock_bh(&cache->lock); | ||
263 | locked = list_empty(&cache->free); | ||
264 | |||
265 | for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) { | ||
266 | entry = &cache->cache[idx]; | ||
267 | /* Policy usage count should be 0 at this time as all queues | ||
268 | should be empty */ | ||
269 | if (WARN_ON(entry->policy.usage_count)) { | ||
270 | entry->policy.usage_count = 0; | ||
271 | list_move(&entry->link, &cache->free); | ||
272 | } | ||
273 | memset(&entry->policy, 0, sizeof(entry->policy)); | ||
274 | } | ||
275 | if (locked) | ||
276 | cw1200_tx_queues_unlock(priv); | ||
277 | |||
278 | cw1200_tx_queues_unlock(priv); | ||
279 | spin_unlock_bh(&cache->lock); | ||
280 | } | ||
281 | |||
282 | /* ******************************************************************** */ | ||
283 | /* External TX policy cache API */ | ||
284 | |||
285 | void tx_policy_init(struct cw1200_common *priv) | ||
286 | { | ||
287 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
288 | int i; | ||
289 | |||
290 | memset(cache, 0, sizeof(*cache)); | ||
291 | |||
292 | spin_lock_init(&cache->lock); | ||
293 | INIT_LIST_HEAD(&cache->used); | ||
294 | INIT_LIST_HEAD(&cache->free); | ||
295 | |||
296 | for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) | ||
297 | list_add(&cache->cache[i].link, &cache->free); | ||
298 | } | ||
299 | |||
300 | static int tx_policy_get(struct cw1200_common *priv, | ||
301 | struct ieee80211_tx_rate *rates, | ||
302 | size_t count, bool *renew) | ||
303 | { | ||
304 | int idx; | ||
305 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
306 | struct tx_policy wanted; | ||
307 | |||
308 | tx_policy_build(priv, &wanted, rates, count); | ||
309 | |||
310 | spin_lock_bh(&cache->lock); | ||
311 | if (WARN_ON_ONCE(list_empty(&cache->free))) { | ||
312 | spin_unlock_bh(&cache->lock); | ||
313 | return CW1200_INVALID_RATE_ID; | ||
314 | } | ||
315 | idx = tx_policy_find(cache, &wanted); | ||
316 | if (idx >= 0) { | ||
317 | pr_debug("[TX policy] Used TX policy: %d\n", idx); | ||
318 | *renew = false; | ||
319 | } else { | ||
320 | struct tx_policy_cache_entry *entry; | ||
321 | *renew = true; | ||
322 | /* If policy is not found create a new one | ||
323 | * using the oldest entry in "free" list */ | ||
324 | entry = list_entry(cache->free.prev, | ||
325 | struct tx_policy_cache_entry, link); | ||
326 | entry->policy = wanted; | ||
327 | idx = entry - cache->cache; | ||
328 | pr_debug("[TX policy] New TX policy: %d\n", idx); | ||
329 | tx_policy_dump(&entry->policy); | ||
330 | } | ||
331 | tx_policy_use(cache, &cache->cache[idx]); | ||
332 | if (list_empty(&cache->free)) { | ||
333 | /* Lock TX queues. */ | ||
334 | cw1200_tx_queues_lock(priv); | ||
335 | } | ||
336 | spin_unlock_bh(&cache->lock); | ||
337 | return idx; | ||
338 | } | ||
339 | |||
340 | static void tx_policy_put(struct cw1200_common *priv, int idx) | ||
341 | { | ||
342 | int usage, locked; | ||
343 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
344 | |||
345 | spin_lock_bh(&cache->lock); | ||
346 | locked = list_empty(&cache->free); | ||
347 | usage = tx_policy_release(cache, &cache->cache[idx]); | ||
348 | if (locked && !usage) { | ||
349 | /* Unlock TX queues. */ | ||
350 | cw1200_tx_queues_unlock(priv); | ||
351 | } | ||
352 | spin_unlock_bh(&cache->lock); | ||
353 | } | ||
354 | |||
355 | static int tx_policy_upload(struct cw1200_common *priv) | ||
356 | { | ||
357 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
358 | int i; | ||
359 | struct wsm_set_tx_rate_retry_policy arg = { | ||
360 | .num = 0, | ||
361 | }; | ||
362 | spin_lock_bh(&cache->lock); | ||
363 | |||
364 | /* Upload only modified entries. */ | ||
365 | for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) { | ||
366 | struct tx_policy *src = &cache->cache[i].policy; | ||
367 | if (src->retry_count && !src->uploaded) { | ||
368 | struct wsm_tx_rate_retry_policy *dst = | ||
369 | &arg.tbl[arg.num]; | ||
370 | dst->index = i; | ||
371 | dst->short_retries = priv->short_frame_max_tx_count; | ||
372 | dst->long_retries = priv->long_frame_max_tx_count; | ||
373 | |||
374 | dst->flags = WSM_TX_RATE_POLICY_FLAG_TERMINATE_WHEN_FINISHED | | ||
375 | WSM_TX_RATE_POLICY_FLAG_COUNT_INITIAL_TRANSMIT; | ||
376 | memcpy(dst->rate_count_indices, src->tbl, | ||
377 | sizeof(dst->rate_count_indices)); | ||
378 | src->uploaded = 1; | ||
379 | ++arg.num; | ||
380 | } | ||
381 | } | ||
382 | spin_unlock_bh(&cache->lock); | ||
383 | cw1200_debug_tx_cache_miss(priv); | ||
384 | pr_debug("[TX policy] Upload %d policies\n", arg.num); | ||
385 | return wsm_set_tx_rate_retry_policy(priv, &arg); | ||
386 | } | ||
387 | |||
388 | void tx_policy_upload_work(struct work_struct *work) | ||
389 | { | ||
390 | struct cw1200_common *priv = | ||
391 | container_of(work, struct cw1200_common, tx_policy_upload_work); | ||
392 | |||
393 | pr_debug("[TX] TX policy upload.\n"); | ||
394 | tx_policy_upload(priv); | ||
395 | |||
396 | wsm_unlock_tx(priv); | ||
397 | cw1200_tx_queues_unlock(priv); | ||
398 | } | ||
399 | |||
400 | /* ******************************************************************** */ | ||
401 | /* cw1200 TX implementation */ | ||
402 | |||
403 | struct cw1200_txinfo { | ||
404 | struct sk_buff *skb; | ||
405 | unsigned queue; | ||
406 | struct ieee80211_tx_info *tx_info; | ||
407 | const struct ieee80211_rate *rate; | ||
408 | struct ieee80211_hdr *hdr; | ||
409 | size_t hdrlen; | ||
410 | const u8 *da; | ||
411 | struct cw1200_sta_priv *sta_priv; | ||
412 | struct ieee80211_sta *sta; | ||
413 | struct cw1200_txpriv txpriv; | ||
414 | }; | ||
415 | |||
416 | u32 cw1200_rate_mask_to_wsm(struct cw1200_common *priv, u32 rates) | ||
417 | { | ||
418 | u32 ret = 0; | ||
419 | int i; | ||
420 | for (i = 0; i < 32; ++i) { | ||
421 | if (rates & BIT(i)) | ||
422 | ret |= BIT(priv->rates[i].hw_value); | ||
423 | } | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | static const struct ieee80211_rate * | ||
428 | cw1200_get_tx_rate(const struct cw1200_common *priv, | ||
429 | const struct ieee80211_tx_rate *rate) | ||
430 | { | ||
431 | if (rate->idx < 0) | ||
432 | return NULL; | ||
433 | if (rate->flags & IEEE80211_TX_RC_MCS) | ||
434 | return &priv->mcs_rates[rate->idx]; | ||
435 | return &priv->hw->wiphy->bands[priv->channel->band]-> | ||
436 | bitrates[rate->idx]; | ||
437 | } | ||
438 | |||
439 | static int | ||
440 | cw1200_tx_h_calc_link_ids(struct cw1200_common *priv, | ||
441 | struct cw1200_txinfo *t) | ||
442 | { | ||
443 | if (t->sta && t->sta_priv->link_id) | ||
444 | t->txpriv.raw_link_id = | ||
445 | t->txpriv.link_id = | ||
446 | t->sta_priv->link_id; | ||
447 | else if (priv->mode != NL80211_IFTYPE_AP) | ||
448 | t->txpriv.raw_link_id = | ||
449 | t->txpriv.link_id = 0; | ||
450 | else if (is_multicast_ether_addr(t->da)) { | ||
451 | if (priv->enable_beacon) { | ||
452 | t->txpriv.raw_link_id = 0; | ||
453 | t->txpriv.link_id = CW1200_LINK_ID_AFTER_DTIM; | ||
454 | } else { | ||
455 | t->txpriv.raw_link_id = 0; | ||
456 | t->txpriv.link_id = 0; | ||
457 | } | ||
458 | } else { | ||
459 | t->txpriv.link_id = cw1200_find_link_id(priv, t->da); | ||
460 | if (!t->txpriv.link_id) | ||
461 | t->txpriv.link_id = cw1200_alloc_link_id(priv, t->da); | ||
462 | if (!t->txpriv.link_id) { | ||
463 | wiphy_err(priv->hw->wiphy, | ||
464 | "No more link IDs available.\n"); | ||
465 | return -ENOENT; | ||
466 | } | ||
467 | t->txpriv.raw_link_id = t->txpriv.link_id; | ||
468 | } | ||
469 | if (t->txpriv.raw_link_id) | ||
470 | priv->link_id_db[t->txpriv.raw_link_id - 1].timestamp = | ||
471 | jiffies; | ||
472 | if (t->sta && (t->sta->uapsd_queues & BIT(t->queue))) | ||
473 | t->txpriv.link_id = CW1200_LINK_ID_UAPSD; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static void | ||
478 | cw1200_tx_h_pm(struct cw1200_common *priv, | ||
479 | struct cw1200_txinfo *t) | ||
480 | { | ||
481 | if (ieee80211_is_auth(t->hdr->frame_control)) { | ||
482 | u32 mask = ~BIT(t->txpriv.raw_link_id); | ||
483 | spin_lock_bh(&priv->ps_state_lock); | ||
484 | priv->sta_asleep_mask &= mask; | ||
485 | priv->pspoll_mask &= mask; | ||
486 | spin_unlock_bh(&priv->ps_state_lock); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | static void | ||
491 | cw1200_tx_h_calc_tid(struct cw1200_common *priv, | ||
492 | struct cw1200_txinfo *t) | ||
493 | { | ||
494 | if (ieee80211_is_data_qos(t->hdr->frame_control)) { | ||
495 | u8 *qos = ieee80211_get_qos_ctl(t->hdr); | ||
496 | t->txpriv.tid = qos[0] & IEEE80211_QOS_CTL_TID_MASK; | ||
497 | } else if (ieee80211_is_data(t->hdr->frame_control)) { | ||
498 | t->txpriv.tid = 0; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | static int | ||
503 | cw1200_tx_h_crypt(struct cw1200_common *priv, | ||
504 | struct cw1200_txinfo *t) | ||
505 | { | ||
506 | if (!t->tx_info->control.hw_key || | ||
507 | !ieee80211_has_protected(t->hdr->frame_control)) | ||
508 | return 0; | ||
509 | |||
510 | t->hdrlen += t->tx_info->control.hw_key->iv_len; | ||
511 | skb_put(t->skb, t->tx_info->control.hw_key->icv_len); | ||
512 | |||
513 | if (t->tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
514 | skb_put(t->skb, 8); /* MIC space */ | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static int | ||
520 | cw1200_tx_h_align(struct cw1200_common *priv, | ||
521 | struct cw1200_txinfo *t, | ||
522 | u8 *flags) | ||
523 | { | ||
524 | size_t offset = (size_t)t->skb->data & 3; | ||
525 | |||
526 | if (!offset) | ||
527 | return 0; | ||
528 | |||
529 | if (offset & 1) { | ||
530 | wiphy_err(priv->hw->wiphy, | ||
531 | "Bug: attempt to transmit a frame with wrong alignment: %zu\n", | ||
532 | offset); | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | if (skb_headroom(t->skb) < offset) { | ||
537 | wiphy_err(priv->hw->wiphy, | ||
538 | "Bug: no space allocated for DMA alignment. headroom: %d\n", | ||
539 | skb_headroom(t->skb)); | ||
540 | return -ENOMEM; | ||
541 | } | ||
542 | skb_push(t->skb, offset); | ||
543 | t->hdrlen += offset; | ||
544 | t->txpriv.offset += offset; | ||
545 | *flags |= WSM_TX_2BYTES_SHIFT; | ||
546 | cw1200_debug_tx_align(priv); | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int | ||
551 | cw1200_tx_h_action(struct cw1200_common *priv, | ||
552 | struct cw1200_txinfo *t) | ||
553 | { | ||
554 | struct ieee80211_mgmt *mgmt = | ||
555 | (struct ieee80211_mgmt *)t->hdr; | ||
556 | if (ieee80211_is_action(t->hdr->frame_control) && | ||
557 | mgmt->u.action.category == WLAN_CATEGORY_BACK) | ||
558 | return 1; | ||
559 | else | ||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | /* Add WSM header */ | ||
564 | static struct wsm_tx * | ||
565 | cw1200_tx_h_wsm(struct cw1200_common *priv, | ||
566 | struct cw1200_txinfo *t) | ||
567 | { | ||
568 | struct wsm_tx *wsm; | ||
569 | |||
570 | if (skb_headroom(t->skb) < sizeof(struct wsm_tx)) { | ||
571 | wiphy_err(priv->hw->wiphy, | ||
572 | "Bug: no space allocated for WSM header. headroom: %d\n", | ||
573 | skb_headroom(t->skb)); | ||
574 | return NULL; | ||
575 | } | ||
576 | |||
577 | wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); | ||
578 | t->txpriv.offset += sizeof(struct wsm_tx); | ||
579 | memset(wsm, 0, sizeof(*wsm)); | ||
580 | wsm->hdr.len = __cpu_to_le16(t->skb->len); | ||
581 | wsm->hdr.id = __cpu_to_le16(0x0004); | ||
582 | wsm->queue_id = wsm_queue_id_to_wsm(t->queue); | ||
583 | return wsm; | ||
584 | } | ||
585 | |||
586 | /* BT Coex specific handling */ | ||
587 | static void | ||
588 | cw1200_tx_h_bt(struct cw1200_common *priv, | ||
589 | struct cw1200_txinfo *t, | ||
590 | struct wsm_tx *wsm) | ||
591 | { | ||
592 | u8 priority = 0; | ||
593 | |||
594 | if (!priv->bt_present) | ||
595 | return; | ||
596 | |||
597 | if (ieee80211_is_nullfunc(t->hdr->frame_control)) { | ||
598 | priority = WSM_EPTA_PRIORITY_MGT; | ||
599 | } else if (ieee80211_is_data(t->hdr->frame_control)) { | ||
600 | /* Skip LLC SNAP header (+6) */ | ||
601 | u8 *payload = &t->skb->data[t->hdrlen]; | ||
602 | u16 *ethertype = (u16 *)&payload[6]; | ||
603 | if (*ethertype == __be16_to_cpu(ETH_P_PAE)) | ||
604 | priority = WSM_EPTA_PRIORITY_EAPOL; | ||
605 | } else if (ieee80211_is_assoc_req(t->hdr->frame_control) || | ||
606 | ieee80211_is_reassoc_req(t->hdr->frame_control)) { | ||
607 | struct ieee80211_mgmt *mgt_frame = | ||
608 | (struct ieee80211_mgmt *)t->hdr; | ||
609 | |||
610 | if (mgt_frame->u.assoc_req.listen_interval < | ||
611 | priv->listen_interval) { | ||
612 | pr_debug("Modified Listen Interval to %d from %d\n", | ||
613 | priv->listen_interval, | ||
614 | mgt_frame->u.assoc_req.listen_interval); | ||
615 | /* Replace listen interval derieved from | ||
616 | * the one read from SDD */ | ||
617 | mgt_frame->u.assoc_req.listen_interval = | ||
618 | priv->listen_interval; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | if (!priority) { | ||
623 | if (ieee80211_is_action(t->hdr->frame_control)) | ||
624 | priority = WSM_EPTA_PRIORITY_ACTION; | ||
625 | else if (ieee80211_is_mgmt(t->hdr->frame_control)) | ||
626 | priority = WSM_EPTA_PRIORITY_MGT; | ||
627 | else if ((wsm->queue_id == WSM_QUEUE_VOICE)) | ||
628 | priority = WSM_EPTA_PRIORITY_VOICE; | ||
629 | else if ((wsm->queue_id == WSM_QUEUE_VIDEO)) | ||
630 | priority = WSM_EPTA_PRIORITY_VIDEO; | ||
631 | else | ||
632 | priority = WSM_EPTA_PRIORITY_DATA; | ||
633 | } | ||
634 | |||
635 | pr_debug("[TX] EPTA priority %d.\n", priority); | ||
636 | |||
637 | wsm->flags |= priority << 1; | ||
638 | } | ||
639 | |||
640 | static int | ||
641 | cw1200_tx_h_rate_policy(struct cw1200_common *priv, | ||
642 | struct cw1200_txinfo *t, | ||
643 | struct wsm_tx *wsm) | ||
644 | { | ||
645 | bool tx_policy_renew = false; | ||
646 | |||
647 | t->txpriv.rate_id = tx_policy_get(priv, | ||
648 | t->tx_info->control.rates, IEEE80211_TX_MAX_RATES, | ||
649 | &tx_policy_renew); | ||
650 | if (t->txpriv.rate_id == CW1200_INVALID_RATE_ID) | ||
651 | return -EFAULT; | ||
652 | |||
653 | wsm->flags |= t->txpriv.rate_id << 4; | ||
654 | |||
655 | t->rate = cw1200_get_tx_rate(priv, | ||
656 | &t->tx_info->control.rates[0]), | ||
657 | wsm->max_tx_rate = t->rate->hw_value; | ||
658 | if (t->rate->flags & IEEE80211_TX_RC_MCS) { | ||
659 | if (cw1200_ht_greenfield(&priv->ht_info)) | ||
660 | wsm->ht_tx_parameters |= | ||
661 | __cpu_to_le32(WSM_HT_TX_GREENFIELD); | ||
662 | else | ||
663 | wsm->ht_tx_parameters |= | ||
664 | __cpu_to_le32(WSM_HT_TX_MIXED); | ||
665 | } | ||
666 | |||
667 | if (tx_policy_renew) { | ||
668 | pr_debug("[TX] TX policy renew.\n"); | ||
669 | /* It's not so optimal to stop TX queues every now and then. | ||
670 | * Better to reimplement task scheduling with | ||
671 | * a counter. TODO. */ | ||
672 | wsm_lock_tx_async(priv); | ||
673 | cw1200_tx_queues_lock(priv); | ||
674 | if (queue_work(priv->workqueue, | ||
675 | &priv->tx_policy_upload_work) <= 0) { | ||
676 | cw1200_tx_queues_unlock(priv); | ||
677 | wsm_unlock_tx(priv); | ||
678 | } | ||
679 | } | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | static bool | ||
684 | cw1200_tx_h_pm_state(struct cw1200_common *priv, | ||
685 | struct cw1200_txinfo *t) | ||
686 | { | ||
687 | int was_buffered = 1; | ||
688 | |||
689 | if (t->txpriv.link_id == CW1200_LINK_ID_AFTER_DTIM && | ||
690 | !priv->buffered_multicasts) { | ||
691 | priv->buffered_multicasts = true; | ||
692 | if (priv->sta_asleep_mask) | ||
693 | queue_work(priv->workqueue, | ||
694 | &priv->multicast_start_work); | ||
695 | } | ||
696 | |||
697 | if (t->txpriv.raw_link_id && t->txpriv.tid < CW1200_MAX_TID) | ||
698 | was_buffered = priv->link_id_db[t->txpriv.raw_link_id - 1].buffered[t->txpriv.tid]++; | ||
699 | |||
700 | return !was_buffered; | ||
701 | } | ||
702 | |||
703 | /* ******************************************************************** */ | ||
704 | |||
705 | void cw1200_tx(struct ieee80211_hw *dev, | ||
706 | struct ieee80211_tx_control *control, | ||
707 | struct sk_buff *skb) | ||
708 | { | ||
709 | struct cw1200_common *priv = dev->priv; | ||
710 | struct cw1200_txinfo t = { | ||
711 | .skb = skb, | ||
712 | .queue = skb_get_queue_mapping(skb), | ||
713 | .tx_info = IEEE80211_SKB_CB(skb), | ||
714 | .hdr = (struct ieee80211_hdr *)skb->data, | ||
715 | .txpriv.tid = CW1200_MAX_TID, | ||
716 | .txpriv.rate_id = CW1200_INVALID_RATE_ID, | ||
717 | }; | ||
718 | struct ieee80211_sta *sta; | ||
719 | struct wsm_tx *wsm; | ||
720 | bool tid_update = 0; | ||
721 | u8 flags = 0; | ||
722 | int ret; | ||
723 | |||
724 | if (priv->bh_error) | ||
725 | goto drop; | ||
726 | |||
727 | t.hdrlen = ieee80211_hdrlen(t.hdr->frame_control); | ||
728 | t.da = ieee80211_get_DA(t.hdr); | ||
729 | if (control) { | ||
730 | t.sta = control->sta; | ||
731 | t.sta_priv = (struct cw1200_sta_priv *)&t.sta->drv_priv; | ||
732 | } | ||
733 | |||
734 | if (WARN_ON(t.queue >= 4)) | ||
735 | goto drop; | ||
736 | |||
737 | ret = cw1200_tx_h_calc_link_ids(priv, &t); | ||
738 | if (ret) | ||
739 | goto drop; | ||
740 | |||
741 | pr_debug("[TX] TX %d bytes (queue: %d, link_id: %d (%d)).\n", | ||
742 | skb->len, t.queue, t.txpriv.link_id, | ||
743 | t.txpriv.raw_link_id); | ||
744 | |||
745 | cw1200_tx_h_pm(priv, &t); | ||
746 | cw1200_tx_h_calc_tid(priv, &t); | ||
747 | ret = cw1200_tx_h_crypt(priv, &t); | ||
748 | if (ret) | ||
749 | goto drop; | ||
750 | ret = cw1200_tx_h_align(priv, &t, &flags); | ||
751 | if (ret) | ||
752 | goto drop; | ||
753 | ret = cw1200_tx_h_action(priv, &t); | ||
754 | if (ret) | ||
755 | goto drop; | ||
756 | wsm = cw1200_tx_h_wsm(priv, &t); | ||
757 | if (!wsm) { | ||
758 | ret = -ENOMEM; | ||
759 | goto drop; | ||
760 | } | ||
761 | wsm->flags |= flags; | ||
762 | cw1200_tx_h_bt(priv, &t, wsm); | ||
763 | ret = cw1200_tx_h_rate_policy(priv, &t, wsm); | ||
764 | if (ret) | ||
765 | goto drop; | ||
766 | |||
767 | rcu_read_lock(); | ||
768 | sta = rcu_dereference(t.sta); | ||
769 | |||
770 | spin_lock_bh(&priv->ps_state_lock); | ||
771 | { | ||
772 | tid_update = cw1200_tx_h_pm_state(priv, &t); | ||
773 | BUG_ON(cw1200_queue_put(&priv->tx_queue[t.queue], | ||
774 | t.skb, &t.txpriv)); | ||
775 | } | ||
776 | spin_unlock_bh(&priv->ps_state_lock); | ||
777 | |||
778 | if (tid_update && sta) | ||
779 | ieee80211_sta_set_buffered(sta, t.txpriv.tid, true); | ||
780 | |||
781 | rcu_read_unlock(); | ||
782 | |||
783 | cw1200_bh_wakeup(priv); | ||
784 | |||
785 | return; | ||
786 | |||
787 | drop: | ||
788 | cw1200_skb_dtor(priv, skb, &t.txpriv); | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | /* ******************************************************************** */ | ||
793 | |||
794 | static int cw1200_handle_action_rx(struct cw1200_common *priv, | ||
795 | struct sk_buff *skb) | ||
796 | { | ||
797 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
798 | |||
799 | /* Filter block ACK negotiation: fully controlled by firmware */ | ||
800 | if (mgmt->u.action.category == WLAN_CATEGORY_BACK) | ||
801 | return 1; | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int cw1200_handle_pspoll(struct cw1200_common *priv, | ||
807 | struct sk_buff *skb) | ||
808 | { | ||
809 | struct ieee80211_sta *sta; | ||
810 | struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data; | ||
811 | int link_id = 0; | ||
812 | u32 pspoll_mask = 0; | ||
813 | int drop = 1; | ||
814 | int i; | ||
815 | |||
816 | if (priv->join_status != CW1200_JOIN_STATUS_AP) | ||
817 | goto done; | ||
818 | if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) | ||
819 | goto done; | ||
820 | |||
821 | rcu_read_lock(); | ||
822 | sta = ieee80211_find_sta(priv->vif, pspoll->ta); | ||
823 | if (sta) { | ||
824 | struct cw1200_sta_priv *sta_priv; | ||
825 | sta_priv = (struct cw1200_sta_priv *)&sta->drv_priv; | ||
826 | link_id = sta_priv->link_id; | ||
827 | pspoll_mask = BIT(sta_priv->link_id); | ||
828 | } | ||
829 | rcu_read_unlock(); | ||
830 | if (!link_id) | ||
831 | goto done; | ||
832 | |||
833 | priv->pspoll_mask |= pspoll_mask; | ||
834 | drop = 0; | ||
835 | |||
836 | /* Do not report pspols if data for given link id is | ||
837 | * queued already. */ | ||
838 | for (i = 0; i < 4; ++i) { | ||
839 | if (cw1200_queue_get_num_queued(&priv->tx_queue[i], | ||
840 | pspoll_mask)) { | ||
841 | cw1200_bh_wakeup(priv); | ||
842 | drop = 1; | ||
843 | break; | ||
844 | } | ||
845 | } | ||
846 | pr_debug("[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); | ||
847 | done: | ||
848 | return drop; | ||
849 | } | ||
850 | |||
851 | /* ******************************************************************** */ | ||
852 | |||
853 | void cw1200_tx_confirm_cb(struct cw1200_common *priv, | ||
854 | int link_id, | ||
855 | struct wsm_tx_confirm *arg) | ||
856 | { | ||
857 | u8 queue_id = cw1200_queue_get_queue_id(arg->packet_id); | ||
858 | struct cw1200_queue *queue = &priv->tx_queue[queue_id]; | ||
859 | struct sk_buff *skb; | ||
860 | const struct cw1200_txpriv *txpriv; | ||
861 | |||
862 | pr_debug("[TX] TX confirm: %d, %d.\n", | ||
863 | arg->status, arg->ack_failures); | ||
864 | |||
865 | if (cw1200_itp_tx_running(priv)) | ||
866 | return; | ||
867 | |||
868 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
869 | /* STA is stopped. */ | ||
870 | return; | ||
871 | } | ||
872 | |||
873 | if (WARN_ON(queue_id >= 4)) | ||
874 | return; | ||
875 | |||
876 | if (arg->status) | ||
877 | pr_debug("TX failed: %d.\n", arg->status); | ||
878 | |||
879 | if ((arg->status == WSM_REQUEUE) && | ||
880 | (arg->flags & WSM_TX_STATUS_REQUEUE)) { | ||
881 | /* "Requeue" means "implicit suspend" */ | ||
882 | struct wsm_suspend_resume suspend = { | ||
883 | .link_id = link_id, | ||
884 | .stop = 1, | ||
885 | .multicast = !link_id, | ||
886 | }; | ||
887 | cw1200_suspend_resume(priv, &suspend); | ||
888 | wiphy_warn(priv->hw->wiphy, "Requeue for link_id %d (try %d). STAs asleep: 0x%.8X\n", | ||
889 | link_id, | ||
890 | cw1200_queue_get_generation(arg->packet_id) + 1, | ||
891 | priv->sta_asleep_mask); | ||
892 | cw1200_queue_requeue(queue, arg->packet_id); | ||
893 | spin_lock_bh(&priv->ps_state_lock); | ||
894 | if (!link_id) { | ||
895 | priv->buffered_multicasts = true; | ||
896 | if (priv->sta_asleep_mask) { | ||
897 | queue_work(priv->workqueue, | ||
898 | &priv->multicast_start_work); | ||
899 | } | ||
900 | } | ||
901 | spin_unlock_bh(&priv->ps_state_lock); | ||
902 | } else if (!cw1200_queue_get_skb(queue, arg->packet_id, | ||
903 | &skb, &txpriv)) { | ||
904 | struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb); | ||
905 | int tx_count = arg->ack_failures; | ||
906 | u8 ht_flags = 0; | ||
907 | int i; | ||
908 | |||
909 | if (cw1200_ht_greenfield(&priv->ht_info)) | ||
910 | ht_flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
911 | |||
912 | spin_lock(&priv->bss_loss_lock); | ||
913 | if (priv->bss_loss_state && | ||
914 | arg->packet_id == priv->bss_loss_confirm_id) { | ||
915 | if (arg->status) { | ||
916 | /* Recovery failed */ | ||
917 | __cw1200_cqm_bssloss_sm(priv, 0, 0, 1); | ||
918 | } else { | ||
919 | /* Recovery succeeded */ | ||
920 | __cw1200_cqm_bssloss_sm(priv, 0, 1, 0); | ||
921 | } | ||
922 | } | ||
923 | spin_unlock(&priv->bss_loss_lock); | ||
924 | |||
925 | if (!arg->status) { | ||
926 | tx->flags |= IEEE80211_TX_STAT_ACK; | ||
927 | ++tx_count; | ||
928 | cw1200_debug_txed(priv); | ||
929 | if (arg->flags & WSM_TX_STATUS_AGGREGATION) { | ||
930 | /* Do not report aggregation to mac80211: | ||
931 | * it confuses minstrel a lot. */ | ||
932 | /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ | ||
933 | cw1200_debug_txed_agg(priv); | ||
934 | } | ||
935 | } else { | ||
936 | if (tx_count) | ||
937 | ++tx_count; | ||
938 | } | ||
939 | |||
940 | for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { | ||
941 | if (tx->status.rates[i].count >= tx_count) { | ||
942 | tx->status.rates[i].count = tx_count; | ||
943 | break; | ||
944 | } | ||
945 | tx_count -= tx->status.rates[i].count; | ||
946 | if (tx->status.rates[i].flags & IEEE80211_TX_RC_MCS) | ||
947 | tx->status.rates[i].flags |= ht_flags; | ||
948 | } | ||
949 | |||
950 | for (++i; i < IEEE80211_TX_MAX_RATES; ++i) { | ||
951 | tx->status.rates[i].count = 0; | ||
952 | tx->status.rates[i].idx = -1; | ||
953 | } | ||
954 | |||
955 | /* Pull off any crypto trailers that we added on */ | ||
956 | if (tx->control.hw_key) { | ||
957 | skb_trim(skb, skb->len - tx->control.hw_key->icv_len); | ||
958 | if (tx->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
959 | skb_trim(skb, skb->len - 8); /* MIC space */ | ||
960 | } | ||
961 | cw1200_queue_remove(queue, arg->packet_id); | ||
962 | } | ||
963 | /* XXX TODO: Only wake if there are pending transmits.. */ | ||
964 | cw1200_bh_wakeup(priv); | ||
965 | } | ||
966 | |||
967 | static void cw1200_notify_buffered_tx(struct cw1200_common *priv, | ||
968 | struct sk_buff *skb, int link_id, int tid) | ||
969 | { | ||
970 | struct ieee80211_sta *sta; | ||
971 | struct ieee80211_hdr *hdr; | ||
972 | u8 *buffered; | ||
973 | u8 still_buffered = 0; | ||
974 | |||
975 | if (link_id && tid < CW1200_MAX_TID) { | ||
976 | buffered = priv->link_id_db | ||
977 | [link_id - 1].buffered; | ||
978 | |||
979 | spin_lock_bh(&priv->ps_state_lock); | ||
980 | if (!WARN_ON(!buffered[tid])) | ||
981 | still_buffered = --buffered[tid]; | ||
982 | spin_unlock_bh(&priv->ps_state_lock); | ||
983 | |||
984 | if (!still_buffered && tid < CW1200_MAX_TID) { | ||
985 | hdr = (struct ieee80211_hdr *)skb->data; | ||
986 | rcu_read_lock(); | ||
987 | sta = ieee80211_find_sta(priv->vif, hdr->addr1); | ||
988 | if (sta) | ||
989 | ieee80211_sta_set_buffered(sta, tid, false); | ||
990 | rcu_read_unlock(); | ||
991 | } | ||
992 | } | ||
993 | } | ||
994 | |||
995 | void cw1200_skb_dtor(struct cw1200_common *priv, | ||
996 | struct sk_buff *skb, | ||
997 | const struct cw1200_txpriv *txpriv) | ||
998 | { | ||
999 | skb_pull(skb, txpriv->offset); | ||
1000 | if (txpriv->rate_id != CW1200_INVALID_RATE_ID) { | ||
1001 | cw1200_notify_buffered_tx(priv, skb, | ||
1002 | txpriv->raw_link_id, txpriv->tid); | ||
1003 | tx_policy_put(priv, txpriv->rate_id); | ||
1004 | } | ||
1005 | if (!cw1200_is_itp(priv)) | ||
1006 | ieee80211_tx_status(priv->hw, skb); | ||
1007 | } | ||
1008 | |||
1009 | void cw1200_rx_cb(struct cw1200_common *priv, | ||
1010 | struct wsm_rx *arg, | ||
1011 | int link_id, | ||
1012 | struct sk_buff **skb_p) | ||
1013 | { | ||
1014 | struct sk_buff *skb = *skb_p; | ||
1015 | struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); | ||
1016 | struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; | ||
1017 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1018 | struct cw1200_link_entry *entry = NULL; | ||
1019 | unsigned long grace_period; | ||
1020 | |||
1021 | bool early_data = false; | ||
1022 | bool p2p = priv->vif && priv->vif->p2p; | ||
1023 | size_t hdrlen; | ||
1024 | hdr->flag = 0; | ||
1025 | |||
1026 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
1027 | /* STA is stopped. */ | ||
1028 | goto drop; | ||
1029 | } | ||
1030 | |||
1031 | if (link_id && link_id <= CW1200_MAX_STA_IN_AP_MODE) { | ||
1032 | entry = &priv->link_id_db[link_id - 1]; | ||
1033 | if (entry->status == CW1200_LINK_SOFT && | ||
1034 | ieee80211_is_data(frame->frame_control)) | ||
1035 | early_data = true; | ||
1036 | entry->timestamp = jiffies; | ||
1037 | } else if (p2p && | ||
1038 | ieee80211_is_action(frame->frame_control) && | ||
1039 | (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { | ||
1040 | pr_debug("[RX] Going to MAP&RESET link ID\n"); | ||
1041 | WARN_ON(work_pending(&priv->linkid_reset_work)); | ||
1042 | memcpy(&priv->action_frame_sa[0], | ||
1043 | ieee80211_get_SA(frame), ETH_ALEN); | ||
1044 | priv->action_linkid = 0; | ||
1045 | schedule_work(&priv->linkid_reset_work); | ||
1046 | } | ||
1047 | |||
1048 | if (link_id && p2p && | ||
1049 | ieee80211_is_action(frame->frame_control) && | ||
1050 | (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { | ||
1051 | /* Link ID already exists for the ACTION frame. | ||
1052 | * Reset and Remap */ | ||
1053 | WARN_ON(work_pending(&priv->linkid_reset_work)); | ||
1054 | memcpy(&priv->action_frame_sa[0], | ||
1055 | ieee80211_get_SA(frame), ETH_ALEN); | ||
1056 | priv->action_linkid = link_id; | ||
1057 | schedule_work(&priv->linkid_reset_work); | ||
1058 | } | ||
1059 | if (arg->status) { | ||
1060 | if (arg->status == WSM_STATUS_MICFAILURE) { | ||
1061 | pr_debug("[RX] MIC failure.\n"); | ||
1062 | hdr->flag |= RX_FLAG_MMIC_ERROR; | ||
1063 | } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { | ||
1064 | pr_debug("[RX] No key found.\n"); | ||
1065 | goto drop; | ||
1066 | } else { | ||
1067 | pr_debug("[RX] Receive failure: %d.\n", | ||
1068 | arg->status); | ||
1069 | goto drop; | ||
1070 | } | ||
1071 | } | ||
1072 | |||
1073 | if (skb->len < sizeof(struct ieee80211_pspoll)) { | ||
1074 | wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. Size is lesser than IEEE header.\n"); | ||
1075 | goto drop; | ||
1076 | } | ||
1077 | |||
1078 | if (ieee80211_is_pspoll(frame->frame_control)) | ||
1079 | if (cw1200_handle_pspoll(priv, skb)) | ||
1080 | goto drop; | ||
1081 | |||
1082 | hdr->mactime = 0; /* Not supported by WSM */ | ||
1083 | hdr->band = ((arg->channel_number & 0xff00) || | ||
1084 | (arg->channel_number > 14)) ? | ||
1085 | IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; | ||
1086 | hdr->freq = ieee80211_channel_to_frequency( | ||
1087 | arg->channel_number, | ||
1088 | hdr->band); | ||
1089 | |||
1090 | if (arg->rx_rate >= 14) { | ||
1091 | hdr->flag |= RX_FLAG_HT; | ||
1092 | hdr->rate_idx = arg->rx_rate - 14; | ||
1093 | } else if (arg->rx_rate >= 4) { | ||
1094 | hdr->rate_idx = arg->rx_rate - 2; | ||
1095 | } else { | ||
1096 | hdr->rate_idx = arg->rx_rate; | ||
1097 | } | ||
1098 | |||
1099 | hdr->signal = (s8)arg->rcpi_rssi; | ||
1100 | hdr->antenna = 0; | ||
1101 | |||
1102 | hdrlen = ieee80211_hdrlen(frame->frame_control); | ||
1103 | |||
1104 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { | ||
1105 | size_t iv_len = 0, icv_len = 0; | ||
1106 | |||
1107 | hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; | ||
1108 | |||
1109 | /* Oops... There is no fast way to ask mac80211 about | ||
1110 | * IV/ICV lengths. Even defineas are not exposed.*/ | ||
1111 | switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { | ||
1112 | case WSM_RX_STATUS_WEP: | ||
1113 | iv_len = 4 /* WEP_IV_LEN */; | ||
1114 | icv_len = 4 /* WEP_ICV_LEN */; | ||
1115 | break; | ||
1116 | case WSM_RX_STATUS_TKIP: | ||
1117 | iv_len = 8 /* TKIP_IV_LEN */; | ||
1118 | icv_len = 4 /* TKIP_ICV_LEN */ | ||
1119 | + 8 /*MICHAEL_MIC_LEN*/; | ||
1120 | hdr->flag |= RX_FLAG_MMIC_STRIPPED; | ||
1121 | break; | ||
1122 | case WSM_RX_STATUS_AES: | ||
1123 | iv_len = 8 /* CCMP_HDR_LEN */; | ||
1124 | icv_len = 8 /* CCMP_MIC_LEN */; | ||
1125 | break; | ||
1126 | case WSM_RX_STATUS_WAPI: | ||
1127 | iv_len = 18 /* WAPI_HDR_LEN */; | ||
1128 | icv_len = 16 /* WAPI_MIC_LEN */; | ||
1129 | break; | ||
1130 | default: | ||
1131 | pr_warn("Unknown encryption type %d\n", | ||
1132 | WSM_RX_STATUS_ENCRYPTION(arg->flags)); | ||
1133 | goto drop; | ||
1134 | } | ||
1135 | |||
1136 | /* Firmware strips ICV in case of MIC failure. */ | ||
1137 | if (arg->status == WSM_STATUS_MICFAILURE) | ||
1138 | icv_len = 0; | ||
1139 | |||
1140 | if (skb->len < hdrlen + iv_len + icv_len) { | ||
1141 | wiphy_warn(priv->hw->wiphy, "Malformed SDU rx'ed. Size is lesser than crypto headers.\n"); | ||
1142 | goto drop; | ||
1143 | } | ||
1144 | |||
1145 | /* Remove IV, ICV and MIC */ | ||
1146 | skb_trim(skb, skb->len - icv_len); | ||
1147 | memmove(skb->data + iv_len, skb->data, hdrlen); | ||
1148 | skb_pull(skb, iv_len); | ||
1149 | } | ||
1150 | |||
1151 | /* Remove TSF from the end of frame */ | ||
1152 | if (arg->flags & WSM_RX_STATUS_TSF_INCLUDED) { | ||
1153 | memcpy(&hdr->mactime, skb->data + skb->len - 8, 8); | ||
1154 | hdr->mactime = le64_to_cpu(hdr->mactime); | ||
1155 | if (skb->len >= 8) | ||
1156 | skb_trim(skb, skb->len - 8); | ||
1157 | } | ||
1158 | |||
1159 | cw1200_debug_rxed(priv); | ||
1160 | if (arg->flags & WSM_RX_STATUS_AGGREGATE) | ||
1161 | cw1200_debug_rxed_agg(priv); | ||
1162 | |||
1163 | if (ieee80211_is_action(frame->frame_control) && | ||
1164 | (arg->flags & WSM_RX_STATUS_ADDRESS1)) { | ||
1165 | if (cw1200_handle_action_rx(priv, skb)) | ||
1166 | return; | ||
1167 | } else if (ieee80211_is_beacon(frame->frame_control) && | ||
1168 | !arg->status && | ||
1169 | !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid, | ||
1170 | ETH_ALEN)) { | ||
1171 | const u8 *tim_ie; | ||
1172 | u8 *ies = ((struct ieee80211_mgmt *) | ||
1173 | (skb->data))->u.beacon.variable; | ||
1174 | size_t ies_len = skb->len - (ies - (u8 *)(skb->data)); | ||
1175 | |||
1176 | tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len); | ||
1177 | if (tim_ie) { | ||
1178 | struct ieee80211_tim_ie *tim = | ||
1179 | (struct ieee80211_tim_ie *)&tim_ie[2]; | ||
1180 | |||
1181 | if (priv->join_dtim_period != tim->dtim_period) { | ||
1182 | priv->join_dtim_period = tim->dtim_period; | ||
1183 | queue_work(priv->workqueue, | ||
1184 | &priv->set_beacon_wakeup_period_work); | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | /* Disable beacon filter once we're associated... */ | ||
1189 | if (priv->disable_beacon_filter && | ||
1190 | (priv->vif->bss_conf.assoc || | ||
1191 | priv->vif->bss_conf.ibss_joined)) { | ||
1192 | priv->disable_beacon_filter = false; | ||
1193 | queue_work(priv->workqueue, | ||
1194 | &priv->update_filtering_work); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /* Stay awake after frame is received to give | ||
1199 | * userspace chance to react and acquire appropriate | ||
1200 | * wakelock. */ | ||
1201 | if (ieee80211_is_auth(frame->frame_control)) | ||
1202 | grace_period = 5 * HZ; | ||
1203 | else if (ieee80211_is_deauth(frame->frame_control)) | ||
1204 | grace_period = 5 * HZ; | ||
1205 | else | ||
1206 | grace_period = 1 * HZ; | ||
1207 | cw1200_pm_stay_awake(&priv->pm_state, grace_period); | ||
1208 | |||
1209 | if (cw1200_itp_rxed(priv, skb)) { | ||
1210 | consume_skb(skb); | ||
1211 | } else if (early_data) { | ||
1212 | spin_lock_bh(&priv->ps_state_lock); | ||
1213 | /* Double-check status with lock held */ | ||
1214 | if (entry->status == CW1200_LINK_SOFT) | ||
1215 | skb_queue_tail(&entry->rx_queue, skb); | ||
1216 | else | ||
1217 | ieee80211_rx_irqsafe(priv->hw, skb); | ||
1218 | spin_unlock_bh(&priv->ps_state_lock); | ||
1219 | } else { | ||
1220 | ieee80211_rx_irqsafe(priv->hw, skb); | ||
1221 | } | ||
1222 | *skb_p = NULL; | ||
1223 | |||
1224 | return; | ||
1225 | |||
1226 | drop: | ||
1227 | /* TODO: update failure counters */ | ||
1228 | return; | ||
1229 | } | ||
1230 | |||
1231 | /* ******************************************************************** */ | ||
1232 | /* Security */ | ||
1233 | |||
1234 | int cw1200_alloc_key(struct cw1200_common *priv) | ||
1235 | { | ||
1236 | int idx; | ||
1237 | |||
1238 | idx = ffs(~priv->key_map) - 1; | ||
1239 | if (idx < 0 || idx > WSM_KEY_MAX_INDEX) | ||
1240 | return -1; | ||
1241 | |||
1242 | priv->key_map |= BIT(idx); | ||
1243 | priv->keys[idx].index = idx; | ||
1244 | return idx; | ||
1245 | } | ||
1246 | |||
1247 | void cw1200_free_key(struct cw1200_common *priv, int idx) | ||
1248 | { | ||
1249 | BUG_ON(!(priv->key_map & BIT(idx))); | ||
1250 | memset(&priv->keys[idx], 0, sizeof(priv->keys[idx])); | ||
1251 | priv->key_map &= ~BIT(idx); | ||
1252 | } | ||
1253 | |||
1254 | void cw1200_free_keys(struct cw1200_common *priv) | ||
1255 | { | ||
1256 | memset(&priv->keys, 0, sizeof(priv->keys)); | ||
1257 | priv->key_map = 0; | ||
1258 | } | ||
1259 | |||
1260 | int cw1200_upload_keys(struct cw1200_common *priv) | ||
1261 | { | ||
1262 | int idx, ret = 0; | ||
1263 | for (idx = 0; idx <= WSM_KEY_MAX_INDEX; ++idx) | ||
1264 | if (priv->key_map & BIT(idx)) { | ||
1265 | ret = wsm_add_key(priv, &priv->keys[idx]); | ||
1266 | if (ret < 0) | ||
1267 | break; | ||
1268 | } | ||
1269 | return ret; | ||
1270 | } | ||
1271 | |||
1272 | /* Workaround for WFD test case 6.1.10 */ | ||
1273 | void cw1200_link_id_reset(struct work_struct *work) | ||
1274 | { | ||
1275 | struct cw1200_common *priv = | ||
1276 | container_of(work, struct cw1200_common, linkid_reset_work); | ||
1277 | int temp_linkid; | ||
1278 | |||
1279 | if (!priv->action_linkid) { | ||
1280 | /* In GO mode we can receive ACTION frames without a linkID */ | ||
1281 | temp_linkid = cw1200_alloc_link_id(priv, | ||
1282 | &priv->action_frame_sa[0]); | ||
1283 | WARN_ON(!temp_linkid); | ||
1284 | if (temp_linkid) { | ||
1285 | /* Make sure we execute the WQ */ | ||
1286 | flush_workqueue(priv->workqueue); | ||
1287 | /* Release the link ID */ | ||
1288 | spin_lock_bh(&priv->ps_state_lock); | ||
1289 | priv->link_id_db[temp_linkid - 1].prev_status = | ||
1290 | priv->link_id_db[temp_linkid - 1].status; | ||
1291 | priv->link_id_db[temp_linkid - 1].status = | ||
1292 | CW1200_LINK_RESET; | ||
1293 | spin_unlock_bh(&priv->ps_state_lock); | ||
1294 | wsm_lock_tx_async(priv); | ||
1295 | if (queue_work(priv->workqueue, | ||
1296 | &priv->link_id_work) <= 0) | ||
1297 | wsm_unlock_tx(priv); | ||
1298 | } | ||
1299 | } else { | ||
1300 | spin_lock_bh(&priv->ps_state_lock); | ||
1301 | priv->link_id_db[priv->action_linkid - 1].prev_status = | ||
1302 | priv->link_id_db[priv->action_linkid - 1].status; | ||
1303 | priv->link_id_db[priv->action_linkid - 1].status = | ||
1304 | CW1200_LINK_RESET_REMAP; | ||
1305 | spin_unlock_bh(&priv->ps_state_lock); | ||
1306 | wsm_lock_tx_async(priv); | ||
1307 | if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) | ||
1308 | wsm_unlock_tx(priv); | ||
1309 | flush_workqueue(priv->workqueue); | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | int cw1200_find_link_id(struct cw1200_common *priv, const u8 *mac) | ||
1314 | { | ||
1315 | int i, ret = 0; | ||
1316 | spin_lock_bh(&priv->ps_state_lock); | ||
1317 | for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { | ||
1318 | if (!memcmp(mac, priv->link_id_db[i].mac, ETH_ALEN) && | ||
1319 | priv->link_id_db[i].status) { | ||
1320 | priv->link_id_db[i].timestamp = jiffies; | ||
1321 | ret = i + 1; | ||
1322 | break; | ||
1323 | } | ||
1324 | } | ||
1325 | spin_unlock_bh(&priv->ps_state_lock); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | |||
1329 | int cw1200_alloc_link_id(struct cw1200_common *priv, const u8 *mac) | ||
1330 | { | ||
1331 | int i, ret = 0; | ||
1332 | unsigned long max_inactivity = 0; | ||
1333 | unsigned long now = jiffies; | ||
1334 | |||
1335 | spin_lock_bh(&priv->ps_state_lock); | ||
1336 | for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { | ||
1337 | if (!priv->link_id_db[i].status) { | ||
1338 | ret = i + 1; | ||
1339 | break; | ||
1340 | } else if (priv->link_id_db[i].status != CW1200_LINK_HARD && | ||
1341 | !priv->tx_queue_stats.link_map_cache[i + 1]) { | ||
1342 | unsigned long inactivity = | ||
1343 | now - priv->link_id_db[i].timestamp; | ||
1344 | if (inactivity < max_inactivity) | ||
1345 | continue; | ||
1346 | max_inactivity = inactivity; | ||
1347 | ret = i + 1; | ||
1348 | } | ||
1349 | } | ||
1350 | if (ret) { | ||
1351 | struct cw1200_link_entry *entry = &priv->link_id_db[ret - 1]; | ||
1352 | pr_debug("[AP] STA added, link_id: %d\n", ret); | ||
1353 | entry->status = CW1200_LINK_RESERVE; | ||
1354 | memcpy(&entry->mac, mac, ETH_ALEN); | ||
1355 | memset(&entry->buffered, 0, CW1200_MAX_TID); | ||
1356 | skb_queue_head_init(&entry->rx_queue); | ||
1357 | wsm_lock_tx_async(priv); | ||
1358 | if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) | ||
1359 | wsm_unlock_tx(priv); | ||
1360 | } else { | ||
1361 | wiphy_info(priv->hw->wiphy, | ||
1362 | "[AP] Early: no more link IDs available.\n"); | ||
1363 | } | ||
1364 | |||
1365 | spin_unlock_bh(&priv->ps_state_lock); | ||
1366 | return ret; | ||
1367 | } | ||
1368 | |||
1369 | void cw1200_link_id_work(struct work_struct *work) | ||
1370 | { | ||
1371 | struct cw1200_common *priv = | ||
1372 | container_of(work, struct cw1200_common, link_id_work); | ||
1373 | wsm_flush_tx(priv); | ||
1374 | cw1200_link_id_gc_work(&priv->link_id_gc_work.work); | ||
1375 | wsm_unlock_tx(priv); | ||
1376 | } | ||
1377 | |||
1378 | void cw1200_link_id_gc_work(struct work_struct *work) | ||
1379 | { | ||
1380 | struct cw1200_common *priv = | ||
1381 | container_of(work, struct cw1200_common, link_id_gc_work.work); | ||
1382 | struct wsm_reset reset = { | ||
1383 | .reset_statistics = false, | ||
1384 | }; | ||
1385 | struct wsm_map_link map_link = { | ||
1386 | .link_id = 0, | ||
1387 | }; | ||
1388 | unsigned long now = jiffies; | ||
1389 | unsigned long next_gc = -1; | ||
1390 | long ttl; | ||
1391 | bool need_reset; | ||
1392 | u32 mask; | ||
1393 | int i; | ||
1394 | |||
1395 | if (priv->join_status != CW1200_JOIN_STATUS_AP) | ||
1396 | return; | ||
1397 | |||
1398 | wsm_lock_tx(priv); | ||
1399 | spin_lock_bh(&priv->ps_state_lock); | ||
1400 | for (i = 0; i < CW1200_MAX_STA_IN_AP_MODE; ++i) { | ||
1401 | need_reset = false; | ||
1402 | mask = BIT(i + 1); | ||
1403 | if (priv->link_id_db[i].status == CW1200_LINK_RESERVE || | ||
1404 | (priv->link_id_db[i].status == CW1200_LINK_HARD && | ||
1405 | !(priv->link_id_map & mask))) { | ||
1406 | if (priv->link_id_map & mask) { | ||
1407 | priv->sta_asleep_mask &= ~mask; | ||
1408 | priv->pspoll_mask &= ~mask; | ||
1409 | need_reset = true; | ||
1410 | } | ||
1411 | priv->link_id_map |= mask; | ||
1412 | if (priv->link_id_db[i].status != CW1200_LINK_HARD) | ||
1413 | priv->link_id_db[i].status = CW1200_LINK_SOFT; | ||
1414 | memcpy(map_link.mac_addr, priv->link_id_db[i].mac, | ||
1415 | ETH_ALEN); | ||
1416 | spin_unlock_bh(&priv->ps_state_lock); | ||
1417 | if (need_reset) { | ||
1418 | reset.link_id = i + 1; | ||
1419 | wsm_reset(priv, &reset); | ||
1420 | } | ||
1421 | map_link.link_id = i + 1; | ||
1422 | wsm_map_link(priv, &map_link); | ||
1423 | next_gc = min(next_gc, CW1200_LINK_ID_GC_TIMEOUT); | ||
1424 | spin_lock_bh(&priv->ps_state_lock); | ||
1425 | } else if (priv->link_id_db[i].status == CW1200_LINK_SOFT) { | ||
1426 | ttl = priv->link_id_db[i].timestamp - now + | ||
1427 | CW1200_LINK_ID_GC_TIMEOUT; | ||
1428 | if (ttl <= 0) { | ||
1429 | need_reset = true; | ||
1430 | priv->link_id_db[i].status = CW1200_LINK_OFF; | ||
1431 | priv->link_id_map &= ~mask; | ||
1432 | priv->sta_asleep_mask &= ~mask; | ||
1433 | priv->pspoll_mask &= ~mask; | ||
1434 | memset(map_link.mac_addr, 0, ETH_ALEN); | ||
1435 | spin_unlock_bh(&priv->ps_state_lock); | ||
1436 | reset.link_id = i + 1; | ||
1437 | wsm_reset(priv, &reset); | ||
1438 | spin_lock_bh(&priv->ps_state_lock); | ||
1439 | } else { | ||
1440 | next_gc = min_t(unsigned long, next_gc, ttl); | ||
1441 | } | ||
1442 | } else if (priv->link_id_db[i].status == CW1200_LINK_RESET || | ||
1443 | priv->link_id_db[i].status == | ||
1444 | CW1200_LINK_RESET_REMAP) { | ||
1445 | int status = priv->link_id_db[i].status; | ||
1446 | priv->link_id_db[i].status = | ||
1447 | priv->link_id_db[i].prev_status; | ||
1448 | priv->link_id_db[i].timestamp = now; | ||
1449 | reset.link_id = i + 1; | ||
1450 | spin_unlock_bh(&priv->ps_state_lock); | ||
1451 | wsm_reset(priv, &reset); | ||
1452 | if (status == CW1200_LINK_RESET_REMAP) { | ||
1453 | memcpy(map_link.mac_addr, | ||
1454 | priv->link_id_db[i].mac, | ||
1455 | ETH_ALEN); | ||
1456 | map_link.link_id = i + 1; | ||
1457 | wsm_map_link(priv, &map_link); | ||
1458 | next_gc = min(next_gc, | ||
1459 | CW1200_LINK_ID_GC_TIMEOUT); | ||
1460 | } | ||
1461 | spin_lock_bh(&priv->ps_state_lock); | ||
1462 | } | ||
1463 | if (need_reset) { | ||
1464 | skb_queue_purge(&priv->link_id_db[i].rx_queue); | ||
1465 | pr_debug("[AP] STA removed, link_id: %d\n", | ||
1466 | reset.link_id); | ||
1467 | } | ||
1468 | } | ||
1469 | spin_unlock_bh(&priv->ps_state_lock); | ||
1470 | if (next_gc != -1) | ||
1471 | queue_delayed_work(priv->workqueue, | ||
1472 | &priv->link_id_gc_work, next_gc); | ||
1473 | wsm_unlock_tx(priv); | ||
1474 | } | ||
diff --git a/drivers/net/wireless/cw1200/txrx.h b/drivers/net/wireless/cw1200/txrx.h new file mode 100644 index 000000000000..492a4e14213b --- /dev/null +++ b/drivers/net/wireless/cw1200/txrx.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Datapath interface for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef CW1200_TXRX_H | ||
13 | #define CW1200_TXRX_H | ||
14 | |||
15 | #include <linux/list.h> | ||
16 | |||
17 | /* extern */ struct ieee80211_hw; | ||
18 | /* extern */ struct sk_buff; | ||
19 | /* extern */ struct wsm_tx; | ||
20 | /* extern */ struct wsm_rx; | ||
21 | /* extern */ struct wsm_tx_confirm; | ||
22 | /* extern */ struct cw1200_txpriv; | ||
23 | |||
24 | struct tx_policy { | ||
25 | union { | ||
26 | __le32 tbl[3]; | ||
27 | u8 raw[12]; | ||
28 | }; | ||
29 | u8 defined; | ||
30 | u8 usage_count; | ||
31 | u8 retry_count; | ||
32 | u8 uploaded; | ||
33 | }; | ||
34 | |||
35 | struct tx_policy_cache_entry { | ||
36 | struct tx_policy policy; | ||
37 | struct list_head link; | ||
38 | }; | ||
39 | |||
40 | #define TX_POLICY_CACHE_SIZE (8) | ||
41 | struct tx_policy_cache { | ||
42 | struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; | ||
43 | struct list_head used; | ||
44 | struct list_head free; | ||
45 | spinlock_t lock; /* Protect policy cache */ | ||
46 | }; | ||
47 | |||
48 | /* ******************************************************************** */ | ||
49 | /* TX policy cache */ | ||
50 | /* Intention of TX policy cache is an overcomplicated WSM API. | ||
51 | * Device does not accept per-PDU tx retry sequence. | ||
52 | * It uses "tx retry policy id" instead, so driver code has to sync | ||
53 | * linux tx retry sequences with a retry policy table in the device. | ||
54 | */ | ||
55 | void tx_policy_init(struct cw1200_common *priv); | ||
56 | void tx_policy_upload_work(struct work_struct *work); | ||
57 | void tx_policy_clean(struct cw1200_common *priv); | ||
58 | |||
59 | /* ******************************************************************** */ | ||
60 | /* TX implementation */ | ||
61 | |||
62 | u32 cw1200_rate_mask_to_wsm(struct cw1200_common *priv, | ||
63 | u32 rates); | ||
64 | void cw1200_tx(struct ieee80211_hw *dev, | ||
65 | struct ieee80211_tx_control *control, | ||
66 | struct sk_buff *skb); | ||
67 | void cw1200_skb_dtor(struct cw1200_common *priv, | ||
68 | struct sk_buff *skb, | ||
69 | const struct cw1200_txpriv *txpriv); | ||
70 | |||
71 | /* ******************************************************************** */ | ||
72 | /* WSM callbacks */ | ||
73 | |||
74 | void cw1200_tx_confirm_cb(struct cw1200_common *priv, | ||
75 | int link_id, | ||
76 | struct wsm_tx_confirm *arg); | ||
77 | void cw1200_rx_cb(struct cw1200_common *priv, | ||
78 | struct wsm_rx *arg, | ||
79 | int link_id, | ||
80 | struct sk_buff **skb_p); | ||
81 | |||
82 | /* ******************************************************************** */ | ||
83 | /* Timeout */ | ||
84 | |||
85 | void cw1200_tx_timeout(struct work_struct *work); | ||
86 | |||
87 | /* ******************************************************************** */ | ||
88 | /* Security */ | ||
89 | int cw1200_alloc_key(struct cw1200_common *priv); | ||
90 | void cw1200_free_key(struct cw1200_common *priv, int idx); | ||
91 | void cw1200_free_keys(struct cw1200_common *priv); | ||
92 | int cw1200_upload_keys(struct cw1200_common *priv); | ||
93 | |||
94 | /* ******************************************************************** */ | ||
95 | /* Workaround for WFD test case 6.1.10 */ | ||
96 | void cw1200_link_id_reset(struct work_struct *work); | ||
97 | |||
98 | #define CW1200_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) | ||
99 | |||
100 | int cw1200_find_link_id(struct cw1200_common *priv, const u8 *mac); | ||
101 | int cw1200_alloc_link_id(struct cw1200_common *priv, const u8 *mac); | ||
102 | void cw1200_link_id_work(struct work_struct *work); | ||
103 | void cw1200_link_id_gc_work(struct work_struct *work); | ||
104 | |||
105 | |||
106 | #endif /* CW1200_TXRX_H */ | ||
diff --git a/drivers/net/wireless/cw1200/wsm.c b/drivers/net/wireless/cw1200/wsm.c new file mode 100644 index 000000000000..f3fd9b218724 --- /dev/null +++ b/drivers/net/wireless/cw1200/wsm.c | |||
@@ -0,0 +1,1883 @@ | |||
1 | /* | ||
2 | * WSM host interface (HI) implementation for | ||
3 | * ST-Ericsson CW1200 mac80211 drivers. | ||
4 | * | ||
5 | * Copyright (c) 2010, ST-Ericsson | ||
6 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/wait.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/random.h> | ||
18 | |||
19 | #include "cw1200.h" | ||
20 | #include "wsm.h" | ||
21 | #include "bh.h" | ||
22 | #include "sta.h" | ||
23 | #include "debug.h" | ||
24 | #include "itp.h" | ||
25 | |||
26 | #define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ | ||
27 | #define WSM_CMD_START_TIMEOUT (7 * HZ) | ||
28 | #define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */ | ||
29 | #define WSM_CMD_MAX_TIMEOUT (3 * HZ) | ||
30 | |||
31 | #define WSM_SKIP(buf, size) \ | ||
32 | do { \ | ||
33 | if ((buf)->data + size > (buf)->end) \ | ||
34 | goto underflow; \ | ||
35 | (buf)->data += size; \ | ||
36 | } while (0) | ||
37 | |||
38 | #define WSM_GET(buf, ptr, size) \ | ||
39 | do { \ | ||
40 | if ((buf)->data + size > (buf)->end) \ | ||
41 | goto underflow; \ | ||
42 | memcpy(ptr, (buf)->data, size); \ | ||
43 | (buf)->data += size; \ | ||
44 | } while (0) | ||
45 | |||
46 | #define __WSM_GET(buf, type, cvt) \ | ||
47 | ({ \ | ||
48 | type val; \ | ||
49 | if ((buf)->data + sizeof(type) > (buf)->end) \ | ||
50 | goto underflow; \ | ||
51 | val = cvt(*(type *)(buf)->data); \ | ||
52 | (buf)->data += sizeof(type); \ | ||
53 | val; \ | ||
54 | }) | ||
55 | |||
56 | #define WSM_GET8(buf) __WSM_GET(buf, u8, (u8)) | ||
57 | #define WSM_GET16(buf) __WSM_GET(buf, u16, __le16_to_cpu) | ||
58 | #define WSM_GET32(buf) __WSM_GET(buf, u32, __le32_to_cpu) | ||
59 | |||
60 | #define WSM_PUT(buf, ptr, size) \ | ||
61 | do { \ | ||
62 | if ((buf)->data + size > (buf)->end) \ | ||
63 | if (wsm_buf_reserve((buf), size)) \ | ||
64 | goto nomem; \ | ||
65 | memcpy((buf)->data, ptr, size); \ | ||
66 | (buf)->data += size; \ | ||
67 | } while (0) | ||
68 | |||
69 | #define __WSM_PUT(buf, val, type, cvt) \ | ||
70 | do { \ | ||
71 | if ((buf)->data + sizeof(type) > (buf)->end) \ | ||
72 | if (wsm_buf_reserve((buf), sizeof(type))) \ | ||
73 | goto nomem; \ | ||
74 | *(type *)(buf)->data = cvt(val); \ | ||
75 | (buf)->data += sizeof(type); \ | ||
76 | } while (0) | ||
77 | |||
78 | #define WSM_PUT8(buf, val) __WSM_PUT(buf, val, u8, (u8)) | ||
79 | #define WSM_PUT16(buf, val) __WSM_PUT(buf, val, u16, __cpu_to_le16) | ||
80 | #define WSM_PUT32(buf, val) __WSM_PUT(buf, val, u32, __cpu_to_le32) | ||
81 | |||
82 | static void wsm_buf_reset(struct wsm_buf *buf); | ||
83 | static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size); | ||
84 | |||
85 | static int wsm_cmd_send(struct cw1200_common *priv, | ||
86 | struct wsm_buf *buf, | ||
87 | void *arg, u16 cmd, long tmo); | ||
88 | |||
89 | #define wsm_cmd_lock(__priv) mutex_lock(&((__priv)->wsm_cmd_mux)) | ||
90 | #define wsm_cmd_unlock(__priv) mutex_unlock(&((__priv)->wsm_cmd_mux)) | ||
91 | |||
92 | /* ******************************************************************** */ | ||
93 | /* WSM API implementation */ | ||
94 | |||
95 | static int wsm_generic_confirm(struct cw1200_common *priv, | ||
96 | void *arg, | ||
97 | struct wsm_buf *buf) | ||
98 | { | ||
99 | u32 status = WSM_GET32(buf); | ||
100 | if (status != WSM_STATUS_SUCCESS) | ||
101 | return -EINVAL; | ||
102 | return 0; | ||
103 | |||
104 | underflow: | ||
105 | WARN_ON(1); | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | int wsm_configuration(struct cw1200_common *priv, struct wsm_configuration *arg) | ||
110 | { | ||
111 | int ret; | ||
112 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
113 | |||
114 | wsm_cmd_lock(priv); | ||
115 | |||
116 | WSM_PUT32(buf, arg->dot11MaxTransmitMsduLifeTime); | ||
117 | WSM_PUT32(buf, arg->dot11MaxReceiveLifeTime); | ||
118 | WSM_PUT32(buf, arg->dot11RtsThreshold); | ||
119 | |||
120 | /* DPD block. */ | ||
121 | WSM_PUT16(buf, arg->dpdData_size + 12); | ||
122 | WSM_PUT16(buf, 1); /* DPD version */ | ||
123 | WSM_PUT(buf, arg->dot11StationId, ETH_ALEN); | ||
124 | WSM_PUT16(buf, 5); /* DPD flags */ | ||
125 | WSM_PUT(buf, arg->dpdData, arg->dpdData_size); | ||
126 | |||
127 | ret = wsm_cmd_send(priv, buf, arg, | ||
128 | WSM_CONFIGURATION_REQ_ID, WSM_CMD_TIMEOUT); | ||
129 | |||
130 | wsm_cmd_unlock(priv); | ||
131 | return ret; | ||
132 | |||
133 | nomem: | ||
134 | wsm_cmd_unlock(priv); | ||
135 | return -ENOMEM; | ||
136 | } | ||
137 | |||
138 | static int wsm_configuration_confirm(struct cw1200_common *priv, | ||
139 | struct wsm_configuration *arg, | ||
140 | struct wsm_buf *buf) | ||
141 | { | ||
142 | int i; | ||
143 | int status; | ||
144 | |||
145 | status = WSM_GET32(buf); | ||
146 | if (WARN_ON(status != WSM_STATUS_SUCCESS)) | ||
147 | return -EINVAL; | ||
148 | |||
149 | WSM_GET(buf, arg->dot11StationId, ETH_ALEN); | ||
150 | arg->dot11FrequencyBandsSupported = WSM_GET8(buf); | ||
151 | WSM_SKIP(buf, 1); | ||
152 | arg->supportedRateMask = WSM_GET32(buf); | ||
153 | for (i = 0; i < 2; ++i) { | ||
154 | arg->txPowerRange[i].min_power_level = WSM_GET32(buf); | ||
155 | arg->txPowerRange[i].max_power_level = WSM_GET32(buf); | ||
156 | arg->txPowerRange[i].stepping = WSM_GET32(buf); | ||
157 | } | ||
158 | return 0; | ||
159 | |||
160 | underflow: | ||
161 | WARN_ON(1); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | /* ******************************************************************** */ | ||
166 | |||
167 | int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg) | ||
168 | { | ||
169 | int ret; | ||
170 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
171 | u16 cmd = WSM_RESET_REQ_ID | WSM_TX_LINK_ID(arg->link_id); | ||
172 | |||
173 | wsm_cmd_lock(priv); | ||
174 | |||
175 | WSM_PUT32(buf, arg->reset_statistics ? 0 : 1); | ||
176 | ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_RESET_TIMEOUT); | ||
177 | wsm_cmd_unlock(priv); | ||
178 | return ret; | ||
179 | |||
180 | nomem: | ||
181 | wsm_cmd_unlock(priv); | ||
182 | return -ENOMEM; | ||
183 | } | ||
184 | |||
185 | /* ******************************************************************** */ | ||
186 | |||
187 | struct wsm_mib { | ||
188 | u16 mib_id; | ||
189 | void *buf; | ||
190 | size_t buf_size; | ||
191 | }; | ||
192 | |||
193 | int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, | ||
194 | size_t buf_size) | ||
195 | { | ||
196 | int ret; | ||
197 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
198 | struct wsm_mib mib_buf = { | ||
199 | .mib_id = mib_id, | ||
200 | .buf = _buf, | ||
201 | .buf_size = buf_size, | ||
202 | }; | ||
203 | wsm_cmd_lock(priv); | ||
204 | |||
205 | WSM_PUT16(buf, mib_id); | ||
206 | WSM_PUT16(buf, 0); | ||
207 | |||
208 | ret = wsm_cmd_send(priv, buf, &mib_buf, | ||
209 | WSM_READ_MIB_REQ_ID, WSM_CMD_TIMEOUT); | ||
210 | wsm_cmd_unlock(priv); | ||
211 | return ret; | ||
212 | |||
213 | nomem: | ||
214 | wsm_cmd_unlock(priv); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | |||
218 | static int wsm_read_mib_confirm(struct cw1200_common *priv, | ||
219 | struct wsm_mib *arg, | ||
220 | struct wsm_buf *buf) | ||
221 | { | ||
222 | u16 size; | ||
223 | if (WARN_ON(WSM_GET32(buf) != WSM_STATUS_SUCCESS)) | ||
224 | return -EINVAL; | ||
225 | |||
226 | if (WARN_ON(WSM_GET16(buf) != arg->mib_id)) | ||
227 | return -EINVAL; | ||
228 | |||
229 | size = WSM_GET16(buf); | ||
230 | if (size > arg->buf_size) | ||
231 | size = arg->buf_size; | ||
232 | |||
233 | WSM_GET(buf, arg->buf, size); | ||
234 | arg->buf_size = size; | ||
235 | return 0; | ||
236 | |||
237 | underflow: | ||
238 | WARN_ON(1); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | /* ******************************************************************** */ | ||
243 | |||
244 | int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, | ||
245 | size_t buf_size) | ||
246 | { | ||
247 | int ret; | ||
248 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
249 | struct wsm_mib mib_buf = { | ||
250 | .mib_id = mib_id, | ||
251 | .buf = _buf, | ||
252 | .buf_size = buf_size, | ||
253 | }; | ||
254 | |||
255 | wsm_cmd_lock(priv); | ||
256 | |||
257 | WSM_PUT16(buf, mib_id); | ||
258 | WSM_PUT16(buf, buf_size); | ||
259 | WSM_PUT(buf, _buf, buf_size); | ||
260 | |||
261 | ret = wsm_cmd_send(priv, buf, &mib_buf, | ||
262 | WSM_WRITE_MIB_REQ_ID, WSM_CMD_TIMEOUT); | ||
263 | wsm_cmd_unlock(priv); | ||
264 | return ret; | ||
265 | |||
266 | nomem: | ||
267 | wsm_cmd_unlock(priv); | ||
268 | return -ENOMEM; | ||
269 | } | ||
270 | |||
271 | static int wsm_write_mib_confirm(struct cw1200_common *priv, | ||
272 | struct wsm_mib *arg, | ||
273 | struct wsm_buf *buf) | ||
274 | { | ||
275 | int ret; | ||
276 | |||
277 | ret = wsm_generic_confirm(priv, arg, buf); | ||
278 | if (ret) | ||
279 | return ret; | ||
280 | |||
281 | if (arg->mib_id == WSM_MIB_ID_OPERATIONAL_POWER_MODE) { | ||
282 | /* OperationalMode: update PM status. */ | ||
283 | const char *p = arg->buf; | ||
284 | cw1200_enable_powersave(priv, (p[0] & 0x0F) ? true : false); | ||
285 | } | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | /* ******************************************************************** */ | ||
290 | |||
291 | int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg) | ||
292 | { | ||
293 | int i; | ||
294 | int ret; | ||
295 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
296 | |||
297 | if (arg->num_channels > 48) | ||
298 | return -EINVAL; | ||
299 | |||
300 | if (arg->num_ssids > 2) | ||
301 | return -EINVAL; | ||
302 | |||
303 | if (arg->band > 1) | ||
304 | return -EINVAL; | ||
305 | |||
306 | wsm_cmd_lock(priv); | ||
307 | |||
308 | WSM_PUT8(buf, arg->band); | ||
309 | WSM_PUT8(buf, arg->type); | ||
310 | WSM_PUT8(buf, arg->flags); | ||
311 | WSM_PUT8(buf, arg->max_tx_rate); | ||
312 | WSM_PUT32(buf, arg->auto_scan_interval); | ||
313 | WSM_PUT8(buf, arg->num_probes); | ||
314 | WSM_PUT8(buf, arg->num_channels); | ||
315 | WSM_PUT8(buf, arg->num_ssids); | ||
316 | WSM_PUT8(buf, arg->probe_delay); | ||
317 | |||
318 | for (i = 0; i < arg->num_channels; ++i) { | ||
319 | WSM_PUT16(buf, arg->ch[i].number); | ||
320 | WSM_PUT16(buf, 0); | ||
321 | WSM_PUT32(buf, arg->ch[i].min_chan_time); | ||
322 | WSM_PUT32(buf, arg->ch[i].max_chan_time); | ||
323 | WSM_PUT32(buf, 0); | ||
324 | } | ||
325 | |||
326 | for (i = 0; i < arg->num_ssids; ++i) { | ||
327 | WSM_PUT32(buf, arg->ssids[i].length); | ||
328 | WSM_PUT(buf, &arg->ssids[i].ssid[0], | ||
329 | sizeof(arg->ssids[i].ssid)); | ||
330 | } | ||
331 | |||
332 | ret = wsm_cmd_send(priv, buf, NULL, | ||
333 | WSM_START_SCAN_REQ_ID, WSM_CMD_TIMEOUT); | ||
334 | wsm_cmd_unlock(priv); | ||
335 | return ret; | ||
336 | |||
337 | nomem: | ||
338 | wsm_cmd_unlock(priv); | ||
339 | return -ENOMEM; | ||
340 | } | ||
341 | |||
342 | /* ******************************************************************** */ | ||
343 | |||
344 | int wsm_stop_scan(struct cw1200_common *priv) | ||
345 | { | ||
346 | int ret; | ||
347 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
348 | wsm_cmd_lock(priv); | ||
349 | ret = wsm_cmd_send(priv, buf, NULL, | ||
350 | WSM_STOP_SCAN_REQ_ID, WSM_CMD_TIMEOUT); | ||
351 | wsm_cmd_unlock(priv); | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | |||
356 | static int wsm_tx_confirm(struct cw1200_common *priv, | ||
357 | struct wsm_buf *buf, | ||
358 | int link_id) | ||
359 | { | ||
360 | struct wsm_tx_confirm tx_confirm; | ||
361 | |||
362 | tx_confirm.packet_id = WSM_GET32(buf); | ||
363 | tx_confirm.status = WSM_GET32(buf); | ||
364 | tx_confirm.tx_rate = WSM_GET8(buf); | ||
365 | tx_confirm.ack_failures = WSM_GET8(buf); | ||
366 | tx_confirm.flags = WSM_GET16(buf); | ||
367 | tx_confirm.media_delay = WSM_GET32(buf); | ||
368 | tx_confirm.tx_queue_delay = WSM_GET32(buf); | ||
369 | |||
370 | cw1200_tx_confirm_cb(priv, link_id, &tx_confirm); | ||
371 | return 0; | ||
372 | |||
373 | underflow: | ||
374 | WARN_ON(1); | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
378 | static int wsm_multi_tx_confirm(struct cw1200_common *priv, | ||
379 | struct wsm_buf *buf, int link_id) | ||
380 | { | ||
381 | int ret; | ||
382 | int count; | ||
383 | int i; | ||
384 | |||
385 | count = WSM_GET32(buf); | ||
386 | if (WARN_ON(count <= 0)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | if (count > 1) { | ||
390 | /* We already released one buffer, now for the rest */ | ||
391 | ret = wsm_release_tx_buffer(priv, count - 1); | ||
392 | if (ret < 0) | ||
393 | return ret; | ||
394 | else if (ret > 0) | ||
395 | cw1200_bh_wakeup(priv); | ||
396 | } | ||
397 | |||
398 | cw1200_debug_txed_multi(priv, count); | ||
399 | for (i = 0; i < count; ++i) { | ||
400 | ret = wsm_tx_confirm(priv, buf, link_id); | ||
401 | if (ret) | ||
402 | return ret; | ||
403 | } | ||
404 | return ret; | ||
405 | |||
406 | underflow: | ||
407 | WARN_ON(1); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | /* ******************************************************************** */ | ||
412 | |||
413 | static int wsm_join_confirm(struct cw1200_common *priv, | ||
414 | struct wsm_join_cnf *arg, | ||
415 | struct wsm_buf *buf) | ||
416 | { | ||
417 | arg->status = WSM_GET32(buf); | ||
418 | if (WARN_ON(arg->status) != WSM_STATUS_SUCCESS) | ||
419 | return -EINVAL; | ||
420 | |||
421 | arg->min_power_level = WSM_GET32(buf); | ||
422 | arg->max_power_level = WSM_GET32(buf); | ||
423 | |||
424 | return 0; | ||
425 | |||
426 | underflow: | ||
427 | WARN_ON(1); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | int wsm_join(struct cw1200_common *priv, struct wsm_join *arg) | ||
432 | { | ||
433 | int ret; | ||
434 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
435 | struct wsm_join_cnf resp; | ||
436 | wsm_cmd_lock(priv); | ||
437 | |||
438 | WSM_PUT8(buf, arg->mode); | ||
439 | WSM_PUT8(buf, arg->band); | ||
440 | WSM_PUT16(buf, arg->channel_number); | ||
441 | WSM_PUT(buf, &arg->bssid[0], sizeof(arg->bssid)); | ||
442 | WSM_PUT16(buf, arg->atim_window); | ||
443 | WSM_PUT8(buf, arg->preamble_type); | ||
444 | WSM_PUT8(buf, arg->probe_for_join); | ||
445 | WSM_PUT8(buf, arg->dtim_period); | ||
446 | WSM_PUT8(buf, arg->flags); | ||
447 | WSM_PUT32(buf, arg->ssid_len); | ||
448 | WSM_PUT(buf, &arg->ssid[0], sizeof(arg->ssid)); | ||
449 | WSM_PUT32(buf, arg->beacon_interval); | ||
450 | WSM_PUT32(buf, arg->basic_rate_set); | ||
451 | |||
452 | priv->tx_burst_idx = -1; | ||
453 | ret = wsm_cmd_send(priv, buf, &resp, | ||
454 | WSM_JOIN_REQ_ID, WSM_CMD_TIMEOUT); | ||
455 | /* TODO: Update state based on resp.min|max_power_level */ | ||
456 | |||
457 | priv->join_complete_status = resp.status; | ||
458 | |||
459 | wsm_cmd_unlock(priv); | ||
460 | return ret; | ||
461 | |||
462 | nomem: | ||
463 | wsm_cmd_unlock(priv); | ||
464 | return -ENOMEM; | ||
465 | } | ||
466 | |||
467 | /* ******************************************************************** */ | ||
468 | |||
469 | int wsm_set_bss_params(struct cw1200_common *priv, | ||
470 | const struct wsm_set_bss_params *arg) | ||
471 | { | ||
472 | int ret; | ||
473 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
474 | |||
475 | wsm_cmd_lock(priv); | ||
476 | |||
477 | WSM_PUT8(buf, (arg->reset_beacon_loss ? 0x1 : 0)); | ||
478 | WSM_PUT8(buf, arg->beacon_lost_count); | ||
479 | WSM_PUT16(buf, arg->aid); | ||
480 | WSM_PUT32(buf, arg->operational_rate_set); | ||
481 | |||
482 | ret = wsm_cmd_send(priv, buf, NULL, | ||
483 | WSM_SET_BSS_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); | ||
484 | |||
485 | wsm_cmd_unlock(priv); | ||
486 | return ret; | ||
487 | |||
488 | nomem: | ||
489 | wsm_cmd_unlock(priv); | ||
490 | return -ENOMEM; | ||
491 | } | ||
492 | |||
493 | /* ******************************************************************** */ | ||
494 | |||
495 | int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg) | ||
496 | { | ||
497 | int ret; | ||
498 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
499 | |||
500 | wsm_cmd_lock(priv); | ||
501 | |||
502 | WSM_PUT(buf, arg, sizeof(*arg)); | ||
503 | |||
504 | ret = wsm_cmd_send(priv, buf, NULL, | ||
505 | WSM_ADD_KEY_REQ_ID, WSM_CMD_TIMEOUT); | ||
506 | |||
507 | wsm_cmd_unlock(priv); | ||
508 | return ret; | ||
509 | |||
510 | nomem: | ||
511 | wsm_cmd_unlock(priv); | ||
512 | return -ENOMEM; | ||
513 | } | ||
514 | |||
515 | /* ******************************************************************** */ | ||
516 | |||
517 | int wsm_remove_key(struct cw1200_common *priv, const struct wsm_remove_key *arg) | ||
518 | { | ||
519 | int ret; | ||
520 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
521 | |||
522 | wsm_cmd_lock(priv); | ||
523 | |||
524 | WSM_PUT8(buf, arg->index); | ||
525 | WSM_PUT8(buf, 0); | ||
526 | WSM_PUT16(buf, 0); | ||
527 | |||
528 | ret = wsm_cmd_send(priv, buf, NULL, | ||
529 | WSM_REMOVE_KEY_REQ_ID, WSM_CMD_TIMEOUT); | ||
530 | |||
531 | wsm_cmd_unlock(priv); | ||
532 | return ret; | ||
533 | |||
534 | nomem: | ||
535 | wsm_cmd_unlock(priv); | ||
536 | return -ENOMEM; | ||
537 | } | ||
538 | |||
539 | /* ******************************************************************** */ | ||
540 | |||
541 | int wsm_set_tx_queue_params(struct cw1200_common *priv, | ||
542 | const struct wsm_set_tx_queue_params *arg, u8 id) | ||
543 | { | ||
544 | int ret; | ||
545 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
546 | u8 queue_id_to_wmm_aci[] = {3, 2, 0, 1}; | ||
547 | |||
548 | wsm_cmd_lock(priv); | ||
549 | |||
550 | WSM_PUT8(buf, queue_id_to_wmm_aci[id]); | ||
551 | WSM_PUT8(buf, 0); | ||
552 | WSM_PUT8(buf, arg->ackPolicy); | ||
553 | WSM_PUT8(buf, 0); | ||
554 | WSM_PUT32(buf, arg->maxTransmitLifetime); | ||
555 | WSM_PUT16(buf, arg->allowedMediumTime); | ||
556 | WSM_PUT16(buf, 0); | ||
557 | |||
558 | ret = wsm_cmd_send(priv, buf, NULL, 0x0012, WSM_CMD_TIMEOUT); | ||
559 | |||
560 | wsm_cmd_unlock(priv); | ||
561 | return ret; | ||
562 | |||
563 | nomem: | ||
564 | wsm_cmd_unlock(priv); | ||
565 | return -ENOMEM; | ||
566 | } | ||
567 | |||
568 | /* ******************************************************************** */ | ||
569 | |||
570 | int wsm_set_edca_params(struct cw1200_common *priv, | ||
571 | const struct wsm_edca_params *arg) | ||
572 | { | ||
573 | int ret; | ||
574 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
575 | |||
576 | wsm_cmd_lock(priv); | ||
577 | |||
578 | /* Implemented according to specification. */ | ||
579 | |||
580 | WSM_PUT16(buf, arg->params[3].cwmin); | ||
581 | WSM_PUT16(buf, arg->params[2].cwmin); | ||
582 | WSM_PUT16(buf, arg->params[1].cwmin); | ||
583 | WSM_PUT16(buf, arg->params[0].cwmin); | ||
584 | |||
585 | WSM_PUT16(buf, arg->params[3].cwmax); | ||
586 | WSM_PUT16(buf, arg->params[2].cwmax); | ||
587 | WSM_PUT16(buf, arg->params[1].cwmax); | ||
588 | WSM_PUT16(buf, arg->params[0].cwmax); | ||
589 | |||
590 | WSM_PUT8(buf, arg->params[3].aifns); | ||
591 | WSM_PUT8(buf, arg->params[2].aifns); | ||
592 | WSM_PUT8(buf, arg->params[1].aifns); | ||
593 | WSM_PUT8(buf, arg->params[0].aifns); | ||
594 | |||
595 | WSM_PUT16(buf, arg->params[3].txop_limit); | ||
596 | WSM_PUT16(buf, arg->params[2].txop_limit); | ||
597 | WSM_PUT16(buf, arg->params[1].txop_limit); | ||
598 | WSM_PUT16(buf, arg->params[0].txop_limit); | ||
599 | |||
600 | WSM_PUT32(buf, arg->params[3].max_rx_lifetime); | ||
601 | WSM_PUT32(buf, arg->params[2].max_rx_lifetime); | ||
602 | WSM_PUT32(buf, arg->params[1].max_rx_lifetime); | ||
603 | WSM_PUT32(buf, arg->params[0].max_rx_lifetime); | ||
604 | |||
605 | ret = wsm_cmd_send(priv, buf, NULL, | ||
606 | WSM_EDCA_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); | ||
607 | wsm_cmd_unlock(priv); | ||
608 | return ret; | ||
609 | |||
610 | nomem: | ||
611 | wsm_cmd_unlock(priv); | ||
612 | return -ENOMEM; | ||
613 | } | ||
614 | |||
615 | /* ******************************************************************** */ | ||
616 | |||
617 | int wsm_switch_channel(struct cw1200_common *priv, | ||
618 | const struct wsm_switch_channel *arg) | ||
619 | { | ||
620 | int ret; | ||
621 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
622 | |||
623 | wsm_cmd_lock(priv); | ||
624 | |||
625 | WSM_PUT8(buf, arg->mode); | ||
626 | WSM_PUT8(buf, arg->switch_count); | ||
627 | WSM_PUT16(buf, arg->channel_number); | ||
628 | |||
629 | priv->channel_switch_in_progress = 1; | ||
630 | |||
631 | ret = wsm_cmd_send(priv, buf, NULL, | ||
632 | WSM_SWITCH_CHANNEL_REQ_ID, WSM_CMD_TIMEOUT); | ||
633 | if (ret) | ||
634 | priv->channel_switch_in_progress = 0; | ||
635 | |||
636 | wsm_cmd_unlock(priv); | ||
637 | return ret; | ||
638 | |||
639 | nomem: | ||
640 | wsm_cmd_unlock(priv); | ||
641 | return -ENOMEM; | ||
642 | } | ||
643 | |||
644 | /* ******************************************************************** */ | ||
645 | |||
646 | int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) | ||
647 | { | ||
648 | int ret; | ||
649 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
650 | priv->ps_mode_switch_in_progress = 1; | ||
651 | |||
652 | wsm_cmd_lock(priv); | ||
653 | |||
654 | WSM_PUT8(buf, arg->mode); | ||
655 | WSM_PUT8(buf, arg->fast_psm_idle_period); | ||
656 | WSM_PUT8(buf, arg->ap_psm_change_period); | ||
657 | WSM_PUT8(buf, arg->min_auto_pspoll_period); | ||
658 | |||
659 | ret = wsm_cmd_send(priv, buf, NULL, | ||
660 | WSM_SET_PM_REQ_ID, WSM_CMD_TIMEOUT); | ||
661 | |||
662 | wsm_cmd_unlock(priv); | ||
663 | return ret; | ||
664 | |||
665 | nomem: | ||
666 | wsm_cmd_unlock(priv); | ||
667 | return -ENOMEM; | ||
668 | } | ||
669 | |||
670 | /* ******************************************************************** */ | ||
671 | |||
672 | int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg) | ||
673 | { | ||
674 | int ret; | ||
675 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
676 | |||
677 | wsm_cmd_lock(priv); | ||
678 | |||
679 | WSM_PUT8(buf, arg->mode); | ||
680 | WSM_PUT8(buf, arg->band); | ||
681 | WSM_PUT16(buf, arg->channel_number); | ||
682 | WSM_PUT32(buf, arg->ct_window); | ||
683 | WSM_PUT32(buf, arg->beacon_interval); | ||
684 | WSM_PUT8(buf, arg->dtim_period); | ||
685 | WSM_PUT8(buf, arg->preamble); | ||
686 | WSM_PUT8(buf, arg->probe_delay); | ||
687 | WSM_PUT8(buf, arg->ssid_len); | ||
688 | WSM_PUT(buf, arg->ssid, sizeof(arg->ssid)); | ||
689 | WSM_PUT32(buf, arg->basic_rate_set); | ||
690 | |||
691 | priv->tx_burst_idx = -1; | ||
692 | ret = wsm_cmd_send(priv, buf, NULL, | ||
693 | WSM_START_REQ_ID, WSM_CMD_START_TIMEOUT); | ||
694 | |||
695 | wsm_cmd_unlock(priv); | ||
696 | return ret; | ||
697 | |||
698 | nomem: | ||
699 | wsm_cmd_unlock(priv); | ||
700 | return -ENOMEM; | ||
701 | } | ||
702 | |||
703 | /* ******************************************************************** */ | ||
704 | |||
705 | int wsm_beacon_transmit(struct cw1200_common *priv, | ||
706 | const struct wsm_beacon_transmit *arg) | ||
707 | { | ||
708 | int ret; | ||
709 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
710 | |||
711 | wsm_cmd_lock(priv); | ||
712 | |||
713 | WSM_PUT32(buf, arg->enable_beaconing ? 1 : 0); | ||
714 | |||
715 | ret = wsm_cmd_send(priv, buf, NULL, | ||
716 | WSM_BEACON_TRANSMIT_REQ_ID, WSM_CMD_TIMEOUT); | ||
717 | |||
718 | wsm_cmd_unlock(priv); | ||
719 | return ret; | ||
720 | |||
721 | nomem: | ||
722 | wsm_cmd_unlock(priv); | ||
723 | return -ENOMEM; | ||
724 | } | ||
725 | |||
726 | /* ******************************************************************** */ | ||
727 | |||
728 | int wsm_start_find(struct cw1200_common *priv) | ||
729 | { | ||
730 | int ret; | ||
731 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
732 | |||
733 | wsm_cmd_lock(priv); | ||
734 | ret = wsm_cmd_send(priv, buf, NULL, 0x0019, WSM_CMD_TIMEOUT); | ||
735 | wsm_cmd_unlock(priv); | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | /* ******************************************************************** */ | ||
740 | |||
741 | int wsm_stop_find(struct cw1200_common *priv) | ||
742 | { | ||
743 | int ret; | ||
744 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
745 | |||
746 | wsm_cmd_lock(priv); | ||
747 | ret = wsm_cmd_send(priv, buf, NULL, 0x001A, WSM_CMD_TIMEOUT); | ||
748 | wsm_cmd_unlock(priv); | ||
749 | return ret; | ||
750 | } | ||
751 | |||
752 | /* ******************************************************************** */ | ||
753 | |||
754 | int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg) | ||
755 | { | ||
756 | int ret; | ||
757 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
758 | u16 cmd = 0x001C | WSM_TX_LINK_ID(arg->link_id); | ||
759 | |||
760 | wsm_cmd_lock(priv); | ||
761 | |||
762 | WSM_PUT(buf, &arg->mac_addr[0], sizeof(arg->mac_addr)); | ||
763 | WSM_PUT16(buf, 0); | ||
764 | |||
765 | ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_TIMEOUT); | ||
766 | |||
767 | wsm_cmd_unlock(priv); | ||
768 | return ret; | ||
769 | |||
770 | nomem: | ||
771 | wsm_cmd_unlock(priv); | ||
772 | return -ENOMEM; | ||
773 | } | ||
774 | |||
775 | /* ******************************************************************** */ | ||
776 | |||
777 | int wsm_update_ie(struct cw1200_common *priv, | ||
778 | const struct wsm_update_ie *arg) | ||
779 | { | ||
780 | int ret; | ||
781 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
782 | |||
783 | wsm_cmd_lock(priv); | ||
784 | |||
785 | WSM_PUT16(buf, arg->what); | ||
786 | WSM_PUT16(buf, arg->count); | ||
787 | WSM_PUT(buf, arg->ies, arg->length); | ||
788 | |||
789 | ret = wsm_cmd_send(priv, buf, NULL, 0x001B, WSM_CMD_TIMEOUT); | ||
790 | |||
791 | wsm_cmd_unlock(priv); | ||
792 | return ret; | ||
793 | |||
794 | nomem: | ||
795 | wsm_cmd_unlock(priv); | ||
796 | return -ENOMEM; | ||
797 | } | ||
798 | |||
799 | /* ******************************************************************** */ | ||
800 | int wsm_set_probe_responder(struct cw1200_common *priv, bool enable) | ||
801 | { | ||
802 | priv->rx_filter.probeResponder = enable; | ||
803 | return wsm_set_rx_filter(priv, &priv->rx_filter); | ||
804 | } | ||
805 | |||
806 | /* ******************************************************************** */ | ||
807 | /* WSM indication events implementation */ | ||
808 | const char * const cw1200_fw_types[] = { | ||
809 | "ETF", | ||
810 | "WFM", | ||
811 | "WSM", | ||
812 | "HI test", | ||
813 | "Platform test" | ||
814 | }; | ||
815 | |||
816 | static int wsm_startup_indication(struct cw1200_common *priv, | ||
817 | struct wsm_buf *buf) | ||
818 | { | ||
819 | priv->wsm_caps.input_buffers = WSM_GET16(buf); | ||
820 | priv->wsm_caps.input_buffer_size = WSM_GET16(buf); | ||
821 | priv->wsm_caps.hw_id = WSM_GET16(buf); | ||
822 | priv->wsm_caps.hw_subid = WSM_GET16(buf); | ||
823 | priv->wsm_caps.status = WSM_GET16(buf); | ||
824 | priv->wsm_caps.fw_cap = WSM_GET16(buf); | ||
825 | priv->wsm_caps.fw_type = WSM_GET16(buf); | ||
826 | priv->wsm_caps.fw_api = WSM_GET16(buf); | ||
827 | priv->wsm_caps.fw_build = WSM_GET16(buf); | ||
828 | priv->wsm_caps.fw_ver = WSM_GET16(buf); | ||
829 | WSM_GET(buf, priv->wsm_caps.fw_label, sizeof(priv->wsm_caps.fw_label)); | ||
830 | priv->wsm_caps.fw_label[sizeof(priv->wsm_caps.fw_label) - 1] = 0; /* Do not trust FW too much... */ | ||
831 | |||
832 | if (WARN_ON(priv->wsm_caps.status)) | ||
833 | return -EINVAL; | ||
834 | |||
835 | if (WARN_ON(priv->wsm_caps.fw_type > 4)) | ||
836 | return -EINVAL; | ||
837 | |||
838 | pr_info("CW1200 WSM init done.\n" | ||
839 | " Input buffers: %d x %d bytes\n" | ||
840 | " Hardware: %d.%d\n" | ||
841 | " %s firmware [%s], ver: %d, build: %d," | ||
842 | " api: %d, cap: 0x%.4X\n", | ||
843 | priv->wsm_caps.input_buffers, | ||
844 | priv->wsm_caps.input_buffer_size, | ||
845 | priv->wsm_caps.hw_id, priv->wsm_caps.hw_subid, | ||
846 | cw1200_fw_types[priv->wsm_caps.fw_type], | ||
847 | priv->wsm_caps.fw_label, priv->wsm_caps.fw_ver, | ||
848 | priv->wsm_caps.fw_build, | ||
849 | priv->wsm_caps.fw_api, priv->wsm_caps.fw_cap); | ||
850 | |||
851 | /* Disable unsupported frequency bands */ | ||
852 | if (!(priv->wsm_caps.fw_cap & 0x1)) | ||
853 | priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; | ||
854 | if (!(priv->wsm_caps.fw_cap & 0x2)) | ||
855 | priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; | ||
856 | |||
857 | priv->firmware_ready = 1; | ||
858 | wake_up(&priv->wsm_startup_done); | ||
859 | return 0; | ||
860 | |||
861 | underflow: | ||
862 | WARN_ON(1); | ||
863 | return -EINVAL; | ||
864 | } | ||
865 | |||
866 | static int wsm_receive_indication(struct cw1200_common *priv, | ||
867 | int link_id, | ||
868 | struct wsm_buf *buf, | ||
869 | struct sk_buff **skb_p) | ||
870 | { | ||
871 | struct wsm_rx rx; | ||
872 | struct ieee80211_hdr *hdr; | ||
873 | size_t hdr_len; | ||
874 | __le16 fctl; | ||
875 | |||
876 | rx.status = WSM_GET32(buf); | ||
877 | rx.channel_number = WSM_GET16(buf); | ||
878 | rx.rx_rate = WSM_GET8(buf); | ||
879 | rx.rcpi_rssi = WSM_GET8(buf); | ||
880 | rx.flags = WSM_GET32(buf); | ||
881 | |||
882 | /* FW Workaround: Drop probe resp or | ||
883 | beacon when RSSI is 0 | ||
884 | */ | ||
885 | hdr = (struct ieee80211_hdr *)(*skb_p)->data; | ||
886 | |||
887 | if (!rx.rcpi_rssi && | ||
888 | (ieee80211_is_probe_resp(hdr->frame_control) || | ||
889 | ieee80211_is_beacon(hdr->frame_control))) | ||
890 | return 0; | ||
891 | |||
892 | /* If no RSSI subscription has been made, | ||
893 | * convert RCPI to RSSI here | ||
894 | */ | ||
895 | if (!priv->cqm_use_rssi) | ||
896 | rx.rcpi_rssi = rx.rcpi_rssi / 2 - 110; | ||
897 | |||
898 | fctl = *(__le16 *)buf->data; | ||
899 | hdr_len = buf->data - buf->begin; | ||
900 | skb_pull(*skb_p, hdr_len); | ||
901 | if (!rx.status && ieee80211_is_deauth(fctl)) { | ||
902 | if (priv->join_status == CW1200_JOIN_STATUS_STA) { | ||
903 | /* Shedule unjoin work */ | ||
904 | pr_debug("[WSM] Issue unjoin command (RX).\n"); | ||
905 | wsm_lock_tx_async(priv); | ||
906 | if (queue_work(priv->workqueue, | ||
907 | &priv->unjoin_work) <= 0) | ||
908 | wsm_unlock_tx(priv); | ||
909 | } | ||
910 | } | ||
911 | cw1200_rx_cb(priv, &rx, link_id, skb_p); | ||
912 | if (*skb_p) | ||
913 | skb_push(*skb_p, hdr_len); | ||
914 | |||
915 | return 0; | ||
916 | |||
917 | underflow: | ||
918 | return -EINVAL; | ||
919 | } | ||
920 | |||
921 | static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf) | ||
922 | { | ||
923 | int first; | ||
924 | struct cw1200_wsm_event *event; | ||
925 | |||
926 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
927 | /* STA is stopped. */ | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL); | ||
932 | |||
933 | event->evt.id = __le32_to_cpu(WSM_GET32(buf)); | ||
934 | event->evt.data = __le32_to_cpu(WSM_GET32(buf)); | ||
935 | |||
936 | pr_debug("[WSM] Event: %d(%d)\n", | ||
937 | event->evt.id, event->evt.data); | ||
938 | |||
939 | spin_lock(&priv->event_queue_lock); | ||
940 | first = list_empty(&priv->event_queue); | ||
941 | list_add_tail(&event->link, &priv->event_queue); | ||
942 | spin_unlock(&priv->event_queue_lock); | ||
943 | |||
944 | if (first) | ||
945 | queue_work(priv->workqueue, &priv->event_handler); | ||
946 | |||
947 | return 0; | ||
948 | |||
949 | underflow: | ||
950 | kfree(event); | ||
951 | return -EINVAL; | ||
952 | } | ||
953 | |||
954 | static int wsm_channel_switch_indication(struct cw1200_common *priv, | ||
955 | struct wsm_buf *buf) | ||
956 | { | ||
957 | WARN_ON(WSM_GET32(buf)); | ||
958 | |||
959 | priv->channel_switch_in_progress = 0; | ||
960 | wake_up(&priv->channel_switch_done); | ||
961 | |||
962 | wsm_unlock_tx(priv); | ||
963 | |||
964 | return 0; | ||
965 | |||
966 | underflow: | ||
967 | return -EINVAL; | ||
968 | } | ||
969 | |||
970 | static int wsm_set_pm_indication(struct cw1200_common *priv, | ||
971 | struct wsm_buf *buf) | ||
972 | { | ||
973 | /* TODO: Check buf (struct wsm_set_pm_complete) for validity */ | ||
974 | if (priv->ps_mode_switch_in_progress) { | ||
975 | priv->ps_mode_switch_in_progress = 0; | ||
976 | wake_up(&priv->ps_mode_switch_done); | ||
977 | } | ||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | static int wsm_scan_started(struct cw1200_common *priv, void *arg, | ||
982 | struct wsm_buf *buf) | ||
983 | { | ||
984 | u32 status = WSM_GET32(buf); | ||
985 | if (status != WSM_STATUS_SUCCESS) { | ||
986 | cw1200_scan_failed_cb(priv); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | return 0; | ||
990 | |||
991 | underflow: | ||
992 | WARN_ON(1); | ||
993 | return -EINVAL; | ||
994 | } | ||
995 | |||
996 | static int wsm_scan_complete_indication(struct cw1200_common *priv, | ||
997 | struct wsm_buf *buf) | ||
998 | { | ||
999 | struct wsm_scan_complete arg; | ||
1000 | arg.status = WSM_GET32(buf); | ||
1001 | arg.psm = WSM_GET8(buf); | ||
1002 | arg.num_channels = WSM_GET8(buf); | ||
1003 | cw1200_scan_complete_cb(priv, &arg); | ||
1004 | |||
1005 | return 0; | ||
1006 | |||
1007 | underflow: | ||
1008 | return -EINVAL; | ||
1009 | } | ||
1010 | |||
1011 | static int wsm_join_complete_indication(struct cw1200_common *priv, | ||
1012 | struct wsm_buf *buf) | ||
1013 | { | ||
1014 | struct wsm_join_complete arg; | ||
1015 | arg.status = WSM_GET32(buf); | ||
1016 | pr_debug("[WSM] Join complete indication, status: %d\n", arg.status); | ||
1017 | cw1200_join_complete_cb(priv, &arg); | ||
1018 | |||
1019 | return 0; | ||
1020 | |||
1021 | underflow: | ||
1022 | return -EINVAL; | ||
1023 | } | ||
1024 | |||
1025 | static int wsm_find_complete_indication(struct cw1200_common *priv, | ||
1026 | struct wsm_buf *buf) | ||
1027 | { | ||
1028 | pr_warn("Implement find_complete_indication\n"); | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static int wsm_ba_timeout_indication(struct cw1200_common *priv, | ||
1033 | struct wsm_buf *buf) | ||
1034 | { | ||
1035 | u32 dummy; | ||
1036 | u8 tid; | ||
1037 | u8 dummy2; | ||
1038 | u8 addr[ETH_ALEN]; | ||
1039 | |||
1040 | dummy = WSM_GET32(buf); | ||
1041 | tid = WSM_GET8(buf); | ||
1042 | dummy2 = WSM_GET8(buf); | ||
1043 | WSM_GET(buf, addr, ETH_ALEN); | ||
1044 | |||
1045 | pr_info("BlockACK timeout, tid %d, addr %pM\n", | ||
1046 | tid, addr); | ||
1047 | |||
1048 | return 0; | ||
1049 | |||
1050 | underflow: | ||
1051 | return -EINVAL; | ||
1052 | } | ||
1053 | |||
1054 | static int wsm_suspend_resume_indication(struct cw1200_common *priv, | ||
1055 | int link_id, struct wsm_buf *buf) | ||
1056 | { | ||
1057 | u32 flags; | ||
1058 | struct wsm_suspend_resume arg; | ||
1059 | |||
1060 | flags = WSM_GET32(buf); | ||
1061 | arg.link_id = link_id; | ||
1062 | arg.stop = !(flags & 1); | ||
1063 | arg.multicast = !!(flags & 8); | ||
1064 | arg.queue = (flags >> 1) & 3; | ||
1065 | |||
1066 | cw1200_suspend_resume(priv, &arg); | ||
1067 | |||
1068 | return 0; | ||
1069 | |||
1070 | underflow: | ||
1071 | return -EINVAL; | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | /* ******************************************************************** */ | ||
1076 | /* WSM TX */ | ||
1077 | |||
1078 | static int wsm_cmd_send(struct cw1200_common *priv, | ||
1079 | struct wsm_buf *buf, | ||
1080 | void *arg, u16 cmd, long tmo) | ||
1081 | { | ||
1082 | size_t buf_len = buf->data - buf->begin; | ||
1083 | int ret; | ||
1084 | |||
1085 | /* Don't bother if we're dead. */ | ||
1086 | if (priv->bh_error) { | ||
1087 | ret = 0; | ||
1088 | goto done; | ||
1089 | } | ||
1090 | |||
1091 | /* Block until the cmd buffer is completed. Tortuous. */ | ||
1092 | spin_lock(&priv->wsm_cmd.lock); | ||
1093 | while (!priv->wsm_cmd.done) { | ||
1094 | spin_unlock(&priv->wsm_cmd.lock); | ||
1095 | spin_lock(&priv->wsm_cmd.lock); | ||
1096 | } | ||
1097 | priv->wsm_cmd.done = 0; | ||
1098 | spin_unlock(&priv->wsm_cmd.lock); | ||
1099 | |||
1100 | if (cmd == WSM_WRITE_MIB_REQ_ID || | ||
1101 | cmd == WSM_READ_MIB_REQ_ID) | ||
1102 | pr_debug("[WSM] >>> 0x%.4X [MIB: 0x%.4X] (%zu)\n", | ||
1103 | cmd, __le16_to_cpu(((__le16 *)buf->begin)[2]), | ||
1104 | buf_len); | ||
1105 | else | ||
1106 | pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len); | ||
1107 | |||
1108 | /* | ||
1109 | * Due to buggy SPI on CW1200, we need to | ||
1110 | * pad the message by a few bytes to ensure | ||
1111 | * that it's completely received. | ||
1112 | */ | ||
1113 | #ifdef CONFIG_CW1200_ETF | ||
1114 | if (!etf_mode) | ||
1115 | #endif | ||
1116 | buf_len += 4; | ||
1117 | |||
1118 | /* Fill HI message header */ | ||
1119 | /* BH will add sequence number */ | ||
1120 | ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); | ||
1121 | ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd); | ||
1122 | |||
1123 | spin_lock(&priv->wsm_cmd.lock); | ||
1124 | BUG_ON(priv->wsm_cmd.ptr); | ||
1125 | priv->wsm_cmd.ptr = buf->begin; | ||
1126 | priv->wsm_cmd.len = buf_len; | ||
1127 | priv->wsm_cmd.arg = arg; | ||
1128 | priv->wsm_cmd.cmd = cmd; | ||
1129 | spin_unlock(&priv->wsm_cmd.lock); | ||
1130 | |||
1131 | cw1200_bh_wakeup(priv); | ||
1132 | |||
1133 | /* Wait for command completion */ | ||
1134 | ret = wait_event_timeout(priv->wsm_cmd_wq, | ||
1135 | priv->wsm_cmd.done, tmo); | ||
1136 | |||
1137 | if (!ret && !priv->wsm_cmd.done) { | ||
1138 | spin_lock(&priv->wsm_cmd.lock); | ||
1139 | priv->wsm_cmd.done = 1; | ||
1140 | priv->wsm_cmd.ptr = NULL; | ||
1141 | spin_unlock(&priv->wsm_cmd.lock); | ||
1142 | if (priv->bh_error) { | ||
1143 | /* Return ok to help system cleanup */ | ||
1144 | ret = 0; | ||
1145 | } else { | ||
1146 | pr_err("CMD req (0x%04x) stuck in firmware, killing BH\n", priv->wsm_cmd.cmd); | ||
1147 | print_hex_dump_bytes("REQDUMP: ", DUMP_PREFIX_NONE, | ||
1148 | buf->begin, buf_len); | ||
1149 | pr_err("Outstanding outgoing frames: %d\n", priv->hw_bufs_used); | ||
1150 | |||
1151 | /* Kill BH thread to report the error to the top layer. */ | ||
1152 | atomic_add(1, &priv->bh_term); | ||
1153 | wake_up(&priv->bh_wq); | ||
1154 | ret = -ETIMEDOUT; | ||
1155 | } | ||
1156 | } else { | ||
1157 | spin_lock(&priv->wsm_cmd.lock); | ||
1158 | BUG_ON(!priv->wsm_cmd.done); | ||
1159 | ret = priv->wsm_cmd.ret; | ||
1160 | spin_unlock(&priv->wsm_cmd.lock); | ||
1161 | } | ||
1162 | done: | ||
1163 | wsm_buf_reset(buf); | ||
1164 | return ret; | ||
1165 | } | ||
1166 | |||
1167 | #ifdef CONFIG_CW1200_ETF | ||
1168 | int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len) | ||
1169 | { | ||
1170 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
1171 | int ret; | ||
1172 | |||
1173 | u16 *cmd = (u16 *)(data + 2); | ||
1174 | |||
1175 | wsm_cmd_lock(priv); | ||
1176 | |||
1177 | WSM_PUT(buf, data + 4, len - 4); /* Skip over header (u16+u16) */ | ||
1178 | |||
1179 | ret = wsm_cmd_send(priv, buf, NULL, __le16_to_cpu(*cmd), WSM_CMD_TIMEOUT); | ||
1180 | |||
1181 | wsm_cmd_unlock(priv); | ||
1182 | return ret; | ||
1183 | |||
1184 | nomem: | ||
1185 | wsm_cmd_unlock(priv); | ||
1186 | return -ENOMEM; | ||
1187 | } | ||
1188 | #endif /* CONFIG_CW1200_ETF */ | ||
1189 | |||
1190 | /* ******************************************************************** */ | ||
1191 | /* WSM TX port control */ | ||
1192 | |||
1193 | void wsm_lock_tx(struct cw1200_common *priv) | ||
1194 | { | ||
1195 | wsm_cmd_lock(priv); | ||
1196 | if (atomic_add_return(1, &priv->tx_lock) == 1) { | ||
1197 | if (wsm_flush_tx(priv)) | ||
1198 | pr_debug("[WSM] TX is locked.\n"); | ||
1199 | } | ||
1200 | wsm_cmd_unlock(priv); | ||
1201 | } | ||
1202 | |||
1203 | void wsm_lock_tx_async(struct cw1200_common *priv) | ||
1204 | { | ||
1205 | if (atomic_add_return(1, &priv->tx_lock) == 1) | ||
1206 | pr_debug("[WSM] TX is locked (async).\n"); | ||
1207 | } | ||
1208 | |||
1209 | bool wsm_flush_tx(struct cw1200_common *priv) | ||
1210 | { | ||
1211 | unsigned long timestamp = jiffies; | ||
1212 | bool pending = false; | ||
1213 | long timeout; | ||
1214 | int i; | ||
1215 | |||
1216 | /* Flush must be called with TX lock held. */ | ||
1217 | BUG_ON(!atomic_read(&priv->tx_lock)); | ||
1218 | |||
1219 | /* First check if we really need to do something. | ||
1220 | * It is safe to use unprotected access, as hw_bufs_used | ||
1221 | * can only decrements. | ||
1222 | */ | ||
1223 | if (!priv->hw_bufs_used) | ||
1224 | return true; | ||
1225 | |||
1226 | if (priv->bh_error) { | ||
1227 | /* In case of failure do not wait for magic. */ | ||
1228 | pr_err("[WSM] Fatal error occured, will not flush TX.\n"); | ||
1229 | return false; | ||
1230 | } else { | ||
1231 | /* Get a timestamp of "oldest" frame */ | ||
1232 | for (i = 0; i < 4; ++i) | ||
1233 | pending |= cw1200_queue_get_xmit_timestamp( | ||
1234 | &priv->tx_queue[i], | ||
1235 | ×tamp, 0xffffffff); | ||
1236 | /* If there's nothing pending, we're good */ | ||
1237 | if (!pending) | ||
1238 | return true; | ||
1239 | |||
1240 | timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies; | ||
1241 | if (timeout < 0 || wait_event_timeout(priv->bh_evt_wq, | ||
1242 | !priv->hw_bufs_used, | ||
1243 | timeout) <= 0) { | ||
1244 | /* Hmmm... Not good. Frame had stuck in firmware. */ | ||
1245 | priv->bh_error = 1; | ||
1246 | wiphy_err(priv->hw->wiphy, "[WSM] TX Frames (%d) stuck in firmware, killing BH\n", priv->hw_bufs_used); | ||
1247 | wake_up(&priv->bh_wq); | ||
1248 | return false; | ||
1249 | } | ||
1250 | |||
1251 | /* Ok, everything is flushed. */ | ||
1252 | return true; | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | void wsm_unlock_tx(struct cw1200_common *priv) | ||
1257 | { | ||
1258 | int tx_lock; | ||
1259 | tx_lock = atomic_sub_return(1, &priv->tx_lock); | ||
1260 | BUG_ON(tx_lock < 0); | ||
1261 | |||
1262 | if (tx_lock == 0) { | ||
1263 | if (!priv->bh_error) | ||
1264 | cw1200_bh_wakeup(priv); | ||
1265 | pr_debug("[WSM] TX is unlocked.\n"); | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | /* ******************************************************************** */ | ||
1270 | /* WSM RX */ | ||
1271 | |||
1272 | int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len) | ||
1273 | { | ||
1274 | struct wsm_buf buf; | ||
1275 | u32 reason; | ||
1276 | u32 reg[18]; | ||
1277 | char fname[48]; | ||
1278 | unsigned int i; | ||
1279 | |||
1280 | static const char * const reason_str[] = { | ||
1281 | "undefined instruction", | ||
1282 | "prefetch abort", | ||
1283 | "data abort", | ||
1284 | "unknown error", | ||
1285 | }; | ||
1286 | |||
1287 | buf.begin = buf.data = data; | ||
1288 | buf.end = &buf.begin[len]; | ||
1289 | |||
1290 | reason = WSM_GET32(&buf); | ||
1291 | for (i = 0; i < ARRAY_SIZE(reg); ++i) | ||
1292 | reg[i] = WSM_GET32(&buf); | ||
1293 | WSM_GET(&buf, fname, sizeof(fname)); | ||
1294 | |||
1295 | if (reason < 4) | ||
1296 | wiphy_err(priv->hw->wiphy, | ||
1297 | "Firmware exception: %s.\n", | ||
1298 | reason_str[reason]); | ||
1299 | else | ||
1300 | wiphy_err(priv->hw->wiphy, | ||
1301 | "Firmware assert at %.*s, line %d\n", | ||
1302 | (int) sizeof(fname), fname, reg[1]); | ||
1303 | |||
1304 | for (i = 0; i < 12; i += 4) | ||
1305 | wiphy_err(priv->hw->wiphy, | ||
1306 | "R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X,\n", | ||
1307 | i + 0, reg[i + 0], i + 1, reg[i + 1], | ||
1308 | i + 2, reg[i + 2], i + 3, reg[i + 3]); | ||
1309 | wiphy_err(priv->hw->wiphy, | ||
1310 | "R12: 0x%.8X, SP: 0x%.8X, LR: 0x%.8X, PC: 0x%.8X,\n", | ||
1311 | reg[i + 0], reg[i + 1], reg[i + 2], reg[i + 3]); | ||
1312 | i += 4; | ||
1313 | wiphy_err(priv->hw->wiphy, | ||
1314 | "CPSR: 0x%.8X, SPSR: 0x%.8X\n", | ||
1315 | reg[i + 0], reg[i + 1]); | ||
1316 | |||
1317 | print_hex_dump_bytes("R1: ", DUMP_PREFIX_NONE, | ||
1318 | fname, sizeof(fname)); | ||
1319 | return 0; | ||
1320 | |||
1321 | underflow: | ||
1322 | wiphy_err(priv->hw->wiphy, "Firmware exception.\n"); | ||
1323 | print_hex_dump_bytes("Exception: ", DUMP_PREFIX_NONE, | ||
1324 | data, len); | ||
1325 | return -EINVAL; | ||
1326 | } | ||
1327 | |||
1328 | int wsm_handle_rx(struct cw1200_common *priv, u16 id, | ||
1329 | struct wsm_hdr *wsm, struct sk_buff **skb_p) | ||
1330 | { | ||
1331 | int ret = 0; | ||
1332 | struct wsm_buf wsm_buf; | ||
1333 | int link_id = (id >> 6) & 0x0F; | ||
1334 | |||
1335 | /* Strip link id. */ | ||
1336 | id &= ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); | ||
1337 | |||
1338 | wsm_buf.begin = (u8 *)&wsm[0]; | ||
1339 | wsm_buf.data = (u8 *)&wsm[1]; | ||
1340 | wsm_buf.end = &wsm_buf.begin[__le32_to_cpu(wsm->len)]; | ||
1341 | |||
1342 | pr_debug("[WSM] <<< 0x%.4X (%td)\n", id, | ||
1343 | wsm_buf.end - wsm_buf.begin); | ||
1344 | |||
1345 | #ifdef CONFIG_CW1200_ETF | ||
1346 | if (etf_mode) { | ||
1347 | struct sk_buff *skb = alloc_skb(wsm_buf.end - wsm_buf.begin, GFP_KERNEL); | ||
1348 | |||
1349 | /* Strip out Sequence num before passing up */ | ||
1350 | wsm->id = __le16_to_cpu(wsm->id); | ||
1351 | wsm->id &= 0x0FFF; | ||
1352 | wsm->id = __cpu_to_le16(wsm->id); | ||
1353 | |||
1354 | memcpy(skb_put(skb, wsm_buf.end - wsm_buf.begin), | ||
1355 | wsm_buf.begin, | ||
1356 | wsm_buf.end - wsm_buf.begin); | ||
1357 | skb_queue_tail(&priv->etf_q, skb); | ||
1358 | |||
1359 | /* Special case for startup */ | ||
1360 | if (id == WSM_STARTUP_IND_ID) { | ||
1361 | wsm_startup_indication(priv, &wsm_buf); | ||
1362 | } else if (id & 0x0400) { | ||
1363 | spin_lock(&priv->wsm_cmd.lock); | ||
1364 | priv->wsm_cmd.done = 1; | ||
1365 | spin_unlock(&priv->wsm_cmd.lock); | ||
1366 | wake_up(&priv->wsm_cmd_wq); | ||
1367 | } | ||
1368 | |||
1369 | goto out; | ||
1370 | } | ||
1371 | #endif | ||
1372 | |||
1373 | if (id == WSM_TX_CONFIRM_IND_ID) { | ||
1374 | ret = wsm_tx_confirm(priv, &wsm_buf, link_id); | ||
1375 | } else if (id == WSM_MULTI_TX_CONFIRM_ID) { | ||
1376 | ret = wsm_multi_tx_confirm(priv, &wsm_buf, link_id); | ||
1377 | } else if (id & 0x0400) { | ||
1378 | void *wsm_arg; | ||
1379 | u16 wsm_cmd; | ||
1380 | |||
1381 | /* Do not trust FW too much. Protection against repeated | ||
1382 | * response and race condition removal (see above). | ||
1383 | */ | ||
1384 | spin_lock(&priv->wsm_cmd.lock); | ||
1385 | wsm_arg = priv->wsm_cmd.arg; | ||
1386 | wsm_cmd = priv->wsm_cmd.cmd & | ||
1387 | ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); | ||
1388 | priv->wsm_cmd.cmd = 0xFFFF; | ||
1389 | spin_unlock(&priv->wsm_cmd.lock); | ||
1390 | |||
1391 | if (WARN_ON((id & ~0x0400) != wsm_cmd)) { | ||
1392 | /* Note that any non-zero is a fatal retcode. */ | ||
1393 | ret = -EINVAL; | ||
1394 | goto out; | ||
1395 | } | ||
1396 | |||
1397 | /* Note that wsm_arg can be NULL in case of timeout in | ||
1398 | * wsm_cmd_send(). | ||
1399 | */ | ||
1400 | |||
1401 | switch (id) { | ||
1402 | case WSM_READ_MIB_RESP_ID: | ||
1403 | if (wsm_arg) | ||
1404 | ret = wsm_read_mib_confirm(priv, wsm_arg, | ||
1405 | &wsm_buf); | ||
1406 | break; | ||
1407 | case WSM_WRITE_MIB_RESP_ID: | ||
1408 | if (wsm_arg) | ||
1409 | ret = wsm_write_mib_confirm(priv, wsm_arg, | ||
1410 | &wsm_buf); | ||
1411 | break; | ||
1412 | case WSM_START_SCAN_RESP_ID: | ||
1413 | if (wsm_arg) | ||
1414 | ret = wsm_scan_started(priv, wsm_arg, &wsm_buf); | ||
1415 | break; | ||
1416 | case WSM_CONFIGURATION_RESP_ID: | ||
1417 | if (wsm_arg) | ||
1418 | ret = wsm_configuration_confirm(priv, wsm_arg, | ||
1419 | &wsm_buf); | ||
1420 | break; | ||
1421 | case WSM_JOIN_RESP_ID: | ||
1422 | if (wsm_arg) | ||
1423 | ret = wsm_join_confirm(priv, wsm_arg, &wsm_buf); | ||
1424 | break; | ||
1425 | case WSM_STOP_SCAN_RESP_ID: | ||
1426 | case WSM_RESET_RESP_ID: | ||
1427 | case WSM_ADD_KEY_RESP_ID: | ||
1428 | case WSM_REMOVE_KEY_RESP_ID: | ||
1429 | case WSM_SET_PM_RESP_ID: | ||
1430 | case WSM_SET_BSS_PARAMS_RESP_ID: | ||
1431 | case 0x0412: /* set_tx_queue_params */ | ||
1432 | case WSM_EDCA_PARAMS_RESP_ID: | ||
1433 | case WSM_SWITCH_CHANNEL_RESP_ID: | ||
1434 | case WSM_START_RESP_ID: | ||
1435 | case WSM_BEACON_TRANSMIT_RESP_ID: | ||
1436 | case 0x0419: /* start_find */ | ||
1437 | case 0x041A: /* stop_find */ | ||
1438 | case 0x041B: /* update_ie */ | ||
1439 | case 0x041C: /* map_link */ | ||
1440 | WARN_ON(wsm_arg != NULL); | ||
1441 | ret = wsm_generic_confirm(priv, wsm_arg, &wsm_buf); | ||
1442 | if (ret) { | ||
1443 | wiphy_warn(priv->hw->wiphy, | ||
1444 | "wsm_generic_confirm failed for request 0x%04x.\n", | ||
1445 | id & ~0x0400); | ||
1446 | |||
1447 | /* often 0x407 and 0x410 occur, this means we're dead.. */ | ||
1448 | if (priv->join_status >= CW1200_JOIN_STATUS_JOINING) { | ||
1449 | wsm_lock_tx(priv); | ||
1450 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1451 | wsm_unlock_tx(priv); | ||
1452 | } | ||
1453 | } | ||
1454 | break; | ||
1455 | default: | ||
1456 | wiphy_warn(priv->hw->wiphy, | ||
1457 | "Unrecognized confirmation 0x%04x\n", | ||
1458 | id & ~0x0400); | ||
1459 | } | ||
1460 | |||
1461 | spin_lock(&priv->wsm_cmd.lock); | ||
1462 | priv->wsm_cmd.ret = ret; | ||
1463 | priv->wsm_cmd.done = 1; | ||
1464 | spin_unlock(&priv->wsm_cmd.lock); | ||
1465 | |||
1466 | ret = 0; /* Error response from device should ne stop BH. */ | ||
1467 | |||
1468 | wake_up(&priv->wsm_cmd_wq); | ||
1469 | } else if (id & 0x0800) { | ||
1470 | switch (id) { | ||
1471 | case WSM_STARTUP_IND_ID: | ||
1472 | ret = wsm_startup_indication(priv, &wsm_buf); | ||
1473 | break; | ||
1474 | case WSM_RECEIVE_IND_ID: | ||
1475 | ret = wsm_receive_indication(priv, link_id, | ||
1476 | &wsm_buf, skb_p); | ||
1477 | break; | ||
1478 | case 0x0805: | ||
1479 | ret = wsm_event_indication(priv, &wsm_buf); | ||
1480 | break; | ||
1481 | case WSM_SCAN_COMPLETE_IND_ID: | ||
1482 | ret = wsm_scan_complete_indication(priv, &wsm_buf); | ||
1483 | break; | ||
1484 | case 0x0808: | ||
1485 | ret = wsm_ba_timeout_indication(priv, &wsm_buf); | ||
1486 | break; | ||
1487 | case 0x0809: | ||
1488 | ret = wsm_set_pm_indication(priv, &wsm_buf); | ||
1489 | break; | ||
1490 | case 0x080A: | ||
1491 | ret = wsm_channel_switch_indication(priv, &wsm_buf); | ||
1492 | break; | ||
1493 | case 0x080B: | ||
1494 | ret = wsm_find_complete_indication(priv, &wsm_buf); | ||
1495 | break; | ||
1496 | case 0x080C: | ||
1497 | ret = wsm_suspend_resume_indication(priv, | ||
1498 | link_id, &wsm_buf); | ||
1499 | break; | ||
1500 | case 0x080F: | ||
1501 | ret = wsm_join_complete_indication(priv, &wsm_buf); | ||
1502 | break; | ||
1503 | default: | ||
1504 | pr_warn("Unrecognised WSM ID %04x\n", id); | ||
1505 | } | ||
1506 | } else { | ||
1507 | WARN_ON(1); | ||
1508 | ret = -EINVAL; | ||
1509 | } | ||
1510 | out: | ||
1511 | return ret; | ||
1512 | } | ||
1513 | |||
1514 | static bool wsm_handle_tx_data(struct cw1200_common *priv, | ||
1515 | struct wsm_tx *wsm, | ||
1516 | const struct ieee80211_tx_info *tx_info, | ||
1517 | const struct cw1200_txpriv *txpriv, | ||
1518 | struct cw1200_queue *queue) | ||
1519 | { | ||
1520 | bool handled = false; | ||
1521 | const struct ieee80211_hdr *frame = | ||
1522 | (struct ieee80211_hdr *)&((u8 *)wsm)[txpriv->offset]; | ||
1523 | __le16 fctl = frame->frame_control; | ||
1524 | enum { | ||
1525 | do_probe, | ||
1526 | do_drop, | ||
1527 | do_wep, | ||
1528 | do_tx, | ||
1529 | } action = do_tx; | ||
1530 | |||
1531 | switch (priv->mode) { | ||
1532 | case NL80211_IFTYPE_STATION: | ||
1533 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) | ||
1534 | action = do_tx; | ||
1535 | else if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) | ||
1536 | action = do_drop; | ||
1537 | break; | ||
1538 | case NL80211_IFTYPE_AP: | ||
1539 | if (!priv->join_status) { | ||
1540 | action = do_drop; | ||
1541 | } else if (!(BIT(txpriv->raw_link_id) & | ||
1542 | (BIT(0) | priv->link_id_map))) { | ||
1543 | wiphy_warn(priv->hw->wiphy, | ||
1544 | "A frame with expired link id is dropped.\n"); | ||
1545 | action = do_drop; | ||
1546 | } | ||
1547 | if (cw1200_queue_get_generation(wsm->packet_id) > | ||
1548 | CW1200_MAX_REQUEUE_ATTEMPTS) { | ||
1549 | /* HACK!!! WSM324 firmware has tendency to requeue | ||
1550 | * multicast frames in a loop, causing performance | ||
1551 | * drop and high power consumption of the driver. | ||
1552 | * In this situation it is better just to drop | ||
1553 | * the problematic frame. | ||
1554 | */ | ||
1555 | wiphy_warn(priv->hw->wiphy, | ||
1556 | "Too many attempts to requeue a frame; dropped.\n"); | ||
1557 | action = do_drop; | ||
1558 | } | ||
1559 | break; | ||
1560 | case NL80211_IFTYPE_ADHOC: | ||
1561 | if (priv->join_status != CW1200_JOIN_STATUS_IBSS) | ||
1562 | action = do_drop; | ||
1563 | break; | ||
1564 | case NL80211_IFTYPE_MESH_POINT: | ||
1565 | action = do_tx; /* TODO: Test me! */ | ||
1566 | break; | ||
1567 | case NL80211_IFTYPE_MONITOR: | ||
1568 | default: | ||
1569 | action = do_drop; | ||
1570 | break; | ||
1571 | } | ||
1572 | |||
1573 | if (action == do_tx) { | ||
1574 | if (ieee80211_is_nullfunc(fctl)) { | ||
1575 | spin_lock(&priv->bss_loss_lock); | ||
1576 | if (priv->bss_loss_state) { | ||
1577 | priv->bss_loss_confirm_id = wsm->packet_id; | ||
1578 | wsm->queue_id = WSM_QUEUE_VOICE; | ||
1579 | } | ||
1580 | spin_unlock(&priv->bss_loss_lock); | ||
1581 | } else if (ieee80211_is_probe_req(fctl)) { | ||
1582 | action = do_probe; | ||
1583 | } else if (ieee80211_is_deauth(fctl) && | ||
1584 | priv->mode != NL80211_IFTYPE_AP) { | ||
1585 | pr_debug("[WSM] Issue unjoin command due to tx deauth.\n"); | ||
1586 | wsm_lock_tx_async(priv); | ||
1587 | if (queue_work(priv->workqueue, | ||
1588 | &priv->unjoin_work) <= 0) | ||
1589 | wsm_unlock_tx(priv); | ||
1590 | } else if (ieee80211_has_protected(fctl) && | ||
1591 | tx_info->control.hw_key && | ||
1592 | tx_info->control.hw_key->keyidx != priv->wep_default_key_id && | ||
1593 | (tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
1594 | tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) { | ||
1595 | action = do_wep; | ||
1596 | } | ||
1597 | } | ||
1598 | |||
1599 | switch (action) { | ||
1600 | case do_probe: | ||
1601 | /* An interesting FW "feature". Device filters probe responses. | ||
1602 | * The easiest way to get it back is to convert | ||
1603 | * probe request into WSM start_scan command. | ||
1604 | */ | ||
1605 | pr_debug("[WSM] Convert probe request to scan.\n"); | ||
1606 | wsm_lock_tx_async(priv); | ||
1607 | priv->pending_frame_id = __le32_to_cpu(wsm->packet_id); | ||
1608 | if (queue_delayed_work(priv->workqueue, | ||
1609 | &priv->scan.probe_work, 0) <= 0) | ||
1610 | wsm_unlock_tx(priv); | ||
1611 | handled = true; | ||
1612 | break; | ||
1613 | case do_drop: | ||
1614 | pr_debug("[WSM] Drop frame (0x%.4X).\n", fctl); | ||
1615 | BUG_ON(cw1200_queue_remove(queue, | ||
1616 | __le32_to_cpu(wsm->packet_id))); | ||
1617 | handled = true; | ||
1618 | break; | ||
1619 | case do_wep: | ||
1620 | pr_debug("[WSM] Issue set_default_wep_key.\n"); | ||
1621 | wsm_lock_tx_async(priv); | ||
1622 | priv->wep_default_key_id = tx_info->control.hw_key->keyidx; | ||
1623 | priv->pending_frame_id = __le32_to_cpu(wsm->packet_id); | ||
1624 | if (queue_work(priv->workqueue, &priv->wep_key_work) <= 0) | ||
1625 | wsm_unlock_tx(priv); | ||
1626 | handled = true; | ||
1627 | break; | ||
1628 | case do_tx: | ||
1629 | pr_debug("[WSM] Transmit frame.\n"); | ||
1630 | break; | ||
1631 | default: | ||
1632 | /* Do nothing */ | ||
1633 | break; | ||
1634 | } | ||
1635 | return handled; | ||
1636 | } | ||
1637 | |||
1638 | static int cw1200_get_prio_queue(struct cw1200_common *priv, | ||
1639 | u32 link_id_map, int *total) | ||
1640 | { | ||
1641 | static const int urgent = BIT(CW1200_LINK_ID_AFTER_DTIM) | | ||
1642 | BIT(CW1200_LINK_ID_UAPSD); | ||
1643 | struct wsm_edca_queue_params *edca; | ||
1644 | unsigned score, best = -1; | ||
1645 | int winner = -1; | ||
1646 | int queued; | ||
1647 | int i; | ||
1648 | |||
1649 | /* search for a winner using edca params */ | ||
1650 | for (i = 0; i < 4; ++i) { | ||
1651 | queued = cw1200_queue_get_num_queued(&priv->tx_queue[i], | ||
1652 | link_id_map); | ||
1653 | if (!queued) | ||
1654 | continue; | ||
1655 | *total += queued; | ||
1656 | edca = &priv->edca.params[i]; | ||
1657 | score = ((edca->aifns + edca->cwmin) << 16) + | ||
1658 | ((edca->cwmax - edca->cwmin) * | ||
1659 | (get_random_int() & 0xFFFF)); | ||
1660 | if (score < best && (winner < 0 || i != 3)) { | ||
1661 | best = score; | ||
1662 | winner = i; | ||
1663 | } | ||
1664 | } | ||
1665 | |||
1666 | /* override winner if bursting */ | ||
1667 | if (winner >= 0 && priv->tx_burst_idx >= 0 && | ||
1668 | winner != priv->tx_burst_idx && | ||
1669 | !cw1200_queue_get_num_queued( | ||
1670 | &priv->tx_queue[winner], | ||
1671 | link_id_map & urgent) && | ||
1672 | cw1200_queue_get_num_queued( | ||
1673 | &priv->tx_queue[priv->tx_burst_idx], | ||
1674 | link_id_map)) | ||
1675 | winner = priv->tx_burst_idx; | ||
1676 | |||
1677 | return winner; | ||
1678 | } | ||
1679 | |||
1680 | static int wsm_get_tx_queue_and_mask(struct cw1200_common *priv, | ||
1681 | struct cw1200_queue **queue_p, | ||
1682 | u32 *tx_allowed_mask_p, | ||
1683 | bool *more) | ||
1684 | { | ||
1685 | int idx; | ||
1686 | u32 tx_allowed_mask; | ||
1687 | int total = 0; | ||
1688 | |||
1689 | /* Search for a queue with multicast frames buffered */ | ||
1690 | if (priv->tx_multicast) { | ||
1691 | tx_allowed_mask = BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1692 | idx = cw1200_get_prio_queue(priv, | ||
1693 | tx_allowed_mask, &total); | ||
1694 | if (idx >= 0) { | ||
1695 | *more = total > 1; | ||
1696 | goto found; | ||
1697 | } | ||
1698 | } | ||
1699 | |||
1700 | /* Search for unicast traffic */ | ||
1701 | tx_allowed_mask = ~priv->sta_asleep_mask; | ||
1702 | tx_allowed_mask |= BIT(CW1200_LINK_ID_UAPSD); | ||
1703 | if (priv->sta_asleep_mask) { | ||
1704 | tx_allowed_mask |= priv->pspoll_mask; | ||
1705 | tx_allowed_mask &= ~BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1706 | } else { | ||
1707 | tx_allowed_mask |= BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1708 | } | ||
1709 | idx = cw1200_get_prio_queue(priv, | ||
1710 | tx_allowed_mask, &total); | ||
1711 | if (idx < 0) | ||
1712 | return -ENOENT; | ||
1713 | |||
1714 | found: | ||
1715 | *queue_p = &priv->tx_queue[idx]; | ||
1716 | *tx_allowed_mask_p = tx_allowed_mask; | ||
1717 | return 0; | ||
1718 | } | ||
1719 | |||
1720 | int wsm_get_tx(struct cw1200_common *priv, u8 **data, | ||
1721 | size_t *tx_len, int *burst) | ||
1722 | { | ||
1723 | struct wsm_tx *wsm = NULL; | ||
1724 | struct ieee80211_tx_info *tx_info; | ||
1725 | struct cw1200_queue *queue = NULL; | ||
1726 | int queue_num; | ||
1727 | u32 tx_allowed_mask = 0; | ||
1728 | const struct cw1200_txpriv *txpriv = NULL; | ||
1729 | int count = 0; | ||
1730 | |||
1731 | /* More is used only for broadcasts. */ | ||
1732 | bool more = false; | ||
1733 | |||
1734 | #ifdef CONFIG_CW1200_ITP | ||
1735 | count = cw1200_itp_get_tx(priv, data, tx_len, burst); | ||
1736 | if (count) | ||
1737 | return count; | ||
1738 | #endif | ||
1739 | |||
1740 | if (priv->wsm_cmd.ptr) { /* CMD request */ | ||
1741 | ++count; | ||
1742 | spin_lock(&priv->wsm_cmd.lock); | ||
1743 | BUG_ON(!priv->wsm_cmd.ptr); | ||
1744 | *data = priv->wsm_cmd.ptr; | ||
1745 | *tx_len = priv->wsm_cmd.len; | ||
1746 | *burst = 1; | ||
1747 | spin_unlock(&priv->wsm_cmd.lock); | ||
1748 | } else { | ||
1749 | for (;;) { | ||
1750 | int ret; | ||
1751 | |||
1752 | if (atomic_add_return(0, &priv->tx_lock)) | ||
1753 | break; | ||
1754 | |||
1755 | spin_lock_bh(&priv->ps_state_lock); | ||
1756 | |||
1757 | ret = wsm_get_tx_queue_and_mask(priv, &queue, | ||
1758 | &tx_allowed_mask, &more); | ||
1759 | queue_num = queue - priv->tx_queue; | ||
1760 | |||
1761 | if (priv->buffered_multicasts && | ||
1762 | (ret || !more) && | ||
1763 | (priv->tx_multicast || !priv->sta_asleep_mask)) { | ||
1764 | priv->buffered_multicasts = false; | ||
1765 | if (priv->tx_multicast) { | ||
1766 | priv->tx_multicast = false; | ||
1767 | queue_work(priv->workqueue, | ||
1768 | &priv->multicast_stop_work); | ||
1769 | } | ||
1770 | } | ||
1771 | |||
1772 | spin_unlock_bh(&priv->ps_state_lock); | ||
1773 | |||
1774 | if (ret) | ||
1775 | break; | ||
1776 | |||
1777 | if (cw1200_queue_get(queue, | ||
1778 | tx_allowed_mask, | ||
1779 | &wsm, &tx_info, &txpriv)) | ||
1780 | continue; | ||
1781 | |||
1782 | if (wsm_handle_tx_data(priv, wsm, | ||
1783 | tx_info, txpriv, queue)) | ||
1784 | continue; /* Handled by WSM */ | ||
1785 | |||
1786 | wsm->hdr.id &= __cpu_to_le16( | ||
1787 | ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)); | ||
1788 | wsm->hdr.id |= cpu_to_le16( | ||
1789 | WSM_TX_LINK_ID(txpriv->raw_link_id)); | ||
1790 | priv->pspoll_mask &= ~BIT(txpriv->raw_link_id); | ||
1791 | |||
1792 | *data = (u8 *)wsm; | ||
1793 | *tx_len = __le16_to_cpu(wsm->hdr.len); | ||
1794 | |||
1795 | /* allow bursting if txop is set */ | ||
1796 | if (priv->edca.params[queue_num].txop_limit) | ||
1797 | *burst = min(*burst, | ||
1798 | (int)cw1200_queue_get_num_queued(queue, tx_allowed_mask) + 1); | ||
1799 | else | ||
1800 | *burst = 1; | ||
1801 | |||
1802 | /* store index of bursting queue */ | ||
1803 | if (*burst > 1) | ||
1804 | priv->tx_burst_idx = queue_num; | ||
1805 | else | ||
1806 | priv->tx_burst_idx = -1; | ||
1807 | |||
1808 | if (more) { | ||
1809 | struct ieee80211_hdr *hdr = | ||
1810 | (struct ieee80211_hdr *) | ||
1811 | &((u8 *)wsm)[txpriv->offset]; | ||
1812 | /* more buffered multicast/broadcast frames | ||
1813 | * ==> set MoreData flag in IEEE 802.11 header | ||
1814 | * to inform PS STAs | ||
1815 | */ | ||
1816 | hdr->frame_control |= | ||
1817 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
1818 | } | ||
1819 | |||
1820 | pr_debug("[WSM] >>> 0x%.4X (%zu) %p %c\n", | ||
1821 | 0x0004, *tx_len, *data, | ||
1822 | wsm->more ? 'M' : ' '); | ||
1823 | ++count; | ||
1824 | break; | ||
1825 | } | ||
1826 | } | ||
1827 | |||
1828 | return count; | ||
1829 | } | ||
1830 | |||
1831 | void wsm_txed(struct cw1200_common *priv, u8 *data) | ||
1832 | { | ||
1833 | if (data == priv->wsm_cmd.ptr) { | ||
1834 | spin_lock(&priv->wsm_cmd.lock); | ||
1835 | priv->wsm_cmd.ptr = NULL; | ||
1836 | spin_unlock(&priv->wsm_cmd.lock); | ||
1837 | } | ||
1838 | } | ||
1839 | |||
1840 | /* ******************************************************************** */ | ||
1841 | /* WSM buffer */ | ||
1842 | |||
1843 | void wsm_buf_init(struct wsm_buf *buf) | ||
1844 | { | ||
1845 | BUG_ON(buf->begin); | ||
1846 | buf->begin = kmalloc(FWLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); | ||
1847 | buf->end = buf->begin ? &buf->begin[FWLOAD_BLOCK_SIZE] : buf->begin; | ||
1848 | wsm_buf_reset(buf); | ||
1849 | } | ||
1850 | |||
1851 | void wsm_buf_deinit(struct wsm_buf *buf) | ||
1852 | { | ||
1853 | kfree(buf->begin); | ||
1854 | buf->begin = buf->data = buf->end = NULL; | ||
1855 | } | ||
1856 | |||
1857 | static void wsm_buf_reset(struct wsm_buf *buf) | ||
1858 | { | ||
1859 | if (buf->begin) { | ||
1860 | buf->data = &buf->begin[4]; | ||
1861 | *(u32 *)buf->begin = 0; | ||
1862 | } else { | ||
1863 | buf->data = buf->begin; | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) | ||
1868 | { | ||
1869 | size_t pos = buf->data - buf->begin; | ||
1870 | size_t size = pos + extra_size; | ||
1871 | |||
1872 | size = round_up(size, FWLOAD_BLOCK_SIZE); | ||
1873 | |||
1874 | buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA); | ||
1875 | if (buf->begin) { | ||
1876 | buf->data = &buf->begin[pos]; | ||
1877 | buf->end = &buf->begin[size]; | ||
1878 | return 0; | ||
1879 | } else { | ||
1880 | buf->end = buf->data = buf->begin; | ||
1881 | return -ENOMEM; | ||
1882 | } | ||
1883 | } | ||
diff --git a/drivers/net/wireless/cw1200/wsm.h b/drivers/net/wireless/cw1200/wsm.h new file mode 100644 index 000000000000..8d902d6a7dc4 --- /dev/null +++ b/drivers/net/wireless/cw1200/wsm.h | |||
@@ -0,0 +1,1879 @@ | |||
1 | /* | ||
2 | * WSM host interface (HI) interface for ST-Ericsson CW1200 mac80211 drivers | ||
3 | * | ||
4 | * Copyright (c) 2010, ST-Ericsson | ||
5 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> | ||
6 | * | ||
7 | * Based on CW1200 UMAC WSM API, which is | ||
8 | * Copyright (C) ST-Ericsson SA 2010 | ||
9 | * Author: Stewart Mathers <stewart.mathers@stericsson.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef CW1200_WSM_H_INCLUDED | ||
17 | #define CW1200_WSM_H_INCLUDED | ||
18 | |||
19 | #include <linux/spinlock.h> | ||
20 | |||
21 | struct cw1200_common; | ||
22 | |||
23 | /* Bands */ | ||
24 | /* Radio band 2.412 -2.484 GHz. */ | ||
25 | #define WSM_PHY_BAND_2_4G (0) | ||
26 | |||
27 | /* Radio band 4.9375-5.8250 GHz. */ | ||
28 | #define WSM_PHY_BAND_5G (1) | ||
29 | |||
30 | /* Transmit rates */ | ||
31 | /* 1 Mbps ERP-DSSS */ | ||
32 | #define WSM_TRANSMIT_RATE_1 (0) | ||
33 | |||
34 | /* 2 Mbps ERP-DSSS */ | ||
35 | #define WSM_TRANSMIT_RATE_2 (1) | ||
36 | |||
37 | /* 5.5 Mbps ERP-CCK */ | ||
38 | #define WSM_TRANSMIT_RATE_5 (2) | ||
39 | |||
40 | /* 11 Mbps ERP-CCK */ | ||
41 | #define WSM_TRANSMIT_RATE_11 (3) | ||
42 | |||
43 | /* 22 Mbps ERP-PBCC (Not supported) */ | ||
44 | /* #define WSM_TRANSMIT_RATE_22 (4) */ | ||
45 | |||
46 | /* 33 Mbps ERP-PBCC (Not supported) */ | ||
47 | /* #define WSM_TRANSMIT_RATE_33 (5) */ | ||
48 | |||
49 | /* 6 Mbps (3 Mbps) ERP-OFDM, BPSK coding rate 1/2 */ | ||
50 | #define WSM_TRANSMIT_RATE_6 (6) | ||
51 | |||
52 | /* 9 Mbps (4.5 Mbps) ERP-OFDM, BPSK coding rate 3/4 */ | ||
53 | #define WSM_TRANSMIT_RATE_9 (7) | ||
54 | |||
55 | /* 12 Mbps (6 Mbps) ERP-OFDM, QPSK coding rate 1/2 */ | ||
56 | #define WSM_TRANSMIT_RATE_12 (8) | ||
57 | |||
58 | /* 18 Mbps (9 Mbps) ERP-OFDM, QPSK coding rate 3/4 */ | ||
59 | #define WSM_TRANSMIT_RATE_18 (9) | ||
60 | |||
61 | /* 24 Mbps (12 Mbps) ERP-OFDM, 16QAM coding rate 1/2 */ | ||
62 | #define WSM_TRANSMIT_RATE_24 (10) | ||
63 | |||
64 | /* 36 Mbps (18 Mbps) ERP-OFDM, 16QAM coding rate 3/4 */ | ||
65 | #define WSM_TRANSMIT_RATE_36 (11) | ||
66 | |||
67 | /* 48 Mbps (24 Mbps) ERP-OFDM, 64QAM coding rate 1/2 */ | ||
68 | #define WSM_TRANSMIT_RATE_48 (12) | ||
69 | |||
70 | /* 54 Mbps (27 Mbps) ERP-OFDM, 64QAM coding rate 3/4 */ | ||
71 | #define WSM_TRANSMIT_RATE_54 (13) | ||
72 | |||
73 | /* 6.5 Mbps HT-OFDM, BPSK coding rate 1/2 */ | ||
74 | #define WSM_TRANSMIT_RATE_HT_6 (14) | ||
75 | |||
76 | /* 13 Mbps HT-OFDM, QPSK coding rate 1/2 */ | ||
77 | #define WSM_TRANSMIT_RATE_HT_13 (15) | ||
78 | |||
79 | /* 19.5 Mbps HT-OFDM, QPSK coding rate 3/4 */ | ||
80 | #define WSM_TRANSMIT_RATE_HT_19 (16) | ||
81 | |||
82 | /* 26 Mbps HT-OFDM, 16QAM coding rate 1/2 */ | ||
83 | #define WSM_TRANSMIT_RATE_HT_26 (17) | ||
84 | |||
85 | /* 39 Mbps HT-OFDM, 16QAM coding rate 3/4 */ | ||
86 | #define WSM_TRANSMIT_RATE_HT_39 (18) | ||
87 | |||
88 | /* 52 Mbps HT-OFDM, 64QAM coding rate 2/3 */ | ||
89 | #define WSM_TRANSMIT_RATE_HT_52 (19) | ||
90 | |||
91 | /* 58.5 Mbps HT-OFDM, 64QAM coding rate 3/4 */ | ||
92 | #define WSM_TRANSMIT_RATE_HT_58 (20) | ||
93 | |||
94 | /* 65 Mbps HT-OFDM, 64QAM coding rate 5/6 */ | ||
95 | #define WSM_TRANSMIT_RATE_HT_65 (21) | ||
96 | |||
97 | /* Scan types */ | ||
98 | /* Foreground scan */ | ||
99 | #define WSM_SCAN_TYPE_FOREGROUND (0) | ||
100 | |||
101 | /* Background scan */ | ||
102 | #define WSM_SCAN_TYPE_BACKGROUND (1) | ||
103 | |||
104 | /* Auto scan */ | ||
105 | #define WSM_SCAN_TYPE_AUTO (2) | ||
106 | |||
107 | /* Scan flags */ | ||
108 | /* Forced background scan means if the station cannot */ | ||
109 | /* enter the power-save mode, it shall force to perform a */ | ||
110 | /* background scan. Only valid when ScanType is */ | ||
111 | /* background scan. */ | ||
112 | #define WSM_SCAN_FLAG_FORCE_BACKGROUND (BIT(0)) | ||
113 | |||
114 | /* The WLAN device scans one channel at a time so */ | ||
115 | /* that disturbance to the data traffic is minimized. */ | ||
116 | #define WSM_SCAN_FLAG_SPLIT_METHOD (BIT(1)) | ||
117 | |||
118 | /* Preamble Type. Long if not set. */ | ||
119 | #define WSM_SCAN_FLAG_SHORT_PREAMBLE (BIT(2)) | ||
120 | |||
121 | /* 11n Tx Mode. Mixed if not set. */ | ||
122 | #define WSM_SCAN_FLAG_11N_GREENFIELD (BIT(3)) | ||
123 | |||
124 | /* Scan constraints */ | ||
125 | /* Maximum number of channels to be scanned. */ | ||
126 | #define WSM_SCAN_MAX_NUM_OF_CHANNELS (48) | ||
127 | |||
128 | /* The maximum number of SSIDs that the device can scan for. */ | ||
129 | #define WSM_SCAN_MAX_NUM_OF_SSIDS (2) | ||
130 | |||
131 | /* Power management modes */ | ||
132 | /* 802.11 Active mode */ | ||
133 | #define WSM_PSM_ACTIVE (0) | ||
134 | |||
135 | /* 802.11 PS mode */ | ||
136 | #define WSM_PSM_PS BIT(0) | ||
137 | |||
138 | /* Fast Power Save bit */ | ||
139 | #define WSM_PSM_FAST_PS_FLAG BIT(7) | ||
140 | |||
141 | /* Dynamic aka Fast power save */ | ||
142 | #define WSM_PSM_FAST_PS (BIT(0) | BIT(7)) | ||
143 | |||
144 | /* Undetermined */ | ||
145 | /* Note : Undetermined status is reported when the */ | ||
146 | /* NULL data frame used to advertise the PM mode to */ | ||
147 | /* the AP at Pre or Post Background Scan is not Acknowledged */ | ||
148 | #define WSM_PSM_UNKNOWN BIT(1) | ||
149 | |||
150 | /* Queue IDs */ | ||
151 | /* best effort/legacy */ | ||
152 | #define WSM_QUEUE_BEST_EFFORT (0) | ||
153 | |||
154 | /* background */ | ||
155 | #define WSM_QUEUE_BACKGROUND (1) | ||
156 | |||
157 | /* video */ | ||
158 | #define WSM_QUEUE_VIDEO (2) | ||
159 | |||
160 | /* voice */ | ||
161 | #define WSM_QUEUE_VOICE (3) | ||
162 | |||
163 | /* HT TX parameters */ | ||
164 | /* Non-HT */ | ||
165 | #define WSM_HT_TX_NON_HT (0) | ||
166 | |||
167 | /* Mixed format */ | ||
168 | #define WSM_HT_TX_MIXED (1) | ||
169 | |||
170 | /* Greenfield format */ | ||
171 | #define WSM_HT_TX_GREENFIELD (2) | ||
172 | |||
173 | /* STBC allowed */ | ||
174 | #define WSM_HT_TX_STBC (BIT(7)) | ||
175 | |||
176 | /* EPTA prioirty flags for BT Coex */ | ||
177 | /* default epta priority */ | ||
178 | #define WSM_EPTA_PRIORITY_DEFAULT 4 | ||
179 | /* use for normal data */ | ||
180 | #define WSM_EPTA_PRIORITY_DATA 4 | ||
181 | /* use for connect/disconnect/roaming*/ | ||
182 | #define WSM_EPTA_PRIORITY_MGT 5 | ||
183 | /* use for action frames */ | ||
184 | #define WSM_EPTA_PRIORITY_ACTION 5 | ||
185 | /* use for AC_VI data */ | ||
186 | #define WSM_EPTA_PRIORITY_VIDEO 5 | ||
187 | /* use for AC_VO data */ | ||
188 | #define WSM_EPTA_PRIORITY_VOICE 6 | ||
189 | /* use for EAPOL exchange */ | ||
190 | #define WSM_EPTA_PRIORITY_EAPOL 7 | ||
191 | |||
192 | /* TX status */ | ||
193 | /* Frame was sent aggregated */ | ||
194 | /* Only valid for WSM_SUCCESS status. */ | ||
195 | #define WSM_TX_STATUS_AGGREGATION (BIT(0)) | ||
196 | |||
197 | /* Host should requeue this frame later. */ | ||
198 | /* Valid only when status is WSM_REQUEUE. */ | ||
199 | #define WSM_TX_STATUS_REQUEUE (BIT(1)) | ||
200 | |||
201 | /* Normal Ack */ | ||
202 | #define WSM_TX_STATUS_NORMAL_ACK (0<<2) | ||
203 | |||
204 | /* No Ack */ | ||
205 | #define WSM_TX_STATUS_NO_ACK (1<<2) | ||
206 | |||
207 | /* No explicit acknowledgement */ | ||
208 | #define WSM_TX_STATUS_NO_EXPLICIT_ACK (2<<2) | ||
209 | |||
210 | /* Block Ack */ | ||
211 | /* Only valid for WSM_SUCCESS status. */ | ||
212 | #define WSM_TX_STATUS_BLOCK_ACK (3<<2) | ||
213 | |||
214 | /* RX status */ | ||
215 | /* Unencrypted */ | ||
216 | #define WSM_RX_STATUS_UNENCRYPTED (0<<0) | ||
217 | |||
218 | /* WEP */ | ||
219 | #define WSM_RX_STATUS_WEP (1<<0) | ||
220 | |||
221 | /* TKIP */ | ||
222 | #define WSM_RX_STATUS_TKIP (2<<0) | ||
223 | |||
224 | /* AES */ | ||
225 | #define WSM_RX_STATUS_AES (3<<0) | ||
226 | |||
227 | /* WAPI */ | ||
228 | #define WSM_RX_STATUS_WAPI (4<<0) | ||
229 | |||
230 | /* Macro to fetch encryption subfield. */ | ||
231 | #define WSM_RX_STATUS_ENCRYPTION(status) ((status) & 0x07) | ||
232 | |||
233 | /* Frame was part of an aggregation */ | ||
234 | #define WSM_RX_STATUS_AGGREGATE (BIT(3)) | ||
235 | |||
236 | /* Frame was first in the aggregation */ | ||
237 | #define WSM_RX_STATUS_AGGREGATE_FIRST (BIT(4)) | ||
238 | |||
239 | /* Frame was last in the aggregation */ | ||
240 | #define WSM_RX_STATUS_AGGREGATE_LAST (BIT(5)) | ||
241 | |||
242 | /* Indicates a defragmented frame */ | ||
243 | #define WSM_RX_STATUS_DEFRAGMENTED (BIT(6)) | ||
244 | |||
245 | /* Indicates a Beacon frame */ | ||
246 | #define WSM_RX_STATUS_BEACON (BIT(7)) | ||
247 | |||
248 | /* Indicates STA bit beacon TIM field */ | ||
249 | #define WSM_RX_STATUS_TIM (BIT(8)) | ||
250 | |||
251 | /* Indicates Beacon frame's virtual bitmap contains multicast bit */ | ||
252 | #define WSM_RX_STATUS_MULTICAST (BIT(9)) | ||
253 | |||
254 | /* Indicates frame contains a matching SSID */ | ||
255 | #define WSM_RX_STATUS_MATCHING_SSID (BIT(10)) | ||
256 | |||
257 | /* Indicates frame contains a matching BSSI */ | ||
258 | #define WSM_RX_STATUS_MATCHING_BSSI (BIT(11)) | ||
259 | |||
260 | /* Indicates More bit set in Framectl field */ | ||
261 | #define WSM_RX_STATUS_MORE_DATA (BIT(12)) | ||
262 | |||
263 | /* Indicates frame received during a measurement process */ | ||
264 | #define WSM_RX_STATUS_MEASUREMENT (BIT(13)) | ||
265 | |||
266 | /* Indicates frame received as an HT packet */ | ||
267 | #define WSM_RX_STATUS_HT (BIT(14)) | ||
268 | |||
269 | /* Indicates frame received with STBC */ | ||
270 | #define WSM_RX_STATUS_STBC (BIT(15)) | ||
271 | |||
272 | /* Indicates Address 1 field matches dot11StationId */ | ||
273 | #define WSM_RX_STATUS_ADDRESS1 (BIT(16)) | ||
274 | |||
275 | /* Indicates Group address present in the Address 1 field */ | ||
276 | #define WSM_RX_STATUS_GROUP (BIT(17)) | ||
277 | |||
278 | /* Indicates Broadcast address present in the Address 1 field */ | ||
279 | #define WSM_RX_STATUS_BROADCAST (BIT(18)) | ||
280 | |||
281 | /* Indicates group key used with encrypted frames */ | ||
282 | #define WSM_RX_STATUS_GROUP_KEY (BIT(19)) | ||
283 | |||
284 | /* Macro to fetch encryption key index. */ | ||
285 | #define WSM_RX_STATUS_KEY_IDX(status) (((status >> 20)) & 0x0F) | ||
286 | |||
287 | /* Indicates TSF inclusion after 802.11 frame body */ | ||
288 | #define WSM_RX_STATUS_TSF_INCLUDED (BIT(24)) | ||
289 | |||
290 | /* Frame Control field starts at Frame offset + 2 */ | ||
291 | #define WSM_TX_2BYTES_SHIFT (BIT(7)) | ||
292 | |||
293 | /* Join mode */ | ||
294 | /* IBSS */ | ||
295 | #define WSM_JOIN_MODE_IBSS (0) | ||
296 | |||
297 | /* BSS */ | ||
298 | #define WSM_JOIN_MODE_BSS (1) | ||
299 | |||
300 | /* PLCP preamble type */ | ||
301 | /* For long preamble */ | ||
302 | #define WSM_JOIN_PREAMBLE_LONG (0) | ||
303 | |||
304 | /* For short preamble (Long for 1Mbps) */ | ||
305 | #define WSM_JOIN_PREAMBLE_SHORT (1) | ||
306 | |||
307 | /* For short preamble (Long for 1 and 2Mbps) */ | ||
308 | #define WSM_JOIN_PREAMBLE_SHORT_2 (2) | ||
309 | |||
310 | /* Join flags */ | ||
311 | /* Unsynchronized */ | ||
312 | #define WSM_JOIN_FLAGS_UNSYNCRONIZED BIT(0) | ||
313 | /* The BSS owner is a P2P GO */ | ||
314 | #define WSM_JOIN_FLAGS_P2P_GO BIT(1) | ||
315 | /* Force to join BSS with the BSSID and the | ||
316 | * SSID specified without waiting for beacons. The | ||
317 | * ProbeForJoin parameter is ignored. */ | ||
318 | #define WSM_JOIN_FLAGS_FORCE BIT(2) | ||
319 | /* Give probe request/response higher | ||
320 | * priority over the BT traffic */ | ||
321 | #define WSM_JOIN_FLAGS_PRIO BIT(3) | ||
322 | /* Issue immediate join confirmation and use | ||
323 | * join complete to notify about completion */ | ||
324 | #define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5) | ||
325 | |||
326 | /* Key types */ | ||
327 | #define WSM_KEY_TYPE_WEP_DEFAULT (0) | ||
328 | #define WSM_KEY_TYPE_WEP_PAIRWISE (1) | ||
329 | #define WSM_KEY_TYPE_TKIP_GROUP (2) | ||
330 | #define WSM_KEY_TYPE_TKIP_PAIRWISE (3) | ||
331 | #define WSM_KEY_TYPE_AES_GROUP (4) | ||
332 | #define WSM_KEY_TYPE_AES_PAIRWISE (5) | ||
333 | #define WSM_KEY_TYPE_WAPI_GROUP (6) | ||
334 | #define WSM_KEY_TYPE_WAPI_PAIRWISE (7) | ||
335 | |||
336 | /* Key indexes */ | ||
337 | #define WSM_KEY_MAX_INDEX (10) | ||
338 | |||
339 | /* ACK policy */ | ||
340 | #define WSM_ACK_POLICY_NORMAL (0) | ||
341 | #define WSM_ACK_POLICY_NO_ACK (1) | ||
342 | |||
343 | /* Start modes */ | ||
344 | #define WSM_START_MODE_AP (0) /* Mini AP */ | ||
345 | #define WSM_START_MODE_P2P_GO (1) /* P2P GO */ | ||
346 | #define WSM_START_MODE_P2P_DEV (2) /* P2P device */ | ||
347 | |||
348 | /* SetAssociationMode MIB flags */ | ||
349 | #define WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE (BIT(0)) | ||
350 | #define WSM_ASSOCIATION_MODE_USE_HT_MODE (BIT(1)) | ||
351 | #define WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET (BIT(2)) | ||
352 | #define WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING (BIT(3)) | ||
353 | #define WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES (BIT(4)) | ||
354 | |||
355 | /* RcpiRssiThreshold MIB flags */ | ||
356 | #define WSM_RCPI_RSSI_THRESHOLD_ENABLE (BIT(0)) | ||
357 | #define WSM_RCPI_RSSI_USE_RSSI (BIT(1)) | ||
358 | #define WSM_RCPI_RSSI_DONT_USE_UPPER (BIT(2)) | ||
359 | #define WSM_RCPI_RSSI_DONT_USE_LOWER (BIT(3)) | ||
360 | |||
361 | /* Update-ie constants */ | ||
362 | #define WSM_UPDATE_IE_BEACON (BIT(0)) | ||
363 | #define WSM_UPDATE_IE_PROBE_RESP (BIT(1)) | ||
364 | #define WSM_UPDATE_IE_PROBE_REQ (BIT(2)) | ||
365 | |||
366 | /* WSM events */ | ||
367 | /* Error */ | ||
368 | #define WSM_EVENT_ERROR (0) | ||
369 | |||
370 | /* BSS lost */ | ||
371 | #define WSM_EVENT_BSS_LOST (1) | ||
372 | |||
373 | /* BSS regained */ | ||
374 | #define WSM_EVENT_BSS_REGAINED (2) | ||
375 | |||
376 | /* Radar detected */ | ||
377 | #define WSM_EVENT_RADAR_DETECTED (3) | ||
378 | |||
379 | /* RCPI or RSSI threshold triggered */ | ||
380 | #define WSM_EVENT_RCPI_RSSI (4) | ||
381 | |||
382 | /* BT inactive */ | ||
383 | #define WSM_EVENT_BT_INACTIVE (5) | ||
384 | |||
385 | /* BT active */ | ||
386 | #define WSM_EVENT_BT_ACTIVE (6) | ||
387 | |||
388 | /* MIB IDs */ | ||
389 | /* 4.1 dot11StationId */ | ||
390 | #define WSM_MIB_ID_DOT11_STATION_ID 0x0000 | ||
391 | |||
392 | /* 4.2 dot11MaxtransmitMsduLifeTime */ | ||
393 | #define WSM_MIB_ID_DOT11_MAX_TRANSMIT_LIFTIME 0x0001 | ||
394 | |||
395 | /* 4.3 dot11MaxReceiveLifeTime */ | ||
396 | #define WSM_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME 0x0002 | ||
397 | |||
398 | /* 4.4 dot11SlotTime */ | ||
399 | #define WSM_MIB_ID_DOT11_SLOT_TIME 0x0003 | ||
400 | |||
401 | /* 4.5 dot11GroupAddressesTable */ | ||
402 | #define WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE 0x0004 | ||
403 | #define WSM_MAX_GRP_ADDRTABLE_ENTRIES 8 | ||
404 | |||
405 | /* 4.6 dot11WepDefaultKeyId */ | ||
406 | #define WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID 0x0005 | ||
407 | |||
408 | /* 4.7 dot11CurrentTxPowerLevel */ | ||
409 | #define WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL 0x0006 | ||
410 | |||
411 | /* 4.8 dot11RTSThreshold */ | ||
412 | #define WSM_MIB_ID_DOT11_RTS_THRESHOLD 0x0007 | ||
413 | |||
414 | /* 4.9 NonErpProtection */ | ||
415 | #define WSM_MIB_ID_NON_ERP_PROTECTION 0x1000 | ||
416 | |||
417 | /* 4.10 ArpIpAddressesTable */ | ||
418 | #define WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE 0x1001 | ||
419 | #define WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES 1 | ||
420 | |||
421 | /* 4.11 TemplateFrame */ | ||
422 | #define WSM_MIB_ID_TEMPLATE_FRAME 0x1002 | ||
423 | |||
424 | /* 4.12 RxFilter */ | ||
425 | #define WSM_MIB_ID_RX_FILTER 0x1003 | ||
426 | |||
427 | /* 4.13 BeaconFilterTable */ | ||
428 | #define WSM_MIB_ID_BEACON_FILTER_TABLE 0x1004 | ||
429 | |||
430 | /* 4.14 BeaconFilterEnable */ | ||
431 | #define WSM_MIB_ID_BEACON_FILTER_ENABLE 0x1005 | ||
432 | |||
433 | /* 4.15 OperationalPowerMode */ | ||
434 | #define WSM_MIB_ID_OPERATIONAL_POWER_MODE 0x1006 | ||
435 | |||
436 | /* 4.16 BeaconWakeUpPeriod */ | ||
437 | #define WSM_MIB_ID_BEACON_WAKEUP_PERIOD 0x1007 | ||
438 | |||
439 | /* 4.17 RcpiRssiThreshold */ | ||
440 | #define WSM_MIB_ID_RCPI_RSSI_THRESHOLD 0x1009 | ||
441 | |||
442 | /* 4.18 StatisticsTable */ | ||
443 | #define WSM_MIB_ID_STATISTICS_TABLE 0x100A | ||
444 | |||
445 | /* 4.19 IbssPsConfig */ | ||
446 | #define WSM_MIB_ID_IBSS_PS_CONFIG 0x100B | ||
447 | |||
448 | /* 4.20 CountersTable */ | ||
449 | #define WSM_MIB_ID_COUNTERS_TABLE 0x100C | ||
450 | |||
451 | /* 4.21 BlockAckPolicy */ | ||
452 | #define WSM_MIB_ID_BLOCK_ACK_POLICY 0x100E | ||
453 | |||
454 | /* 4.22 OverrideInternalTxRate */ | ||
455 | #define WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE 0x100F | ||
456 | |||
457 | /* 4.23 SetAssociationMode */ | ||
458 | #define WSM_MIB_ID_SET_ASSOCIATION_MODE 0x1010 | ||
459 | |||
460 | /* 4.24 UpdateEptaConfigData */ | ||
461 | #define WSM_MIB_ID_UPDATE_EPTA_CONFIG_DATA 0x1011 | ||
462 | |||
463 | /* 4.25 SelectCcaMethod */ | ||
464 | #define WSM_MIB_ID_SELECT_CCA_METHOD 0x1012 | ||
465 | |||
466 | /* 4.26 SetUpasdInformation */ | ||
467 | #define WSM_MIB_ID_SET_UAPSD_INFORMATION 0x1013 | ||
468 | |||
469 | /* 4.27 SetAutoCalibrationMode WBF00004073 */ | ||
470 | #define WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE 0x1015 | ||
471 | |||
472 | /* 4.28 SetTxRateRetryPolicy */ | ||
473 | #define WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY 0x1016 | ||
474 | |||
475 | /* 4.29 SetHostMessageTypeFilter */ | ||
476 | #define WSM_MIB_ID_SET_HOST_MSG_TYPE_FILTER 0x1017 | ||
477 | |||
478 | /* 4.30 P2PFindInfo */ | ||
479 | #define WSM_MIB_ID_P2P_FIND_INFO 0x1018 | ||
480 | |||
481 | /* 4.31 P2PPsModeInfo */ | ||
482 | #define WSM_MIB_ID_P2P_PS_MODE_INFO 0x1019 | ||
483 | |||
484 | /* 4.32 SetEtherTypeDataFrameFilter */ | ||
485 | #define WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER 0x101A | ||
486 | |||
487 | /* 4.33 SetUDPPortDataFrameFilter */ | ||
488 | #define WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER 0x101B | ||
489 | |||
490 | /* 4.34 SetMagicDataFrameFilter */ | ||
491 | #define WSM_MIB_ID_SET_MAGIC_DATAFRAME_FILTER 0x101C | ||
492 | |||
493 | /* 4.35 P2PDeviceInfo */ | ||
494 | #define WSM_MIB_ID_P2P_DEVICE_INFO 0x101D | ||
495 | |||
496 | /* 4.36 SetWCDMABand */ | ||
497 | #define WSM_MIB_ID_SET_WCDMA_BAND 0x101E | ||
498 | |||
499 | /* 4.37 GroupTxSequenceCounter */ | ||
500 | #define WSM_MIB_ID_GRP_SEQ_COUNTER 0x101F | ||
501 | |||
502 | /* 4.38 ProtectedMgmtPolicy */ | ||
503 | #define WSM_MIB_ID_PROTECTED_MGMT_POLICY 0x1020 | ||
504 | |||
505 | /* 4.39 SetHtProtection */ | ||
506 | #define WSM_MIB_ID_SET_HT_PROTECTION 0x1021 | ||
507 | |||
508 | /* 4.40 GPIO Command */ | ||
509 | #define WSM_MIB_ID_GPIO_COMMAND 0x1022 | ||
510 | |||
511 | /* 4.41 TSF Counter Value */ | ||
512 | #define WSM_MIB_ID_TSF_COUNTER 0x1023 | ||
513 | |||
514 | /* Test Purposes Only */ | ||
515 | #define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D | ||
516 | |||
517 | /* 4.42 UseMultiTxConfMessage */ | ||
518 | #define WSM_MIB_USE_MULTI_TX_CONF 0x1024 | ||
519 | |||
520 | /* 4.43 Keep-alive period */ | ||
521 | #define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025 | ||
522 | |||
523 | /* 4.44 Disable BSSID filter */ | ||
524 | #define WSM_MIB_ID_DISABLE_BSSID_FILTER 0x1026 | ||
525 | |||
526 | /* Frame template types */ | ||
527 | #define WSM_FRAME_TYPE_PROBE_REQUEST (0) | ||
528 | #define WSM_FRAME_TYPE_BEACON (1) | ||
529 | #define WSM_FRAME_TYPE_NULL (2) | ||
530 | #define WSM_FRAME_TYPE_QOS_NULL (3) | ||
531 | #define WSM_FRAME_TYPE_PS_POLL (4) | ||
532 | #define WSM_FRAME_TYPE_PROBE_RESPONSE (5) | ||
533 | |||
534 | #define WSM_FRAME_GREENFIELD (0x80) /* See 4.11 */ | ||
535 | |||
536 | /* Status */ | ||
537 | /* The WSM firmware has completed a request */ | ||
538 | /* successfully. */ | ||
539 | #define WSM_STATUS_SUCCESS (0) | ||
540 | |||
541 | /* This is a generic failure code if other error codes do */ | ||
542 | /* not apply. */ | ||
543 | #define WSM_STATUS_FAILURE (1) | ||
544 | |||
545 | /* A request contains one or more invalid parameters. */ | ||
546 | #define WSM_INVALID_PARAMETER (2) | ||
547 | |||
548 | /* The request cannot perform because the device is in */ | ||
549 | /* an inappropriate mode. */ | ||
550 | #define WSM_ACCESS_DENIED (3) | ||
551 | |||
552 | /* The frame received includes a decryption error. */ | ||
553 | #define WSM_STATUS_DECRYPTFAILURE (4) | ||
554 | |||
555 | /* A MIC failure is detected in the received packets. */ | ||
556 | #define WSM_STATUS_MICFAILURE (5) | ||
557 | |||
558 | /* The transmit request failed due to retry limit being */ | ||
559 | /* exceeded. */ | ||
560 | #define WSM_STATUS_RETRY_EXCEEDED (6) | ||
561 | |||
562 | /* The transmit request failed due to MSDU life time */ | ||
563 | /* being exceeded. */ | ||
564 | #define WSM_STATUS_TX_LIFETIME_EXCEEDED (7) | ||
565 | |||
566 | /* The link to the AP is lost. */ | ||
567 | #define WSM_STATUS_LINK_LOST (8) | ||
568 | |||
569 | /* No key was found for the encrypted frame */ | ||
570 | #define WSM_STATUS_NO_KEY_FOUND (9) | ||
571 | |||
572 | /* Jammer was detected when transmitting this frame */ | ||
573 | #define WSM_STATUS_JAMMER_DETECTED (10) | ||
574 | |||
575 | /* The message should be requeued later. */ | ||
576 | /* This is applicable only to Transmit */ | ||
577 | #define WSM_REQUEUE (11) | ||
578 | |||
579 | /* Advanced filtering options */ | ||
580 | #define WSM_MAX_FILTER_ELEMENTS (4) | ||
581 | |||
582 | #define WSM_FILTER_ACTION_IGNORE (0) | ||
583 | #define WSM_FILTER_ACTION_FILTER_IN (1) | ||
584 | #define WSM_FILTER_ACTION_FILTER_OUT (2) | ||
585 | |||
586 | #define WSM_FILTER_PORT_TYPE_DST (0) | ||
587 | #define WSM_FILTER_PORT_TYPE_SRC (1) | ||
588 | |||
589 | /* Actual header of WSM messages */ | ||
590 | struct wsm_hdr { | ||
591 | __le16 len; | ||
592 | __le16 id; | ||
593 | }; | ||
594 | |||
595 | #define WSM_TX_SEQ_MAX (7) | ||
596 | #define WSM_TX_SEQ(seq) \ | ||
597 | ((seq & WSM_TX_SEQ_MAX) << 13) | ||
598 | #define WSM_TX_LINK_ID_MAX (0x0F) | ||
599 | #define WSM_TX_LINK_ID(link_id) \ | ||
600 | ((link_id & WSM_TX_LINK_ID_MAX) << 6) | ||
601 | |||
602 | #define MAX_BEACON_SKIP_TIME_MS 1000 | ||
603 | |||
604 | #define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 3 / 2) | ||
605 | |||
606 | /* ******************************************************************** */ | ||
607 | /* WSM capability */ | ||
608 | |||
609 | #define WSM_STARTUP_IND_ID 0x0801 | ||
610 | |||
611 | struct wsm_startup_ind { | ||
612 | u16 input_buffers; | ||
613 | u16 input_buffer_size; | ||
614 | u16 status; | ||
615 | u16 hw_id; | ||
616 | u16 hw_subid; | ||
617 | u16 fw_cap; | ||
618 | u16 fw_type; | ||
619 | u16 fw_api; | ||
620 | u16 fw_build; | ||
621 | u16 fw_ver; | ||
622 | char fw_label[128]; | ||
623 | u32 config[4]; | ||
624 | }; | ||
625 | |||
626 | /* ******************************************************************** */ | ||
627 | /* WSM commands */ | ||
628 | |||
629 | /* 3.1 */ | ||
630 | #define WSM_CONFIGURATION_REQ_ID 0x0009 | ||
631 | #define WSM_CONFIGURATION_RESP_ID 0x0409 | ||
632 | |||
633 | struct wsm_tx_power_range { | ||
634 | int min_power_level; | ||
635 | int max_power_level; | ||
636 | u32 stepping; | ||
637 | }; | ||
638 | |||
639 | struct wsm_configuration { | ||
640 | /* [in] */ u32 dot11MaxTransmitMsduLifeTime; | ||
641 | /* [in] */ u32 dot11MaxReceiveLifeTime; | ||
642 | /* [in] */ u32 dot11RtsThreshold; | ||
643 | /* [in, out] */ u8 *dot11StationId; | ||
644 | /* [in] */ const void *dpdData; | ||
645 | /* [in] */ size_t dpdData_size; | ||
646 | /* [out] */ u8 dot11FrequencyBandsSupported; | ||
647 | /* [out] */ u32 supportedRateMask; | ||
648 | /* [out] */ struct wsm_tx_power_range txPowerRange[2]; | ||
649 | }; | ||
650 | |||
651 | int wsm_configuration(struct cw1200_common *priv, | ||
652 | struct wsm_configuration *arg); | ||
653 | |||
654 | /* 3.3 */ | ||
655 | #define WSM_RESET_REQ_ID 0x000A | ||
656 | #define WSM_RESET_RESP_ID 0x040A | ||
657 | struct wsm_reset { | ||
658 | /* [in] */ int link_id; | ||
659 | /* [in] */ bool reset_statistics; | ||
660 | }; | ||
661 | |||
662 | int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg); | ||
663 | |||
664 | /* 3.5 */ | ||
665 | #define WSM_READ_MIB_REQ_ID 0x0005 | ||
666 | #define WSM_READ_MIB_RESP_ID 0x0405 | ||
667 | int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *buf, | ||
668 | size_t buf_size); | ||
669 | |||
670 | /* 3.7 */ | ||
671 | #define WSM_WRITE_MIB_REQ_ID 0x0006 | ||
672 | #define WSM_WRITE_MIB_RESP_ID 0x0406 | ||
673 | int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *buf, | ||
674 | size_t buf_size); | ||
675 | |||
676 | /* 3.9 */ | ||
677 | #define WSM_START_SCAN_REQ_ID 0x0007 | ||
678 | #define WSM_START_SCAN_RESP_ID 0x0407 | ||
679 | |||
680 | struct wsm_ssid { | ||
681 | u8 ssid[32]; | ||
682 | u32 length; | ||
683 | }; | ||
684 | |||
685 | struct wsm_scan_ch { | ||
686 | u16 number; | ||
687 | u32 min_chan_time; | ||
688 | u32 max_chan_time; | ||
689 | u32 tx_power_level; | ||
690 | }; | ||
691 | |||
692 | struct wsm_scan { | ||
693 | /* WSM_PHY_BAND_... */ | ||
694 | u8 band; | ||
695 | |||
696 | /* WSM_SCAN_TYPE_... */ | ||
697 | u8 type; | ||
698 | |||
699 | /* WSM_SCAN_FLAG_... */ | ||
700 | u8 flags; | ||
701 | |||
702 | /* WSM_TRANSMIT_RATE_... */ | ||
703 | u8 max_tx_rate; | ||
704 | |||
705 | /* Interval period in TUs that the device shall the re- */ | ||
706 | /* execute the requested scan. Max value supported by the device */ | ||
707 | /* is 256s. */ | ||
708 | u32 auto_scan_interval; | ||
709 | |||
710 | /* Number of probe requests (per SSID) sent to one (1) */ | ||
711 | /* channel. Zero (0) means that none is send, which */ | ||
712 | /* means that a passive scan is to be done. Value */ | ||
713 | /* greater than zero (0) means that an active scan is to */ | ||
714 | /* be done. */ | ||
715 | u32 num_probes; | ||
716 | |||
717 | /* Number of channels to be scanned. */ | ||
718 | /* Maximum value is WSM_SCAN_MAX_NUM_OF_CHANNELS. */ | ||
719 | u8 num_channels; | ||
720 | |||
721 | /* Number of SSID provided in the scan command (this */ | ||
722 | /* is zero (0) in broadcast scan) */ | ||
723 | /* The maximum number of SSIDs is WSM_SCAN_MAX_NUM_OF_SSIDS. */ | ||
724 | u8 num_ssids; | ||
725 | |||
726 | /* The delay time (in microseconds) period */ | ||
727 | /* before sending a probe-request. */ | ||
728 | u8 probe_delay; | ||
729 | |||
730 | /* SSIDs to be scanned [numOfSSIDs]; */ | ||
731 | struct wsm_ssid *ssids; | ||
732 | |||
733 | /* Channels to be scanned [numOfChannels]; */ | ||
734 | struct wsm_scan_ch *ch; | ||
735 | }; | ||
736 | |||
737 | int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg); | ||
738 | |||
739 | /* 3.11 */ | ||
740 | #define WSM_STOP_SCAN_REQ_ID 0x0008 | ||
741 | #define WSM_STOP_SCAN_RESP_ID 0x0408 | ||
742 | int wsm_stop_scan(struct cw1200_common *priv); | ||
743 | |||
744 | /* 3.13 */ | ||
745 | #define WSM_SCAN_COMPLETE_IND_ID 0x0806 | ||
746 | struct wsm_scan_complete { | ||
747 | /* WSM_STATUS_... */ | ||
748 | u32 status; | ||
749 | |||
750 | /* WSM_PSM_... */ | ||
751 | u8 psm; | ||
752 | |||
753 | /* Number of channels that the scan operation completed. */ | ||
754 | u8 num_channels; | ||
755 | }; | ||
756 | |||
757 | /* 3.14 */ | ||
758 | #define WSM_TX_CONFIRM_IND_ID 0x0404 | ||
759 | #define WSM_MULTI_TX_CONFIRM_ID 0x041E | ||
760 | |||
761 | struct wsm_tx_confirm { | ||
762 | /* Packet identifier used in wsm_tx. */ | ||
763 | u32 packet_id; | ||
764 | |||
765 | /* WSM_STATUS_... */ | ||
766 | u32 status; | ||
767 | |||
768 | /* WSM_TRANSMIT_RATE_... */ | ||
769 | u8 tx_rate; | ||
770 | |||
771 | /* The number of times the frame was transmitted */ | ||
772 | /* without receiving an acknowledgement. */ | ||
773 | u8 ack_failures; | ||
774 | |||
775 | /* WSM_TX_STATUS_... */ | ||
776 | u16 flags; | ||
777 | |||
778 | /* The total time in microseconds that the frame spent in */ | ||
779 | /* the WLAN device before transmission as completed. */ | ||
780 | u32 media_delay; | ||
781 | |||
782 | /* The total time in microseconds that the frame spent in */ | ||
783 | /* the WLAN device before transmission was started. */ | ||
784 | u32 tx_queue_delay; | ||
785 | }; | ||
786 | |||
787 | /* 3.15 */ | ||
788 | typedef void (*wsm_tx_confirm_cb) (struct cw1200_common *priv, | ||
789 | struct wsm_tx_confirm *arg); | ||
790 | |||
791 | /* Note that ideology of wsm_tx struct is different against the rest of | ||
792 | * WSM API. wsm_hdr is /not/ a caller-adapted struct to be used as an input | ||
793 | * argument for WSM call, but a prepared bytestream to be sent to firmware. | ||
794 | * It is filled partly in cw1200_tx, partly in low-level WSM code. | ||
795 | * Please pay attention once again: ideology is different. | ||
796 | * | ||
797 | * Legend: | ||
798 | * - [in]: cw1200_tx must fill this field. | ||
799 | * - [wsm]: the field is filled by low-level WSM. | ||
800 | */ | ||
801 | struct wsm_tx { | ||
802 | /* common WSM header */ | ||
803 | struct wsm_hdr hdr; | ||
804 | |||
805 | /* Packet identifier that meant to be used in completion. */ | ||
806 | __le32 packet_id; | ||
807 | |||
808 | /* WSM_TRANSMIT_RATE_... */ | ||
809 | u8 max_tx_rate; | ||
810 | |||
811 | /* WSM_QUEUE_... */ | ||
812 | u8 queue_id; | ||
813 | |||
814 | /* True: another packet is pending on the host for transmission. */ | ||
815 | u8 more; | ||
816 | |||
817 | /* Bit 0 = 0 - Start expiry time from first Tx attempt (default) */ | ||
818 | /* Bit 0 = 1 - Start expiry time from receipt of Tx Request */ | ||
819 | /* Bits 3:1 - PTA Priority */ | ||
820 | /* Bits 6:4 - Tx Rate Retry Policy */ | ||
821 | /* Bit 7 - Reserved */ | ||
822 | u8 flags; | ||
823 | |||
824 | /* Should be 0. */ | ||
825 | __le32 reserved; | ||
826 | |||
827 | /* The elapsed time in TUs, after the initial transmission */ | ||
828 | /* of an MSDU, after which further attempts to transmit */ | ||
829 | /* the MSDU shall be terminated. Overrides the global */ | ||
830 | /* dot11MaxTransmitMsduLifeTime setting [optional] */ | ||
831 | /* Device will set the default value if this is 0. */ | ||
832 | __le32 expire_time; | ||
833 | |||
834 | /* WSM_HT_TX_... */ | ||
835 | __le32 ht_tx_parameters; | ||
836 | }; | ||
837 | |||
838 | /* = sizeof(generic hi hdr) + sizeof(wsm hdr) + sizeof(alignment) */ | ||
839 | #define WSM_TX_EXTRA_HEADROOM (28) | ||
840 | |||
841 | /* 3.16 */ | ||
842 | #define WSM_RECEIVE_IND_ID 0x0804 | ||
843 | |||
844 | struct wsm_rx { | ||
845 | /* WSM_STATUS_... */ | ||
846 | __le32 status; | ||
847 | |||
848 | /* Specifies the channel of the received packet. */ | ||
849 | __le16 channel_number; | ||
850 | |||
851 | /* WSM_TRANSMIT_RATE_... */ | ||
852 | u8 rx_rate; | ||
853 | |||
854 | /* This value is expressed in signed Q8.0 format for */ | ||
855 | /* RSSI and unsigned Q7.1 format for RCPI. */ | ||
856 | u8 rcpi_rssi; | ||
857 | |||
858 | /* WSM_RX_STATUS_... */ | ||
859 | __le32 flags; | ||
860 | |||
861 | /* Payload */ | ||
862 | u8 data[0]; | ||
863 | } __packed; | ||
864 | |||
865 | /* = sizeof(generic hi hdr) + sizeof(wsm hdr) */ | ||
866 | #define WSM_RX_EXTRA_HEADROOM (16) | ||
867 | |||
868 | typedef void (*wsm_rx_cb) (struct cw1200_common *priv, struct wsm_rx *arg, | ||
869 | struct sk_buff **skb_p); | ||
870 | |||
871 | /* 3.17 */ | ||
872 | struct wsm_event { | ||
873 | /* WSM_STATUS_... */ | ||
874 | /* [out] */ u32 id; | ||
875 | |||
876 | /* Indication parameters. */ | ||
877 | /* For error indication, this shall be a 32-bit WSM status. */ | ||
878 | /* For RCPI or RSSI indication, this should be an 8-bit */ | ||
879 | /* RCPI or RSSI value. */ | ||
880 | /* [out] */ u32 data; | ||
881 | }; | ||
882 | |||
883 | struct cw1200_wsm_event { | ||
884 | struct list_head link; | ||
885 | struct wsm_event evt; | ||
886 | }; | ||
887 | |||
888 | /* 3.18 - 3.22 */ | ||
889 | /* Measurement. Skipped for now. Irrelevent. */ | ||
890 | |||
891 | typedef void (*wsm_event_cb) (struct cw1200_common *priv, | ||
892 | struct wsm_event *arg); | ||
893 | |||
894 | /* 3.23 */ | ||
895 | #define WSM_JOIN_REQ_ID 0x000B | ||
896 | #define WSM_JOIN_RESP_ID 0x040B | ||
897 | |||
898 | struct wsm_join { | ||
899 | /* WSM_JOIN_MODE_... */ | ||
900 | u8 mode; | ||
901 | |||
902 | /* WSM_PHY_BAND_... */ | ||
903 | u8 band; | ||
904 | |||
905 | /* Specifies the channel number to join. The channel */ | ||
906 | /* number will be mapped to an actual frequency */ | ||
907 | /* according to the band */ | ||
908 | u16 channel_number; | ||
909 | |||
910 | /* Specifies the BSSID of the BSS or IBSS to be joined */ | ||
911 | /* or the IBSS to be started. */ | ||
912 | u8 bssid[6]; | ||
913 | |||
914 | /* ATIM window of IBSS */ | ||
915 | /* When ATIM window is zero the initiated IBSS does */ | ||
916 | /* not support power saving. */ | ||
917 | u16 atim_window; | ||
918 | |||
919 | /* WSM_JOIN_PREAMBLE_... */ | ||
920 | u8 preamble_type; | ||
921 | |||
922 | /* Specifies if a probe request should be send with the */ | ||
923 | /* specified SSID when joining to the network. */ | ||
924 | u8 probe_for_join; | ||
925 | |||
926 | /* DTIM Period (In multiples of beacon interval) */ | ||
927 | u8 dtim_period; | ||
928 | |||
929 | /* WSM_JOIN_FLAGS_... */ | ||
930 | u8 flags; | ||
931 | |||
932 | /* Length of the SSID */ | ||
933 | u32 ssid_len; | ||
934 | |||
935 | /* Specifies the SSID of the IBSS to join or start */ | ||
936 | u8 ssid[32]; | ||
937 | |||
938 | /* Specifies the time between TBTTs in TUs */ | ||
939 | u32 beacon_interval; | ||
940 | |||
941 | /* A bit mask that defines the BSS basic rate set. */ | ||
942 | u32 basic_rate_set; | ||
943 | }; | ||
944 | |||
945 | struct wsm_join_cnf { | ||
946 | u32 status; | ||
947 | |||
948 | /* Minimum transmission power level in units of 0.1dBm */ | ||
949 | u32 min_power_level; | ||
950 | |||
951 | /* Maximum transmission power level in units of 0.1dBm */ | ||
952 | u32 max_power_level; | ||
953 | }; | ||
954 | |||
955 | int wsm_join(struct cw1200_common *priv, struct wsm_join *arg); | ||
956 | |||
957 | /* 3.24 */ | ||
958 | struct wsm_join_complete { | ||
959 | /* WSM_STATUS_... */ | ||
960 | u32 status; | ||
961 | }; | ||
962 | |||
963 | /* 3.25 */ | ||
964 | #define WSM_SET_PM_REQ_ID 0x0010 | ||
965 | #define WSM_SET_PM_RESP_ID 0x0410 | ||
966 | struct wsm_set_pm { | ||
967 | /* WSM_PSM_... */ | ||
968 | u8 mode; | ||
969 | |||
970 | /* in unit of 500us; 0 to use default */ | ||
971 | u8 fast_psm_idle_period; | ||
972 | |||
973 | /* in unit of 500us; 0 to use default */ | ||
974 | u8 ap_psm_change_period; | ||
975 | |||
976 | /* in unit of 500us; 0 to disable auto-pspoll */ | ||
977 | u8 min_auto_pspoll_period; | ||
978 | }; | ||
979 | |||
980 | int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); | ||
981 | |||
982 | /* 3.27 */ | ||
983 | struct wsm_set_pm_complete { | ||
984 | u8 psm; /* WSM_PSM_... */ | ||
985 | }; | ||
986 | |||
987 | /* 3.28 */ | ||
988 | #define WSM_SET_BSS_PARAMS_REQ_ID 0x0011 | ||
989 | #define WSM_SET_BSS_PARAMS_RESP_ID 0x0411 | ||
990 | struct wsm_set_bss_params { | ||
991 | /* This resets the beacon loss counters only */ | ||
992 | u8 reset_beacon_loss; | ||
993 | |||
994 | /* The number of lost consecutive beacons after which */ | ||
995 | /* the WLAN device should indicate the BSS-Lost event */ | ||
996 | /* to the WLAN host driver. */ | ||
997 | u8 beacon_lost_count; | ||
998 | |||
999 | /* The AID received during the association process. */ | ||
1000 | u16 aid; | ||
1001 | |||
1002 | /* The operational rate set mask */ | ||
1003 | u32 operational_rate_set; | ||
1004 | }; | ||
1005 | |||
1006 | int wsm_set_bss_params(struct cw1200_common *priv, | ||
1007 | const struct wsm_set_bss_params *arg); | ||
1008 | |||
1009 | /* 3.30 */ | ||
1010 | #define WSM_ADD_KEY_REQ_ID 0x000C | ||
1011 | #define WSM_ADD_KEY_RESP_ID 0x040C | ||
1012 | struct wsm_add_key { | ||
1013 | u8 type; /* WSM_KEY_TYPE_... */ | ||
1014 | u8 index; /* Key entry index: 0 -- WSM_KEY_MAX_INDEX */ | ||
1015 | u16 reserved; | ||
1016 | union { | ||
1017 | struct { | ||
1018 | u8 peer[6]; /* MAC address of the | ||
1019 | * peer station */ | ||
1020 | u8 reserved; | ||
1021 | u8 keylen; /* Key length in bytes */ | ||
1022 | u8 keydata[16]; /* Key data */ | ||
1023 | } __packed wep_pairwise; | ||
1024 | struct { | ||
1025 | u8 keyid; /* Unique per key identifier | ||
1026 | * (0..3) */ | ||
1027 | u8 keylen; /* Key length in bytes */ | ||
1028 | u16 reserved; | ||
1029 | u8 keydata[16]; /* Key data */ | ||
1030 | } __packed wep_group; | ||
1031 | struct { | ||
1032 | u8 peer[6]; /* MAC address of the | ||
1033 | * peer station */ | ||
1034 | u16 reserved; | ||
1035 | u8 keydata[16]; /* TKIP key data */ | ||
1036 | u8 rx_mic_key[8]; /* Rx MIC key */ | ||
1037 | u8 tx_mic_key[8]; /* Tx MIC key */ | ||
1038 | } __packed tkip_pairwise; | ||
1039 | struct { | ||
1040 | u8 keydata[16]; /* TKIP key data */ | ||
1041 | u8 rx_mic_key[8]; /* Rx MIC key */ | ||
1042 | u8 keyid; /* Key ID */ | ||
1043 | u8 reserved[3]; | ||
1044 | u8 rx_seqnum[8]; /* Receive Sequence Counter */ | ||
1045 | } __packed tkip_group; | ||
1046 | struct { | ||
1047 | u8 peer[6]; /* MAC address of the | ||
1048 | * peer station */ | ||
1049 | u16 reserved; | ||
1050 | u8 keydata[16]; /* AES key data */ | ||
1051 | } __packed aes_pairwise; | ||
1052 | struct { | ||
1053 | u8 keydata[16]; /* AES key data */ | ||
1054 | u8 keyid; /* Key ID */ | ||
1055 | u8 reserved[3]; | ||
1056 | u8 rx_seqnum[8]; /* Receive Sequence Counter */ | ||
1057 | } __packed aes_group; | ||
1058 | struct { | ||
1059 | u8 peer[6]; /* MAC address of the | ||
1060 | * peer station */ | ||
1061 | u8 keyid; /* Key ID */ | ||
1062 | u8 reserved; | ||
1063 | u8 keydata[16]; /* WAPI key data */ | ||
1064 | u8 mic_key[16]; /* MIC key data */ | ||
1065 | } __packed wapi_pairwise; | ||
1066 | struct { | ||
1067 | u8 keydata[16]; /* WAPI key data */ | ||
1068 | u8 mic_key[16]; /* MIC key data */ | ||
1069 | u8 keyid; /* Key ID */ | ||
1070 | u8 reserved[3]; | ||
1071 | } __packed wapi_group; | ||
1072 | } __packed; | ||
1073 | } __packed; | ||
1074 | |||
1075 | int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg); | ||
1076 | |||
1077 | /* 3.32 */ | ||
1078 | #define WSM_REMOVE_KEY_REQ_ID 0x000D | ||
1079 | #define WSM_REMOVE_KEY_RESP_ID 0x040D | ||
1080 | struct wsm_remove_key { | ||
1081 | u8 index; /* Key entry index : 0-10 */ | ||
1082 | }; | ||
1083 | |||
1084 | int wsm_remove_key(struct cw1200_common *priv, | ||
1085 | const struct wsm_remove_key *arg); | ||
1086 | |||
1087 | /* 3.34 */ | ||
1088 | struct wsm_set_tx_queue_params { | ||
1089 | /* WSM_ACK_POLICY_... */ | ||
1090 | u8 ackPolicy; | ||
1091 | |||
1092 | /* Medium Time of TSPEC (in 32us units) allowed per */ | ||
1093 | /* One Second Averaging Period for this queue. */ | ||
1094 | u16 allowedMediumTime; | ||
1095 | |||
1096 | /* dot11MaxTransmitMsduLifetime to be used for the */ | ||
1097 | /* specified queue. */ | ||
1098 | u32 maxTransmitLifetime; | ||
1099 | }; | ||
1100 | |||
1101 | struct wsm_tx_queue_params { | ||
1102 | /* NOTE: index is a linux queue id. */ | ||
1103 | struct wsm_set_tx_queue_params params[4]; | ||
1104 | }; | ||
1105 | |||
1106 | |||
1107 | #define WSM_TX_QUEUE_SET(queue_params, queue, ack_policy, allowed_time,\ | ||
1108 | max_life_time) \ | ||
1109 | do { \ | ||
1110 | struct wsm_set_tx_queue_params *p = &(queue_params)->params[queue]; \ | ||
1111 | p->ackPolicy = (ack_policy); \ | ||
1112 | p->allowedMediumTime = (allowed_time); \ | ||
1113 | p->maxTransmitLifetime = (max_life_time); \ | ||
1114 | } while (0) | ||
1115 | |||
1116 | int wsm_set_tx_queue_params(struct cw1200_common *priv, | ||
1117 | const struct wsm_set_tx_queue_params *arg, u8 id); | ||
1118 | |||
1119 | /* 3.36 */ | ||
1120 | #define WSM_EDCA_PARAMS_REQ_ID 0x0013 | ||
1121 | #define WSM_EDCA_PARAMS_RESP_ID 0x0413 | ||
1122 | struct wsm_edca_queue_params { | ||
1123 | /* CWmin (in slots) for the access class. */ | ||
1124 | __le16 cwmin; | ||
1125 | |||
1126 | /* CWmax (in slots) for the access class. */ | ||
1127 | __le16 cwmax; | ||
1128 | |||
1129 | /* AIFS (in slots) for the access class. */ | ||
1130 | __le16 aifns; | ||
1131 | |||
1132 | /* TX OP Limit (in microseconds) for the access class. */ | ||
1133 | __le16 txop_limit; | ||
1134 | |||
1135 | /* dot11MaxReceiveLifetime to be used for the specified */ | ||
1136 | /* the access class. Overrides the global */ | ||
1137 | /* dot11MaxReceiveLifetime value */ | ||
1138 | __le32 max_rx_lifetime; | ||
1139 | } __packed; | ||
1140 | |||
1141 | struct wsm_edca_params { | ||
1142 | /* NOTE: index is a linux queue id. */ | ||
1143 | struct wsm_edca_queue_params params[4]; | ||
1144 | bool uapsd_enable[4]; | ||
1145 | }; | ||
1146 | |||
1147 | #define TXOP_UNIT 32 | ||
1148 | #define WSM_EDCA_SET(__edca, __queue, __aifs, __cw_min, __cw_max, __txop, __lifetime,\ | ||
1149 | __uapsd) \ | ||
1150 | do { \ | ||
1151 | struct wsm_edca_queue_params *p = &(__edca)->params[__queue]; \ | ||
1152 | p->cwmin = (__cw_min); \ | ||
1153 | p->cwmax = (__cw_max); \ | ||
1154 | p->aifns = (__aifs); \ | ||
1155 | p->txop_limit = ((__txop) * TXOP_UNIT); \ | ||
1156 | p->max_rx_lifetime = (__lifetime); \ | ||
1157 | (__edca)->uapsd_enable[__queue] = (__uapsd); \ | ||
1158 | } while (0) | ||
1159 | |||
1160 | int wsm_set_edca_params(struct cw1200_common *priv, | ||
1161 | const struct wsm_edca_params *arg); | ||
1162 | |||
1163 | int wsm_set_uapsd_param(struct cw1200_common *priv, | ||
1164 | const struct wsm_edca_params *arg); | ||
1165 | |||
1166 | /* 3.38 */ | ||
1167 | /* Set-System info. Skipped for now. Irrelevent. */ | ||
1168 | |||
1169 | /* 3.40 */ | ||
1170 | #define WSM_SWITCH_CHANNEL_REQ_ID 0x0016 | ||
1171 | #define WSM_SWITCH_CHANNEL_RESP_ID 0x0416 | ||
1172 | |||
1173 | struct wsm_switch_channel { | ||
1174 | /* 1 - means the STA shall not transmit any further */ | ||
1175 | /* frames until the channel switch has completed */ | ||
1176 | u8 mode; | ||
1177 | |||
1178 | /* Number of TBTTs until channel switch occurs. */ | ||
1179 | /* 0 - indicates switch shall occur at any time */ | ||
1180 | /* 1 - occurs immediately before the next TBTT */ | ||
1181 | u8 switch_count; | ||
1182 | |||
1183 | /* The new channel number to switch to. */ | ||
1184 | /* Note this is defined as per section 2.7. */ | ||
1185 | u16 channel_number; | ||
1186 | }; | ||
1187 | |||
1188 | int wsm_switch_channel(struct cw1200_common *priv, | ||
1189 | const struct wsm_switch_channel *arg); | ||
1190 | |||
1191 | typedef void (*wsm_channel_switch_cb) (struct cw1200_common *priv); | ||
1192 | |||
1193 | #define WSM_START_REQ_ID 0x0017 | ||
1194 | #define WSM_START_RESP_ID 0x0417 | ||
1195 | |||
1196 | struct wsm_start { | ||
1197 | /* WSM_START_MODE_... */ | ||
1198 | /* [in] */ u8 mode; | ||
1199 | |||
1200 | /* WSM_PHY_BAND_... */ | ||
1201 | /* [in] */ u8 band; | ||
1202 | |||
1203 | /* Channel number */ | ||
1204 | /* [in] */ u16 channel_number; | ||
1205 | |||
1206 | /* Client Traffic window in units of TU */ | ||
1207 | /* Valid only when mode == ..._P2P */ | ||
1208 | /* [in] */ u32 ct_window; | ||
1209 | |||
1210 | /* Interval between two consecutive */ | ||
1211 | /* beacon transmissions in TU. */ | ||
1212 | /* [in] */ u32 beacon_interval; | ||
1213 | |||
1214 | /* DTIM period in terms of beacon intervals */ | ||
1215 | /* [in] */ u8 dtim_period; | ||
1216 | |||
1217 | /* WSM_JOIN_PREAMBLE_... */ | ||
1218 | /* [in] */ u8 preamble; | ||
1219 | |||
1220 | /* The delay time (in microseconds) period */ | ||
1221 | /* before sending a probe-request. */ | ||
1222 | /* [in] */ u8 probe_delay; | ||
1223 | |||
1224 | /* Length of the SSID */ | ||
1225 | /* [in] */ u8 ssid_len; | ||
1226 | |||
1227 | /* SSID of the BSS or P2P_GO to be started now. */ | ||
1228 | /* [in] */ u8 ssid[32]; | ||
1229 | |||
1230 | /* The basic supported rates for the MiniAP. */ | ||
1231 | /* [in] */ u32 basic_rate_set; | ||
1232 | }; | ||
1233 | |||
1234 | int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg); | ||
1235 | |||
1236 | #define WSM_BEACON_TRANSMIT_REQ_ID 0x0018 | ||
1237 | #define WSM_BEACON_TRANSMIT_RESP_ID 0x0418 | ||
1238 | |||
1239 | struct wsm_beacon_transmit { | ||
1240 | /* 1: enable; 0: disable */ | ||
1241 | /* [in] */ u8 enable_beaconing; | ||
1242 | }; | ||
1243 | |||
1244 | int wsm_beacon_transmit(struct cw1200_common *priv, | ||
1245 | const struct wsm_beacon_transmit *arg); | ||
1246 | |||
1247 | int wsm_start_find(struct cw1200_common *priv); | ||
1248 | |||
1249 | int wsm_stop_find(struct cw1200_common *priv); | ||
1250 | |||
1251 | typedef void (*wsm_find_complete_cb) (struct cw1200_common *priv, u32 status); | ||
1252 | |||
1253 | struct wsm_suspend_resume { | ||
1254 | /* See 3.52 */ | ||
1255 | /* Link ID */ | ||
1256 | /* [out] */ int link_id; | ||
1257 | /* Stop sending further Tx requests down to device for this link */ | ||
1258 | /* [out] */ bool stop; | ||
1259 | /* Transmit multicast Frames */ | ||
1260 | /* [out] */ bool multicast; | ||
1261 | /* The AC on which Tx to be suspended /resumed. */ | ||
1262 | /* This is applicable only for U-APSD */ | ||
1263 | /* WSM_QUEUE_... */ | ||
1264 | /* [out] */ int queue; | ||
1265 | }; | ||
1266 | |||
1267 | typedef void (*wsm_suspend_resume_cb) (struct cw1200_common *priv, | ||
1268 | struct wsm_suspend_resume *arg); | ||
1269 | |||
1270 | /* 3.54 Update-IE request. */ | ||
1271 | struct wsm_update_ie { | ||
1272 | /* WSM_UPDATE_IE_... */ | ||
1273 | /* [in] */ u16 what; | ||
1274 | /* [in] */ u16 count; | ||
1275 | /* [in] */ u8 *ies; | ||
1276 | /* [in] */ size_t length; | ||
1277 | }; | ||
1278 | |||
1279 | int wsm_update_ie(struct cw1200_common *priv, | ||
1280 | const struct wsm_update_ie *arg); | ||
1281 | |||
1282 | /* 3.56 */ | ||
1283 | struct wsm_map_link { | ||
1284 | /* MAC address of the remote device */ | ||
1285 | /* [in] */ u8 mac_addr[6]; | ||
1286 | /* [in] */ u8 link_id; | ||
1287 | }; | ||
1288 | |||
1289 | int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg); | ||
1290 | |||
1291 | /* ******************************************************************** */ | ||
1292 | /* MIB shortcats */ | ||
1293 | |||
1294 | static inline int wsm_set_output_power(struct cw1200_common *priv, | ||
1295 | int power_level) | ||
1296 | { | ||
1297 | __le32 val = __cpu_to_le32(power_level); | ||
1298 | return wsm_write_mib(priv, WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL, | ||
1299 | &val, sizeof(val)); | ||
1300 | } | ||
1301 | |||
1302 | static inline int wsm_set_beacon_wakeup_period(struct cw1200_common *priv, | ||
1303 | unsigned dtim_interval, | ||
1304 | unsigned listen_interval) | ||
1305 | { | ||
1306 | struct { | ||
1307 | u8 numBeaconPeriods; | ||
1308 | u8 reserved; | ||
1309 | __le16 listenInterval; | ||
1310 | } val = { | ||
1311 | dtim_interval, 0, __cpu_to_le16(listen_interval) | ||
1312 | }; | ||
1313 | |||
1314 | if (dtim_interval > 0xFF || listen_interval > 0xFFFF) | ||
1315 | return -EINVAL; | ||
1316 | else | ||
1317 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_WAKEUP_PERIOD, | ||
1318 | &val, sizeof(val)); | ||
1319 | } | ||
1320 | |||
1321 | struct wsm_rcpi_rssi_threshold { | ||
1322 | u8 rssiRcpiMode; /* WSM_RCPI_RSSI_... */ | ||
1323 | u8 lowerThreshold; | ||
1324 | u8 upperThreshold; | ||
1325 | u8 rollingAverageCount; | ||
1326 | }; | ||
1327 | |||
1328 | static inline int wsm_set_rcpi_rssi_threshold(struct cw1200_common *priv, | ||
1329 | struct wsm_rcpi_rssi_threshold *arg) | ||
1330 | { | ||
1331 | return wsm_write_mib(priv, WSM_MIB_ID_RCPI_RSSI_THRESHOLD, arg, | ||
1332 | sizeof(*arg)); | ||
1333 | } | ||
1334 | |||
1335 | struct wsm_mib_counters_table { | ||
1336 | __le32 plcp_errors; | ||
1337 | __le32 fcs_errors; | ||
1338 | __le32 tx_packets; | ||
1339 | __le32 rx_packets; | ||
1340 | __le32 rx_packet_errors; | ||
1341 | __le32 rx_decryption_failures; | ||
1342 | __le32 rx_mic_failures; | ||
1343 | __le32 rx_no_key_failures; | ||
1344 | __le32 tx_multicast_frames; | ||
1345 | __le32 tx_frames_success; | ||
1346 | __le32 tx_frame_failures; | ||
1347 | __le32 tx_frames_retried; | ||
1348 | __le32 tx_frames_multi_retried; | ||
1349 | __le32 rx_frame_duplicates; | ||
1350 | __le32 rts_success; | ||
1351 | __le32 rts_failures; | ||
1352 | __le32 ack_failures; | ||
1353 | __le32 rx_multicast_frames; | ||
1354 | __le32 rx_frames_success; | ||
1355 | __le32 rx_cmac_icv_errors; | ||
1356 | __le32 rx_cmac_replays; | ||
1357 | __le32 rx_mgmt_ccmp_replays; | ||
1358 | } __packed; | ||
1359 | |||
1360 | static inline int wsm_get_counters_table(struct cw1200_common *priv, | ||
1361 | struct wsm_mib_counters_table *arg) | ||
1362 | { | ||
1363 | return wsm_read_mib(priv, WSM_MIB_ID_COUNTERS_TABLE, | ||
1364 | arg, sizeof(*arg)); | ||
1365 | } | ||
1366 | |||
1367 | static inline int wsm_get_station_id(struct cw1200_common *priv, u8 *mac) | ||
1368 | { | ||
1369 | return wsm_read_mib(priv, WSM_MIB_ID_DOT11_STATION_ID, mac, ETH_ALEN); | ||
1370 | } | ||
1371 | |||
1372 | struct wsm_rx_filter { | ||
1373 | bool promiscuous; | ||
1374 | bool bssid; | ||
1375 | bool fcs; | ||
1376 | bool probeResponder; | ||
1377 | }; | ||
1378 | |||
1379 | static inline int wsm_set_rx_filter(struct cw1200_common *priv, | ||
1380 | const struct wsm_rx_filter *arg) | ||
1381 | { | ||
1382 | __le32 val = 0; | ||
1383 | if (arg->promiscuous) | ||
1384 | val |= __cpu_to_le32(BIT(0)); | ||
1385 | if (arg->bssid) | ||
1386 | val |= __cpu_to_le32(BIT(1)); | ||
1387 | if (arg->fcs) | ||
1388 | val |= __cpu_to_le32(BIT(2)); | ||
1389 | if (arg->probeResponder) | ||
1390 | val |= __cpu_to_le32(BIT(3)); | ||
1391 | return wsm_write_mib(priv, WSM_MIB_ID_RX_FILTER, &val, sizeof(val)); | ||
1392 | } | ||
1393 | |||
1394 | int wsm_set_probe_responder(struct cw1200_common *priv, bool enable); | ||
1395 | |||
1396 | #define WSM_BEACON_FILTER_IE_HAS_CHANGED BIT(0) | ||
1397 | #define WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT BIT(1) | ||
1398 | #define WSM_BEACON_FILTER_IE_HAS_APPEARED BIT(2) | ||
1399 | |||
1400 | struct wsm_beacon_filter_table_entry { | ||
1401 | u8 ie_id; | ||
1402 | u8 flags; | ||
1403 | u8 oui[3]; | ||
1404 | u8 match_data[3]; | ||
1405 | } __packed; | ||
1406 | |||
1407 | struct wsm_mib_beacon_filter_table { | ||
1408 | __le32 num; | ||
1409 | struct wsm_beacon_filter_table_entry entry[10]; | ||
1410 | } __packed; | ||
1411 | |||
1412 | static inline int wsm_set_beacon_filter_table(struct cw1200_common *priv, | ||
1413 | struct wsm_mib_beacon_filter_table *ft) | ||
1414 | { | ||
1415 | size_t size = __le32_to_cpu(ft->num) * | ||
1416 | sizeof(struct wsm_beacon_filter_table_entry) + | ||
1417 | sizeof(__le32); | ||
1418 | |||
1419 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size); | ||
1420 | } | ||
1421 | |||
1422 | #define WSM_BEACON_FILTER_ENABLE BIT(0) /* Enable/disable beacon filtering */ | ||
1423 | #define WSM_BEACON_FILTER_AUTO_ERP BIT(1) /* If 1 FW will handle ERP IE changes internally */ | ||
1424 | |||
1425 | struct wsm_beacon_filter_control { | ||
1426 | int enabled; | ||
1427 | int bcn_count; | ||
1428 | }; | ||
1429 | |||
1430 | static inline int wsm_beacon_filter_control(struct cw1200_common *priv, | ||
1431 | struct wsm_beacon_filter_control *arg) | ||
1432 | { | ||
1433 | struct { | ||
1434 | __le32 enabled; | ||
1435 | __le32 bcn_count; | ||
1436 | } val; | ||
1437 | val.enabled = __cpu_to_le32(arg->enabled); | ||
1438 | val.bcn_count = __cpu_to_le32(arg->bcn_count); | ||
1439 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val, | ||
1440 | sizeof(val)); | ||
1441 | } | ||
1442 | |||
1443 | enum wsm_power_mode { | ||
1444 | wsm_power_mode_active = 0, | ||
1445 | wsm_power_mode_doze = 1, | ||
1446 | wsm_power_mode_quiescent = 2, | ||
1447 | }; | ||
1448 | |||
1449 | struct wsm_operational_mode { | ||
1450 | enum wsm_power_mode power_mode; | ||
1451 | int disable_more_flag_usage; | ||
1452 | int perform_ant_diversity; | ||
1453 | }; | ||
1454 | |||
1455 | static inline int wsm_set_operational_mode(struct cw1200_common *priv, | ||
1456 | const struct wsm_operational_mode *arg) | ||
1457 | { | ||
1458 | u8 val = arg->power_mode; | ||
1459 | if (arg->disable_more_flag_usage) | ||
1460 | val |= BIT(4); | ||
1461 | if (arg->perform_ant_diversity) | ||
1462 | val |= BIT(5); | ||
1463 | return wsm_write_mib(priv, WSM_MIB_ID_OPERATIONAL_POWER_MODE, &val, | ||
1464 | sizeof(val)); | ||
1465 | } | ||
1466 | |||
1467 | struct wsm_template_frame { | ||
1468 | u8 frame_type; | ||
1469 | u8 rate; | ||
1470 | struct sk_buff *skb; | ||
1471 | }; | ||
1472 | |||
1473 | static inline int wsm_set_template_frame(struct cw1200_common *priv, | ||
1474 | struct wsm_template_frame *arg) | ||
1475 | { | ||
1476 | int ret; | ||
1477 | u8 *p = skb_push(arg->skb, 4); | ||
1478 | p[0] = arg->frame_type; | ||
1479 | p[1] = arg->rate; | ||
1480 | ((u16 *)p)[1] = __cpu_to_le16(arg->skb->len - 4); | ||
1481 | ret = wsm_write_mib(priv, WSM_MIB_ID_TEMPLATE_FRAME, p, arg->skb->len); | ||
1482 | skb_pull(arg->skb, 4); | ||
1483 | return ret; | ||
1484 | } | ||
1485 | |||
1486 | |||
1487 | struct wsm_protected_mgmt_policy { | ||
1488 | bool protectedMgmtEnable; | ||
1489 | bool unprotectedMgmtFramesAllowed; | ||
1490 | bool encryptionForAuthFrame; | ||
1491 | }; | ||
1492 | |||
1493 | static inline int wsm_set_protected_mgmt_policy(struct cw1200_common *priv, | ||
1494 | struct wsm_protected_mgmt_policy *arg) | ||
1495 | { | ||
1496 | __le32 val = 0; | ||
1497 | int ret; | ||
1498 | if (arg->protectedMgmtEnable) | ||
1499 | val |= __cpu_to_le32(BIT(0)); | ||
1500 | if (arg->unprotectedMgmtFramesAllowed) | ||
1501 | val |= __cpu_to_le32(BIT(1)); | ||
1502 | if (arg->encryptionForAuthFrame) | ||
1503 | val |= __cpu_to_le32(BIT(2)); | ||
1504 | ret = wsm_write_mib(priv, WSM_MIB_ID_PROTECTED_MGMT_POLICY, | ||
1505 | &val, sizeof(val)); | ||
1506 | return ret; | ||
1507 | } | ||
1508 | |||
1509 | struct wsm_mib_block_ack_policy { | ||
1510 | u8 tx_tid; | ||
1511 | u8 reserved1; | ||
1512 | u8 rx_tid; | ||
1513 | u8 reserved2; | ||
1514 | } __packed; | ||
1515 | |||
1516 | static inline int wsm_set_block_ack_policy(struct cw1200_common *priv, | ||
1517 | u8 tx_tid_policy, | ||
1518 | u8 rx_tid_policy) | ||
1519 | { | ||
1520 | struct wsm_mib_block_ack_policy val = { | ||
1521 | .tx_tid = tx_tid_policy, | ||
1522 | .rx_tid = rx_tid_policy, | ||
1523 | }; | ||
1524 | return wsm_write_mib(priv, WSM_MIB_ID_BLOCK_ACK_POLICY, &val, | ||
1525 | sizeof(val)); | ||
1526 | } | ||
1527 | |||
1528 | struct wsm_mib_association_mode { | ||
1529 | u8 flags; /* WSM_ASSOCIATION_MODE_... */ | ||
1530 | u8 preamble; /* WSM_JOIN_PREAMBLE_... */ | ||
1531 | u8 greenfield; /* 1 for greenfield */ | ||
1532 | u8 mpdu_start_spacing; | ||
1533 | __le32 basic_rate_set; | ||
1534 | } __packed; | ||
1535 | |||
1536 | static inline int wsm_set_association_mode(struct cw1200_common *priv, | ||
1537 | struct wsm_mib_association_mode *arg) | ||
1538 | { | ||
1539 | return wsm_write_mib(priv, WSM_MIB_ID_SET_ASSOCIATION_MODE, arg, | ||
1540 | sizeof(*arg)); | ||
1541 | } | ||
1542 | |||
1543 | #define WSM_TX_RATE_POLICY_FLAG_TERMINATE_WHEN_FINISHED BIT(2) | ||
1544 | #define WSM_TX_RATE_POLICY_FLAG_COUNT_INITIAL_TRANSMIT BIT(3) | ||
1545 | struct wsm_tx_rate_retry_policy { | ||
1546 | u8 index; | ||
1547 | u8 short_retries; | ||
1548 | u8 long_retries; | ||
1549 | /* BIT(2) - Terminate retries when Tx rate retry policy | ||
1550 | * finishes. | ||
1551 | * BIT(3) - Count initial frame transmission as part of | ||
1552 | * rate retry counting but not as a retry | ||
1553 | * attempt */ | ||
1554 | u8 flags; | ||
1555 | u8 rate_recoveries; | ||
1556 | u8 reserved[3]; | ||
1557 | __le32 rate_count_indices[3]; | ||
1558 | } __packed; | ||
1559 | |||
1560 | struct wsm_set_tx_rate_retry_policy { | ||
1561 | u8 num; | ||
1562 | u8 reserved[3]; | ||
1563 | struct wsm_tx_rate_retry_policy tbl[8]; | ||
1564 | } __packed; | ||
1565 | |||
1566 | static inline int wsm_set_tx_rate_retry_policy(struct cw1200_common *priv, | ||
1567 | struct wsm_set_tx_rate_retry_policy *arg) | ||
1568 | { | ||
1569 | size_t size = 4 + arg->num * sizeof(struct wsm_tx_rate_retry_policy); | ||
1570 | return wsm_write_mib(priv, WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, | ||
1571 | size); | ||
1572 | } | ||
1573 | |||
1574 | /* 4.32 SetEtherTypeDataFrameFilter */ | ||
1575 | struct wsm_ether_type_filter_hdr { | ||
1576 | u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ | ||
1577 | u8 reserved[3]; | ||
1578 | } __packed; | ||
1579 | |||
1580 | struct wsm_ether_type_filter { | ||
1581 | u8 action; /* WSM_FILTER_ACTION_XXX */ | ||
1582 | u8 reserved; | ||
1583 | __le16 type; /* Type of ethernet frame */ | ||
1584 | } __packed; | ||
1585 | |||
1586 | static inline int wsm_set_ether_type_filter(struct cw1200_common *priv, | ||
1587 | struct wsm_ether_type_filter_hdr *arg) | ||
1588 | { | ||
1589 | size_t size = sizeof(struct wsm_ether_type_filter_hdr) + | ||
1590 | arg->num * sizeof(struct wsm_ether_type_filter); | ||
1591 | return wsm_write_mib(priv, WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER, | ||
1592 | arg, size); | ||
1593 | } | ||
1594 | |||
1595 | /* 4.33 SetUDPPortDataFrameFilter */ | ||
1596 | struct wsm_udp_port_filter_hdr { | ||
1597 | u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ | ||
1598 | u8 reserved[3]; | ||
1599 | } __packed; | ||
1600 | |||
1601 | struct wsm_udp_port_filter { | ||
1602 | u8 action; /* WSM_FILTER_ACTION_XXX */ | ||
1603 | u8 type; /* WSM_FILTER_PORT_TYPE_XXX */ | ||
1604 | __le16 port; /* Port number */ | ||
1605 | } __packed; | ||
1606 | |||
1607 | static inline int wsm_set_udp_port_filter(struct cw1200_common *priv, | ||
1608 | struct wsm_udp_port_filter_hdr *arg) | ||
1609 | { | ||
1610 | size_t size = sizeof(struct wsm_udp_port_filter_hdr) + | ||
1611 | arg->num * sizeof(struct wsm_udp_port_filter); | ||
1612 | return wsm_write_mib(priv, WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER, | ||
1613 | arg, size); | ||
1614 | } | ||
1615 | |||
1616 | /* Undocumented MIBs: */ | ||
1617 | /* 4.35 P2PDeviceInfo */ | ||
1618 | #define D11_MAX_SSID_LEN (32) | ||
1619 | |||
1620 | struct wsm_p2p_device_type { | ||
1621 | __le16 categoryId; | ||
1622 | u8 oui[4]; | ||
1623 | __le16 subCategoryId; | ||
1624 | } __packed; | ||
1625 | |||
1626 | struct wsm_p2p_device_info { | ||
1627 | struct wsm_p2p_device_type primaryDevice; | ||
1628 | u8 reserved1[3]; | ||
1629 | u8 devNameSize; | ||
1630 | u8 localDevName[D11_MAX_SSID_LEN]; | ||
1631 | u8 reserved2[3]; | ||
1632 | u8 numSecDevSupported; | ||
1633 | struct wsm_p2p_device_type secondaryDevices[0]; | ||
1634 | } __packed; | ||
1635 | |||
1636 | /* 4.36 SetWCDMABand - WO */ | ||
1637 | struct wsm_cdma_band { | ||
1638 | u8 WCDMA_Band; | ||
1639 | u8 reserved[3]; | ||
1640 | } __packed; | ||
1641 | |||
1642 | /* 4.37 GroupTxSequenceCounter - RO */ | ||
1643 | struct wsm_group_tx_seq { | ||
1644 | __le32 bits_47_16; | ||
1645 | __le16 bits_15_00; | ||
1646 | __le16 reserved; | ||
1647 | } __packed; | ||
1648 | |||
1649 | /* 4.39 SetHtProtection - WO */ | ||
1650 | #define WSM_DUAL_CTS_PROT_ENB (1 << 0) | ||
1651 | #define WSM_NON_GREENFIELD_STA_PRESENT (1 << 1) | ||
1652 | #define WSM_HT_PROT_MODE__NO_PROT (0 << 2) | ||
1653 | #define WSM_HT_PROT_MODE__NON_MEMBER (1 << 2) | ||
1654 | #define WSM_HT_PROT_MODE__20_MHZ (2 << 2) | ||
1655 | #define WSM_HT_PROT_MODE__NON_HT_MIXED (3 << 2) | ||
1656 | #define WSM_LSIG_TXOP_PROT_FULL (1 << 4) | ||
1657 | #define WSM_LARGE_L_LENGTH_PROT (1 << 5) | ||
1658 | |||
1659 | struct wsm_ht_protection { | ||
1660 | __le32 flags; | ||
1661 | } __packed; | ||
1662 | |||
1663 | /* 4.40 GPIO Command - R/W */ | ||
1664 | #define WSM_GPIO_COMMAND_SETUP 0 | ||
1665 | #define WSM_GPIO_COMMAND_READ 1 | ||
1666 | #define WSM_GPIO_COMMAND_WRITE 2 | ||
1667 | #define WSM_GPIO_COMMAND_RESET 3 | ||
1668 | #define WSM_GPIO_ALL_PINS 0xFF | ||
1669 | |||
1670 | struct wsm_gpio_command { | ||
1671 | u8 GPIO_Command; | ||
1672 | u8 pin; | ||
1673 | __le16 config; | ||
1674 | } __packed; | ||
1675 | |||
1676 | /* 4.41 TSFCounter - RO */ | ||
1677 | struct wsm_tsf_counter { | ||
1678 | __le64 TSF_Counter; | ||
1679 | } __packed; | ||
1680 | |||
1681 | /* 4.43 Keep alive period */ | ||
1682 | struct wsm_keep_alive_period { | ||
1683 | __le16 keepAlivePeriod; | ||
1684 | u8 reserved[2]; | ||
1685 | } __packed; | ||
1686 | |||
1687 | static inline int wsm_keep_alive_period(struct cw1200_common *priv, | ||
1688 | int period) | ||
1689 | { | ||
1690 | struct wsm_keep_alive_period arg = { | ||
1691 | .keepAlivePeriod = __cpu_to_le16(period), | ||
1692 | }; | ||
1693 | return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, | ||
1694 | &arg, sizeof(arg)); | ||
1695 | }; | ||
1696 | |||
1697 | /* BSSID filtering */ | ||
1698 | struct wsm_set_bssid_filtering { | ||
1699 | u8 filter; | ||
1700 | u8 reserved[3]; | ||
1701 | } __packed; | ||
1702 | |||
1703 | static inline int wsm_set_bssid_filtering(struct cw1200_common *priv, | ||
1704 | bool enabled) | ||
1705 | { | ||
1706 | struct wsm_set_bssid_filtering arg = { | ||
1707 | .filter = !enabled, | ||
1708 | }; | ||
1709 | return wsm_write_mib(priv, WSM_MIB_ID_DISABLE_BSSID_FILTER, | ||
1710 | &arg, sizeof(arg)); | ||
1711 | } | ||
1712 | |||
1713 | /* Multicast filtering - 4.5 */ | ||
1714 | struct wsm_mib_multicast_filter { | ||
1715 | __le32 enable; | ||
1716 | __le32 num_addrs; | ||
1717 | u8 macaddrs[WSM_MAX_GRP_ADDRTABLE_ENTRIES][ETH_ALEN]; | ||
1718 | } __packed; | ||
1719 | |||
1720 | static inline int wsm_set_multicast_filter(struct cw1200_common *priv, | ||
1721 | struct wsm_mib_multicast_filter *fp) | ||
1722 | { | ||
1723 | return wsm_write_mib(priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, | ||
1724 | fp, sizeof(*fp)); | ||
1725 | } | ||
1726 | |||
1727 | /* ARP IPv4 filtering - 4.10 */ | ||
1728 | struct wsm_mib_arp_ipv4_filter { | ||
1729 | __le32 enable; | ||
1730 | __be32 ipv4addrs[WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES]; | ||
1731 | } __packed; | ||
1732 | |||
1733 | static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv, | ||
1734 | struct wsm_mib_arp_ipv4_filter *fp) | ||
1735 | { | ||
1736 | return wsm_write_mib(priv, WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE, | ||
1737 | fp, sizeof(*fp)); | ||
1738 | } | ||
1739 | |||
1740 | /* P2P Power Save Mode Info - 4.31 */ | ||
1741 | struct wsm_p2p_ps_modeinfo { | ||
1742 | u8 oppPsCTWindow; | ||
1743 | u8 count; | ||
1744 | u8 reserved; | ||
1745 | u8 dtimCount; | ||
1746 | __le32 duration; | ||
1747 | __le32 interval; | ||
1748 | __le32 startTime; | ||
1749 | } __packed; | ||
1750 | |||
1751 | static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv, | ||
1752 | struct wsm_p2p_ps_modeinfo *mi) | ||
1753 | { | ||
1754 | return wsm_write_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, | ||
1755 | mi, sizeof(*mi)); | ||
1756 | } | ||
1757 | |||
1758 | static inline int wsm_get_p2p_ps_modeinfo(struct cw1200_common *priv, | ||
1759 | struct wsm_p2p_ps_modeinfo *mi) | ||
1760 | { | ||
1761 | return wsm_read_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, | ||
1762 | mi, sizeof(*mi)); | ||
1763 | } | ||
1764 | |||
1765 | /* UseMultiTxConfMessage */ | ||
1766 | |||
1767 | static inline int wsm_use_multi_tx_conf(struct cw1200_common *priv, | ||
1768 | bool enabled) | ||
1769 | { | ||
1770 | __le32 arg = enabled ? __cpu_to_le32(1) : 0; | ||
1771 | |||
1772 | return wsm_write_mib(priv, WSM_MIB_USE_MULTI_TX_CONF, | ||
1773 | &arg, sizeof(arg)); | ||
1774 | } | ||
1775 | |||
1776 | |||
1777 | /* 4.26 SetUpasdInformation */ | ||
1778 | struct wsm_uapsd_info { | ||
1779 | __le16 uapsd_flags; | ||
1780 | __le16 min_auto_trigger_interval; | ||
1781 | __le16 max_auto_trigger_interval; | ||
1782 | __le16 auto_trigger_step; | ||
1783 | }; | ||
1784 | |||
1785 | static inline int wsm_set_uapsd_info(struct cw1200_common *priv, | ||
1786 | struct wsm_uapsd_info *arg) | ||
1787 | { | ||
1788 | return wsm_write_mib(priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, | ||
1789 | arg, sizeof(*arg)); | ||
1790 | } | ||
1791 | |||
1792 | /* 4.22 OverrideInternalTxRate */ | ||
1793 | struct wsm_override_internal_txrate { | ||
1794 | u8 internalTxRate; | ||
1795 | u8 nonErpInternalTxRate; | ||
1796 | u8 reserved[2]; | ||
1797 | } __packed; | ||
1798 | |||
1799 | static inline int wsm_set_override_internal_txrate(struct cw1200_common *priv, | ||
1800 | struct wsm_override_internal_txrate *arg) | ||
1801 | { | ||
1802 | return wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, | ||
1803 | arg, sizeof(*arg)); | ||
1804 | } | ||
1805 | |||
1806 | /* ******************************************************************** */ | ||
1807 | /* WSM TX port control */ | ||
1808 | |||
1809 | void wsm_lock_tx(struct cw1200_common *priv); | ||
1810 | void wsm_lock_tx_async(struct cw1200_common *priv); | ||
1811 | bool wsm_flush_tx(struct cw1200_common *priv); | ||
1812 | void wsm_unlock_tx(struct cw1200_common *priv); | ||
1813 | |||
1814 | /* ******************************************************************** */ | ||
1815 | /* WSM / BH API */ | ||
1816 | |||
1817 | int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len); | ||
1818 | int wsm_handle_rx(struct cw1200_common *priv, u16 id, struct wsm_hdr *wsm, | ||
1819 | struct sk_buff **skb_p); | ||
1820 | |||
1821 | /* ******************************************************************** */ | ||
1822 | /* wsm_buf API */ | ||
1823 | |||
1824 | struct wsm_buf { | ||
1825 | u8 *begin; | ||
1826 | u8 *data; | ||
1827 | u8 *end; | ||
1828 | }; | ||
1829 | |||
1830 | void wsm_buf_init(struct wsm_buf *buf); | ||
1831 | void wsm_buf_deinit(struct wsm_buf *buf); | ||
1832 | |||
1833 | /* ******************************************************************** */ | ||
1834 | /* wsm_cmd API */ | ||
1835 | |||
1836 | struct wsm_cmd { | ||
1837 | spinlock_t lock; /* Protect structure from multiple access */ | ||
1838 | int done; | ||
1839 | u8 *ptr; | ||
1840 | size_t len; | ||
1841 | void *arg; | ||
1842 | int ret; | ||
1843 | u16 cmd; | ||
1844 | }; | ||
1845 | |||
1846 | /* ******************************************************************** */ | ||
1847 | /* WSM TX buffer access */ | ||
1848 | |||
1849 | int wsm_get_tx(struct cw1200_common *priv, u8 **data, | ||
1850 | size_t *tx_len, int *burst); | ||
1851 | void wsm_txed(struct cw1200_common *priv, u8 *data); | ||
1852 | |||
1853 | /* ******************************************************************** */ | ||
1854 | /* Queue mapping: WSM <---> linux */ | ||
1855 | /* Linux: VO VI BE BK */ | ||
1856 | /* WSM: BE BK VI VO */ | ||
1857 | |||
1858 | static inline u8 wsm_queue_id_to_linux(u8 queue_id) | ||
1859 | { | ||
1860 | static const u8 queue_mapping[] = { | ||
1861 | 2, 3, 1, 0 | ||
1862 | }; | ||
1863 | return queue_mapping[queue_id]; | ||
1864 | } | ||
1865 | |||
1866 | static inline u8 wsm_queue_id_to_wsm(u8 queue_id) | ||
1867 | { | ||
1868 | static const u8 queue_mapping[] = { | ||
1869 | 3, 2, 0, 1 | ||
1870 | }; | ||
1871 | return queue_mapping[queue_id]; | ||
1872 | } | ||
1873 | |||
1874 | |||
1875 | #ifdef CONFIG_CW1200_ETF | ||
1876 | int wsm_raw_cmd(struct cw1200_common *priv, u8 *data, size_t len); | ||
1877 | #endif | ||
1878 | |||
1879 | #endif /* CW1200_HWIO_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 15920aaa5dd6..f8ab193009cd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c | |||
@@ -6242,8 +6242,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, | |||
6242 | if ((val & 0x0000ff00) != 0) | 6242 | if ((val & 0x0000ff00) != 0) |
6243 | pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); | 6243 | pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff); |
6244 | 6244 | ||
6245 | pci_set_power_state(pci_dev, PCI_D0); | ||
6246 | |||
6247 | if (!ipw2100_hw_is_adapter_in_system(dev)) { | 6245 | if (!ipw2100_hw_is_adapter_in_system(dev)) { |
6248 | printk(KERN_WARNING DRV_NAME | 6246 | printk(KERN_WARNING DRV_NAME |
6249 | "Device not found via register read.\n"); | 6247 | "Device not found via register read.\n"); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 48545ab00311..de2c9514bef6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -76,13 +76,16 @@ | |||
76 | #define IWL_INVALID_STATION 255 | 76 | #define IWL_INVALID_STATION 255 |
77 | 77 | ||
78 | /* device operations */ | 78 | /* device operations */ |
79 | extern struct iwl_lib_ops iwl1000_lib; | 79 | extern const struct iwl_dvm_cfg iwl_dvm_1000_cfg; |
80 | extern struct iwl_lib_ops iwl2000_lib; | 80 | extern const struct iwl_dvm_cfg iwl_dvm_2000_cfg; |
81 | extern struct iwl_lib_ops iwl2030_lib; | 81 | extern const struct iwl_dvm_cfg iwl_dvm_105_cfg; |
82 | extern struct iwl_lib_ops iwl5000_lib; | 82 | extern const struct iwl_dvm_cfg iwl_dvm_2030_cfg; |
83 | extern struct iwl_lib_ops iwl5150_lib; | 83 | extern const struct iwl_dvm_cfg iwl_dvm_5000_cfg; |
84 | extern struct iwl_lib_ops iwl6000_lib; | 84 | extern const struct iwl_dvm_cfg iwl_dvm_5150_cfg; |
85 | extern struct iwl_lib_ops iwl6030_lib; | 85 | extern const struct iwl_dvm_cfg iwl_dvm_6000_cfg; |
86 | extern const struct iwl_dvm_cfg iwl_dvm_6005_cfg; | ||
87 | extern const struct iwl_dvm_cfg iwl_dvm_6050_cfg; | ||
88 | extern const struct iwl_dvm_cfg iwl_dvm_6030_cfg; | ||
86 | 89 | ||
87 | 90 | ||
88 | #define TIME_UNIT 1024 | 91 | #define TIME_UNIT 1024 |
@@ -291,8 +294,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena); | |||
291 | 294 | ||
292 | static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) | 295 | static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) |
293 | { | 296 | { |
294 | return priv->cfg->bt_params && | 297 | return priv->lib->bt_params && |
295 | priv->cfg->bt_params->advanced_bt_coexist; | 298 | priv->lib->bt_params->advanced_bt_coexist; |
296 | } | 299 | } |
297 | 300 | ||
298 | #ifdef CONFIG_IWLWIFI_DEBUG | 301 | #ifdef CONFIG_IWLWIFI_DEBUG |
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c index d6c4cf2ad7c5..1b0f0d502568 100644 --- a/drivers/net/wireless/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/iwlwifi/dvm/calib.c | |||
@@ -521,7 +521,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) | |||
521 | 521 | ||
522 | iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); | 522 | iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); |
523 | 523 | ||
524 | if (priv->cfg->base_params->hd_v2) { | 524 | if (priv->lib->hd_v2) { |
525 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = | 525 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = |
526 | HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; | 526 | HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; |
527 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = | 527 | cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = |
@@ -895,7 +895,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, | |||
895 | continue; | 895 | continue; |
896 | } | 896 | } |
897 | 897 | ||
898 | delta_g = (priv->cfg->base_params->chain_noise_scale * | 898 | delta_g = (priv->lib->chain_noise_scale * |
899 | ((s32)average_noise[default_chain] - | 899 | ((s32)average_noise[default_chain] - |
900 | (s32)average_noise[i])) / 1500; | 900 | (s32)average_noise[i])) / 1500; |
901 | 901 | ||
@@ -1051,8 +1051,8 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) | |||
1051 | return; | 1051 | return; |
1052 | 1052 | ||
1053 | /* Analyze signal for disconnected antenna */ | 1053 | /* Analyze signal for disconnected antenna */ |
1054 | if (priv->cfg->bt_params && | 1054 | if (priv->lib->bt_params && |
1055 | priv->cfg->bt_params->advanced_bt_coexist) { | 1055 | priv->lib->bt_params->advanced_bt_coexist) { |
1056 | /* Disable disconnected antenna algorithm for advanced | 1056 | /* Disable disconnected antenna algorithm for advanced |
1057 | bt coex, assuming valid antennas are connected */ | 1057 | bt coex, assuming valid antennas are connected */ |
1058 | data->active_chains = priv->nvm_data->valid_rx_ant; | 1058 | data->active_chains = priv->nvm_data->valid_rx_ant; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 174b0f169497..ebdac909f0cd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -838,10 +838,6 @@ struct iwl_qosparam_cmd { | |||
838 | #define STA_MODIFY_DELBA_TID_MSK 0x10 | 838 | #define STA_MODIFY_DELBA_TID_MSK 0x10 |
839 | #define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20 | 839 | #define STA_MODIFY_SLEEP_TX_COUNT_MSK 0x20 |
840 | 840 | ||
841 | /* Receiver address (actually, Rx station's index into station table), | ||
842 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ | ||
843 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) | ||
844 | |||
845 | /* agn */ | 841 | /* agn */ |
846 | struct iwl_keyinfo { | 842 | struct iwl_keyinfo { |
847 | __le16 key_flags; | 843 | __le16 key_flags; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index e71acfd344aa..5cd87f949266 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h | |||
@@ -568,16 +568,61 @@ struct iwl_hw_params { | |||
568 | const struct iwl_sensitivity_ranges *sens; | 568 | const struct iwl_sensitivity_ranges *sens; |
569 | }; | 569 | }; |
570 | 570 | ||
571 | struct iwl_lib_ops { | 571 | /** |
572 | /* set hw dependent parameters */ | 572 | * struct iwl_dvm_bt_params - DVM specific BT (coex) parameters |
573 | * @advanced_bt_coexist: support advanced bt coexist | ||
574 | * @bt_init_traffic_load: specify initial bt traffic load | ||
575 | * @bt_prio_boost: default bt priority boost value | ||
576 | * @agg_time_limit: maximum number of uSec in aggregation | ||
577 | * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode | ||
578 | */ | ||
579 | struct iwl_dvm_bt_params { | ||
580 | bool advanced_bt_coexist; | ||
581 | u8 bt_init_traffic_load; | ||
582 | u32 bt_prio_boost; | ||
583 | u16 agg_time_limit; | ||
584 | bool bt_sco_disable; | ||
585 | bool bt_session_2; | ||
586 | }; | ||
587 | |||
588 | /** | ||
589 | * struct iwl_dvm_cfg - DVM firmware specific device configuration | ||
590 | * @set_hw_params: set hardware parameters | ||
591 | * @set_channel_switch: send channel switch command | ||
592 | * @nic_config: apply device specific configuration | ||
593 | * @temperature: read temperature | ||
594 | * @adv_thermal_throttle: support advance thermal throttle | ||
595 | * @support_ct_kill_exit: support ct kill exit condition | ||
596 | * @plcp_delta_threshold: plcp error rate threshold used to trigger | ||
597 | * radio tuning when there is a high receiving plcp error rate | ||
598 | * @chain_noise_scale: default chain noise scale used for gain computation | ||
599 | * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up | ||
600 | * @no_idle_support: do not support idle mode | ||
601 | * @bt_params: pointer to BT parameters | ||
602 | * @need_temp_offset_calib: need to perform temperature offset calibration | ||
603 | * @no_xtal_calib: some devices do not need crystal calibration data, | ||
604 | * don't send it to those | ||
605 | * @temp_offset_v2: support v2 of temperature offset calibration | ||
606 | * @adv_pm: advanced power management | ||
607 | */ | ||
608 | struct iwl_dvm_cfg { | ||
573 | void (*set_hw_params)(struct iwl_priv *priv); | 609 | void (*set_hw_params)(struct iwl_priv *priv); |
574 | int (*set_channel_switch)(struct iwl_priv *priv, | 610 | int (*set_channel_switch)(struct iwl_priv *priv, |
575 | struct ieee80211_channel_switch *ch_switch); | 611 | struct ieee80211_channel_switch *ch_switch); |
576 | /* device specific configuration */ | ||
577 | void (*nic_config)(struct iwl_priv *priv); | 612 | void (*nic_config)(struct iwl_priv *priv); |
578 | |||
579 | /* temperature */ | ||
580 | void (*temperature)(struct iwl_priv *priv); | 613 | void (*temperature)(struct iwl_priv *priv); |
614 | |||
615 | const struct iwl_dvm_bt_params *bt_params; | ||
616 | s32 chain_noise_scale; | ||
617 | u8 plcp_delta_threshold; | ||
618 | bool adv_thermal_throttle; | ||
619 | bool support_ct_kill_exit; | ||
620 | bool hd_v2; | ||
621 | bool no_idle_support; | ||
622 | bool need_temp_offset_calib; | ||
623 | bool no_xtal_calib; | ||
624 | bool temp_offset_v2; | ||
625 | bool adv_pm; | ||
581 | }; | 626 | }; |
582 | 627 | ||
583 | struct iwl_wipan_noa_data { | 628 | struct iwl_wipan_noa_data { |
@@ -610,7 +655,7 @@ struct iwl_priv { | |||
610 | struct device *dev; /* for debug prints only */ | 655 | struct device *dev; /* for debug prints only */ |
611 | const struct iwl_cfg *cfg; | 656 | const struct iwl_cfg *cfg; |
612 | const struct iwl_fw *fw; | 657 | const struct iwl_fw *fw; |
613 | const struct iwl_lib_ops *lib; | 658 | const struct iwl_dvm_cfg *lib; |
614 | unsigned long status; | 659 | unsigned long status; |
615 | 660 | ||
616 | spinlock_t sta_lock; | 661 | spinlock_t sta_lock; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index c48907c8ab43..352c6cb7b4f1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c | |||
@@ -174,10 +174,13 @@ static void iwl1000_hw_set_hw_params(struct iwl_priv *priv) | |||
174 | priv->hw_params.sens = &iwl1000_sensitivity; | 174 | priv->hw_params.sens = &iwl1000_sensitivity; |
175 | } | 175 | } |
176 | 176 | ||
177 | struct iwl_lib_ops iwl1000_lib = { | 177 | const struct iwl_dvm_cfg iwl_dvm_1000_cfg = { |
178 | .set_hw_params = iwl1000_hw_set_hw_params, | 178 | .set_hw_params = iwl1000_hw_set_hw_params, |
179 | .nic_config = iwl1000_nic_config, | 179 | .nic_config = iwl1000_nic_config, |
180 | .temperature = iwlagn_temperature, | 180 | .temperature = iwlagn_temperature, |
181 | .support_ct_kill_exit = true, | ||
182 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, | ||
183 | .chain_noise_scale = 1000, | ||
181 | }; | 184 | }; |
182 | 185 | ||
183 | 186 | ||
@@ -232,16 +235,56 @@ static void iwl2000_hw_set_hw_params(struct iwl_priv *priv) | |||
232 | priv->hw_params.sens = &iwl2000_sensitivity; | 235 | priv->hw_params.sens = &iwl2000_sensitivity; |
233 | } | 236 | } |
234 | 237 | ||
235 | struct iwl_lib_ops iwl2000_lib = { | 238 | const struct iwl_dvm_cfg iwl_dvm_2000_cfg = { |
236 | .set_hw_params = iwl2000_hw_set_hw_params, | 239 | .set_hw_params = iwl2000_hw_set_hw_params, |
237 | .nic_config = iwl2000_nic_config, | 240 | .nic_config = iwl2000_nic_config, |
238 | .temperature = iwlagn_temperature, | 241 | .temperature = iwlagn_temperature, |
242 | .adv_thermal_throttle = true, | ||
243 | .support_ct_kill_exit = true, | ||
244 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
245 | .chain_noise_scale = 1000, | ||
246 | .hd_v2 = true, | ||
247 | .need_temp_offset_calib = true, | ||
248 | .temp_offset_v2 = true, | ||
239 | }; | 249 | }; |
240 | 250 | ||
241 | struct iwl_lib_ops iwl2030_lib = { | 251 | const struct iwl_dvm_cfg iwl_dvm_105_cfg = { |
242 | .set_hw_params = iwl2000_hw_set_hw_params, | 252 | .set_hw_params = iwl2000_hw_set_hw_params, |
243 | .nic_config = iwl2000_nic_config, | 253 | .nic_config = iwl2000_nic_config, |
244 | .temperature = iwlagn_temperature, | 254 | .temperature = iwlagn_temperature, |
255 | .adv_thermal_throttle = true, | ||
256 | .support_ct_kill_exit = true, | ||
257 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
258 | .chain_noise_scale = 1000, | ||
259 | .hd_v2 = true, | ||
260 | .need_temp_offset_calib = true, | ||
261 | .temp_offset_v2 = true, | ||
262 | .adv_pm = true, | ||
263 | }; | ||
264 | |||
265 | static const struct iwl_dvm_bt_params iwl2030_bt_params = { | ||
266 | /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ | ||
267 | .advanced_bt_coexist = true, | ||
268 | .agg_time_limit = BT_AGG_THRESHOLD_DEF, | ||
269 | .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, | ||
270 | .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32, | ||
271 | .bt_sco_disable = true, | ||
272 | .bt_session_2 = true, | ||
273 | }; | ||
274 | |||
275 | const struct iwl_dvm_cfg iwl_dvm_2030_cfg = { | ||
276 | .set_hw_params = iwl2000_hw_set_hw_params, | ||
277 | .nic_config = iwl2000_nic_config, | ||
278 | .temperature = iwlagn_temperature, | ||
279 | .adv_thermal_throttle = true, | ||
280 | .support_ct_kill_exit = true, | ||
281 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
282 | .chain_noise_scale = 1000, | ||
283 | .hd_v2 = true, | ||
284 | .bt_params = &iwl2030_bt_params, | ||
285 | .need_temp_offset_calib = true, | ||
286 | .temp_offset_v2 = true, | ||
287 | .adv_pm = true, | ||
245 | }; | 288 | }; |
246 | 289 | ||
247 | /* | 290 | /* |
@@ -420,16 +463,23 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, | |||
420 | return iwl_dvm_send_cmd(priv, &hcmd); | 463 | return iwl_dvm_send_cmd(priv, &hcmd); |
421 | } | 464 | } |
422 | 465 | ||
423 | struct iwl_lib_ops iwl5000_lib = { | 466 | const struct iwl_dvm_cfg iwl_dvm_5000_cfg = { |
424 | .set_hw_params = iwl5000_hw_set_hw_params, | 467 | .set_hw_params = iwl5000_hw_set_hw_params, |
425 | .set_channel_switch = iwl5000_hw_channel_switch, | 468 | .set_channel_switch = iwl5000_hw_channel_switch, |
426 | .temperature = iwlagn_temperature, | 469 | .temperature = iwlagn_temperature, |
470 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | ||
471 | .chain_noise_scale = 1000, | ||
472 | .no_idle_support = true, | ||
427 | }; | 473 | }; |
428 | 474 | ||
429 | struct iwl_lib_ops iwl5150_lib = { | 475 | const struct iwl_dvm_cfg iwl_dvm_5150_cfg = { |
430 | .set_hw_params = iwl5150_hw_set_hw_params, | 476 | .set_hw_params = iwl5150_hw_set_hw_params, |
431 | .set_channel_switch = iwl5000_hw_channel_switch, | 477 | .set_channel_switch = iwl5000_hw_channel_switch, |
432 | .temperature = iwl5150_temperature, | 478 | .temperature = iwl5150_temperature, |
479 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | ||
480 | .chain_noise_scale = 1000, | ||
481 | .no_idle_support = true, | ||
482 | .no_xtal_calib = true, | ||
433 | }; | 483 | }; |
434 | 484 | ||
435 | 485 | ||
@@ -584,16 +634,59 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, | |||
584 | return err; | 634 | return err; |
585 | } | 635 | } |
586 | 636 | ||
587 | struct iwl_lib_ops iwl6000_lib = { | 637 | const struct iwl_dvm_cfg iwl_dvm_6000_cfg = { |
588 | .set_hw_params = iwl6000_hw_set_hw_params, | 638 | .set_hw_params = iwl6000_hw_set_hw_params, |
589 | .set_channel_switch = iwl6000_hw_channel_switch, | 639 | .set_channel_switch = iwl6000_hw_channel_switch, |
590 | .nic_config = iwl6000_nic_config, | 640 | .nic_config = iwl6000_nic_config, |
591 | .temperature = iwlagn_temperature, | 641 | .temperature = iwlagn_temperature, |
642 | .adv_thermal_throttle = true, | ||
643 | .support_ct_kill_exit = true, | ||
644 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
645 | .chain_noise_scale = 1000, | ||
646 | }; | ||
647 | |||
648 | const struct iwl_dvm_cfg iwl_dvm_6005_cfg = { | ||
649 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
650 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
651 | .nic_config = iwl6000_nic_config, | ||
652 | .temperature = iwlagn_temperature, | ||
653 | .adv_thermal_throttle = true, | ||
654 | .support_ct_kill_exit = true, | ||
655 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
656 | .chain_noise_scale = 1000, | ||
657 | .need_temp_offset_calib = true, | ||
658 | }; | ||
659 | |||
660 | const struct iwl_dvm_cfg iwl_dvm_6050_cfg = { | ||
661 | .set_hw_params = iwl6000_hw_set_hw_params, | ||
662 | .set_channel_switch = iwl6000_hw_channel_switch, | ||
663 | .nic_config = iwl6000_nic_config, | ||
664 | .temperature = iwlagn_temperature, | ||
665 | .adv_thermal_throttle = true, | ||
666 | .support_ct_kill_exit = true, | ||
667 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
668 | .chain_noise_scale = 1500, | ||
669 | }; | ||
670 | |||
671 | static const struct iwl_dvm_bt_params iwl6000_bt_params = { | ||
672 | /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ | ||
673 | .advanced_bt_coexist = true, | ||
674 | .agg_time_limit = BT_AGG_THRESHOLD_DEF, | ||
675 | .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, | ||
676 | .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, | ||
677 | .bt_sco_disable = true, | ||
592 | }; | 678 | }; |
593 | 679 | ||
594 | struct iwl_lib_ops iwl6030_lib = { | 680 | const struct iwl_dvm_cfg iwl_dvm_6030_cfg = { |
595 | .set_hw_params = iwl6000_hw_set_hw_params, | 681 | .set_hw_params = iwl6000_hw_set_hw_params, |
596 | .set_channel_switch = iwl6000_hw_channel_switch, | 682 | .set_channel_switch = iwl6000_hw_channel_switch, |
597 | .nic_config = iwl6000_nic_config, | 683 | .nic_config = iwl6000_nic_config, |
598 | .temperature = iwlagn_temperature, | 684 | .temperature = iwlagn_temperature, |
685 | .adv_thermal_throttle = true, | ||
686 | .support_ct_kill_exit = true, | ||
687 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
688 | .chain_noise_scale = 1000, | ||
689 | .bt_params = &iwl6000_bt_params, | ||
690 | .need_temp_offset_calib = true, | ||
691 | .adv_pm = true, | ||
599 | }; | 692 | }; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 54f553380aa8..9879550a0fea 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c | |||
@@ -254,23 +254,23 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) | |||
254 | BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != | 254 | BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != |
255 | sizeof(basic.bt3_lookup_table)); | 255 | sizeof(basic.bt3_lookup_table)); |
256 | 256 | ||
257 | if (priv->cfg->bt_params) { | 257 | if (priv->lib->bt_params) { |
258 | /* | 258 | /* |
259 | * newer generation of devices (2000 series and newer) | 259 | * newer generation of devices (2000 series and newer) |
260 | * use the version 2 of the bt command | 260 | * use the version 2 of the bt command |
261 | * we need to make sure sending the host command | 261 | * we need to make sure sending the host command |
262 | * with correct data structure to avoid uCode assert | 262 | * with correct data structure to avoid uCode assert |
263 | */ | 263 | */ |
264 | if (priv->cfg->bt_params->bt_session_2) { | 264 | if (priv->lib->bt_params->bt_session_2) { |
265 | bt_cmd_v2.prio_boost = cpu_to_le32( | 265 | bt_cmd_v2.prio_boost = cpu_to_le32( |
266 | priv->cfg->bt_params->bt_prio_boost); | 266 | priv->lib->bt_params->bt_prio_boost); |
267 | bt_cmd_v2.tx_prio_boost = 0; | 267 | bt_cmd_v2.tx_prio_boost = 0; |
268 | bt_cmd_v2.rx_prio_boost = 0; | 268 | bt_cmd_v2.rx_prio_boost = 0; |
269 | } else { | 269 | } else { |
270 | /* older version only has 8 bits */ | 270 | /* older version only has 8 bits */ |
271 | WARN_ON(priv->cfg->bt_params->bt_prio_boost & ~0xFF); | 271 | WARN_ON(priv->lib->bt_params->bt_prio_boost & ~0xFF); |
272 | bt_cmd_v1.prio_boost = | 272 | bt_cmd_v1.prio_boost = |
273 | priv->cfg->bt_params->bt_prio_boost; | 273 | priv->lib->bt_params->bt_prio_boost; |
274 | bt_cmd_v1.tx_prio_boost = 0; | 274 | bt_cmd_v1.tx_prio_boost = 0; |
275 | bt_cmd_v1.rx_prio_boost = 0; | 275 | bt_cmd_v1.rx_prio_boost = 0; |
276 | } | 276 | } |
@@ -330,7 +330,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) | |||
330 | priv->bt_full_concurrent ? | 330 | priv->bt_full_concurrent ? |
331 | "full concurrency" : "3-wire"); | 331 | "full concurrency" : "3-wire"); |
332 | 332 | ||
333 | if (priv->cfg->bt_params->bt_session_2) { | 333 | if (priv->lib->bt_params->bt_session_2) { |
334 | memcpy(&bt_cmd_v2.basic, &basic, | 334 | memcpy(&bt_cmd_v2.basic, &basic, |
335 | sizeof(basic)); | 335 | sizeof(basic)); |
336 | ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, | 336 | ret = iwl_dvm_send_cmd_pdu(priv, REPLY_BT_CONFIG, |
@@ -758,8 +758,8 @@ static bool is_single_rx_stream(struct iwl_priv *priv) | |||
758 | */ | 758 | */ |
759 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | 759 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) |
760 | { | 760 | { |
761 | if (priv->cfg->bt_params && | 761 | if (priv->lib->bt_params && |
762 | priv->cfg->bt_params->advanced_bt_coexist && | 762 | priv->lib->bt_params->advanced_bt_coexist && |
763 | (priv->bt_full_concurrent || | 763 | (priv->bt_full_concurrent || |
764 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | 764 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { |
765 | /* | 765 | /* |
@@ -830,8 +830,8 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
830 | else | 830 | else |
831 | active_chains = priv->nvm_data->valid_rx_ant; | 831 | active_chains = priv->nvm_data->valid_rx_ant; |
832 | 832 | ||
833 | if (priv->cfg->bt_params && | 833 | if (priv->lib->bt_params && |
834 | priv->cfg->bt_params->advanced_bt_coexist && | 834 | priv->lib->bt_params->advanced_bt_coexist && |
835 | (priv->bt_full_concurrent || | 835 | (priv->bt_full_concurrent || |
836 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | 836 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { |
837 | /* | 837 | /* |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 661b5e71aac8..f10c755d952c 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -427,6 +427,10 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | |||
427 | if (ret) | 427 | if (ret) |
428 | goto error; | 428 | goto error; |
429 | 429 | ||
430 | /* let the ucode operate on its own */ | ||
431 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, | ||
432 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
433 | |||
430 | iwl_trans_d3_suspend(priv->trans); | 434 | iwl_trans_d3_suspend(priv->trans); |
431 | 435 | ||
432 | goto out; | 436 | goto out; |
@@ -510,6 +514,10 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
510 | goto out_unlock; | 514 | goto out_unlock; |
511 | } | 515 | } |
512 | 516 | ||
517 | /* uCode is no longer operating by itself */ | ||
518 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, | ||
519 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
520 | |||
513 | base = priv->device_pointers.error_event_table; | 521 | base = priv->device_pointers.error_event_table; |
514 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { | 522 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { |
515 | IWL_WARN(priv, "Invalid error table during resume!\n"); | 523 | IWL_WARN(priv, "Invalid error table during resume!\n"); |
@@ -1277,8 +1285,8 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, | |||
1277 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 1285 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
1278 | mutex_lock(&priv->mutex); | 1286 | mutex_lock(&priv->mutex); |
1279 | 1287 | ||
1280 | if (priv->cfg->bt_params && | 1288 | if (priv->lib->bt_params && |
1281 | priv->cfg->bt_params->advanced_bt_coexist) { | 1289 | priv->lib->bt_params->advanced_bt_coexist) { |
1282 | if (rssi_event == RSSI_EVENT_LOW) | 1290 | if (rssi_event == RSSI_EVENT_LOW) |
1283 | priv->bt_enable_pspoll = true; | 1291 | priv->bt_enable_pspoll = true; |
1284 | else if (rssi_event == RSSI_EVENT_HIGH) | 1292 | else if (rssi_event == RSSI_EVENT_HIGH) |
@@ -1388,7 +1396,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, | |||
1388 | return err; | 1396 | return err; |
1389 | } | 1397 | } |
1390 | 1398 | ||
1391 | if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && | 1399 | if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist && |
1392 | vif->type == NL80211_IFTYPE_ADHOC) { | 1400 | vif->type == NL80211_IFTYPE_ADHOC) { |
1393 | /* | 1401 | /* |
1394 | * pretend to have high BT traffic as long as we | 1402 | * pretend to have high BT traffic as long as we |
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 74d7572e7091..68f754659570 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c | |||
@@ -615,7 +615,7 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) | |||
615 | 615 | ||
616 | priv->thermal_throttle.ct_kill_toggle = false; | 616 | priv->thermal_throttle.ct_kill_toggle = false; |
617 | 617 | ||
618 | if (priv->cfg->base_params->support_ct_kill_exit) { | 618 | if (priv->lib->support_ct_kill_exit) { |
619 | adv_cmd.critical_temperature_enter = | 619 | adv_cmd.critical_temperature_enter = |
620 | cpu_to_le32(priv->hw_params.ct_kill_threshold); | 620 | cpu_to_le32(priv->hw_params.ct_kill_threshold); |
621 | adv_cmd.critical_temperature_exit = | 621 | adv_cmd.critical_temperature_exit = |
@@ -732,10 +732,10 @@ int iwl_alive_start(struct iwl_priv *priv) | |||
732 | } | 732 | } |
733 | 733 | ||
734 | /* download priority table before any calibration request */ | 734 | /* download priority table before any calibration request */ |
735 | if (priv->cfg->bt_params && | 735 | if (priv->lib->bt_params && |
736 | priv->cfg->bt_params->advanced_bt_coexist) { | 736 | priv->lib->bt_params->advanced_bt_coexist) { |
737 | /* Configure Bluetooth device coexistence support */ | 737 | /* Configure Bluetooth device coexistence support */ |
738 | if (priv->cfg->bt_params->bt_sco_disable) | 738 | if (priv->lib->bt_params->bt_sco_disable) |
739 | priv->bt_enable_pspoll = false; | 739 | priv->bt_enable_pspoll = false; |
740 | else | 740 | else |
741 | priv->bt_enable_pspoll = true; | 741 | priv->bt_enable_pspoll = true; |
@@ -873,9 +873,9 @@ void iwl_down(struct iwl_priv *priv) | |||
873 | priv->bt_status = 0; | 873 | priv->bt_status = 0; |
874 | priv->cur_rssi_ctx = NULL; | 874 | priv->cur_rssi_ctx = NULL; |
875 | priv->bt_is_sco = 0; | 875 | priv->bt_is_sco = 0; |
876 | if (priv->cfg->bt_params) | 876 | if (priv->lib->bt_params) |
877 | priv->bt_traffic_load = | 877 | priv->bt_traffic_load = |
878 | priv->cfg->bt_params->bt_init_traffic_load; | 878 | priv->lib->bt_params->bt_init_traffic_load; |
879 | else | 879 | else |
880 | priv->bt_traffic_load = 0; | 880 | priv->bt_traffic_load = 0; |
881 | priv->bt_full_concurrent = false; | 881 | priv->bt_full_concurrent = false; |
@@ -1058,7 +1058,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
1058 | 1058 | ||
1059 | iwl_setup_scan_deferred_work(priv); | 1059 | iwl_setup_scan_deferred_work(priv); |
1060 | 1060 | ||
1061 | if (priv->cfg->bt_params) | 1061 | if (priv->lib->bt_params) |
1062 | iwlagn_bt_setup_deferred_work(priv); | 1062 | iwlagn_bt_setup_deferred_work(priv); |
1063 | 1063 | ||
1064 | init_timer(&priv->statistics_periodic); | 1064 | init_timer(&priv->statistics_periodic); |
@@ -1072,7 +1072,7 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) | |||
1072 | 1072 | ||
1073 | void iwl_cancel_deferred_work(struct iwl_priv *priv) | 1073 | void iwl_cancel_deferred_work(struct iwl_priv *priv) |
1074 | { | 1074 | { |
1075 | if (priv->cfg->bt_params) | 1075 | if (priv->lib->bt_params) |
1076 | iwlagn_bt_cancel_deferred_work(priv); | 1076 | iwlagn_bt_cancel_deferred_work(priv); |
1077 | 1077 | ||
1078 | cancel_work_sync(&priv->run_time_calib_work); | 1078 | cancel_work_sync(&priv->run_time_calib_work); |
@@ -1098,8 +1098,7 @@ static int iwl_init_drv(struct iwl_priv *priv) | |||
1098 | 1098 | ||
1099 | priv->band = IEEE80211_BAND_2GHZ; | 1099 | priv->band = IEEE80211_BAND_2GHZ; |
1100 | 1100 | ||
1101 | priv->plcp_delta_threshold = | 1101 | priv->plcp_delta_threshold = priv->lib->plcp_delta_threshold; |
1102 | priv->cfg->base_params->plcp_delta_threshold; | ||
1103 | 1102 | ||
1104 | priv->iw_mode = NL80211_IFTYPE_STATION; | 1103 | priv->iw_mode = NL80211_IFTYPE_STATION; |
1105 | priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; | 1104 | priv->current_ht_config.smps = IEEE80211_SMPS_STATIC; |
@@ -1116,8 +1115,8 @@ static int iwl_init_drv(struct iwl_priv *priv) | |||
1116 | iwl_init_scan_params(priv); | 1115 | iwl_init_scan_params(priv); |
1117 | 1116 | ||
1118 | /* init bt coex */ | 1117 | /* init bt coex */ |
1119 | if (priv->cfg->bt_params && | 1118 | if (priv->lib->bt_params && |
1120 | priv->cfg->bt_params->advanced_bt_coexist) { | 1119 | priv->lib->bt_params->advanced_bt_coexist) { |
1121 | priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; | 1120 | priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT; |
1122 | priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; | 1121 | priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT; |
1123 | priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; | 1122 | priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK; |
@@ -1264,31 +1263,37 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, | |||
1264 | switch (priv->cfg->device_family) { | 1263 | switch (priv->cfg->device_family) { |
1265 | case IWL_DEVICE_FAMILY_1000: | 1264 | case IWL_DEVICE_FAMILY_1000: |
1266 | case IWL_DEVICE_FAMILY_100: | 1265 | case IWL_DEVICE_FAMILY_100: |
1267 | priv->lib = &iwl1000_lib; | 1266 | priv->lib = &iwl_dvm_1000_cfg; |
1268 | break; | 1267 | break; |
1269 | case IWL_DEVICE_FAMILY_2000: | 1268 | case IWL_DEVICE_FAMILY_2000: |
1269 | priv->lib = &iwl_dvm_2000_cfg; | ||
1270 | break; | ||
1270 | case IWL_DEVICE_FAMILY_105: | 1271 | case IWL_DEVICE_FAMILY_105: |
1271 | priv->lib = &iwl2000_lib; | 1272 | priv->lib = &iwl_dvm_105_cfg; |
1272 | break; | 1273 | break; |
1273 | case IWL_DEVICE_FAMILY_2030: | 1274 | case IWL_DEVICE_FAMILY_2030: |
1274 | case IWL_DEVICE_FAMILY_135: | 1275 | case IWL_DEVICE_FAMILY_135: |
1275 | priv->lib = &iwl2030_lib; | 1276 | priv->lib = &iwl_dvm_2030_cfg; |
1276 | break; | 1277 | break; |
1277 | case IWL_DEVICE_FAMILY_5000: | 1278 | case IWL_DEVICE_FAMILY_5000: |
1278 | priv->lib = &iwl5000_lib; | 1279 | priv->lib = &iwl_dvm_5000_cfg; |
1279 | break; | 1280 | break; |
1280 | case IWL_DEVICE_FAMILY_5150: | 1281 | case IWL_DEVICE_FAMILY_5150: |
1281 | priv->lib = &iwl5150_lib; | 1282 | priv->lib = &iwl_dvm_5150_cfg; |
1282 | break; | 1283 | break; |
1283 | case IWL_DEVICE_FAMILY_6000: | 1284 | case IWL_DEVICE_FAMILY_6000: |
1284 | case IWL_DEVICE_FAMILY_6005: | ||
1285 | case IWL_DEVICE_FAMILY_6000i: | 1285 | case IWL_DEVICE_FAMILY_6000i: |
1286 | priv->lib = &iwl_dvm_6000_cfg; | ||
1287 | break; | ||
1288 | case IWL_DEVICE_FAMILY_6005: | ||
1289 | priv->lib = &iwl_dvm_6005_cfg; | ||
1290 | break; | ||
1286 | case IWL_DEVICE_FAMILY_6050: | 1291 | case IWL_DEVICE_FAMILY_6050: |
1287 | case IWL_DEVICE_FAMILY_6150: | 1292 | case IWL_DEVICE_FAMILY_6150: |
1288 | priv->lib = &iwl6000_lib; | 1293 | priv->lib = &iwl_dvm_6050_cfg; |
1289 | break; | 1294 | break; |
1290 | case IWL_DEVICE_FAMILY_6030: | 1295 | case IWL_DEVICE_FAMILY_6030: |
1291 | priv->lib = &iwl6030_lib; | 1296 | priv->lib = &iwl_dvm_6030_cfg; |
1292 | break; | 1297 | break; |
1293 | default: | 1298 | default: |
1294 | break; | 1299 | break; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c index bd69018d07a9..77cb59712235 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/iwlwifi/dvm/power.c | |||
@@ -163,7 +163,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, | |||
163 | u8 skip; | 163 | u8 skip; |
164 | u32 slp_itrvl; | 164 | u32 slp_itrvl; |
165 | 165 | ||
166 | if (priv->cfg->adv_pm) { | 166 | if (priv->lib->adv_pm) { |
167 | table = apm_range_2; | 167 | table = apm_range_2; |
168 | if (period <= IWL_DTIM_RANGE_1_MAX) | 168 | if (period <= IWL_DTIM_RANGE_1_MAX) |
169 | table = apm_range_1; | 169 | table = apm_range_1; |
@@ -217,7 +217,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, | |||
217 | cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; | 217 | cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; |
218 | 218 | ||
219 | if (iwl_advanced_bt_coexist(priv)) { | 219 | if (iwl_advanced_bt_coexist(priv)) { |
220 | if (!priv->cfg->bt_params->bt_sco_disable) | 220 | if (!priv->lib->bt_params->bt_sco_disable) |
221 | cmd->flags |= IWL_POWER_BT_SCO_ENA; | 221 | cmd->flags |= IWL_POWER_BT_SCO_ENA; |
222 | else | 222 | else |
223 | cmd->flags &= ~IWL_POWER_BT_SCO_ENA; | 223 | cmd->flags &= ~IWL_POWER_BT_SCO_ENA; |
@@ -293,7 +293,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, | |||
293 | 293 | ||
294 | if (priv->wowlan) | 294 | if (priv->wowlan) |
295 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); | 295 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); |
296 | else if (!priv->cfg->base_params->no_idle_support && | 296 | else if (!priv->lib->no_idle_support && |
297 | priv->hw->conf.flags & IEEE80211_CONF_IDLE) | 297 | priv->hw->conf.flags & IEEE80211_CONF_IDLE) |
298 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); | 298 | iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); |
299 | else if (iwl_tt_is_low_power_state(priv)) { | 299 | else if (iwl_tt_is_low_power_state(priv)) { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 907bd6e50aad..94314a8e1029 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -1088,7 +1088,7 @@ done: | |||
1088 | (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate)) | 1088 | (priv->tm_fixed_rate != lq_sta->dbg_fixed_rate)) |
1089 | rs_program_fix_rate(priv, lq_sta); | 1089 | rs_program_fix_rate(priv, lq_sta); |
1090 | #endif | 1090 | #endif |
1091 | if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) | 1091 | if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist) |
1092 | rs_bt_update_lq(priv, ctx, lq_sta); | 1092 | rs_bt_update_lq(priv, ctx, lq_sta); |
1093 | } | 1093 | } |
1094 | 1094 | ||
@@ -3064,11 +3064,11 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, | |||
3064 | * overwrite if needed, pass aggregation time limit | 3064 | * overwrite if needed, pass aggregation time limit |
3065 | * to uCode in uSec | 3065 | * to uCode in uSec |
3066 | */ | 3066 | */ |
3067 | if (priv && priv->cfg->bt_params && | 3067 | if (priv && priv->lib->bt_params && |
3068 | priv->cfg->bt_params->agg_time_limit && | 3068 | priv->lib->bt_params->agg_time_limit && |
3069 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) | 3069 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) |
3070 | lq_cmd->agg_params.agg_time_limit = | 3070 | lq_cmd->agg_params.agg_time_limit = |
3071 | cpu_to_le16(priv->cfg->bt_params->agg_time_limit); | 3071 | cpu_to_le16(priv->lib->bt_params->agg_time_limit); |
3072 | } | 3072 | } |
3073 | 3073 | ||
3074 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 3074 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index a4eed2055fdb..2f3fd160ab44 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -1102,7 +1102,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) | |||
1102 | iwl_notification_wait_init(&priv->notif_wait); | 1102 | iwl_notification_wait_init(&priv->notif_wait); |
1103 | 1103 | ||
1104 | /* Set up BT Rx handlers */ | 1104 | /* Set up BT Rx handlers */ |
1105 | if (priv->cfg->bt_params) | 1105 | if (priv->lib->bt_params) |
1106 | iwlagn_bt_rx_handler_setup(priv); | 1106 | iwlagn_bt_rx_handler_setup(priv); |
1107 | } | 1107 | } |
1108 | 1108 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index d69b55866714..8c686a5b90ac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c | |||
@@ -801,8 +801,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
801 | * Internal scans are passive, so we can indiscriminately set | 801 | * Internal scans are passive, so we can indiscriminately set |
802 | * the BT ignore flag on 2.4 GHz since it applies to TX only. | 802 | * the BT ignore flag on 2.4 GHz since it applies to TX only. |
803 | */ | 803 | */ |
804 | if (priv->cfg->bt_params && | 804 | if (priv->lib->bt_params && |
805 | priv->cfg->bt_params->advanced_bt_coexist) | 805 | priv->lib->bt_params->advanced_bt_coexist) |
806 | scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; | 806 | scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; |
807 | break; | 807 | break; |
808 | case IEEE80211_BAND_5GHZ: | 808 | case IEEE80211_BAND_5GHZ: |
@@ -844,8 +844,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
844 | band = priv->scan_band; | 844 | band = priv->scan_band; |
845 | 845 | ||
846 | if (band == IEEE80211_BAND_2GHZ && | 846 | if (band == IEEE80211_BAND_2GHZ && |
847 | priv->cfg->bt_params && | 847 | priv->lib->bt_params && |
848 | priv->cfg->bt_params->advanced_bt_coexist) { | 848 | priv->lib->bt_params->advanced_bt_coexist) { |
849 | /* transmit 2.4 GHz probes only on first antenna */ | 849 | /* transmit 2.4 GHz probes only on first antenna */ |
850 | scan_tx_antennas = first_antenna(scan_tx_antennas); | 850 | scan_tx_antennas = first_antenna(scan_tx_antennas); |
851 | } | 851 | } |
@@ -873,8 +873,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | |||
873 | 873 | ||
874 | rx_ant = first_antenna(active_chains); | 874 | rx_ant = first_antenna(active_chains); |
875 | } | 875 | } |
876 | if (priv->cfg->bt_params && | 876 | if (priv->lib->bt_params && |
877 | priv->cfg->bt_params->advanced_bt_coexist && | 877 | priv->lib->bt_params->advanced_bt_coexist && |
878 | priv->bt_full_concurrent) { | 878 | priv->bt_full_concurrent) { |
879 | /* operated as 1x1 in full concurrency mode */ | 879 | /* operated as 1x1 in full concurrency mode */ |
880 | rx_ant = first_antenna(rx_ant); | 880 | rx_ant = first_antenna(rx_ant); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index db183b44e038..c3c13ce96eb0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -735,7 +735,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | |||
735 | memcpy(&lq, priv->stations[i].lq, | 735 | memcpy(&lq, priv->stations[i].lq, |
736 | sizeof(struct iwl_link_quality_cmd)); | 736 | sizeof(struct iwl_link_quality_cmd)); |
737 | 737 | ||
738 | if (!memcmp(&lq, &zero_lq, sizeof(lq))) | 738 | if (memcmp(&lq, &zero_lq, sizeof(lq))) |
739 | send_lq = true; | 739 | send_lq = true; |
740 | } | 740 | } |
741 | spin_unlock_bh(&priv->sta_lock); | 741 | spin_unlock_bh(&priv->sta_lock); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index 03f9bc01c0cc..fbeee081ee2f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c | |||
@@ -627,7 +627,7 @@ void iwl_tt_initialize(struct iwl_priv *priv) | |||
627 | INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); | 627 | INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter); |
628 | INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); | 628 | INIT_WORK(&priv->ct_exit, iwl_bg_ct_exit); |
629 | 629 | ||
630 | if (priv->cfg->base_params->adv_thermal_throttle) { | 630 | if (priv->lib->adv_thermal_throttle) { |
631 | IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n"); | 631 | IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n"); |
632 | tt->restriction = kcalloc(IWL_TI_STATE_MAX, | 632 | tt->restriction = kcalloc(IWL_TI_STATE_MAX, |
633 | sizeof(struct iwl_tt_restriction), | 633 | sizeof(struct iwl_tt_restriction), |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index a900aaf47790..353a053b4eb1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -83,8 +83,8 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, | |||
83 | else if (ieee80211_is_back_req(fc)) | 83 | else if (ieee80211_is_back_req(fc)) |
84 | tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; | 84 | tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; |
85 | else if (info->band == IEEE80211_BAND_2GHZ && | 85 | else if (info->band == IEEE80211_BAND_2GHZ && |
86 | priv->cfg->bt_params && | 86 | priv->lib->bt_params && |
87 | priv->cfg->bt_params->advanced_bt_coexist && | 87 | priv->lib->bt_params->advanced_bt_coexist && |
88 | (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || | 88 | (ieee80211_is_auth(fc) || ieee80211_is_assoc_req(fc) || |
89 | ieee80211_is_reassoc_req(fc) || | 89 | ieee80211_is_reassoc_req(fc) || |
90 | skb->protocol == cpu_to_be16(ETH_P_PAE))) | 90 | skb->protocol == cpu_to_be16(ETH_P_PAE))) |
@@ -202,8 +202,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | |||
202 | rate_flags |= RATE_MCS_CCK_MSK; | 202 | rate_flags |= RATE_MCS_CCK_MSK; |
203 | 203 | ||
204 | /* Set up antennas */ | 204 | /* Set up antennas */ |
205 | if (priv->cfg->bt_params && | 205 | if (priv->lib->bt_params && |
206 | priv->cfg->bt_params->advanced_bt_coexist && | 206 | priv->lib->bt_params->advanced_bt_coexist && |
207 | priv->bt_full_concurrent) { | 207 | priv->bt_full_concurrent) { |
208 | /* operated as 1x1 in full concurrency mode */ | 208 | /* operated as 1x1 in full concurrency mode */ |
209 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, | 209 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, |
@@ -986,8 +986,8 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, | |||
986 | * notification again. | 986 | * notification again. |
987 | */ | 987 | */ |
988 | if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && | 988 | if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && |
989 | priv->cfg->bt_params && | 989 | priv->lib->bt_params && |
990 | priv->cfg->bt_params->advanced_bt_coexist) { | 990 | priv->lib->bt_params->advanced_bt_coexist) { |
991 | IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); | 991 | IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); |
992 | } | 992 | } |
993 | 993 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 0a1cdc5e856b..86270b69cd02 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c | |||
@@ -132,8 +132,8 @@ int iwl_init_alive_start(struct iwl_priv *priv) | |||
132 | { | 132 | { |
133 | int ret; | 133 | int ret; |
134 | 134 | ||
135 | if (priv->cfg->bt_params && | 135 | if (priv->lib->bt_params && |
136 | priv->cfg->bt_params->advanced_bt_coexist) { | 136 | priv->lib->bt_params->advanced_bt_coexist) { |
137 | /* | 137 | /* |
138 | * Tell uCode we are ready to perform calibration | 138 | * Tell uCode we are ready to perform calibration |
139 | * need to perform this before any calibration | 139 | * need to perform this before any calibration |
@@ -155,8 +155,8 @@ int iwl_init_alive_start(struct iwl_priv *priv) | |||
155 | * temperature offset calibration is only needed for runtime ucode, | 155 | * temperature offset calibration is only needed for runtime ucode, |
156 | * so prepare the value now. | 156 | * so prepare the value now. |
157 | */ | 157 | */ |
158 | if (priv->cfg->need_temp_offset_calib) { | 158 | if (priv->lib->need_temp_offset_calib) { |
159 | if (priv->cfg->temp_offset_v2) | 159 | if (priv->lib->temp_offset_v2) |
160 | return iwl_set_temperature_offset_calib_v2(priv); | 160 | return iwl_set_temperature_offset_calib_v2(priv); |
161 | else | 161 | else |
162 | return iwl_set_temperature_offset_calib(priv); | 162 | return iwl_set_temperature_offset_calib(priv); |
@@ -277,7 +277,7 @@ static int iwl_alive_notify(struct iwl_priv *priv) | |||
277 | if (ret) | 277 | if (ret) |
278 | return ret; | 278 | return ret; |
279 | 279 | ||
280 | if (!priv->cfg->no_xtal_calib) { | 280 | if (!priv->lib->no_xtal_calib) { |
281 | ret = iwl_set_Xtal_calib(priv); | 281 | ret = iwl_set_Xtal_calib(priv); |
282 | if (ret) | 282 | if (ret) |
283 | return ret; | 283 | return ret; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index c080ae3070b2..0d2afe098afc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c | |||
@@ -60,9 +60,6 @@ static const struct iwl_base_params iwl1000_base_params = { | |||
60 | .max_ll_items = OTP_MAX_LL_ITEMS_1000, | 60 | .max_ll_items = OTP_MAX_LL_ITEMS_1000, |
61 | .shadow_ram_support = false, | 61 | .shadow_ram_support = false, |
62 | .led_compensation = 51, | 62 | .led_compensation = 51, |
63 | .support_ct_kill_exit = true, | ||
64 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, | ||
65 | .chain_noise_scale = 1000, | ||
66 | .wd_timeout = IWL_WATCHDOG_DISABLED, | 63 | .wd_timeout = IWL_WATCHDOG_DISABLED, |
67 | .max_event_log_size = 128, | 64 | .max_event_log_size = 128, |
68 | }; | 65 | }; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index a6ddd2f9fba0..c727ec7c90a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c | |||
@@ -72,14 +72,9 @@ static const struct iwl_base_params iwl2000_base_params = { | |||
72 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, | 72 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, |
73 | .shadow_ram_support = true, | 73 | .shadow_ram_support = true, |
74 | .led_compensation = 51, | 74 | .led_compensation = 51, |
75 | .adv_thermal_throttle = true, | ||
76 | .support_ct_kill_exit = true, | ||
77 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
78 | .chain_noise_scale = 1000, | ||
79 | .wd_timeout = IWL_DEF_WD_TIMEOUT, | 75 | .wd_timeout = IWL_DEF_WD_TIMEOUT, |
80 | .max_event_log_size = 512, | 76 | .max_event_log_size = 512, |
81 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 77 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ |
82 | .hd_v2 = true, | ||
83 | }; | 78 | }; |
84 | 79 | ||
85 | 80 | ||
@@ -90,14 +85,9 @@ static const struct iwl_base_params iwl2030_base_params = { | |||
90 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, | 85 | .max_ll_items = OTP_MAX_LL_ITEMS_2x00, |
91 | .shadow_ram_support = true, | 86 | .shadow_ram_support = true, |
92 | .led_compensation = 57, | 87 | .led_compensation = 57, |
93 | .adv_thermal_throttle = true, | ||
94 | .support_ct_kill_exit = true, | ||
95 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
96 | .chain_noise_scale = 1000, | ||
97 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | 88 | .wd_timeout = IWL_LONG_WD_TIMEOUT, |
98 | .max_event_log_size = 512, | 89 | .max_event_log_size = 512, |
99 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 90 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ |
100 | .hd_v2 = true, | ||
101 | }; | 91 | }; |
102 | 92 | ||
103 | static const struct iwl_ht_params iwl2000_ht_params = { | 93 | static const struct iwl_ht_params iwl2000_ht_params = { |
@@ -106,16 +96,6 @@ static const struct iwl_ht_params iwl2000_ht_params = { | |||
106 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ), | 96 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ), |
107 | }; | 97 | }; |
108 | 98 | ||
109 | static const struct iwl_bt_params iwl2030_bt_params = { | ||
110 | /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ | ||
111 | .advanced_bt_coexist = true, | ||
112 | .agg_time_limit = BT_AGG_THRESHOLD_DEF, | ||
113 | .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, | ||
114 | .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32, | ||
115 | .bt_sco_disable = true, | ||
116 | .bt_session_2 = true, | ||
117 | }; | ||
118 | |||
119 | static const struct iwl_eeprom_params iwl20x0_eeprom_params = { | 99 | static const struct iwl_eeprom_params iwl20x0_eeprom_params = { |
120 | .regulatory_bands = { | 100 | .regulatory_bands = { |
121 | EEPROM_REG_BAND_1_CHANNELS, | 101 | EEPROM_REG_BAND_1_CHANNELS, |
@@ -137,12 +117,10 @@ static const struct iwl_eeprom_params iwl20x0_eeprom_params = { | |||
137 | .device_family = IWL_DEVICE_FAMILY_2000, \ | 117 | .device_family = IWL_DEVICE_FAMILY_2000, \ |
138 | .max_inst_size = IWL60_RTC_INST_SIZE, \ | 118 | .max_inst_size = IWL60_RTC_INST_SIZE, \ |
139 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | 119 | .max_data_size = IWL60_RTC_DATA_SIZE, \ |
140 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ | 120 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ |
141 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 121 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
142 | .base_params = &iwl2000_base_params, \ | 122 | .base_params = &iwl2000_base_params, \ |
143 | .eeprom_params = &iwl20x0_eeprom_params, \ | 123 | .eeprom_params = &iwl20x0_eeprom_params, \ |
144 | .need_temp_offset_calib = true, \ | ||
145 | .temp_offset_v2 = true, \ | ||
146 | .led_mode = IWL_LED_RF_STATE | 124 | .led_mode = IWL_LED_RF_STATE |
147 | 125 | ||
148 | const struct iwl_cfg iwl2000_2bgn_cfg = { | 126 | const struct iwl_cfg iwl2000_2bgn_cfg = { |
@@ -168,12 +146,8 @@ const struct iwl_cfg iwl2000_2bgn_d_cfg = { | |||
168 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ | 146 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ |
169 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 147 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
170 | .base_params = &iwl2030_base_params, \ | 148 | .base_params = &iwl2030_base_params, \ |
171 | .bt_params = &iwl2030_bt_params, \ | ||
172 | .eeprom_params = &iwl20x0_eeprom_params, \ | 149 | .eeprom_params = &iwl20x0_eeprom_params, \ |
173 | .need_temp_offset_calib = true, \ | 150 | .led_mode = IWL_LED_RF_STATE |
174 | .temp_offset_v2 = true, \ | ||
175 | .led_mode = IWL_LED_RF_STATE, \ | ||
176 | .adv_pm = true | ||
177 | 151 | ||
178 | const struct iwl_cfg iwl2030_2bgn_cfg = { | 152 | const struct iwl_cfg iwl2030_2bgn_cfg = { |
179 | .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", | 153 | .name = "Intel(R) Centrino(R) Wireless-N 2230 BGN", |
@@ -193,10 +167,7 @@ const struct iwl_cfg iwl2030_2bgn_cfg = { | |||
193 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 167 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
194 | .base_params = &iwl2000_base_params, \ | 168 | .base_params = &iwl2000_base_params, \ |
195 | .eeprom_params = &iwl20x0_eeprom_params, \ | 169 | .eeprom_params = &iwl20x0_eeprom_params, \ |
196 | .need_temp_offset_calib = true, \ | ||
197 | .temp_offset_v2 = true, \ | ||
198 | .led_mode = IWL_LED_RF_STATE, \ | 170 | .led_mode = IWL_LED_RF_STATE, \ |
199 | .adv_pm = true, \ | ||
200 | .rx_with_siso_diversity = true | 171 | .rx_with_siso_diversity = true |
201 | 172 | ||
202 | const struct iwl_cfg iwl105_bgn_cfg = { | 173 | const struct iwl_cfg iwl105_bgn_cfg = { |
@@ -222,12 +193,8 @@ const struct iwl_cfg iwl105_bgn_d_cfg = { | |||
222 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ | 193 | .nvm_ver = EEPROM_2000_EEPROM_VERSION, \ |
223 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ | 194 | .nvm_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ |
224 | .base_params = &iwl2030_base_params, \ | 195 | .base_params = &iwl2030_base_params, \ |
225 | .bt_params = &iwl2030_bt_params, \ | ||
226 | .eeprom_params = &iwl20x0_eeprom_params, \ | 196 | .eeprom_params = &iwl20x0_eeprom_params, \ |
227 | .need_temp_offset_calib = true, \ | ||
228 | .temp_offset_v2 = true, \ | ||
229 | .led_mode = IWL_LED_RF_STATE, \ | 197 | .led_mode = IWL_LED_RF_STATE, \ |
230 | .adv_pm = true, \ | ||
231 | .rx_with_siso_diversity = true | 198 | .rx_with_siso_diversity = true |
232 | 199 | ||
233 | const struct iwl_cfg iwl135_bgn_cfg = { | 200 | const struct iwl_cfg iwl135_bgn_cfg = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 403f3f224bf6..ecc01e1a61a1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -59,11 +59,8 @@ static const struct iwl_base_params iwl5000_base_params = { | |||
59 | .num_of_queues = IWLAGN_NUM_QUEUES, | 59 | .num_of_queues = IWLAGN_NUM_QUEUES, |
60 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, | 60 | .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, |
61 | .led_compensation = 51, | 61 | .led_compensation = 51, |
62 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, | ||
63 | .chain_noise_scale = 1000, | ||
64 | .wd_timeout = IWL_WATCHDOG_DISABLED, | 62 | .wd_timeout = IWL_WATCHDOG_DISABLED, |
65 | .max_event_log_size = 512, | 63 | .max_event_log_size = 512, |
66 | .no_idle_support = true, | ||
67 | }; | 64 | }; |
68 | 65 | ||
69 | static const struct iwl_ht_params iwl5000_ht_params = { | 66 | static const struct iwl_ht_params iwl5000_ht_params = { |
@@ -159,7 +156,6 @@ const struct iwl_cfg iwl5350_agn_cfg = { | |||
159 | .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ | 156 | .nvm_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ |
160 | .base_params = &iwl5000_base_params, \ | 157 | .base_params = &iwl5000_base_params, \ |
161 | .eeprom_params = &iwl5000_eeprom_params, \ | 158 | .eeprom_params = &iwl5000_eeprom_params, \ |
162 | .no_xtal_calib = true, \ | ||
163 | .led_mode = IWL_LED_BLINK, \ | 159 | .led_mode = IWL_LED_BLINK, \ |
164 | .internal_wimax_coex = true | 160 | .internal_wimax_coex = true |
165 | 161 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b5ab8d1bcac0..30d45e2fc193 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c | |||
@@ -82,10 +82,6 @@ static const struct iwl_base_params iwl6000_base_params = { | |||
82 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | 82 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, |
83 | .shadow_ram_support = true, | 83 | .shadow_ram_support = true, |
84 | .led_compensation = 51, | 84 | .led_compensation = 51, |
85 | .adv_thermal_throttle = true, | ||
86 | .support_ct_kill_exit = true, | ||
87 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
88 | .chain_noise_scale = 1000, | ||
89 | .wd_timeout = IWL_DEF_WD_TIMEOUT, | 85 | .wd_timeout = IWL_DEF_WD_TIMEOUT, |
90 | .max_event_log_size = 512, | 86 | .max_event_log_size = 512, |
91 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 87 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ |
@@ -98,10 +94,6 @@ static const struct iwl_base_params iwl6050_base_params = { | |||
98 | .max_ll_items = OTP_MAX_LL_ITEMS_6x50, | 94 | .max_ll_items = OTP_MAX_LL_ITEMS_6x50, |
99 | .shadow_ram_support = true, | 95 | .shadow_ram_support = true, |
100 | .led_compensation = 51, | 96 | .led_compensation = 51, |
101 | .adv_thermal_throttle = true, | ||
102 | .support_ct_kill_exit = true, | ||
103 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
104 | .chain_noise_scale = 1500, | ||
105 | .wd_timeout = IWL_DEF_WD_TIMEOUT, | 97 | .wd_timeout = IWL_DEF_WD_TIMEOUT, |
106 | .max_event_log_size = 1024, | 98 | .max_event_log_size = 1024, |
107 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 99 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ |
@@ -114,10 +106,6 @@ static const struct iwl_base_params iwl6000_g2_base_params = { | |||
114 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, | 106 | .max_ll_items = OTP_MAX_LL_ITEMS_6x00, |
115 | .shadow_ram_support = true, | 107 | .shadow_ram_support = true, |
116 | .led_compensation = 57, | 108 | .led_compensation = 57, |
117 | .adv_thermal_throttle = true, | ||
118 | .support_ct_kill_exit = true, | ||
119 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
120 | .chain_noise_scale = 1000, | ||
121 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | 109 | .wd_timeout = IWL_LONG_WD_TIMEOUT, |
122 | .max_event_log_size = 512, | 110 | .max_event_log_size = 512, |
123 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 111 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ |
@@ -129,15 +117,6 @@ static const struct iwl_ht_params iwl6000_ht_params = { | |||
129 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), | 117 | .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ), |
130 | }; | 118 | }; |
131 | 119 | ||
132 | static const struct iwl_bt_params iwl6000_bt_params = { | ||
133 | /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ | ||
134 | .advanced_bt_coexist = true, | ||
135 | .agg_time_limit = BT_AGG_THRESHOLD_DEF, | ||
136 | .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, | ||
137 | .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, | ||
138 | .bt_sco_disable = true, | ||
139 | }; | ||
140 | |||
141 | static const struct iwl_eeprom_params iwl6000_eeprom_params = { | 120 | static const struct iwl_eeprom_params iwl6000_eeprom_params = { |
142 | .regulatory_bands = { | 121 | .regulatory_bands = { |
143 | EEPROM_REG_BAND_1_CHANNELS, | 122 | EEPROM_REG_BAND_1_CHANNELS, |
@@ -163,7 +142,6 @@ static const struct iwl_eeprom_params iwl6000_eeprom_params = { | |||
163 | .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ | 142 | .nvm_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ |
164 | .base_params = &iwl6000_g2_base_params, \ | 143 | .base_params = &iwl6000_g2_base_params, \ |
165 | .eeprom_params = &iwl6000_eeprom_params, \ | 144 | .eeprom_params = &iwl6000_eeprom_params, \ |
166 | .need_temp_offset_calib = true, \ | ||
167 | .led_mode = IWL_LED_RF_STATE | 145 | .led_mode = IWL_LED_RF_STATE |
168 | 146 | ||
169 | const struct iwl_cfg iwl6005_2agn_cfg = { | 147 | const struct iwl_cfg iwl6005_2agn_cfg = { |
@@ -217,11 +195,8 @@ const struct iwl_cfg iwl6005_2agn_mow2_cfg = { | |||
217 | .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ | 195 | .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ |
218 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ | 196 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ |
219 | .base_params = &iwl6000_g2_base_params, \ | 197 | .base_params = &iwl6000_g2_base_params, \ |
220 | .bt_params = &iwl6000_bt_params, \ | ||
221 | .eeprom_params = &iwl6000_eeprom_params, \ | 198 | .eeprom_params = &iwl6000_eeprom_params, \ |
222 | .need_temp_offset_calib = true, \ | 199 | .led_mode = IWL_LED_RF_STATE |
223 | .led_mode = IWL_LED_RF_STATE, \ | ||
224 | .adv_pm = true \ | ||
225 | 200 | ||
226 | const struct iwl_cfg iwl6030_2agn_cfg = { | 201 | const struct iwl_cfg iwl6030_2agn_cfg = { |
227 | .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", | 202 | .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN", |
@@ -256,11 +231,8 @@ const struct iwl_cfg iwl6030_2bg_cfg = { | |||
256 | .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ | 231 | .nvm_ver = EEPROM_6030_EEPROM_VERSION, \ |
257 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ | 232 | .nvm_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ |
258 | .base_params = &iwl6000_g2_base_params, \ | 233 | .base_params = &iwl6000_g2_base_params, \ |
259 | .bt_params = &iwl6000_bt_params, \ | ||
260 | .eeprom_params = &iwl6000_eeprom_params, \ | 234 | .eeprom_params = &iwl6000_eeprom_params, \ |
261 | .need_temp_offset_calib = true, \ | 235 | .led_mode = IWL_LED_RF_STATE |
262 | .led_mode = IWL_LED_RF_STATE, \ | ||
263 | .adv_pm = true | ||
264 | 236 | ||
265 | const struct iwl_cfg iwl6035_2agn_cfg = { | 237 | const struct iwl_cfg iwl6035_2agn_cfg = { |
266 | .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", | 238 | .name = "Intel(R) Centrino(R) Advanced-N 6235 AGN", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 50263e87fe15..d4f3b4864ab1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c | |||
@@ -96,13 +96,9 @@ static const struct iwl_base_params iwl7000_base_params = { | |||
96 | .pll_cfg_val = 0, | 96 | .pll_cfg_val = 0, |
97 | .shadow_ram_support = true, | 97 | .shadow_ram_support = true, |
98 | .led_compensation = 57, | 98 | .led_compensation = 57, |
99 | .adv_thermal_throttle = true, | ||
100 | .support_ct_kill_exit = true, | ||
101 | .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, | ||
102 | .chain_noise_scale = 1000, | ||
103 | .wd_timeout = IWL_LONG_WD_TIMEOUT, | 99 | .wd_timeout = IWL_LONG_WD_TIMEOUT, |
104 | .max_event_log_size = 512, | 100 | .max_event_log_size = 512, |
105 | .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ | 101 | .shadow_reg_enable = true, |
106 | }; | 102 | }; |
107 | 103 | ||
108 | static const struct iwl_ht_params iwl7000_ht_params = { | 104 | static const struct iwl_ht_params iwl7000_ht_params = { |
@@ -118,14 +114,11 @@ static const struct iwl_ht_params iwl7000_ht_params = { | |||
118 | .max_inst_size = IWL60_RTC_INST_SIZE, \ | 114 | .max_inst_size = IWL60_RTC_INST_SIZE, \ |
119 | .max_data_size = IWL60_RTC_DATA_SIZE, \ | 115 | .max_data_size = IWL60_RTC_DATA_SIZE, \ |
120 | .base_params = &iwl7000_base_params, \ | 116 | .base_params = &iwl7000_base_params, \ |
121 | /* TODO: .bt_params? */ \ | 117 | .led_mode = IWL_LED_RF_STATE |
122 | .need_temp_offset_calib = true, \ | ||
123 | .led_mode = IWL_LED_RF_STATE, \ | ||
124 | .adv_pm = true \ | ||
125 | 118 | ||
126 | 119 | ||
127 | const struct iwl_cfg iwl7260_2ac_cfg = { | 120 | const struct iwl_cfg iwl7260_2ac_cfg = { |
128 | .name = "Intel(R) Dual Band Wireless AC7260", | 121 | .name = "Intel(R) Dual Band Wireless AC 7260", |
129 | .fw_name_pre = IWL7260_FW_PRE, | 122 | .fw_name_pre = IWL7260_FW_PRE, |
130 | IWL_DEVICE_7000, | 123 | IWL_DEVICE_7000, |
131 | .ht_params = &iwl7000_ht_params, | 124 | .ht_params = &iwl7000_ht_params, |
@@ -133,8 +126,44 @@ const struct iwl_cfg iwl7260_2ac_cfg = { | |||
133 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | 126 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, |
134 | }; | 127 | }; |
135 | 128 | ||
136 | const struct iwl_cfg iwl3160_ac_cfg = { | 129 | const struct iwl_cfg iwl7260_2n_cfg = { |
137 | .name = "Intel(R) Dual Band Wireless AC3160", | 130 | .name = "Intel(R) Dual Band Wireless N 7260", |
131 | .fw_name_pre = IWL7260_FW_PRE, | ||
132 | IWL_DEVICE_7000, | ||
133 | .ht_params = &iwl7000_ht_params, | ||
134 | .nvm_ver = IWL7260_NVM_VERSION, | ||
135 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | ||
136 | }; | ||
137 | |||
138 | const struct iwl_cfg iwl7260_n_cfg = { | ||
139 | .name = "Intel(R) Wireless N 7260", | ||
140 | .fw_name_pre = IWL7260_FW_PRE, | ||
141 | IWL_DEVICE_7000, | ||
142 | .ht_params = &iwl7000_ht_params, | ||
143 | .nvm_ver = IWL7260_NVM_VERSION, | ||
144 | .nvm_calib_ver = IWL7260_TX_POWER_VERSION, | ||
145 | }; | ||
146 | |||
147 | const struct iwl_cfg iwl3160_2ac_cfg = { | ||
148 | .name = "Intel(R) Dual Band Wireless AC 3160", | ||
149 | .fw_name_pre = IWL3160_FW_PRE, | ||
150 | IWL_DEVICE_7000, | ||
151 | .ht_params = &iwl7000_ht_params, | ||
152 | .nvm_ver = IWL3160_NVM_VERSION, | ||
153 | .nvm_calib_ver = IWL3160_TX_POWER_VERSION, | ||
154 | }; | ||
155 | |||
156 | const struct iwl_cfg iwl3160_2n_cfg = { | ||
157 | .name = "Intel(R) Dual Band Wireless N 3160", | ||
158 | .fw_name_pre = IWL3160_FW_PRE, | ||
159 | IWL_DEVICE_7000, | ||
160 | .ht_params = &iwl7000_ht_params, | ||
161 | .nvm_ver = IWL3160_NVM_VERSION, | ||
162 | .nvm_calib_ver = IWL3160_TX_POWER_VERSION, | ||
163 | }; | ||
164 | |||
165 | const struct iwl_cfg iwl3160_n_cfg = { | ||
166 | .name = "Intel(R) Wireless N 3160", | ||
138 | .fw_name_pre = IWL3160_FW_PRE, | 167 | .fw_name_pre = IWL3160_FW_PRE, |
139 | IWL_DEVICE_7000, | 168 | IWL_DEVICE_7000, |
140 | .ht_params = &iwl7000_ht_params, | 169 | .ht_params = &iwl7000_ht_params, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index c38aa8f77554..a193832fc790 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h | |||
@@ -136,17 +136,9 @@ enum iwl_led_mode { | |||
136 | * @led_compensation: compensate on the led on/off time per HW according | 136 | * @led_compensation: compensate on the led on/off time per HW according |
137 | * to the deviation to achieve the desired led frequency. | 137 | * to the deviation to achieve the desired led frequency. |
138 | * The detail algorithm is described in iwl-led.c | 138 | * The detail algorithm is described in iwl-led.c |
139 | * @chain_noise_num_beacons: number of beacons used to compute chain noise | ||
140 | * @adv_thermal_throttle: support advance thermal throttle | ||
141 | * @support_ct_kill_exit: support ct kill exit condition | ||
142 | * @plcp_delta_threshold: plcp error rate threshold used to trigger | ||
143 | * radio tuning when there is a high receiving plcp error rate | ||
144 | * @chain_noise_scale: default chain noise scale used for gain computation | ||
145 | * @wd_timeout: TX queues watchdog timeout | 139 | * @wd_timeout: TX queues watchdog timeout |
146 | * @max_event_log_size: size of event log buffer size for ucode event logging | 140 | * @max_event_log_size: size of event log buffer size for ucode event logging |
147 | * @shadow_reg_enable: HW shadow register support | 141 | * @shadow_reg_enable: HW shadow register support |
148 | * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up | ||
149 | * @no_idle_support: do not support idle mode | ||
150 | */ | 142 | */ |
151 | struct iwl_base_params { | 143 | struct iwl_base_params { |
152 | int eeprom_size; | 144 | int eeprom_size; |
@@ -157,31 +149,9 @@ struct iwl_base_params { | |||
157 | const u16 max_ll_items; | 149 | const u16 max_ll_items; |
158 | const bool shadow_ram_support; | 150 | const bool shadow_ram_support; |
159 | u16 led_compensation; | 151 | u16 led_compensation; |
160 | bool adv_thermal_throttle; | ||
161 | bool support_ct_kill_exit; | ||
162 | u8 plcp_delta_threshold; | ||
163 | s32 chain_noise_scale; | ||
164 | unsigned int wd_timeout; | 152 | unsigned int wd_timeout; |
165 | u32 max_event_log_size; | 153 | u32 max_event_log_size; |
166 | const bool shadow_reg_enable; | 154 | const bool shadow_reg_enable; |
167 | const bool hd_v2; | ||
168 | const bool no_idle_support; | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * @advanced_bt_coexist: support advanced bt coexist | ||
173 | * @bt_init_traffic_load: specify initial bt traffic load | ||
174 | * @bt_prio_boost: default bt priority boost value | ||
175 | * @agg_time_limit: maximum number of uSec in aggregation | ||
176 | * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode | ||
177 | */ | ||
178 | struct iwl_bt_params { | ||
179 | bool advanced_bt_coexist; | ||
180 | u8 bt_init_traffic_load; | ||
181 | u32 bt_prio_boost; | ||
182 | u16 agg_time_limit; | ||
183 | bool bt_sco_disable; | ||
184 | bool bt_session_2; | ||
185 | }; | 155 | }; |
186 | 156 | ||
187 | /* | 157 | /* |
@@ -231,16 +201,10 @@ struct iwl_eeprom_params { | |||
231 | * @nvm_calib_ver: NVM calibration version | 201 | * @nvm_calib_ver: NVM calibration version |
232 | * @lib: pointer to the lib ops | 202 | * @lib: pointer to the lib ops |
233 | * @base_params: pointer to basic parameters | 203 | * @base_params: pointer to basic parameters |
234 | * @ht_params: point to ht patameters | 204 | * @ht_params: point to ht parameters |
235 | * @bt_params: pointer to bt parameters | ||
236 | * @need_temp_offset_calib: need to perform temperature offset calibration | ||
237 | * @no_xtal_calib: some devices do not need crystal calibration data, | ||
238 | * don't send it to those | ||
239 | * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) | 205 | * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) |
240 | * @adv_pm: advance power management | ||
241 | * @rx_with_siso_diversity: 1x1 device with rx antenna diversity | 206 | * @rx_with_siso_diversity: 1x1 device with rx antenna diversity |
242 | * @internal_wimax_coex: internal wifi/wimax combo device | 207 | * @internal_wimax_coex: internal wifi/wimax combo device |
243 | * @temp_offset_v2: support v2 of temperature offset calibration | ||
244 | * | 208 | * |
245 | * We enable the driver to be backward compatible wrt. hardware features. | 209 | * We enable the driver to be backward compatible wrt. hardware features. |
246 | * API differences in uCode shouldn't be handled here but through TLVs | 210 | * API differences in uCode shouldn't be handled here but through TLVs |
@@ -264,15 +228,10 @@ struct iwl_cfg { | |||
264 | const struct iwl_base_params *base_params; | 228 | const struct iwl_base_params *base_params; |
265 | /* params likely to change within a device family */ | 229 | /* params likely to change within a device family */ |
266 | const struct iwl_ht_params *ht_params; | 230 | const struct iwl_ht_params *ht_params; |
267 | const struct iwl_bt_params *bt_params; | ||
268 | const struct iwl_eeprom_params *eeprom_params; | 231 | const struct iwl_eeprom_params *eeprom_params; |
269 | const bool need_temp_offset_calib; /* if used set to true */ | ||
270 | const bool no_xtal_calib; | ||
271 | enum iwl_led_mode led_mode; | 232 | enum iwl_led_mode led_mode; |
272 | const bool adv_pm; | ||
273 | const bool rx_with_siso_diversity; | 233 | const bool rx_with_siso_diversity; |
274 | const bool internal_wimax_coex; | 234 | const bool internal_wimax_coex; |
275 | const bool temp_offset_v2; | ||
276 | }; | 235 | }; |
277 | 236 | ||
278 | /* | 237 | /* |
@@ -320,6 +279,10 @@ extern const struct iwl_cfg iwl105_bgn_cfg; | |||
320 | extern const struct iwl_cfg iwl105_bgn_d_cfg; | 279 | extern const struct iwl_cfg iwl105_bgn_d_cfg; |
321 | extern const struct iwl_cfg iwl135_bgn_cfg; | 280 | extern const struct iwl_cfg iwl135_bgn_cfg; |
322 | extern const struct iwl_cfg iwl7260_2ac_cfg; | 281 | extern const struct iwl_cfg iwl7260_2ac_cfg; |
323 | extern const struct iwl_cfg iwl3160_ac_cfg; | 282 | extern const struct iwl_cfg iwl7260_2n_cfg; |
283 | extern const struct iwl_cfg iwl7260_n_cfg; | ||
284 | extern const struct iwl_cfg iwl3160_2ac_cfg; | ||
285 | extern const struct iwl_cfg iwl3160_2n_cfg; | ||
286 | extern const struct iwl_cfg iwl3160_n_cfg; | ||
324 | 287 | ||
325 | #endif /* __IWL_CONFIG_H__ */ | 288 | #endif /* __IWL_CONFIG_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 20e845d4da04..a276af476e2d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -472,4 +472,23 @@ | |||
472 | #define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) | 472 | #define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) |
473 | #define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) | 473 | #define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) |
474 | 474 | ||
475 | /***************************************************************************** | ||
476 | * 7000/3000 series SHR DTS addresses * | ||
477 | *****************************************************************************/ | ||
478 | |||
479 | /* Diode Results Register Structure: */ | ||
480 | enum dtd_diode_reg { | ||
481 | DTS_DIODE_REG_DIG_VAL = 0x000000FF, /* bits [7:0] */ | ||
482 | DTS_DIODE_REG_VREF_LOW = 0x0000FF00, /* bits [15:8] */ | ||
483 | DTS_DIODE_REG_VREF_HIGH = 0x00FF0000, /* bits [23:16] */ | ||
484 | DTS_DIODE_REG_VREF_ID = 0x03000000, /* bits [25:24] */ | ||
485 | DTS_DIODE_REG_PASS_ONCE = 0x80000000, /* bits [31:31] */ | ||
486 | DTS_DIODE_REG_FLAGS_MSK = 0xFF000000, /* bits [31:24] */ | ||
487 | /* Those are the masks INSIDE the flags bit-field: */ | ||
488 | DTS_DIODE_REG_FLAGS_VREFS_ID_POS = 0, | ||
489 | DTS_DIODE_REG_FLAGS_VREFS_ID = 0x00000003, /* bits [1:0] */ | ||
490 | DTS_DIODE_REG_FLAGS_PASS_ONCE_POS = 7, | ||
491 | DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */ | ||
492 | }; | ||
493 | |||
475 | #endif /* !__iwl_csr_h__ */ | 494 | #endif /* !__iwl_csr_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 39aad9893e0b..4f886133639a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c | |||
@@ -1234,6 +1234,9 @@ MODULE_PARM_DESC(wd_disable, | |||
1234 | "Disable stuck queue watchdog timer 0=system default, " | 1234 | "Disable stuck queue watchdog timer 0=system default, " |
1235 | "1=disable, 2=enable (default: 0)"); | 1235 | "1=disable, 2=enable (default: 0)"); |
1236 | 1236 | ||
1237 | module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); | ||
1238 | MODULE_PARM_DESC(nvm_file, "NVM file name"); | ||
1239 | |||
1237 | /* | 1240 | /* |
1238 | * set bt_coex_active to true, uCode will do kill/defer | 1241 | * set bt_coex_active to true, uCode will do kill/defer |
1239 | * every time the priority line is asserted (BT is sending signals on the | 1242 | * every time the priority line is asserted (BT is sending signals on the |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 600c9fdd7f71..4c887f365908 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | |||
@@ -732,17 +732,16 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data, | |||
732 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | 732 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, |
733 | struct iwl_nvm_data *data, | 733 | struct iwl_nvm_data *data, |
734 | struct ieee80211_sta_ht_cap *ht_info, | 734 | struct ieee80211_sta_ht_cap *ht_info, |
735 | enum ieee80211_band band) | 735 | enum ieee80211_band band, |
736 | u8 tx_chains, u8 rx_chains) | ||
736 | { | 737 | { |
737 | int max_bit_rate = 0; | 738 | int max_bit_rate = 0; |
738 | u8 rx_chains; | ||
739 | u8 tx_chains; | ||
740 | 739 | ||
741 | tx_chains = hweight8(data->valid_tx_ant); | 740 | tx_chains = hweight8(tx_chains); |
742 | if (cfg->rx_with_siso_diversity) | 741 | if (cfg->rx_with_siso_diversity) |
743 | rx_chains = 1; | 742 | rx_chains = 1; |
744 | else | 743 | else |
745 | rx_chains = hweight8(data->valid_rx_ant); | 744 | rx_chains = hweight8(rx_chains); |
746 | 745 | ||
747 | if (!(data->sku_cap_11n_enable) || !cfg->ht_params) { | 746 | if (!(data->sku_cap_11n_enable) || !cfg->ht_params) { |
748 | ht_info->ht_supported = false; | 747 | ht_info->ht_supported = false; |
@@ -806,7 +805,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
806 | sband->n_bitrates = N_RATES_24; | 805 | sband->n_bitrates = N_RATES_24; |
807 | n_used += iwl_init_sband_channels(data, sband, n_channels, | 806 | n_used += iwl_init_sband_channels(data, sband, n_channels, |
808 | IEEE80211_BAND_2GHZ); | 807 | IEEE80211_BAND_2GHZ); |
809 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ); | 808 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ, |
809 | data->valid_tx_ant, data->valid_rx_ant); | ||
810 | 810 | ||
811 | sband = &data->bands[IEEE80211_BAND_5GHZ]; | 811 | sband = &data->bands[IEEE80211_BAND_5GHZ]; |
812 | sband->band = IEEE80211_BAND_5GHZ; | 812 | sband->band = IEEE80211_BAND_5GHZ; |
@@ -814,7 +814,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
814 | sband->n_bitrates = N_RATES_52; | 814 | sband->n_bitrates = N_RATES_52; |
815 | n_used += iwl_init_sband_channels(data, sband, n_channels, | 815 | n_used += iwl_init_sband_channels(data, sband, n_channels, |
816 | IEEE80211_BAND_5GHZ); | 816 | IEEE80211_BAND_5GHZ); |
817 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ); | 817 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, |
818 | data->valid_tx_ant, data->valid_rx_ant); | ||
818 | 819 | ||
819 | if (n_channels != n_used) | 820 | if (n_channels != n_used) |
820 | IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n", | 821 | IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n", |
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index 37f115390b19..d73304a23ec2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h | |||
@@ -133,6 +133,7 @@ int iwl_init_sband_channels(struct iwl_nvm_data *data, | |||
133 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, | 133 | void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg, |
134 | struct iwl_nvm_data *data, | 134 | struct iwl_nvm_data *data, |
135 | struct ieee80211_sta_ht_cap *ht_info, | 135 | struct ieee80211_sta_ht_cap *ht_info, |
136 | enum ieee80211_band band); | 136 | enum ieee80211_band band, |
137 | u8 tx_chains, u8 rx_chains); | ||
137 | 138 | ||
138 | #endif /* __iwl_eeprom_parse_h__ */ | 139 | #endif /* __iwl_eeprom_parse_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index c4c446d41eb0..f844d5c748c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -106,11 +106,14 @@ enum iwl_ucode_type { | |||
106 | 106 | ||
107 | /* | 107 | /* |
108 | * enumeration of ucode section. | 108 | * enumeration of ucode section. |
109 | * This enumeration is used for legacy tlv style (before 16.0 uCode). | 109 | * This enumeration is used directly for older firmware (before 16.0). |
110 | * For new firmware, there can be up to 4 sections (see below) but the | ||
111 | * first one packaged into the firmware file is the DATA section and | ||
112 | * some debugging code accesses that. | ||
110 | */ | 113 | */ |
111 | enum iwl_ucode_sec { | 114 | enum iwl_ucode_sec { |
112 | IWL_UCODE_SECTION_INST, | ||
113 | IWL_UCODE_SECTION_DATA, | 115 | IWL_UCODE_SECTION_DATA, |
116 | IWL_UCODE_SECTION_INST, | ||
114 | }; | 117 | }; |
115 | /* | 118 | /* |
116 | * For 16.0 uCode and above, there is no differentiation between sections, | 119 | * For 16.0 uCode and above, there is no differentiation between sections, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index d6f6c37c09fd..36dfe0919f6b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h | |||
@@ -119,6 +119,7 @@ struct iwl_mod_params { | |||
119 | int ant_coupling; | 119 | int ant_coupling; |
120 | bool bt_ch_announce; | 120 | bool bt_ch_announce; |
121 | bool auto_agg; | 121 | bool auto_agg; |
122 | char *nvm_file; | ||
122 | }; | 123 | }; |
123 | 124 | ||
124 | #endif /* #__iwl_modparams_h__ */ | 125 | #endif /* #__iwl_modparams_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index 6199a0a597a6..acd2665afb8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | |||
@@ -89,6 +89,7 @@ enum nvm_sku_bits { | |||
89 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), | 89 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), |
90 | NVM_SKU_CAP_BAND_52GHZ = BIT(1), | 90 | NVM_SKU_CAP_BAND_52GHZ = BIT(1), |
91 | NVM_SKU_CAP_11N_ENABLE = BIT(2), | 91 | NVM_SKU_CAP_11N_ENABLE = BIT(2), |
92 | NVM_SKU_CAP_11AC_ENABLE = BIT(3), | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | /* radio config bits (actual values from NVM definition) */ | 95 | /* radio config bits (actual values from NVM definition) */ |
@@ -258,8 +259,6 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
258 | struct iwl_nvm_data *data, | 259 | struct iwl_nvm_data *data, |
259 | struct ieee80211_sta_vht_cap *vht_cap) | 260 | struct ieee80211_sta_vht_cap *vht_cap) |
260 | { | 261 | { |
261 | /* For now, assume new devices with NVM are VHT capable */ | ||
262 | |||
263 | vht_cap->vht_supported = true; | 262 | vht_cap->vht_supported = true; |
264 | 263 | ||
265 | vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 | | 264 | vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 | |
@@ -292,7 +291,8 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, | |||
292 | } | 291 | } |
293 | 292 | ||
294 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | 293 | static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, |
295 | struct iwl_nvm_data *data, const __le16 *nvm_sw) | 294 | struct iwl_nvm_data *data, const __le16 *nvm_sw, |
295 | bool enable_vht, u8 tx_chains, u8 rx_chains) | ||
296 | { | 296 | { |
297 | int n_channels = iwl_init_channel_map(dev, cfg, data, | 297 | int n_channels = iwl_init_channel_map(dev, cfg, data, |
298 | &nvm_sw[NVM_CHANNELS]); | 298 | &nvm_sw[NVM_CHANNELS]); |
@@ -305,7 +305,8 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
305 | sband->n_bitrates = N_RATES_24; | 305 | sband->n_bitrates = N_RATES_24; |
306 | n_used += iwl_init_sband_channels(data, sband, n_channels, | 306 | n_used += iwl_init_sband_channels(data, sband, n_channels, |
307 | IEEE80211_BAND_2GHZ); | 307 | IEEE80211_BAND_2GHZ); |
308 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ); | 308 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ, |
309 | tx_chains, rx_chains); | ||
309 | 310 | ||
310 | sband = &data->bands[IEEE80211_BAND_5GHZ]; | 311 | sband = &data->bands[IEEE80211_BAND_5GHZ]; |
311 | sband->band = IEEE80211_BAND_5GHZ; | 312 | sband->band = IEEE80211_BAND_5GHZ; |
@@ -313,8 +314,10 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
313 | sband->n_bitrates = N_RATES_52; | 314 | sband->n_bitrates = N_RATES_52; |
314 | n_used += iwl_init_sband_channels(data, sband, n_channels, | 315 | n_used += iwl_init_sband_channels(data, sband, n_channels, |
315 | IEEE80211_BAND_5GHZ); | 316 | IEEE80211_BAND_5GHZ); |
316 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ); | 317 | iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ, |
317 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap); | 318 | tx_chains, rx_chains); |
319 | if (enable_vht) | ||
320 | iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap); | ||
318 | 321 | ||
319 | if (n_channels != n_used) | 322 | if (n_channels != n_used) |
320 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", | 323 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", |
@@ -324,7 +327,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, | |||
324 | struct iwl_nvm_data * | 327 | struct iwl_nvm_data * |
325 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 328 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
326 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 329 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
327 | const __le16 *nvm_calib) | 330 | const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains) |
328 | { | 331 | { |
329 | struct iwl_nvm_data *data; | 332 | struct iwl_nvm_data *data; |
330 | u8 hw_addr[ETH_ALEN]; | 333 | u8 hw_addr[ETH_ALEN]; |
@@ -380,7 +383,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | |||
380 | data->hw_addr[4] = hw_addr[5]; | 383 | data->hw_addr[4] = hw_addr[5]; |
381 | data->hw_addr[5] = hw_addr[4]; | 384 | data->hw_addr[5] = hw_addr[4]; |
382 | 385 | ||
383 | iwl_init_sbands(dev, cfg, data, nvm_sw); | 386 | iwl_init_sbands(dev, cfg, data, nvm_sw, sku & NVM_SKU_CAP_11AC_ENABLE, |
387 | tx_chains, rx_chains); | ||
384 | 388 | ||
385 | data->calib_version = 255; /* TODO: | 389 | data->calib_version = 255; /* TODO: |
386 | this value will prevent some checks from | 390 | this value will prevent some checks from |
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index e57fb989661e..3325059c52d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h | |||
@@ -75,6 +75,6 @@ | |||
75 | struct iwl_nvm_data * | 75 | struct iwl_nvm_data * |
76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, | 76 | iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg, |
77 | const __le16 *nvm_hw, const __le16 *nvm_sw, | 77 | const __le16 *nvm_hw, const __le16 *nvm_sw, |
78 | const __le16 *nvm_calib); | 78 | const __le16 *nvm_calib, u8 tx_chains, u8 rx_chains); |
79 | 79 | ||
80 | #endif /* __iwl_nvm_parse_h__ */ | 80 | #endif /* __iwl_nvm_parse_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 386f2a7c87cb..ff8cc75c189d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -100,6 +100,18 @@ | |||
100 | /* Device system time */ | 100 | /* Device system time */ |
101 | #define DEVICE_SYSTEM_TIME_REG 0xA0206C | 101 | #define DEVICE_SYSTEM_TIME_REG 0xA0206C |
102 | 102 | ||
103 | /***************************************************************************** | ||
104 | * 7000/3000 series SHR DTS addresses * | ||
105 | *****************************************************************************/ | ||
106 | |||
107 | #define SHR_MISC_WFM_DTS_EN (0x00a10024) | ||
108 | #define DTSC_CFG_MODE (0x00a10604) | ||
109 | #define DTSC_VREF_AVG (0x00a10648) | ||
110 | #define DTSC_VREF5_AVG (0x00a1064c) | ||
111 | #define DTSC_CFG_MODE_PERIODIC (0x2) | ||
112 | #define DTSC_PTAT_AVG (0x00a10650) | ||
113 | |||
114 | |||
103 | /** | 115 | /** |
104 | * Tx Scheduler | 116 | * Tx Scheduler |
105 | * | 117 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7a13790b5bfe..84f1c8dc9741 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -189,7 +189,8 @@ enum CMD_MODE { | |||
189 | CMD_SYNC = 0, | 189 | CMD_SYNC = 0, |
190 | CMD_ASYNC = BIT(0), | 190 | CMD_ASYNC = BIT(0), |
191 | CMD_WANT_SKB = BIT(1), | 191 | CMD_WANT_SKB = BIT(1), |
192 | CMD_ON_DEMAND = BIT(2), | 192 | CMD_SEND_IN_RFKILL = BIT(2), |
193 | CMD_ON_DEMAND = BIT(3), | ||
193 | }; | 194 | }; |
194 | 195 | ||
195 | #define DEF_CMD_PAYLOAD_SIZE 320 | 196 | #define DEF_CMD_PAYLOAD_SIZE 320 |
@@ -455,7 +456,7 @@ struct iwl_trans_ops { | |||
455 | int (*read_mem)(struct iwl_trans *trans, u32 addr, | 456 | int (*read_mem)(struct iwl_trans *trans, u32 addr, |
456 | void *buf, int dwords); | 457 | void *buf, int dwords); |
457 | int (*write_mem)(struct iwl_trans *trans, u32 addr, | 458 | int (*write_mem)(struct iwl_trans *trans, u32 addr, |
458 | void *buf, int dwords); | 459 | const void *buf, int dwords); |
459 | void (*configure)(struct iwl_trans *trans, | 460 | void (*configure)(struct iwl_trans *trans, |
460 | const struct iwl_trans_config *trans_cfg); | 461 | const struct iwl_trans_config *trans_cfg); |
461 | void (*set_pmi)(struct iwl_trans *trans, bool state); | 462 | void (*set_pmi)(struct iwl_trans *trans, bool state); |
@@ -761,7 +762,7 @@ static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr) | |||
761 | } | 762 | } |
762 | 763 | ||
763 | static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, | 764 | static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, |
764 | void *buf, int dwords) | 765 | const void *buf, int dwords) |
765 | { | 766 | { |
766 | return trans->ops->write_mem(trans, addr, buf, dwords); | 767 | return trans->ops->write_mem(trans, addr, buf, dwords); |
767 | } | 768 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 2acc44b40986..ff856e543ae8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile | |||
@@ -3,7 +3,7 @@ iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o | |||
3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o | 3 | iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o |
4 | iwlmvm-y += scan.o time-event.o rs.o | 4 | iwlmvm-y += scan.o time-event.o rs.o |
5 | iwlmvm-y += power.o bt-coex.o | 5 | iwlmvm-y += power.o bt-coex.o |
6 | iwlmvm-y += led.o | 6 | iwlmvm-y += led.o tt.o |
7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o | 7 | iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o |
8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o | 8 | iwlmvm-$(CONFIG_PM_SLEEP) += d3.o |
9 | 9 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index 810bfa5f6de0..f03655f303aa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -351,6 +351,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
351 | enum ieee80211_band band; | 351 | enum ieee80211_band band; |
352 | int ave_rssi; | 352 | int ave_rssi; |
353 | 353 | ||
354 | lockdep_assert_held(&mvm->mutex); | ||
354 | if (vif->type != NL80211_IFTYPE_STATION) | 355 | if (vif->type != NL80211_IFTYPE_STATION) |
355 | return; | 356 | return; |
356 | 357 | ||
@@ -365,7 +366,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
365 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | 366 | smps_mode = IEEE80211_SMPS_AUTOMATIC; |
366 | 367 | ||
367 | if (band != IEEE80211_BAND_2GHZ) { | 368 | if (band != IEEE80211_BAND_2GHZ) { |
368 | ieee80211_request_smps(vif, smps_mode); | 369 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, |
370 | smps_mode); | ||
369 | return; | 371 | return; |
370 | } | 372 | } |
371 | 373 | ||
@@ -380,7 +382,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, | |||
380 | mvmvif->id, data->notif->bt_status, | 382 | mvmvif->id, data->notif->bt_status, |
381 | data->notif->bt_traffic_load, smps_mode); | 383 | data->notif->bt_traffic_load, smps_mode); |
382 | 384 | ||
383 | ieee80211_request_smps(vif, smps_mode); | 385 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX, smps_mode); |
384 | 386 | ||
385 | /* don't reduce the Tx power if in loose scheme */ | 387 | /* don't reduce the Tx power if in loose scheme */ |
386 | if (is_loose_coex()) | 388 | if (is_loose_coex()) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 16bbdcc8627a..4d3c978b5c76 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -1007,6 +1007,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1007 | if (ret) | 1007 | if (ret) |
1008 | goto out; | 1008 | goto out; |
1009 | 1009 | ||
1010 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
1011 | if (ret) | ||
1012 | goto out; | ||
1013 | |||
1010 | /* must be last -- this switches firmware state */ | 1014 | /* must be last -- this switches firmware state */ |
1011 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, | 1015 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, |
1012 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | 1016 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); |
@@ -1214,6 +1218,26 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1214 | iwl_free_resp(&cmd); | 1218 | iwl_free_resp(&cmd); |
1215 | } | 1219 | } |
1216 | 1220 | ||
1221 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) | ||
1222 | { | ||
1223 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1224 | const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN]; | ||
1225 | u32 len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
1226 | u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset; | ||
1227 | |||
1228 | if (!mvm->store_d3_resume_sram) | ||
1229 | return; | ||
1230 | |||
1231 | if (!mvm->d3_resume_sram) { | ||
1232 | mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL); | ||
1233 | if (!mvm->d3_resume_sram) | ||
1234 | return; | ||
1235 | } | ||
1236 | |||
1237 | iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len); | ||
1238 | #endif | ||
1239 | } | ||
1240 | |||
1217 | int iwl_mvm_resume(struct ieee80211_hw *hw) | 1241 | int iwl_mvm_resume(struct ieee80211_hw *hw) |
1218 | { | 1242 | { |
1219 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1243 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
@@ -1245,6 +1269,9 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
1245 | goto out_unlock; | 1269 | goto out_unlock; |
1246 | } | 1270 | } |
1247 | 1271 | ||
1272 | /* query SRAM first in case we want event logging */ | ||
1273 | iwl_mvm_read_d3_sram(mvm); | ||
1274 | |||
1248 | iwl_mvm_query_wakeup_reasons(mvm, vif); | 1275 | iwl_mvm_query_wakeup_reasons(mvm, vif); |
1249 | 1276 | ||
1250 | out_unlock: | 1277 | out_unlock: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2053dccefcd6..69e0806075a2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -145,15 +145,18 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | |||
145 | char *buf; | 145 | char *buf; |
146 | u8 *ptr; | 146 | u8 *ptr; |
147 | 147 | ||
148 | if (!mvm->ucode_loaded) | ||
149 | return -EINVAL; | ||
150 | |||
148 | /* default is to dump the entire data segment */ | 151 | /* default is to dump the entire data segment */ |
149 | if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) { | 152 | if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) { |
150 | mvm->dbgfs_sram_offset = 0x800000; | ||
151 | if (!mvm->ucode_loaded) | ||
152 | return -EINVAL; | ||
153 | img = &mvm->fw->img[mvm->cur_ucode]; | 153 | img = &mvm->fw->img[mvm->cur_ucode]; |
154 | mvm->dbgfs_sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; | 154 | ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; |
155 | len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
156 | } else { | ||
157 | ofs = mvm->dbgfs_sram_offset; | ||
158 | len = mvm->dbgfs_sram_len; | ||
155 | } | 159 | } |
156 | len = mvm->dbgfs_sram_len; | ||
157 | 160 | ||
158 | bufsz = len * 4 + 256; | 161 | bufsz = len * 4 + 256; |
159 | buf = kzalloc(bufsz, GFP_KERNEL); | 162 | buf = kzalloc(bufsz, GFP_KERNEL); |
@@ -167,12 +170,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, | |||
167 | } | 170 | } |
168 | 171 | ||
169 | pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len); | 172 | pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len); |
170 | pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", | 173 | pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs); |
171 | mvm->dbgfs_sram_offset); | ||
172 | 174 | ||
173 | iwl_trans_read_mem_bytes(mvm->trans, | 175 | iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len); |
174 | mvm->dbgfs_sram_offset, | ||
175 | ptr, len); | ||
176 | for (ofs = 0; ofs < len; ofs += 16) { | 176 | for (ofs = 0; ofs < len; ofs += 16) { |
177 | pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs); | 177 | pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs); |
178 | hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, | 178 | hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, |
@@ -300,6 +300,146 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file, | |||
300 | return count; | 300 | return count; |
301 | } | 301 | } |
302 | 302 | ||
303 | static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, | ||
304 | struct ieee80211_vif *vif, | ||
305 | enum iwl_dbgfs_pm_mask param, int val) | ||
306 | { | ||
307 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
308 | struct iwl_dbgfs_pm *dbgfs_pm = &mvmvif->dbgfs_pm; | ||
309 | |||
310 | dbgfs_pm->mask |= param; | ||
311 | |||
312 | switch (param) { | ||
313 | case MVM_DEBUGFS_PM_KEEP_ALIVE: { | ||
314 | struct ieee80211_hw *hw = mvm->hw; | ||
315 | int dtimper = hw->conf.ps_dtim_period ?: 1; | ||
316 | int dtimper_msec = dtimper * vif->bss_conf.beacon_int; | ||
317 | |||
318 | IWL_DEBUG_POWER(mvm, "debugfs: set keep_alive= %d sec\n", val); | ||
319 | if (val * MSEC_PER_SEC < 3 * dtimper_msec) { | ||
320 | IWL_WARN(mvm, | ||
321 | "debugfs: keep alive period (%ld msec) is less than minimum required (%d msec)\n", | ||
322 | val * MSEC_PER_SEC, 3 * dtimper_msec); | ||
323 | } | ||
324 | dbgfs_pm->keep_alive_seconds = val; | ||
325 | break; | ||
326 | } | ||
327 | case MVM_DEBUGFS_PM_SKIP_OVER_DTIM: | ||
328 | IWL_DEBUG_POWER(mvm, "skip_over_dtim %s\n", | ||
329 | val ? "enabled" : "disabled"); | ||
330 | dbgfs_pm->skip_over_dtim = val; | ||
331 | break; | ||
332 | case MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS: | ||
333 | IWL_DEBUG_POWER(mvm, "skip_dtim_periods=%d\n", val); | ||
334 | dbgfs_pm->skip_dtim_periods = val; | ||
335 | break; | ||
336 | case MVM_DEBUGFS_PM_RX_DATA_TIMEOUT: | ||
337 | IWL_DEBUG_POWER(mvm, "rx_data_timeout=%d\n", val); | ||
338 | dbgfs_pm->rx_data_timeout = val; | ||
339 | break; | ||
340 | case MVM_DEBUGFS_PM_TX_DATA_TIMEOUT: | ||
341 | IWL_DEBUG_POWER(mvm, "tx_data_timeout=%d\n", val); | ||
342 | dbgfs_pm->tx_data_timeout = val; | ||
343 | break; | ||
344 | case MVM_DEBUGFS_PM_DISABLE_POWER_OFF: | ||
345 | IWL_DEBUG_POWER(mvm, "disable_power_off=%d\n", val); | ||
346 | dbgfs_pm->disable_power_off = val; | ||
347 | break; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static ssize_t iwl_dbgfs_pm_params_write(struct file *file, | ||
352 | const char __user *user_buf, | ||
353 | size_t count, loff_t *ppos) | ||
354 | { | ||
355 | struct ieee80211_vif *vif = file->private_data; | ||
356 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
357 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
358 | enum iwl_dbgfs_pm_mask param; | ||
359 | char buf[32] = {}; | ||
360 | int val; | ||
361 | int ret; | ||
362 | |||
363 | if (copy_from_user(buf, user_buf, sizeof(buf))) | ||
364 | return -EFAULT; | ||
365 | |||
366 | if (!strncmp("keep_alive=", buf, 11)) { | ||
367 | if (sscanf(buf + 11, "%d", &val) != 1) | ||
368 | return -EINVAL; | ||
369 | param = MVM_DEBUGFS_PM_KEEP_ALIVE; | ||
370 | } else if (!strncmp("skip_over_dtim=", buf, 15)) { | ||
371 | if (sscanf(buf + 15, "%d", &val) != 1) | ||
372 | return -EINVAL; | ||
373 | param = MVM_DEBUGFS_PM_SKIP_OVER_DTIM; | ||
374 | } else if (!strncmp("skip_dtim_periods=", buf, 18)) { | ||
375 | if (sscanf(buf + 18, "%d", &val) != 1) | ||
376 | return -EINVAL; | ||
377 | param = MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS; | ||
378 | } else if (!strncmp("rx_data_timeout=", buf, 16)) { | ||
379 | if (sscanf(buf + 16, "%d", &val) != 1) | ||
380 | return -EINVAL; | ||
381 | param = MVM_DEBUGFS_PM_RX_DATA_TIMEOUT; | ||
382 | } else if (!strncmp("tx_data_timeout=", buf, 16)) { | ||
383 | if (sscanf(buf + 16, "%d", &val) != 1) | ||
384 | return -EINVAL; | ||
385 | param = MVM_DEBUGFS_PM_TX_DATA_TIMEOUT; | ||
386 | } else if (!strncmp("disable_power_off=", buf, 18)) { | ||
387 | if (sscanf(buf + 18, "%d", &val) != 1) | ||
388 | return -EINVAL; | ||
389 | param = MVM_DEBUGFS_PM_DISABLE_POWER_OFF; | ||
390 | } else { | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | mutex_lock(&mvm->mutex); | ||
395 | iwl_dbgfs_update_pm(mvm, vif, param, val); | ||
396 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
397 | mutex_unlock(&mvm->mutex); | ||
398 | |||
399 | return ret ?: count; | ||
400 | } | ||
401 | |||
402 | static ssize_t iwl_dbgfs_pm_params_read(struct file *file, | ||
403 | char __user *user_buf, | ||
404 | size_t count, loff_t *ppos) | ||
405 | { | ||
406 | struct ieee80211_vif *vif = file->private_data; | ||
407 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
408 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
409 | struct iwl_powertable_cmd cmd = {}; | ||
410 | char buf[256]; | ||
411 | int bufsz = sizeof(buf); | ||
412 | int pos = 0; | ||
413 | |||
414 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | ||
415 | |||
416 | pos += scnprintf(buf+pos, bufsz-pos, "disable_power_off = %d\n", | ||
417 | (cmd.flags & | ||
418 | cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK)) ? | ||
419 | 0 : 1); | ||
420 | pos += scnprintf(buf+pos, bufsz-pos, "skip_dtim_periods = %d\n", | ||
421 | le32_to_cpu(cmd.skip_dtim_periods)); | ||
422 | pos += scnprintf(buf+pos, bufsz-pos, "power_scheme = %d\n", | ||
423 | iwlmvm_mod_params.power_scheme); | ||
424 | pos += scnprintf(buf+pos, bufsz-pos, "flags = %d\n", | ||
425 | le16_to_cpu(cmd.flags)); | ||
426 | pos += scnprintf(buf+pos, bufsz-pos, "keep_alive = %d\n", | ||
427 | cmd.keep_alive_seconds); | ||
428 | |||
429 | if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) { | ||
430 | pos += scnprintf(buf+pos, bufsz-pos, "skip_over_dtim = %d\n", | ||
431 | (cmd.flags & | ||
432 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) ? | ||
433 | 1 : 0); | ||
434 | pos += scnprintf(buf+pos, bufsz-pos, "rx_data_timeout = %d\n", | ||
435 | le32_to_cpu(cmd.rx_data_timeout)); | ||
436 | pos += scnprintf(buf+pos, bufsz-pos, "tx_data_timeout = %d\n", | ||
437 | le32_to_cpu(cmd.tx_data_timeout)); | ||
438 | } | ||
439 | |||
440 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
441 | } | ||
442 | |||
303 | static ssize_t iwl_dbgfs_mac_params_read(struct file *file, | 443 | static ssize_t iwl_dbgfs_mac_params_read(struct file *file, |
304 | char __user *user_buf, | 444 | char __user *user_buf, |
305 | size_t count, loff_t *ppos) | 445 | size_t count, loff_t *ppos) |
@@ -481,6 +621,255 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct file *file, | |||
481 | return count; | 621 | return count; |
482 | } | 622 | } |
483 | 623 | ||
624 | static void iwl_dbgfs_update_bf(struct ieee80211_vif *vif, | ||
625 | enum iwl_dbgfs_bf_mask param, int value) | ||
626 | { | ||
627 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
628 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; | ||
629 | |||
630 | dbgfs_bf->mask |= param; | ||
631 | |||
632 | switch (param) { | ||
633 | case MVM_DEBUGFS_BF_ENERGY_DELTA: | ||
634 | dbgfs_bf->bf_energy_delta = value; | ||
635 | break; | ||
636 | case MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA: | ||
637 | dbgfs_bf->bf_roaming_energy_delta = value; | ||
638 | break; | ||
639 | case MVM_DEBUGFS_BF_ROAMING_STATE: | ||
640 | dbgfs_bf->bf_roaming_state = value; | ||
641 | break; | ||
642 | case MVM_DEBUGFS_BF_TEMPERATURE_DELTA: | ||
643 | dbgfs_bf->bf_temperature_delta = value; | ||
644 | break; | ||
645 | case MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER: | ||
646 | dbgfs_bf->bf_enable_beacon_filter = value; | ||
647 | break; | ||
648 | case MVM_DEBUGFS_BF_DEBUG_FLAG: | ||
649 | dbgfs_bf->bf_debug_flag = value; | ||
650 | break; | ||
651 | case MVM_DEBUGFS_BF_ESCAPE_TIMER: | ||
652 | dbgfs_bf->bf_escape_timer = value; | ||
653 | break; | ||
654 | case MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT: | ||
655 | dbgfs_bf->ba_enable_beacon_abort = value; | ||
656 | break; | ||
657 | case MVM_DEBUGFS_BA_ESCAPE_TIMER: | ||
658 | dbgfs_bf->ba_escape_timer = value; | ||
659 | break; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static ssize_t iwl_dbgfs_bf_params_write(struct file *file, | ||
664 | const char __user *user_buf, | ||
665 | size_t count, loff_t *ppos) | ||
666 | { | ||
667 | struct ieee80211_vif *vif = file->private_data; | ||
668 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
669 | struct iwl_mvm *mvm = mvmvif->dbgfs_data; | ||
670 | enum iwl_dbgfs_bf_mask param; | ||
671 | char buf[256]; | ||
672 | int buf_size; | ||
673 | int value; | ||
674 | int ret = 0; | ||
675 | |||
676 | memset(buf, 0, sizeof(buf)); | ||
677 | buf_size = min(count, sizeof(buf) - 1); | ||
678 | if (copy_from_user(buf, user_buf, buf_size)) | ||
679 | return -EFAULT; | ||
680 | |||
681 | if (!strncmp("bf_energy_delta=", buf, 16)) { | ||
682 | if (sscanf(buf+16, "%d", &value) != 1) | ||
683 | return -EINVAL; | ||
684 | if (value < IWL_BF_ENERGY_DELTA_MIN || | ||
685 | value > IWL_BF_ENERGY_DELTA_MAX) | ||
686 | return -EINVAL; | ||
687 | param = MVM_DEBUGFS_BF_ENERGY_DELTA; | ||
688 | } else if (!strncmp("bf_roaming_energy_delta=", buf, 24)) { | ||
689 | if (sscanf(buf+24, "%d", &value) != 1) | ||
690 | return -EINVAL; | ||
691 | if (value < IWL_BF_ROAMING_ENERGY_DELTA_MIN || | ||
692 | value > IWL_BF_ROAMING_ENERGY_DELTA_MAX) | ||
693 | return -EINVAL; | ||
694 | param = MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA; | ||
695 | } else if (!strncmp("bf_roaming_state=", buf, 17)) { | ||
696 | if (sscanf(buf+17, "%d", &value) != 1) | ||
697 | return -EINVAL; | ||
698 | if (value < IWL_BF_ROAMING_STATE_MIN || | ||
699 | value > IWL_BF_ROAMING_STATE_MAX) | ||
700 | return -EINVAL; | ||
701 | param = MVM_DEBUGFS_BF_ROAMING_STATE; | ||
702 | } else if (!strncmp("bf_temperature_delta=", buf, 21)) { | ||
703 | if (sscanf(buf+21, "%d", &value) != 1) | ||
704 | return -EINVAL; | ||
705 | if (value < IWL_BF_TEMPERATURE_DELTA_MIN || | ||
706 | value > IWL_BF_TEMPERATURE_DELTA_MAX) | ||
707 | return -EINVAL; | ||
708 | param = MVM_DEBUGFS_BF_TEMPERATURE_DELTA; | ||
709 | } else if (!strncmp("bf_enable_beacon_filter=", buf, 24)) { | ||
710 | if (sscanf(buf+24, "%d", &value) != 1) | ||
711 | return -EINVAL; | ||
712 | if (value < 0 || value > 1) | ||
713 | return -EINVAL; | ||
714 | param = MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER; | ||
715 | } else if (!strncmp("bf_debug_flag=", buf, 14)) { | ||
716 | if (sscanf(buf+14, "%d", &value) != 1) | ||
717 | return -EINVAL; | ||
718 | if (value < 0 || value > 1) | ||
719 | return -EINVAL; | ||
720 | param = MVM_DEBUGFS_BF_DEBUG_FLAG; | ||
721 | } else if (!strncmp("bf_escape_timer=", buf, 16)) { | ||
722 | if (sscanf(buf+16, "%d", &value) != 1) | ||
723 | return -EINVAL; | ||
724 | if (value < IWL_BF_ESCAPE_TIMER_MIN || | ||
725 | value > IWL_BF_ESCAPE_TIMER_MAX) | ||
726 | return -EINVAL; | ||
727 | param = MVM_DEBUGFS_BF_ESCAPE_TIMER; | ||
728 | } else if (!strncmp("ba_escape_timer=", buf, 16)) { | ||
729 | if (sscanf(buf+16, "%d", &value) != 1) | ||
730 | return -EINVAL; | ||
731 | if (value < IWL_BA_ESCAPE_TIMER_MIN || | ||
732 | value > IWL_BA_ESCAPE_TIMER_MAX) | ||
733 | return -EINVAL; | ||
734 | param = MVM_DEBUGFS_BA_ESCAPE_TIMER; | ||
735 | } else if (!strncmp("ba_enable_beacon_abort=", buf, 23)) { | ||
736 | if (sscanf(buf+23, "%d", &value) != 1) | ||
737 | return -EINVAL; | ||
738 | if (value < 0 || value > 1) | ||
739 | return -EINVAL; | ||
740 | param = MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT; | ||
741 | } else { | ||
742 | return -EINVAL; | ||
743 | } | ||
744 | |||
745 | mutex_lock(&mvm->mutex); | ||
746 | iwl_dbgfs_update_bf(vif, param, value); | ||
747 | if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) { | ||
748 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
749 | } else { | ||
750 | if (mvmvif->bf_enabled) | ||
751 | ret = iwl_mvm_enable_beacon_filter(mvm, vif); | ||
752 | else | ||
753 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
754 | } | ||
755 | mutex_unlock(&mvm->mutex); | ||
756 | |||
757 | return ret ?: count; | ||
758 | } | ||
759 | |||
760 | static ssize_t iwl_dbgfs_bf_params_read(struct file *file, | ||
761 | char __user *user_buf, | ||
762 | size_t count, loff_t *ppos) | ||
763 | { | ||
764 | struct ieee80211_vif *vif = file->private_data; | ||
765 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
766 | char buf[256]; | ||
767 | int pos = 0; | ||
768 | const size_t bufsz = sizeof(buf); | ||
769 | struct iwl_beacon_filter_cmd cmd = { | ||
770 | .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, | ||
771 | .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, | ||
772 | .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, | ||
773 | .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, | ||
774 | .bf_enable_beacon_filter = IWL_BF_ENABLE_BEACON_FILTER_DEFAULT, | ||
775 | .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, | ||
776 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), | ||
777 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT), | ||
778 | .ba_enable_beacon_abort = IWL_BA_ENABLE_BEACON_ABORT_DEFAULT, | ||
779 | }; | ||
780 | |||
781 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | ||
782 | if (mvmvif->bf_enabled) | ||
783 | cmd.bf_enable_beacon_filter = 1; | ||
784 | else | ||
785 | cmd.bf_enable_beacon_filter = 0; | ||
786 | |||
787 | pos += scnprintf(buf+pos, bufsz-pos, "bf_energy_delta = %d\n", | ||
788 | cmd.bf_energy_delta); | ||
789 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_energy_delta = %d\n", | ||
790 | cmd.bf_roaming_energy_delta); | ||
791 | pos += scnprintf(buf+pos, bufsz-pos, "bf_roaming_state = %d\n", | ||
792 | cmd.bf_roaming_state); | ||
793 | pos += scnprintf(buf+pos, bufsz-pos, "bf_temperature_delta = %d\n", | ||
794 | cmd.bf_temperature_delta); | ||
795 | pos += scnprintf(buf+pos, bufsz-pos, "bf_enable_beacon_filter = %d\n", | ||
796 | cmd.bf_enable_beacon_filter); | ||
797 | pos += scnprintf(buf+pos, bufsz-pos, "bf_debug_flag = %d\n", | ||
798 | cmd.bf_debug_flag); | ||
799 | pos += scnprintf(buf+pos, bufsz-pos, "bf_escape_timer = %d\n", | ||
800 | cmd.bf_escape_timer); | ||
801 | pos += scnprintf(buf+pos, bufsz-pos, "ba_escape_timer = %d\n", | ||
802 | cmd.ba_escape_timer); | ||
803 | pos += scnprintf(buf+pos, bufsz-pos, "ba_enable_beacon_abort = %d\n", | ||
804 | cmd.ba_enable_beacon_abort); | ||
805 | |||
806 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
807 | } | ||
808 | |||
809 | #ifdef CONFIG_PM_SLEEP | ||
810 | static ssize_t iwl_dbgfs_d3_sram_write(struct file *file, | ||
811 | const char __user *user_buf, | ||
812 | size_t count, loff_t *ppos) | ||
813 | { | ||
814 | struct iwl_mvm *mvm = file->private_data; | ||
815 | char buf[8] = {}; | ||
816 | int store; | ||
817 | |||
818 | if (copy_from_user(buf, user_buf, sizeof(buf))) | ||
819 | return -EFAULT; | ||
820 | |||
821 | if (sscanf(buf, "%d", &store) != 1) | ||
822 | return -EINVAL; | ||
823 | |||
824 | mvm->store_d3_resume_sram = store; | ||
825 | |||
826 | return count; | ||
827 | } | ||
828 | |||
829 | static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf, | ||
830 | size_t count, loff_t *ppos) | ||
831 | { | ||
832 | struct iwl_mvm *mvm = file->private_data; | ||
833 | const struct fw_img *img; | ||
834 | int ofs, len, pos = 0; | ||
835 | size_t bufsz, ret; | ||
836 | char *buf; | ||
837 | u8 *ptr = mvm->d3_resume_sram; | ||
838 | |||
839 | img = &mvm->fw->img[IWL_UCODE_WOWLAN]; | ||
840 | len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
841 | |||
842 | bufsz = len * 4 + 256; | ||
843 | buf = kzalloc(bufsz, GFP_KERNEL); | ||
844 | if (!buf) | ||
845 | return -ENOMEM; | ||
846 | |||
847 | pos += scnprintf(buf, bufsz, "D3 SRAM capture: %sabled\n", | ||
848 | mvm->store_d3_resume_sram ? "en" : "dis"); | ||
849 | |||
850 | if (ptr) { | ||
851 | for (ofs = 0; ofs < len; ofs += 16) { | ||
852 | pos += scnprintf(buf + pos, bufsz - pos, | ||
853 | "0x%.4x ", ofs); | ||
854 | hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, | ||
855 | bufsz - pos, false); | ||
856 | pos += strlen(buf + pos); | ||
857 | if (bufsz - pos > 0) | ||
858 | buf[pos++] = '\n'; | ||
859 | } | ||
860 | } else { | ||
861 | pos += scnprintf(buf + pos, bufsz - pos, | ||
862 | "(no data captured)\n"); | ||
863 | } | ||
864 | |||
865 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
866 | |||
867 | kfree(buf); | ||
868 | |||
869 | return ret; | ||
870 | } | ||
871 | #endif | ||
872 | |||
484 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ | 873 | #define MVM_DEBUGFS_READ_FILE_OPS(name) \ |
485 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ | 874 | static const struct file_operations iwl_dbgfs_##name##_ops = { \ |
486 | .read = iwl_dbgfs_##name##_read, \ | 875 | .read = iwl_dbgfs_##name##_read, \ |
@@ -524,9 +913,14 @@ MVM_DEBUGFS_READ_FILE_OPS(bt_notif); | |||
524 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); | 913 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow); |
525 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); | 914 | MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow); |
526 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); | 915 | MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart); |
916 | #ifdef CONFIG_PM_SLEEP | ||
917 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram); | ||
918 | #endif | ||
527 | 919 | ||
528 | /* Interface specific debugfs entries */ | 920 | /* Interface specific debugfs entries */ |
529 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); | 921 | MVM_DEBUGFS_READ_FILE_OPS(mac_params); |
922 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params); | ||
923 | MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params); | ||
530 | 924 | ||
531 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | 925 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) |
532 | { | 926 | { |
@@ -542,6 +936,9 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) | |||
542 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); | 936 | MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR); |
543 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); | 937 | MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR); |
544 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); | 938 | MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); |
939 | #ifdef CONFIG_PM_SLEEP | ||
940 | MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); | ||
941 | #endif | ||
545 | 942 | ||
546 | /* | 943 | /* |
547 | * Create a symlink with mac80211. It will be removed when mac80211 | 944 | * Create a symlink with mac80211. It will be removed when mac80211 |
@@ -577,9 +974,19 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
577 | return; | 974 | return; |
578 | } | 975 | } |
579 | 976 | ||
977 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && | ||
978 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p) | ||
979 | MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | | ||
980 | S_IRUSR); | ||
981 | |||
580 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | 982 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, |
581 | S_IRUSR); | 983 | S_IRUSR); |
582 | 984 | ||
985 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && | ||
986 | mvmvif == mvm->bf_allowed_vif) | ||
987 | MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, | ||
988 | S_IRUSR | S_IWUSR); | ||
989 | |||
583 | /* | 990 | /* |
584 | * Create symlink for convenience pointing to interface specific | 991 | * Create symlink for convenience pointing to interface specific |
585 | * debugfs entries for the driver. For example, under | 992 | * debugfs entries for the driver. For example, under |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 51e015d1dfb2..6f8b2c16ae17 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | |||
@@ -75,13 +75,15 @@ enum iwl_d3_wakeup_flags { | |||
75 | * struct iwl_d3_manager_config - D3 manager configuration command | 75 | * struct iwl_d3_manager_config - D3 manager configuration command |
76 | * @min_sleep_time: minimum sleep time (in usec) | 76 | * @min_sleep_time: minimum sleep time (in usec) |
77 | * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags | 77 | * @wakeup_flags: wakeup flags, see &enum iwl_d3_wakeup_flags |
78 | * @wakeup_host_timer: force wakeup after this many seconds | ||
78 | * | 79 | * |
79 | * The structure is used for the D3_CONFIG_CMD command. | 80 | * The structure is used for the D3_CONFIG_CMD command. |
80 | */ | 81 | */ |
81 | struct iwl_d3_manager_config { | 82 | struct iwl_d3_manager_config { |
82 | __le32 min_sleep_time; | 83 | __le32 min_sleep_time; |
83 | __le32 wakeup_flags; | 84 | __le32 wakeup_flags; |
84 | } __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_3 */ | 85 | __le32 wakeup_host_timer; |
86 | } __packed; /* D3_MANAGER_CONFIG_CMD_S_VER_4 */ | ||
85 | 87 | ||
86 | 88 | ||
87 | /* TODO: OFFLOADS_QUERY_API_S_VER_1 */ | 89 | /* TODO: OFFLOADS_QUERY_API_S_VER_1 */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 81fe45f46be7..d8e19290b0f3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | |||
@@ -101,20 +101,107 @@ enum iwl_power_flags { | |||
101 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to | 101 | * @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to |
102 | * PSM transition - legacy PM | 102 | * PSM transition - legacy PM |
103 | * @sleep_interval: not in use | 103 | * @sleep_interval: not in use |
104 | * @keep_alive_beacons: not in use | 104 | * @skip_dtim_periods: Number of DTIM periods to skip if Skip over DTIM flag |
105 | * is set. For example, if it is required to skip over | ||
106 | * one DTIM, this value need to be set to 2 (DTIM periods). | ||
105 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. | 107 | * @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled. |
106 | * Default: 80dbm | 108 | * Default: 80dbm |
107 | */ | 109 | */ |
108 | struct iwl_powertable_cmd { | 110 | struct iwl_powertable_cmd { |
109 | /* PM_POWER_TABLE_CMD_API_S_VER_5 */ | 111 | /* PM_POWER_TABLE_CMD_API_S_VER_6 */ |
110 | __le16 flags; | 112 | __le16 flags; |
111 | u8 keep_alive_seconds; | 113 | u8 keep_alive_seconds; |
112 | u8 debug_flags; | 114 | u8 debug_flags; |
113 | __le32 rx_data_timeout; | 115 | __le32 rx_data_timeout; |
114 | __le32 tx_data_timeout; | 116 | __le32 tx_data_timeout; |
115 | __le32 sleep_interval[IWL_POWER_VEC_SIZE]; | 117 | __le32 sleep_interval[IWL_POWER_VEC_SIZE]; |
116 | __le32 keep_alive_beacons; | 118 | __le32 skip_dtim_periods; |
117 | __le32 lprx_rssi_threshold; | 119 | __le32 lprx_rssi_threshold; |
118 | } __packed; | 120 | } __packed; |
119 | 121 | ||
122 | /** | ||
123 | * struct iwl_beacon_filter_cmd | ||
124 | * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) | ||
125 | * @id_and_color: MAC contex identifier | ||
126 | * @bf_energy_delta: Used for RSSI filtering, if in 'normal' state. Send beacon | ||
127 | * to driver if delta in Energy values calculated for this and last | ||
128 | * passed beacon is greater than this threshold. Zero value means that | ||
129 | * the Energy change is ignored for beacon filtering, and beacon will | ||
130 | * not be forced to be sent to driver regardless of this delta. Typical | ||
131 | * energy delta 5dB. | ||
132 | * @bf_roaming_energy_delta: Used for RSSI filtering, if in 'roaming' state. | ||
133 | * Send beacon to driver if delta in Energy values calculated for this | ||
134 | * and last passed beacon is greater than this threshold. Zero value | ||
135 | * means that the Energy change is ignored for beacon filtering while in | ||
136 | * Roaming state, typical energy delta 1dB. | ||
137 | * @bf_roaming_state: Used for RSSI filtering. If absolute Energy values | ||
138 | * calculated for current beacon is less than the threshold, use | ||
139 | * Roaming Energy Delta Threshold, otherwise use normal Energy Delta | ||
140 | * Threshold. Typical energy threshold is -72dBm. | ||
141 | * @bf_temperature_delta: Send Beacon to driver if delta in temperature values | ||
142 | * calculated for this and the last passed beacon is greater than this | ||
143 | * threshold. Zero value means that the temperature changeis ignored for | ||
144 | * beacon filtering; beacons will not be forced to be sent to driver | ||
145 | * regardless of whether its temerature has been changed. | ||
146 | * @bf_enable_beacon_filter: 1, beacon filtering is enabled; 0, disabled. | ||
147 | * @bf_filter_escape_timer: Send beacons to to driver if no beacons were passed | ||
148 | * for a specific period of time. Units: Beacons. | ||
149 | * @ba_escape_timer: Fully receive and parse beacon if no beacons were passed | ||
150 | * for a longer period of time then this escape-timeout. Units: Beacons. | ||
151 | * @ba_enable_beacon_abort: 1, beacon abort is enabled; 0, disabled. | ||
152 | */ | ||
153 | struct iwl_beacon_filter_cmd { | ||
154 | u8 bf_energy_delta; | ||
155 | u8 bf_roaming_energy_delta; | ||
156 | u8 bf_roaming_state; | ||
157 | u8 bf_temperature_delta; | ||
158 | u8 bf_enable_beacon_filter; | ||
159 | u8 bf_debug_flag; | ||
160 | __le16 reserved1; | ||
161 | __le32 bf_escape_timer; | ||
162 | __le32 ba_escape_timer; | ||
163 | u8 ba_enable_beacon_abort; | ||
164 | u8 reserved2[3]; | ||
165 | } __packed; | ||
166 | |||
167 | /* Beacon filtering and beacon abort */ | ||
168 | #define IWL_BF_ENERGY_DELTA_DEFAULT 5 | ||
169 | #define IWL_BF_ENERGY_DELTA_MAX 255 | ||
170 | #define IWL_BF_ENERGY_DELTA_MIN 0 | ||
171 | |||
172 | #define IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT 1 | ||
173 | #define IWL_BF_ROAMING_ENERGY_DELTA_MAX 255 | ||
174 | #define IWL_BF_ROAMING_ENERGY_DELTA_MIN 0 | ||
175 | |||
176 | #define IWL_BF_ROAMING_STATE_DEFAULT 72 | ||
177 | #define IWL_BF_ROAMING_STATE_MAX 255 | ||
178 | #define IWL_BF_ROAMING_STATE_MIN 0 | ||
179 | |||
180 | #define IWL_BF_TEMPERATURE_DELTA_DEFAULT 5 | ||
181 | #define IWL_BF_TEMPERATURE_DELTA_MAX 255 | ||
182 | #define IWL_BF_TEMPERATURE_DELTA_MIN 0 | ||
183 | |||
184 | #define IWL_BF_ENABLE_BEACON_FILTER_DEFAULT 1 | ||
185 | |||
186 | #define IWL_BF_DEBUG_FLAG_DEFAULT 0 | ||
187 | |||
188 | #define IWL_BF_ESCAPE_TIMER_DEFAULT 50 | ||
189 | #define IWL_BF_ESCAPE_TIMER_MAX 1024 | ||
190 | #define IWL_BF_ESCAPE_TIMER_MIN 0 | ||
191 | |||
192 | #define IWL_BA_ESCAPE_TIMER_DEFAULT 3 | ||
193 | #define IWL_BA_ESCAPE_TIMER_MAX 1024 | ||
194 | #define IWL_BA_ESCAPE_TIMER_MIN 0 | ||
195 | |||
196 | #define IWL_BA_ENABLE_BEACON_ABORT_DEFAULT 1 | ||
197 | |||
198 | #define IWL_BF_CMD_CONFIG_DEFAULTS \ | ||
199 | .bf_energy_delta = IWL_BF_ENERGY_DELTA_DEFAULT, \ | ||
200 | .bf_roaming_energy_delta = IWL_BF_ROAMING_ENERGY_DELTA_DEFAULT, \ | ||
201 | .bf_roaming_state = IWL_BF_ROAMING_STATE_DEFAULT, \ | ||
202 | .bf_temperature_delta = IWL_BF_TEMPERATURE_DELTA_DEFAULT, \ | ||
203 | .bf_debug_flag = IWL_BF_DEBUG_FLAG_DEFAULT, \ | ||
204 | .bf_escape_timer = cpu_to_le32(IWL_BF_ESCAPE_TIMER_DEFAULT), \ | ||
205 | .ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_DEFAULT) | ||
206 | |||
120 | #endif | 207 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 007a93b25bd7..6994232f5726 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | |||
@@ -134,6 +134,7 @@ enum iwl_tx_flags { | |||
134 | #define TX_CMD_SEC_WEP 0x01 | 134 | #define TX_CMD_SEC_WEP 0x01 |
135 | #define TX_CMD_SEC_CCM 0x02 | 135 | #define TX_CMD_SEC_CCM 0x02 |
136 | #define TX_CMD_SEC_TKIP 0x03 | 136 | #define TX_CMD_SEC_TKIP 0x03 |
137 | #define TX_CMD_SEC_MSK 0x07 | ||
137 | #define TX_CMD_SEC_WEP_KEY_IDX_POS 6 | 138 | #define TX_CMD_SEC_WEP_KEY_IDX_POS 6 |
138 | #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 | 139 | #define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0 |
139 | #define TX_CMD_SEC_KEY128 0x08 | 140 | #define TX_CMD_SEC_KEY128 0x08 |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 191dcae8ba47..cbfb3beae783 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -139,6 +139,9 @@ enum { | |||
139 | /* Power */ | 139 | /* Power */ |
140 | POWER_TABLE_CMD = 0x77, | 140 | POWER_TABLE_CMD = 0x77, |
141 | 141 | ||
142 | /* Thermal Throttling*/ | ||
143 | REPLY_THERMAL_MNG_BACKOFF = 0x7e, | ||
144 | |||
142 | /* Scanning */ | 145 | /* Scanning */ |
143 | SCAN_REQUEST_CMD = 0x80, | 146 | SCAN_REQUEST_CMD = 0x80, |
144 | SCAN_ABORT_CMD = 0x81, | 147 | SCAN_ABORT_CMD = 0x81, |
@@ -161,6 +164,8 @@ enum { | |||
161 | CARD_STATE_CMD = 0xa0, | 164 | CARD_STATE_CMD = 0xa0, |
162 | CARD_STATE_NOTIFICATION = 0xa1, | 165 | CARD_STATE_NOTIFICATION = 0xa1, |
163 | 166 | ||
167 | MISSED_BEACONS_NOTIFICATION = 0xa2, | ||
168 | |||
164 | REPLY_RX_PHY_CMD = 0xc0, | 169 | REPLY_RX_PHY_CMD = 0xc0, |
165 | REPLY_RX_MPDU_CMD = 0xc1, | 170 | REPLY_RX_MPDU_CMD = 0xc1, |
166 | BA_NOTIF = 0xc5, | 171 | BA_NOTIF = 0xc5, |
@@ -170,9 +175,13 @@ enum { | |||
170 | BT_COEX_PROT_ENV = 0xcd, | 175 | BT_COEX_PROT_ENV = 0xcd, |
171 | BT_PROFILE_NOTIFICATION = 0xce, | 176 | BT_PROFILE_NOTIFICATION = 0xce, |
172 | 177 | ||
178 | REPLY_BEACON_FILTERING_CMD = 0xd2, | ||
179 | |||
173 | REPLY_DEBUG_CMD = 0xf0, | 180 | REPLY_DEBUG_CMD = 0xf0, |
174 | DEBUG_LOG_MSG = 0xf7, | 181 | DEBUG_LOG_MSG = 0xf7, |
175 | 182 | ||
183 | MCAST_FILTER_CMD = 0xd0, | ||
184 | |||
176 | /* D3 commands/notifications */ | 185 | /* D3 commands/notifications */ |
177 | D3_CONFIG_CMD = 0xd3, | 186 | D3_CONFIG_CMD = 0xd3, |
178 | PROT_OFFLOAD_CONFIG_CMD = 0xd4, | 187 | PROT_OFFLOAD_CONFIG_CMD = 0xd4, |
@@ -936,6 +945,24 @@ struct iwl_card_state_notif { | |||
936 | } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ | 945 | } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ |
937 | 946 | ||
938 | /** | 947 | /** |
948 | * struct iwl_missed_beacons_notif - information on missed beacons | ||
949 | * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) | ||
950 | * @mac_id: interface ID | ||
951 | * @consec_missed_beacons_since_last_rx: number of consecutive missed | ||
952 | * beacons since last RX. | ||
953 | * @consec_missed_beacons: number of consecutive missed beacons | ||
954 | * @num_expected_beacons: | ||
955 | * @num_recvd_beacons: | ||
956 | */ | ||
957 | struct iwl_missed_beacons_notif { | ||
958 | __le32 mac_id; | ||
959 | __le32 consec_missed_beacons_since_last_rx; | ||
960 | __le32 consec_missed_beacons; | ||
961 | __le32 num_expected_beacons; | ||
962 | __le32 num_recvd_beacons; | ||
963 | } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ | ||
964 | |||
965 | /** | ||
939 | * struct iwl_set_calib_default_cmd - set default value for calibration. | 966 | * struct iwl_set_calib_default_cmd - set default value for calibration. |
940 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) | 967 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) |
941 | * @calib_index: the calibration to set value for | 968 | * @calib_index: the calibration to set value for |
@@ -948,4 +975,237 @@ struct iwl_set_calib_default_cmd { | |||
948 | u8 data[0]; | 975 | u8 data[0]; |
949 | } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ | 976 | } __packed; /* PHY_CALIB_OVERRIDE_VALUES_S */ |
950 | 977 | ||
978 | #define MAX_PORT_ID_NUM 2 | ||
979 | |||
980 | /** | ||
981 | * struct iwl_mcast_filter_cmd - configure multicast filter. | ||
982 | * @filter_own: Set 1 to filter out multicast packets sent by station itself | ||
983 | * @port_id: Multicast MAC addresses array specifier. This is a strange way | ||
984 | * to identify network interface adopted in host-device IF. | ||
985 | * It is used by FW as index in array of addresses. This array has | ||
986 | * MAX_PORT_ID_NUM members. | ||
987 | * @count: Number of MAC addresses in the array | ||
988 | * @pass_all: Set 1 to pass all multicast packets. | ||
989 | * @bssid: current association BSSID. | ||
990 | * @addr_list: Place holder for array of MAC addresses. | ||
991 | * IMPORTANT: add padding if necessary to ensure DWORD alignment. | ||
992 | */ | ||
993 | struct iwl_mcast_filter_cmd { | ||
994 | u8 filter_own; | ||
995 | u8 port_id; | ||
996 | u8 count; | ||
997 | u8 pass_all; | ||
998 | u8 bssid[6]; | ||
999 | u8 reserved[2]; | ||
1000 | u8 addr_list[0]; | ||
1001 | } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ | ||
1002 | |||
1003 | struct mvm_statistics_dbg { | ||
1004 | __le32 burst_check; | ||
1005 | __le32 burst_count; | ||
1006 | __le32 wait_for_silence_timeout_cnt; | ||
1007 | __le32 reserved[3]; | ||
1008 | } __packed; /* STATISTICS_DEBUG_API_S_VER_2 */ | ||
1009 | |||
1010 | struct mvm_statistics_div { | ||
1011 | __le32 tx_on_a; | ||
1012 | __le32 tx_on_b; | ||
1013 | __le32 exec_time; | ||
1014 | __le32 probe_time; | ||
1015 | __le32 rssi_ant; | ||
1016 | __le32 reserved2; | ||
1017 | } __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */ | ||
1018 | |||
1019 | struct mvm_statistics_general_common { | ||
1020 | __le32 temperature; /* radio temperature */ | ||
1021 | __le32 temperature_m; /* radio voltage */ | ||
1022 | struct mvm_statistics_dbg dbg; | ||
1023 | __le32 sleep_time; | ||
1024 | __le32 slots_out; | ||
1025 | __le32 slots_idle; | ||
1026 | __le32 ttl_timestamp; | ||
1027 | struct mvm_statistics_div div; | ||
1028 | __le32 rx_enable_counter; | ||
1029 | /* | ||
1030 | * num_of_sos_states: | ||
1031 | * count the number of times we have to re-tune | ||
1032 | * in order to get out of bad PHY status | ||
1033 | */ | ||
1034 | __le32 num_of_sos_states; | ||
1035 | } __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ | ||
1036 | |||
1037 | struct mvm_statistics_rx_non_phy { | ||
1038 | __le32 bogus_cts; /* CTS received when not expecting CTS */ | ||
1039 | __le32 bogus_ack; /* ACK received when not expecting ACK */ | ||
1040 | __le32 non_bssid_frames; /* number of frames with BSSID that | ||
1041 | * doesn't belong to the STA BSSID */ | ||
1042 | __le32 filtered_frames; /* count frames that were dumped in the | ||
1043 | * filtering process */ | ||
1044 | __le32 non_channel_beacons; /* beacons with our bss id but not on | ||
1045 | * our serving channel */ | ||
1046 | __le32 channel_beacons; /* beacons with our bss id and in our | ||
1047 | * serving channel */ | ||
1048 | __le32 num_missed_bcon; /* number of missed beacons */ | ||
1049 | __le32 adc_rx_saturation_time; /* count in 0.8us units the time the | ||
1050 | * ADC was in saturation */ | ||
1051 | __le32 ina_detection_search_time;/* total time (in 0.8us) searched | ||
1052 | * for INA */ | ||
1053 | __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ | ||
1054 | __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ | ||
1055 | __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ | ||
1056 | __le32 interference_data_flag; /* flag for interference data | ||
1057 | * availability. 1 when data is | ||
1058 | * available. */ | ||
1059 | __le32 channel_load; /* counts RX Enable time in uSec */ | ||
1060 | __le32 dsp_false_alarms; /* DSP false alarm (both OFDM | ||
1061 | * and CCK) counter */ | ||
1062 | __le32 beacon_rssi_a; | ||
1063 | __le32 beacon_rssi_b; | ||
1064 | __le32 beacon_rssi_c; | ||
1065 | __le32 beacon_energy_a; | ||
1066 | __le32 beacon_energy_b; | ||
1067 | __le32 beacon_energy_c; | ||
1068 | __le32 num_bt_kills; | ||
1069 | __le32 mac_id; | ||
1070 | __le32 directed_data_mpdu; | ||
1071 | } __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */ | ||
1072 | |||
1073 | struct mvm_statistics_rx_phy { | ||
1074 | __le32 ina_cnt; | ||
1075 | __le32 fina_cnt; | ||
1076 | __le32 plcp_err; | ||
1077 | __le32 crc32_err; | ||
1078 | __le32 overrun_err; | ||
1079 | __le32 early_overrun_err; | ||
1080 | __le32 crc32_good; | ||
1081 | __le32 false_alarm_cnt; | ||
1082 | __le32 fina_sync_err_cnt; | ||
1083 | __le32 sfd_timeout; | ||
1084 | __le32 fina_timeout; | ||
1085 | __le32 unresponded_rts; | ||
1086 | __le32 rxe_frame_limit_overrun; | ||
1087 | __le32 sent_ack_cnt; | ||
1088 | __le32 sent_cts_cnt; | ||
1089 | __le32 sent_ba_rsp_cnt; | ||
1090 | __le32 dsp_self_kill; | ||
1091 | __le32 mh_format_err; | ||
1092 | __le32 re_acq_main_rssi_sum; | ||
1093 | __le32 reserved; | ||
1094 | } __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */ | ||
1095 | |||
1096 | struct mvm_statistics_rx_ht_phy { | ||
1097 | __le32 plcp_err; | ||
1098 | __le32 overrun_err; | ||
1099 | __le32 early_overrun_err; | ||
1100 | __le32 crc32_good; | ||
1101 | __le32 crc32_err; | ||
1102 | __le32 mh_format_err; | ||
1103 | __le32 agg_crc32_good; | ||
1104 | __le32 agg_mpdu_cnt; | ||
1105 | __le32 agg_cnt; | ||
1106 | __le32 unsupport_mcs; | ||
1107 | } __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */ | ||
1108 | |||
1109 | #define MAX_CHAINS 3 | ||
1110 | |||
1111 | struct mvm_statistics_tx_non_phy_agg { | ||
1112 | __le32 ba_timeout; | ||
1113 | __le32 ba_reschedule_frames; | ||
1114 | __le32 scd_query_agg_frame_cnt; | ||
1115 | __le32 scd_query_no_agg; | ||
1116 | __le32 scd_query_agg; | ||
1117 | __le32 scd_query_mismatch; | ||
1118 | __le32 frame_not_ready; | ||
1119 | __le32 underrun; | ||
1120 | __le32 bt_prio_kill; | ||
1121 | __le32 rx_ba_rsp_cnt; | ||
1122 | __s8 txpower[MAX_CHAINS]; | ||
1123 | __s8 reserved; | ||
1124 | __le32 reserved2; | ||
1125 | } __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */ | ||
1126 | |||
1127 | struct mvm_statistics_tx_channel_width { | ||
1128 | __le32 ext_cca_narrow_ch20[1]; | ||
1129 | __le32 ext_cca_narrow_ch40[2]; | ||
1130 | __le32 ext_cca_narrow_ch80[3]; | ||
1131 | __le32 ext_cca_narrow_ch160[4]; | ||
1132 | __le32 last_tx_ch_width_indx; | ||
1133 | __le32 rx_detected_per_ch_width[4]; | ||
1134 | __le32 success_per_ch_width[4]; | ||
1135 | __le32 fail_per_ch_width[4]; | ||
1136 | }; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */ | ||
1137 | |||
1138 | struct mvm_statistics_tx { | ||
1139 | __le32 preamble_cnt; | ||
1140 | __le32 rx_detected_cnt; | ||
1141 | __le32 bt_prio_defer_cnt; | ||
1142 | __le32 bt_prio_kill_cnt; | ||
1143 | __le32 few_bytes_cnt; | ||
1144 | __le32 cts_timeout; | ||
1145 | __le32 ack_timeout; | ||
1146 | __le32 expected_ack_cnt; | ||
1147 | __le32 actual_ack_cnt; | ||
1148 | __le32 dump_msdu_cnt; | ||
1149 | __le32 burst_abort_next_frame_mismatch_cnt; | ||
1150 | __le32 burst_abort_missing_next_frame_cnt; | ||
1151 | __le32 cts_timeout_collision; | ||
1152 | __le32 ack_or_ba_timeout_collision; | ||
1153 | struct mvm_statistics_tx_non_phy_agg agg; | ||
1154 | struct mvm_statistics_tx_channel_width channel_width; | ||
1155 | } __packed; /* STATISTICS_TX_API_S_VER_4 */ | ||
1156 | |||
1157 | |||
1158 | struct mvm_statistics_bt_activity { | ||
1159 | __le32 hi_priority_tx_req_cnt; | ||
1160 | __le32 hi_priority_tx_denied_cnt; | ||
1161 | __le32 lo_priority_tx_req_cnt; | ||
1162 | __le32 lo_priority_tx_denied_cnt; | ||
1163 | __le32 hi_priority_rx_req_cnt; | ||
1164 | __le32 hi_priority_rx_denied_cnt; | ||
1165 | __le32 lo_priority_rx_req_cnt; | ||
1166 | __le32 lo_priority_rx_denied_cnt; | ||
1167 | } __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */ | ||
1168 | |||
1169 | struct mvm_statistics_general { | ||
1170 | struct mvm_statistics_general_common common; | ||
1171 | __le32 beacon_filtered; | ||
1172 | __le32 missed_beacons; | ||
1173 | __s8 beacon_filter_everage_energy; | ||
1174 | __s8 beacon_filter_reason; | ||
1175 | __s8 beacon_filter_current_energy; | ||
1176 | __s8 beacon_filter_reserved; | ||
1177 | __le32 beacon_filter_delta_time; | ||
1178 | struct mvm_statistics_bt_activity bt_activity; | ||
1179 | } __packed; /* STATISTICS_GENERAL_API_S_VER_5 */ | ||
1180 | |||
1181 | struct mvm_statistics_rx { | ||
1182 | struct mvm_statistics_rx_phy ofdm; | ||
1183 | struct mvm_statistics_rx_phy cck; | ||
1184 | struct mvm_statistics_rx_non_phy general; | ||
1185 | struct mvm_statistics_rx_ht_phy ofdm_ht; | ||
1186 | } __packed; /* STATISTICS_RX_API_S_VER_3 */ | ||
1187 | |||
1188 | /* | ||
1189 | * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) | ||
1190 | * | ||
1191 | * By default, uCode issues this notification after receiving a beacon | ||
1192 | * while associated. To disable this behavior, set DISABLE_NOTIF flag in the | ||
1193 | * REPLY_STATISTICS_CMD 0x9c, above. | ||
1194 | * | ||
1195 | * Statistics counters continue to increment beacon after beacon, but are | ||
1196 | * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD | ||
1197 | * 0x9c with CLEAR_STATS bit set (see above). | ||
1198 | * | ||
1199 | * uCode also issues this notification during scans. uCode clears statistics | ||
1200 | * appropriately so that each notification contains statistics for only the | ||
1201 | * one channel that has just been scanned. | ||
1202 | */ | ||
1203 | |||
1204 | struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */ | ||
1205 | __le32 flag; | ||
1206 | struct mvm_statistics_rx rx; | ||
1207 | struct mvm_statistics_tx tx; | ||
1208 | struct mvm_statistics_general general; | ||
1209 | } __packed; | ||
1210 | |||
951 | #endif /* __fw_api_h__ */ | 1211 | #endif /* __fw_api_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e18c92dd60ec..cd7c0032cc58 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -326,6 +326,17 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) | |||
326 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); | 326 | ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); |
327 | WARN_ON(ret); | 327 | WARN_ON(ret); |
328 | 328 | ||
329 | /* | ||
330 | * abort after reading the nvm in case RF Kill is on, we will complete | ||
331 | * the init seq later when RF kill will switch to off | ||
332 | */ | ||
333 | if (iwl_mvm_is_radio_killed(mvm)) { | ||
334 | IWL_DEBUG_RF_KILL(mvm, | ||
335 | "jump over all phy activities due to RF kill\n"); | ||
336 | iwl_remove_notification(&mvm->notif_wait, &calib_wait); | ||
337 | return 1; | ||
338 | } | ||
339 | |||
329 | /* Send TX valid antennas before triggering calibrations */ | 340 | /* Send TX valid antennas before triggering calibrations */ |
330 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); | 341 | ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw)); |
331 | if (ret) | 342 | if (ret) |
@@ -388,6 +399,8 @@ out: | |||
388 | int iwl_mvm_up(struct iwl_mvm *mvm) | 399 | int iwl_mvm_up(struct iwl_mvm *mvm) |
389 | { | 400 | { |
390 | int ret, i; | 401 | int ret, i; |
402 | struct ieee80211_channel *chan; | ||
403 | struct cfg80211_chan_def chandef; | ||
391 | 404 | ||
392 | lockdep_assert_held(&mvm->mutex); | 405 | lockdep_assert_held(&mvm->mutex); |
393 | 406 | ||
@@ -400,8 +413,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
400 | ret = iwl_run_init_mvm_ucode(mvm, false); | 413 | ret = iwl_run_init_mvm_ucode(mvm, false); |
401 | if (ret && !iwlmvm_mod_params.init_dbg) { | 414 | if (ret && !iwlmvm_mod_params.init_dbg) { |
402 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); | 415 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); |
416 | /* this can't happen */ | ||
417 | if (WARN_ON(ret > 0)) | ||
418 | ret = -ERFKILL; | ||
403 | goto error; | 419 | goto error; |
404 | } | 420 | } |
421 | /* should stop & start HW since that INIT image just loaded */ | ||
422 | iwl_trans_stop_hw(mvm->trans, false); | ||
423 | ret = iwl_trans_start_hw(mvm->trans); | ||
424 | if (ret) | ||
425 | return ret; | ||
405 | } | 426 | } |
406 | 427 | ||
407 | if (iwlmvm_mod_params.init_dbg) | 428 | if (iwlmvm_mod_params.init_dbg) |
@@ -443,8 +464,22 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
443 | if (ret) | 464 | if (ret) |
444 | goto error; | 465 | goto error; |
445 | 466 | ||
446 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | 467 | /* Add all the PHY contexts */ |
468 | chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; | ||
469 | cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); | ||
470 | for (i = 0; i < NUM_PHY_CTX; i++) { | ||
471 | /* | ||
472 | * The channel used here isn't relevant as it's | ||
473 | * going to be overwritten in the other flows. | ||
474 | * For now use the first channel we have. | ||
475 | */ | ||
476 | ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], | ||
477 | &chandef, 1, 1); | ||
478 | if (ret) | ||
479 | goto error; | ||
480 | } | ||
447 | 481 | ||
482 | IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); | ||
448 | return 0; | 483 | return 0; |
449 | error: | 484 | error: |
450 | iwl_trans_stop_device(mvm->trans); | 485 | iwl_trans_stop_device(mvm->trans); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index e6eca4d66f6c..b4e8e597d2b7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -227,7 +227,7 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
227 | .found_vif = false, | 227 | .found_vif = false, |
228 | }; | 228 | }; |
229 | u32 ac; | 229 | u32 ac; |
230 | int ret; | 230 | int ret, i; |
231 | 231 | ||
232 | /* | 232 | /* |
233 | * Allocate a MAC ID and a TSF for this MAC, along with the queues | 233 | * Allocate a MAC ID and a TSF for this MAC, along with the queues |
@@ -335,6 +335,9 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, | |||
335 | mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; | 335 | mvmvif->bcast_sta.sta_id = IWL_MVM_STATION_COUNT; |
336 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 336 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
337 | 337 | ||
338 | for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) | ||
339 | mvmvif->smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; | ||
340 | |||
338 | return 0; | 341 | return 0; |
339 | 342 | ||
340 | exit_fail: | 343 | exit_fail: |
@@ -586,10 +589,12 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm, | |||
586 | */ | 589 | */ |
587 | static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, | 590 | static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, |
588 | struct ieee80211_vif *vif, | 591 | struct ieee80211_vif *vif, |
589 | struct iwl_mac_data_sta *ctxt_sta) | 592 | struct iwl_mac_data_sta *ctxt_sta, |
593 | bool force_assoc_off) | ||
590 | { | 594 | { |
591 | /* We need the dtim_period to set the MAC as associated */ | 595 | /* We need the dtim_period to set the MAC as associated */ |
592 | if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) { | 596 | if (vif->bss_conf.assoc && vif->bss_conf.dtim_period && |
597 | !force_assoc_off) { | ||
593 | u32 dtim_offs; | 598 | u32 dtim_offs; |
594 | 599 | ||
595 | /* | 600 | /* |
@@ -659,7 +664,8 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm, | |||
659 | cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); | 664 | cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON); |
660 | 665 | ||
661 | /* Fill the data specific for station mode */ | 666 | /* Fill the data specific for station mode */ |
662 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta); | 667 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta, |
668 | action == FW_CTXT_ACTION_ADD); | ||
663 | 669 | ||
664 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); | 670 | return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd); |
665 | } | 671 | } |
@@ -677,7 +683,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm, | |||
677 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); | 683 | iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action); |
678 | 684 | ||
679 | /* Fill the data specific for station mode */ | 685 | /* Fill the data specific for station mode */ |
680 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta); | 686 | iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta, |
687 | action == FW_CTXT_ACTION_ADD); | ||
681 | 688 | ||
682 | cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow & | 689 | cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow & |
683 | IEEE80211_P2P_OPPPS_CTWINDOW_MASK); | 690 | IEEE80211_P2P_OPPPS_CTWINDOW_MASK); |
@@ -1043,3 +1050,28 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1043 | rate); | 1050 | rate); |
1044 | return 0; | 1051 | return 0; |
1045 | } | 1052 | } |
1053 | |||
1054 | static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, | ||
1055 | struct ieee80211_vif *vif) | ||
1056 | { | ||
1057 | u16 *id = _data; | ||
1058 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1059 | |||
1060 | if (mvmvif->id == *id) | ||
1061 | ieee80211_beacon_loss(vif); | ||
1062 | } | ||
1063 | |||
1064 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | ||
1065 | struct iwl_rx_cmd_buffer *rxb, | ||
1066 | struct iwl_device_cmd *cmd) | ||
1067 | { | ||
1068 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1069 | struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data; | ||
1070 | u16 id = (u16)le32_to_cpu(missed_beacons->mac_id); | ||
1071 | |||
1072 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
1073 | IEEE80211_IFACE_ITER_NORMAL, | ||
1074 | iwl_mvm_beacon_loss_iterator, | ||
1075 | &id); | ||
1076 | return 0; | ||
1077 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 827fa641490f..b807ddac650c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -127,6 +127,17 @@ static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = { | |||
127 | }; | 127 | }; |
128 | #endif | 128 | #endif |
129 | 129 | ||
130 | static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | ||
131 | { | ||
132 | int i; | ||
133 | |||
134 | memset(mvm->phy_ctxts, 0, sizeof(mvm->phy_ctxts)); | ||
135 | for (i = 0; i < NUM_PHY_CTX; i++) { | ||
136 | mvm->phy_ctxts[i].id = i; | ||
137 | mvm->phy_ctxts[i].ref = 0; | ||
138 | } | ||
139 | } | ||
140 | |||
130 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 141 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
131 | { | 142 | { |
132 | struct ieee80211_hw *hw = mvm->hw; | 143 | struct ieee80211_hw *hw = mvm->hw; |
@@ -141,7 +152,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
141 | IEEE80211_HW_SUPPORTS_PS | | 152 | IEEE80211_HW_SUPPORTS_PS | |
142 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | 153 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | |
143 | IEEE80211_HW_AMPDU_AGGREGATION | | 154 | IEEE80211_HW_AMPDU_AGGREGATION | |
144 | IEEE80211_HW_TIMING_BEACON_ONLY; | 155 | IEEE80211_HW_TIMING_BEACON_ONLY | |
156 | IEEE80211_HW_CONNECTION_MONITOR; | ||
145 | 157 | ||
146 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; | 158 | hw->queues = IWL_MVM_FIRST_AGG_QUEUE; |
147 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; | 159 | hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; |
@@ -158,7 +170,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
158 | 170 | ||
159 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | 171 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); |
160 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); | 172 | hw->vif_data_size = sizeof(struct iwl_mvm_vif); |
161 | hw->chanctx_data_size = sizeof(struct iwl_mvm_phy_ctxt); | 173 | hw->chanctx_data_size = sizeof(u16); |
162 | 174 | ||
163 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 175 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
164 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 176 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
@@ -193,6 +205,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
193 | hw->wiphy->n_addresses++; | 205 | hw->wiphy->n_addresses++; |
194 | } | 206 | } |
195 | 207 | ||
208 | iwl_mvm_reset_phy_ctxts(mvm); | ||
209 | |||
196 | /* we create the 802.11 header and a max-length SSID element */ | 210 | /* we create the 802.11 header and a max-length SSID element */ |
197 | hw->wiphy->max_scan_ie_len = | 211 | hw->wiphy->max_scan_ie_len = |
198 | mvm->fw->ucode_capa.max_probe_length - 24 - 34; | 212 | mvm->fw->ucode_capa.max_probe_length - 24 - 34; |
@@ -252,8 +266,8 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, | |||
252 | { | 266 | { |
253 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 267 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
254 | 268 | ||
255 | if (test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status)) { | 269 | if (iwl_mvm_is_radio_killed(mvm)) { |
256 | IWL_DEBUG_DROP(mvm, "Dropping - RF KILL\n"); | 270 | IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n"); |
257 | goto drop; | 271 | goto drop; |
258 | } | 272 | } |
259 | 273 | ||
@@ -345,8 +359,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, | |||
345 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); | 359 | iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data); |
346 | spin_unlock_bh(&mvm->time_event_lock); | 360 | spin_unlock_bh(&mvm->time_event_lock); |
347 | 361 | ||
348 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | 362 | mvmvif->phy_ctxt = NULL; |
349 | mvmvif->phy_ctxt = NULL; | ||
350 | } | 363 | } |
351 | 364 | ||
352 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | 365 | static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) |
@@ -363,6 +376,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
363 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, | 376 | mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
364 | iwl_mvm_cleanup_iterator, mvm); | 377 | iwl_mvm_cleanup_iterator, mvm); |
365 | 378 | ||
379 | mvm->p2p_device_vif = NULL; | ||
380 | |||
381 | iwl_mvm_reset_phy_ctxts(mvm); | ||
366 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 382 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
367 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); | 383 | memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); |
368 | 384 | ||
@@ -456,6 +472,20 @@ static void iwl_mvm_power_update_iterator(void *data, u8 *mac, | |||
456 | iwl_mvm_power_update_mode(mvm, vif); | 472 | iwl_mvm_power_update_mode(mvm, vif); |
457 | } | 473 | } |
458 | 474 | ||
475 | static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) | ||
476 | { | ||
477 | u16 i; | ||
478 | |||
479 | lockdep_assert_held(&mvm->mutex); | ||
480 | |||
481 | for (i = 0; i < NUM_PHY_CTX; i++) | ||
482 | if (!mvm->phy_ctxts[i].ref) | ||
483 | return &mvm->phy_ctxts[i]; | ||
484 | |||
485 | IWL_ERR(mvm, "No available PHY context\n"); | ||
486 | return NULL; | ||
487 | } | ||
488 | |||
459 | static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | 489 | static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, |
460 | struct ieee80211_vif *vif) | 490 | struct ieee80211_vif *vif) |
461 | { | 491 | { |
@@ -530,32 +560,34 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
530 | */ | 560 | */ |
531 | iwl_mvm_power_update_mode(mvm, vif); | 561 | iwl_mvm_power_update_mode(mvm, vif); |
532 | 562 | ||
563 | /* beacon filtering */ | ||
564 | if (!mvm->bf_allowed_vif && | ||
565 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p){ | ||
566 | mvm->bf_allowed_vif = mvmvif; | ||
567 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; | ||
568 | } | ||
569 | |||
570 | ret = iwl_mvm_disable_beacon_filter(mvm, vif); | ||
571 | if (ret) | ||
572 | goto out_release; | ||
573 | |||
533 | /* | 574 | /* |
534 | * P2P_DEVICE interface does not have a channel context assigned to it, | 575 | * P2P_DEVICE interface does not have a channel context assigned to it, |
535 | * so a dedicated PHY context is allocated to it and the corresponding | 576 | * so a dedicated PHY context is allocated to it and the corresponding |
536 | * MAC context is bound to it at this stage. | 577 | * MAC context is bound to it at this stage. |
537 | */ | 578 | */ |
538 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { | 579 | if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { |
539 | struct ieee80211_channel *chan; | ||
540 | struct cfg80211_chan_def chandef; | ||
541 | |||
542 | mvmvif->phy_ctxt = &mvm->phy_ctxt_roc; | ||
543 | 580 | ||
544 | /* | 581 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
545 | * The channel used here isn't relevant as it's | 582 | if (!mvmvif->phy_ctxt) { |
546 | * going to be overwritten as part of the ROC flow. | 583 | ret = -ENOSPC; |
547 | * For now use the first channel we have. | ||
548 | */ | ||
549 | chan = &mvm->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels[0]; | ||
550 | cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); | ||
551 | ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->phy_ctxt, | ||
552 | &chandef, 1, 1); | ||
553 | if (ret) | ||
554 | goto out_remove_mac; | 584 | goto out_remove_mac; |
585 | } | ||
555 | 586 | ||
587 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | ||
556 | ret = iwl_mvm_binding_add_vif(mvm, vif); | 588 | ret = iwl_mvm_binding_add_vif(mvm, vif); |
557 | if (ret) | 589 | if (ret) |
558 | goto out_remove_phy; | 590 | goto out_unref_phy; |
559 | 591 | ||
560 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); | 592 | ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta); |
561 | if (ret) | 593 | if (ret) |
@@ -571,8 +603,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
571 | 603 | ||
572 | out_unbind: | 604 | out_unbind: |
573 | iwl_mvm_binding_remove_vif(mvm, vif); | 605 | iwl_mvm_binding_remove_vif(mvm, vif); |
574 | out_remove_phy: | 606 | out_unref_phy: |
575 | iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); | 607 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
576 | out_remove_mac: | 608 | out_remove_mac: |
577 | mvmvif->phy_ctxt = NULL; | 609 | mvmvif->phy_ctxt = NULL; |
578 | iwl_mvm_mac_ctxt_remove(mvm, vif); | 610 | iwl_mvm_mac_ctxt_remove(mvm, vif); |
@@ -646,6 +678,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
646 | 678 | ||
647 | mutex_lock(&mvm->mutex); | 679 | mutex_lock(&mvm->mutex); |
648 | 680 | ||
681 | if (mvm->bf_allowed_vif == mvmvif) { | ||
682 | mvm->bf_allowed_vif = NULL; | ||
683 | vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; | ||
684 | } | ||
685 | |||
649 | iwl_mvm_vif_dbgfs_clean(mvm, vif); | 686 | iwl_mvm_vif_dbgfs_clean(mvm, vif); |
650 | 687 | ||
651 | /* | 688 | /* |
@@ -661,7 +698,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
661 | mvm->p2p_device_vif = NULL; | 698 | mvm->p2p_device_vif = NULL; |
662 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 699 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
663 | iwl_mvm_binding_remove_vif(mvm, vif); | 700 | iwl_mvm_binding_remove_vif(mvm, vif); |
664 | iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); | 701 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
665 | mvmvif->phy_ctxt = NULL; | 702 | mvmvif->phy_ctxt = NULL; |
666 | } | 703 | } |
667 | 704 | ||
@@ -701,6 +738,20 @@ static void iwl_mvm_configure_filter(struct ieee80211_hw *hw, | |||
701 | *total_flags = 0; | 738 | *total_flags = 0; |
702 | } | 739 | } |
703 | 740 | ||
741 | static int iwl_mvm_configure_mcast_filter(struct iwl_mvm *mvm, | ||
742 | struct ieee80211_vif *vif) | ||
743 | { | ||
744 | struct iwl_mcast_filter_cmd mcast_filter_cmd = { | ||
745 | .pass_all = 1, | ||
746 | }; | ||
747 | |||
748 | memcpy(mcast_filter_cmd.bssid, vif->bss_conf.bssid, ETH_ALEN); | ||
749 | |||
750 | return iwl_mvm_send_cmd_pdu(mvm, MCAST_FILTER_CMD, CMD_SYNC, | ||
751 | sizeof(mcast_filter_cmd), | ||
752 | &mcast_filter_cmd); | ||
753 | } | ||
754 | |||
704 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | 755 | static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, |
705 | struct ieee80211_vif *vif, | 756 | struct ieee80211_vif *vif, |
706 | struct ieee80211_bss_conf *bss_conf, | 757 | struct ieee80211_bss_conf *bss_conf, |
@@ -722,6 +773,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
722 | return; | 773 | return; |
723 | } | 774 | } |
724 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); | 775 | iwl_mvm_bt_coex_vif_assoc(mvm, vif); |
776 | iwl_mvm_configure_mcast_filter(mvm, vif); | ||
725 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 777 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
726 | /* remove AP station now that the MAC is unassoc */ | 778 | /* remove AP station now that the MAC is unassoc */ |
727 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 779 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
@@ -931,7 +983,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
931 | 983 | ||
932 | switch (cmd) { | 984 | switch (cmd) { |
933 | case STA_NOTIFY_SLEEP: | 985 | case STA_NOTIFY_SLEEP: |
934 | if (atomic_read(&mvmsta->pending_frames) > 0) | 986 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) |
935 | ieee80211_sta_block_awake(hw, sta, true); | 987 | ieee80211_sta_block_awake(hw, sta, true); |
936 | /* | 988 | /* |
937 | * The fw updates the STA to be asleep. Tx packets on the Tx | 989 | * The fw updates the STA to be asleep. Tx packets on the Tx |
@@ -984,9 +1036,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
984 | mvmvif->phy_ctxt->channel->band); | 1036 | mvmvif->phy_ctxt->channel->band); |
985 | } else if (old_state == IEEE80211_STA_ASSOC && | 1037 | } else if (old_state == IEEE80211_STA_ASSOC && |
986 | new_state == IEEE80211_STA_AUTHORIZED) { | 1038 | new_state == IEEE80211_STA_AUTHORIZED) { |
1039 | /* enable beacon filtering */ | ||
1040 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); | ||
987 | ret = 0; | 1041 | ret = 0; |
988 | } else if (old_state == IEEE80211_STA_AUTHORIZED && | 1042 | } else if (old_state == IEEE80211_STA_AUTHORIZED && |
989 | new_state == IEEE80211_STA_ASSOC) { | 1043 | new_state == IEEE80211_STA_ASSOC) { |
1044 | /* disable beacon filtering */ | ||
1045 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif)); | ||
990 | ret = 0; | 1046 | ret = 0; |
991 | } else if (old_state == IEEE80211_STA_ASSOC && | 1047 | } else if (old_state == IEEE80211_STA_ASSOC && |
992 | new_state == IEEE80211_STA_AUTH) { | 1048 | new_state == IEEE80211_STA_AUTH) { |
@@ -1152,29 +1208,107 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
1152 | enum ieee80211_roc_type type) | 1208 | enum ieee80211_roc_type type) |
1153 | { | 1209 | { |
1154 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1210 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1211 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1155 | struct cfg80211_chan_def chandef; | 1212 | struct cfg80211_chan_def chandef; |
1156 | int ret; | 1213 | struct iwl_mvm_phy_ctxt *phy_ctxt; |
1214 | int ret, i; | ||
1215 | |||
1216 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | ||
1217 | duration, type); | ||
1157 | 1218 | ||
1158 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { | 1219 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { |
1159 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); | 1220 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); |
1160 | return -EINVAL; | 1221 | return -EINVAL; |
1161 | } | 1222 | } |
1162 | 1223 | ||
1163 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | ||
1164 | duration, type); | ||
1165 | |||
1166 | mutex_lock(&mvm->mutex); | 1224 | mutex_lock(&mvm->mutex); |
1167 | 1225 | ||
1226 | for (i = 0; i < NUM_PHY_CTX; i++) { | ||
1227 | phy_ctxt = &mvm->phy_ctxts[i]; | ||
1228 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) | ||
1229 | continue; | ||
1230 | |||
1231 | if (phy_ctxt->ref && channel == phy_ctxt->channel) { | ||
1232 | /* | ||
1233 | * Unbind the P2P_DEVICE from the current PHY context, | ||
1234 | * and if the PHY context is not used remove it. | ||
1235 | */ | ||
1236 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | ||
1237 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | ||
1238 | goto out_unlock; | ||
1239 | |||
1240 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | ||
1241 | |||
1242 | /* Bind the P2P_DEVICE to the current PHY Context */ | ||
1243 | mvmvif->phy_ctxt = phy_ctxt; | ||
1244 | |||
1245 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
1246 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | ||
1247 | goto out_unlock; | ||
1248 | |||
1249 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | ||
1250 | goto schedule_time_event; | ||
1251 | } | ||
1252 | } | ||
1253 | |||
1254 | /* Need to update the PHY context only if the ROC channel changed */ | ||
1255 | if (channel == mvmvif->phy_ctxt->channel) | ||
1256 | goto schedule_time_event; | ||
1257 | |||
1168 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); | 1258 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); |
1169 | ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc, | ||
1170 | &chandef, 1, 1); | ||
1171 | 1259 | ||
1260 | /* | ||
1261 | * Change the PHY context configuration as it is currently referenced | ||
1262 | * only by the P2P Device MAC | ||
1263 | */ | ||
1264 | if (mvmvif->phy_ctxt->ref == 1) { | ||
1265 | ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, | ||
1266 | &chandef, 1, 1); | ||
1267 | if (ret) | ||
1268 | goto out_unlock; | ||
1269 | } else { | ||
1270 | /* | ||
1271 | * The PHY context is shared with other MACs. Need to remove the | ||
1272 | * P2P Device from the binding, allocate an new PHY context and | ||
1273 | * create a new binding | ||
1274 | */ | ||
1275 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | ||
1276 | if (!phy_ctxt) { | ||
1277 | ret = -ENOSPC; | ||
1278 | goto out_unlock; | ||
1279 | } | ||
1280 | |||
1281 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef, | ||
1282 | 1, 1); | ||
1283 | if (ret) { | ||
1284 | IWL_ERR(mvm, "Failed to change PHY context\n"); | ||
1285 | goto out_unlock; | ||
1286 | } | ||
1287 | |||
1288 | /* Unbind the P2P_DEVICE from the current PHY context */ | ||
1289 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | ||
1290 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | ||
1291 | goto out_unlock; | ||
1292 | |||
1293 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | ||
1294 | |||
1295 | /* Bind the P2P_DEVICE to the new allocated PHY context */ | ||
1296 | mvmvif->phy_ctxt = phy_ctxt; | ||
1297 | |||
1298 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
1299 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | ||
1300 | goto out_unlock; | ||
1301 | |||
1302 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | ||
1303 | } | ||
1304 | |||
1305 | schedule_time_event: | ||
1172 | /* Schedule the time events */ | 1306 | /* Schedule the time events */ |
1173 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); | 1307 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); |
1174 | 1308 | ||
1309 | out_unlock: | ||
1175 | mutex_unlock(&mvm->mutex); | 1310 | mutex_unlock(&mvm->mutex); |
1176 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 1311 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
1177 | |||
1178 | return ret; | 1312 | return ret; |
1179 | } | 1313 | } |
1180 | 1314 | ||
@@ -1196,15 +1330,30 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, | |||
1196 | struct ieee80211_chanctx_conf *ctx) | 1330 | struct ieee80211_chanctx_conf *ctx) |
1197 | { | 1331 | { |
1198 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1332 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1199 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1333 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1334 | struct iwl_mvm_phy_ctxt *phy_ctxt; | ||
1200 | int ret; | 1335 | int ret; |
1201 | 1336 | ||
1337 | IWL_DEBUG_MAC80211(mvm, "Add channel context\n"); | ||
1338 | |||
1202 | mutex_lock(&mvm->mutex); | 1339 | mutex_lock(&mvm->mutex); |
1340 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | ||
1341 | if (!phy_ctxt) { | ||
1342 | ret = -ENOSPC; | ||
1343 | goto out; | ||
1344 | } | ||
1345 | |||
1346 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, | ||
1347 | ctx->rx_chains_static, | ||
1348 | ctx->rx_chains_dynamic); | ||
1349 | if (ret) { | ||
1350 | IWL_ERR(mvm, "Failed to add PHY context\n"); | ||
1351 | goto out; | ||
1352 | } | ||
1203 | 1353 | ||
1204 | IWL_DEBUG_MAC80211(mvm, "Add PHY context\n"); | 1354 | iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt); |
1205 | ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def, | 1355 | *phy_ctxt_id = phy_ctxt->id; |
1206 | ctx->rx_chains_static, | 1356 | out: |
1207 | ctx->rx_chains_dynamic); | ||
1208 | mutex_unlock(&mvm->mutex); | 1357 | mutex_unlock(&mvm->mutex); |
1209 | return ret; | 1358 | return ret; |
1210 | } | 1359 | } |
@@ -1213,10 +1362,11 @@ static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, | |||
1213 | struct ieee80211_chanctx_conf *ctx) | 1362 | struct ieee80211_chanctx_conf *ctx) |
1214 | { | 1363 | { |
1215 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1364 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1216 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1365 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1366 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1217 | 1367 | ||
1218 | mutex_lock(&mvm->mutex); | 1368 | mutex_lock(&mvm->mutex); |
1219 | iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt); | 1369 | iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); |
1220 | mutex_unlock(&mvm->mutex); | 1370 | mutex_unlock(&mvm->mutex); |
1221 | } | 1371 | } |
1222 | 1372 | ||
@@ -1225,7 +1375,16 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, | |||
1225 | u32 changed) | 1375 | u32 changed) |
1226 | { | 1376 | { |
1227 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1377 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1228 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1378 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1379 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1380 | |||
1381 | if (WARN_ONCE((phy_ctxt->ref > 1) && | ||
1382 | (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | | ||
1383 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | | ||
1384 | IEEE80211_CHANCTX_CHANGE_RADAR)), | ||
1385 | "Cannot change PHY. Ref=%d, changed=0x%X\n", | ||
1386 | phy_ctxt->ref, changed)) | ||
1387 | return; | ||
1229 | 1388 | ||
1230 | mutex_lock(&mvm->mutex); | 1389 | mutex_lock(&mvm->mutex); |
1231 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, | 1390 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, |
@@ -1239,13 +1398,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1239 | struct ieee80211_chanctx_conf *ctx) | 1398 | struct ieee80211_chanctx_conf *ctx) |
1240 | { | 1399 | { |
1241 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1400 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1242 | struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv; | 1401 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1402 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1243 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1403 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1244 | int ret; | 1404 | int ret; |
1245 | 1405 | ||
1246 | mutex_lock(&mvm->mutex); | 1406 | mutex_lock(&mvm->mutex); |
1247 | 1407 | ||
1248 | mvmvif->phy_ctxt = phyctx; | 1408 | mvmvif->phy_ctxt = phy_ctxt; |
1249 | 1409 | ||
1250 | switch (vif->type) { | 1410 | switch (vif->type) { |
1251 | case NL80211_IFTYPE_AP: | 1411 | case NL80211_IFTYPE_AP: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index b62a948658ac..109200bdf5c5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -109,6 +109,7 @@ extern struct iwl_mvm_mod_params iwlmvm_mod_params; | |||
109 | struct iwl_mvm_phy_ctxt { | 109 | struct iwl_mvm_phy_ctxt { |
110 | u16 id; | 110 | u16 id; |
111 | u16 color; | 111 | u16 color; |
112 | u32 ref; | ||
112 | 113 | ||
113 | /* | 114 | /* |
114 | * TODO: This should probably be removed. Currently here only for rate | 115 | * TODO: This should probably be removed. Currently here only for rate |
@@ -149,6 +150,60 @@ enum iwl_power_scheme { | |||
149 | 150 | ||
150 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | 151 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 |
151 | 152 | ||
153 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
154 | enum iwl_dbgfs_pm_mask { | ||
155 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), | ||
156 | MVM_DEBUGFS_PM_SKIP_OVER_DTIM = BIT(1), | ||
157 | MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2), | ||
158 | MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3), | ||
159 | MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4), | ||
160 | MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), | ||
161 | }; | ||
162 | |||
163 | struct iwl_dbgfs_pm { | ||
164 | u8 keep_alive_seconds; | ||
165 | u32 rx_data_timeout; | ||
166 | u32 tx_data_timeout; | ||
167 | bool skip_over_dtim; | ||
168 | u8 skip_dtim_periods; | ||
169 | bool disable_power_off; | ||
170 | int mask; | ||
171 | }; | ||
172 | |||
173 | /* beacon filtering */ | ||
174 | |||
175 | enum iwl_dbgfs_bf_mask { | ||
176 | MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0), | ||
177 | MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1), | ||
178 | MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2), | ||
179 | MVM_DEBUGFS_BF_TEMPERATURE_DELTA = BIT(3), | ||
180 | MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(4), | ||
181 | MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(5), | ||
182 | MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(6), | ||
183 | MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(7), | ||
184 | MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(8), | ||
185 | }; | ||
186 | |||
187 | struct iwl_dbgfs_bf { | ||
188 | u8 bf_energy_delta; | ||
189 | u8 bf_roaming_energy_delta; | ||
190 | u8 bf_roaming_state; | ||
191 | u8 bf_temperature_delta; | ||
192 | u8 bf_enable_beacon_filter; | ||
193 | u8 bf_debug_flag; | ||
194 | u32 bf_escape_timer; | ||
195 | u32 ba_escape_timer; | ||
196 | u8 ba_enable_beacon_abort; | ||
197 | int mask; | ||
198 | }; | ||
199 | #endif | ||
200 | |||
201 | enum iwl_mvm_smps_type_request { | ||
202 | IWL_MVM_SMPS_REQ_BT_COEX, | ||
203 | IWL_MVM_SMPS_REQ_TT, | ||
204 | NUM_IWL_MVM_SMPS_REQ, | ||
205 | }; | ||
206 | |||
152 | /** | 207 | /** |
153 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context | 208 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context |
154 | * @id: between 0 and 3 | 209 | * @id: between 0 and 3 |
@@ -163,6 +218,8 @@ enum iwl_power_scheme { | |||
163 | * @bcast_sta: station used for broadcast packets. Used by the following | 218 | * @bcast_sta: station used for broadcast packets. Used by the following |
164 | * vifs: P2P_DEVICE, GO and AP. | 219 | * vifs: P2P_DEVICE, GO and AP. |
165 | * @beacon_skb: the skb used to hold the AP/GO beacon template | 220 | * @beacon_skb: the skb used to hold the AP/GO beacon template |
221 | * @smps_requests: the requests of of differents parts of the driver, regard | ||
222 | the desired smps mode. | ||
166 | */ | 223 | */ |
167 | struct iwl_mvm_vif { | 224 | struct iwl_mvm_vif { |
168 | u16 id; | 225 | u16 id; |
@@ -172,6 +229,8 @@ struct iwl_mvm_vif { | |||
172 | bool uploaded; | 229 | bool uploaded; |
173 | bool ap_active; | 230 | bool ap_active; |
174 | bool monitor_active; | 231 | bool monitor_active; |
232 | /* indicate whether beacon filtering is enabled */ | ||
233 | bool bf_enabled; | ||
175 | 234 | ||
176 | u32 ap_beacon_time; | 235 | u32 ap_beacon_time; |
177 | 236 | ||
@@ -214,7 +273,11 @@ struct iwl_mvm_vif { | |||
214 | struct dentry *dbgfs_dir; | 273 | struct dentry *dbgfs_dir; |
215 | struct dentry *dbgfs_slink; | 274 | struct dentry *dbgfs_slink; |
216 | void *dbgfs_data; | 275 | void *dbgfs_data; |
276 | struct iwl_dbgfs_pm dbgfs_pm; | ||
277 | struct iwl_dbgfs_bf dbgfs_bf; | ||
217 | #endif | 278 | #endif |
279 | |||
280 | enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; | ||
218 | }; | 281 | }; |
219 | 282 | ||
220 | static inline struct iwl_mvm_vif * | 283 | static inline struct iwl_mvm_vif * |
@@ -223,12 +286,6 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) | |||
223 | return (void *)vif->drv_priv; | 286 | return (void *)vif->drv_priv; |
224 | } | 287 | } |
225 | 288 | ||
226 | enum iwl_mvm_status { | ||
227 | IWL_MVM_STATUS_HW_RFKILL, | ||
228 | IWL_MVM_STATUS_ROC_RUNNING, | ||
229 | IWL_MVM_STATUS_IN_HW_RESTART, | ||
230 | }; | ||
231 | |||
232 | enum iwl_scan_status { | 289 | enum iwl_scan_status { |
233 | IWL_MVM_SCAN_NONE, | 290 | IWL_MVM_SCAN_NONE, |
234 | IWL_MVM_SCAN_OS, | 291 | IWL_MVM_SCAN_OS, |
@@ -246,6 +303,63 @@ struct iwl_nvm_section { | |||
246 | const u8 *data; | 303 | const u8 *data; |
247 | }; | 304 | }; |
248 | 305 | ||
306 | /* | ||
307 | * Tx-backoff threshold | ||
308 | * @temperature: The threshold in Celsius | ||
309 | * @backoff: The tx-backoff in uSec | ||
310 | */ | ||
311 | struct iwl_tt_tx_backoff { | ||
312 | s32 temperature; | ||
313 | u32 backoff; | ||
314 | }; | ||
315 | |||
316 | #define TT_TX_BACKOFF_SIZE 6 | ||
317 | |||
318 | /** | ||
319 | * struct iwl_tt_params - thermal throttling parameters | ||
320 | * @ct_kill_entry: CT Kill entry threshold | ||
321 | * @ct_kill_exit: CT Kill exit threshold | ||
322 | * @ct_kill_duration: The time intervals (in uSec) in which the driver needs | ||
323 | * to checks whether to exit CT Kill. | ||
324 | * @dynamic_smps_entry: Dynamic SMPS entry threshold | ||
325 | * @dynamic_smps_exit: Dynamic SMPS exit threshold | ||
326 | * @tx_protection_entry: TX protection entry threshold | ||
327 | * @tx_protection_exit: TX protection exit threshold | ||
328 | * @tx_backoff: Array of thresholds for tx-backoff , in ascending order. | ||
329 | * @support_ct_kill: Support CT Kill? | ||
330 | * @support_dynamic_smps: Support dynamic SMPS? | ||
331 | * @support_tx_protection: Support tx protection? | ||
332 | * @support_tx_backoff: Support tx-backoff? | ||
333 | */ | ||
334 | struct iwl_tt_params { | ||
335 | s32 ct_kill_entry; | ||
336 | s32 ct_kill_exit; | ||
337 | u32 ct_kill_duration; | ||
338 | s32 dynamic_smps_entry; | ||
339 | s32 dynamic_smps_exit; | ||
340 | s32 tx_protection_entry; | ||
341 | s32 tx_protection_exit; | ||
342 | struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE]; | ||
343 | bool support_ct_kill; | ||
344 | bool support_dynamic_smps; | ||
345 | bool support_tx_protection; | ||
346 | bool support_tx_backoff; | ||
347 | }; | ||
348 | |||
349 | /** | ||
350 | * struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure | ||
351 | * @ct_kill_exit: worker to exit thermal kill | ||
352 | * @dynamic_smps: Is thermal throttling enabled dynamic_smps? | ||
353 | * @tx_backoff: The current thremal throttling tx backoff in uSec. | ||
354 | * @params: Parameters to configure the thermal throttling algorithm. | ||
355 | */ | ||
356 | struct iwl_mvm_tt_mgmt { | ||
357 | struct delayed_work ct_kill_exit; | ||
358 | bool dynamic_smps; | ||
359 | u32 tx_backoff; | ||
360 | const struct iwl_tt_params *params; | ||
361 | }; | ||
362 | |||
249 | struct iwl_mvm { | 363 | struct iwl_mvm { |
250 | /* for logger access */ | 364 | /* for logger access */ |
251 | struct device *dev; | 365 | struct device *dev; |
@@ -266,6 +380,12 @@ struct iwl_mvm { | |||
266 | 380 | ||
267 | unsigned long status; | 381 | unsigned long status; |
268 | 382 | ||
383 | /* | ||
384 | * for beacon filtering - | ||
385 | * currently only one interface can be supported | ||
386 | */ | ||
387 | struct iwl_mvm_vif *bf_allowed_vif; | ||
388 | |||
269 | enum iwl_ucode_type cur_ucode; | 389 | enum iwl_ucode_type cur_ucode; |
270 | bool ucode_loaded; | 390 | bool ucode_loaded; |
271 | bool init_ucode_run; | 391 | bool init_ucode_run; |
@@ -292,6 +412,7 @@ struct iwl_mvm { | |||
292 | struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; | 412 | struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; |
293 | struct work_struct sta_drained_wk; | 413 | struct work_struct sta_drained_wk; |
294 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; | 414 | unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; |
415 | atomic_t pending_frames[IWL_MVM_STATION_COUNT]; | ||
295 | 416 | ||
296 | /* configured by mac80211 */ | 417 | /* configured by mac80211 */ |
297 | u32 rts_threshold; | 418 | u32 rts_threshold; |
@@ -312,7 +433,7 @@ struct iwl_mvm { | |||
312 | bool prevent_power_down_d3; | 433 | bool prevent_power_down_d3; |
313 | #endif | 434 | #endif |
314 | 435 | ||
315 | struct iwl_mvm_phy_ctxt phy_ctxt_roc; | 436 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; |
316 | 437 | ||
317 | struct list_head time_event_list; | 438 | struct list_head time_event_list; |
318 | spinlock_t time_event_lock; | 439 | spinlock_t time_event_lock; |
@@ -338,11 +459,19 @@ struct iwl_mvm { | |||
338 | #ifdef CONFIG_PM_SLEEP | 459 | #ifdef CONFIG_PM_SLEEP |
339 | struct wiphy_wowlan_support wowlan; | 460 | struct wiphy_wowlan_support wowlan; |
340 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; | 461 | int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen; |
462 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
463 | bool store_d3_resume_sram; | ||
464 | void *d3_resume_sram; | ||
465 | #endif | ||
341 | #endif | 466 | #endif |
342 | 467 | ||
343 | /* BT-Coex */ | 468 | /* BT-Coex */ |
344 | u8 bt_kill_msk; | 469 | u8 bt_kill_msk; |
345 | struct iwl_bt_coex_profile_notif last_bt_notif; | 470 | struct iwl_bt_coex_profile_notif last_bt_notif; |
471 | |||
472 | /* Thermal Throttling and CTkill */ | ||
473 | struct iwl_mvm_tt_mgmt thermal_throttle; | ||
474 | s32 temperature; /* Celsius */ | ||
346 | }; | 475 | }; |
347 | 476 | ||
348 | /* Extract MVM priv from op_mode and _hw */ | 477 | /* Extract MVM priv from op_mode and _hw */ |
@@ -352,6 +481,19 @@ struct iwl_mvm { | |||
352 | #define IWL_MAC80211_GET_MVM(_hw) \ | 481 | #define IWL_MAC80211_GET_MVM(_hw) \ |
353 | IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) | 482 | IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) |
354 | 483 | ||
484 | enum iwl_mvm_status { | ||
485 | IWL_MVM_STATUS_HW_RFKILL, | ||
486 | IWL_MVM_STATUS_HW_CTKILL, | ||
487 | IWL_MVM_STATUS_ROC_RUNNING, | ||
488 | IWL_MVM_STATUS_IN_HW_RESTART, | ||
489 | }; | ||
490 | |||
491 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | ||
492 | { | ||
493 | return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) || | ||
494 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
495 | } | ||
496 | |||
355 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 497 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
356 | 498 | ||
357 | struct iwl_rate_info { | 499 | struct iwl_rate_info { |
@@ -443,8 +585,10 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | |||
443 | int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | 585 | int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, |
444 | struct cfg80211_chan_def *chandef, | 586 | struct cfg80211_chan_def *chandef, |
445 | u8 chains_static, u8 chains_dynamic); | 587 | u8 chains_static, u8 chains_dynamic); |
446 | void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, | 588 | void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, |
447 | struct iwl_mvm_phy_ctxt *ctxt); | 589 | struct iwl_mvm_phy_ctxt *ctxt); |
590 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, | ||
591 | struct iwl_mvm_phy_ctxt *ctxt); | ||
448 | 592 | ||
449 | /* MAC (virtual interface) programming */ | 593 | /* MAC (virtual interface) programming */ |
450 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 594 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -459,6 +603,9 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | |||
459 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | 603 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, |
460 | struct iwl_rx_cmd_buffer *rxb, | 604 | struct iwl_rx_cmd_buffer *rxb, |
461 | struct iwl_device_cmd *cmd); | 605 | struct iwl_device_cmd *cmd); |
606 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | ||
607 | struct iwl_rx_cmd_buffer *rxb, | ||
608 | struct iwl_device_cmd *cmd); | ||
462 | 609 | ||
463 | /* Bindings */ | 610 | /* Bindings */ |
464 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 611 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -534,4 +681,36 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
534 | enum ieee80211_rssi_event rssi_event); | 681 | enum ieee80211_rssi_event rssi_event); |
535 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 682 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
536 | 683 | ||
684 | /* beacon filtering */ | ||
685 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
686 | void | ||
687 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
688 | struct iwl_beacon_filter_cmd *cmd); | ||
689 | int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm); | ||
690 | #else | ||
691 | static inline void | ||
692 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
693 | struct iwl_beacon_filter_cmd *cmd) | ||
694 | {} | ||
695 | static inline int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm) | ||
696 | { | ||
697 | return 0; | ||
698 | } | ||
699 | #endif | ||
700 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | ||
701 | struct ieee80211_vif *vif); | ||
702 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | ||
703 | struct ieee80211_vif *vif); | ||
704 | |||
705 | /* SMPS */ | ||
706 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
707 | enum iwl_mvm_smps_type_request req_type, | ||
708 | enum ieee80211_smps_mode smps_request); | ||
709 | |||
710 | /* Thermal management and CT-kill */ | ||
711 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); | ||
712 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); | ||
713 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | ||
714 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); | ||
715 | |||
537 | #endif /* __IWL_MVM_H__ */ | 716 | #endif /* __IWL_MVM_H__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index b8ec02f89acc..edb94ea31654 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c | |||
@@ -60,6 +60,7 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include <linux/firmware.h> | ||
63 | #include "iwl-trans.h" | 64 | #include "iwl-trans.h" |
64 | #include "mvm.h" | 65 | #include "mvm.h" |
65 | #include "iwl-eeprom-parse.h" | 66 | #include "iwl-eeprom-parse.h" |
@@ -75,31 +76,56 @@ static const int nvm_to_read[] = { | |||
75 | }; | 76 | }; |
76 | 77 | ||
77 | /* Default NVM size to read */ | 78 | /* Default NVM size to read */ |
78 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024); | 79 | #define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024) |
80 | #define IWL_MAX_NVM_SECTION_SIZE 6000 | ||
79 | 81 | ||
80 | static inline void iwl_nvm_fill_read(struct iwl_nvm_access_cmd *cmd, | 82 | #define NVM_WRITE_OPCODE 1 |
81 | u16 offset, u16 length, u16 section) | 83 | #define NVM_READ_OPCODE 0 |
84 | |||
85 | /* | ||
86 | * prepare the NVM host command w/ the pointers to the nvm buffer | ||
87 | * and send it to fw | ||
88 | */ | ||
89 | static int iwl_nvm_write_chunk(struct iwl_mvm *mvm, u16 section, | ||
90 | u16 offset, u16 length, const u8 *data) | ||
82 | { | 91 | { |
83 | cmd->offset = cpu_to_le16(offset); | 92 | struct iwl_nvm_access_cmd nvm_access_cmd = { |
84 | cmd->length = cpu_to_le16(length); | 93 | .offset = cpu_to_le16(offset), |
85 | cmd->type = cpu_to_le16(section); | 94 | .length = cpu_to_le16(length), |
95 | .type = cpu_to_le16(section), | ||
96 | .op_code = NVM_WRITE_OPCODE, | ||
97 | }; | ||
98 | struct iwl_host_cmd cmd = { | ||
99 | .id = NVM_ACCESS_CMD, | ||
100 | .len = { sizeof(struct iwl_nvm_access_cmd), length }, | ||
101 | .flags = CMD_SYNC | CMD_SEND_IN_RFKILL, | ||
102 | .data = { &nvm_access_cmd, data }, | ||
103 | /* data may come from vmalloc, so use _DUP */ | ||
104 | .dataflags = { 0, IWL_HCMD_DFL_DUP }, | ||
105 | }; | ||
106 | |||
107 | return iwl_mvm_send_cmd(mvm, &cmd); | ||
86 | } | 108 | } |
87 | 109 | ||
88 | static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, | 110 | static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, |
89 | u16 offset, u16 length, u8 *data) | 111 | u16 offset, u16 length, u8 *data) |
90 | { | 112 | { |
91 | struct iwl_nvm_access_cmd nvm_access_cmd = {}; | 113 | struct iwl_nvm_access_cmd nvm_access_cmd = { |
114 | .offset = cpu_to_le16(offset), | ||
115 | .length = cpu_to_le16(length), | ||
116 | .type = cpu_to_le16(section), | ||
117 | .op_code = NVM_READ_OPCODE, | ||
118 | }; | ||
92 | struct iwl_nvm_access_resp *nvm_resp; | 119 | struct iwl_nvm_access_resp *nvm_resp; |
93 | struct iwl_rx_packet *pkt; | 120 | struct iwl_rx_packet *pkt; |
94 | struct iwl_host_cmd cmd = { | 121 | struct iwl_host_cmd cmd = { |
95 | .id = NVM_ACCESS_CMD, | 122 | .id = NVM_ACCESS_CMD, |
96 | .flags = CMD_SYNC | CMD_WANT_SKB, | 123 | .flags = CMD_SYNC | CMD_WANT_SKB | CMD_SEND_IN_RFKILL, |
97 | .data = { &nvm_access_cmd, }, | 124 | .data = { &nvm_access_cmd, }, |
98 | }; | 125 | }; |
99 | int ret, bytes_read, offset_read; | 126 | int ret, bytes_read, offset_read; |
100 | u8 *resp_data; | 127 | u8 *resp_data; |
101 | 128 | ||
102 | iwl_nvm_fill_read(&nvm_access_cmd, offset, length, section); | ||
103 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd); | 129 | cmd.len[0] = sizeof(struct iwl_nvm_access_cmd); |
104 | 130 | ||
105 | ret = iwl_mvm_send_cmd(mvm, &cmd); | 131 | ret = iwl_mvm_send_cmd(mvm, &cmd); |
@@ -144,6 +170,30 @@ exit: | |||
144 | return ret; | 170 | return ret; |
145 | } | 171 | } |
146 | 172 | ||
173 | static int iwl_nvm_write_section(struct iwl_mvm *mvm, u16 section, | ||
174 | const u8 *data, u16 length) | ||
175 | { | ||
176 | int offset = 0; | ||
177 | |||
178 | /* copy data in chunks of 2k (and remainder if any) */ | ||
179 | |||
180 | while (offset < length) { | ||
181 | int chunk_size, ret; | ||
182 | |||
183 | chunk_size = min(IWL_NVM_DEFAULT_CHUNK_SIZE, | ||
184 | length - offset); | ||
185 | |||
186 | ret = iwl_nvm_write_chunk(mvm, section, offset, | ||
187 | chunk_size, data + offset); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | |||
191 | offset += chunk_size; | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
147 | /* | 197 | /* |
148 | * Reads an NVM section completely. | 198 | * Reads an NVM section completely. |
149 | * NICs prior to 7000 family doesn't have a real NVM, but just read | 199 | * NICs prior to 7000 family doesn't have a real NVM, but just read |
@@ -177,7 +227,8 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section, | |||
177 | offset += ret; | 227 | offset += ret; |
178 | } | 228 | } |
179 | 229 | ||
180 | IWL_INFO(mvm, "NVM section %d read completed\n", section); | 230 | IWL_DEBUG_EEPROM(mvm->trans->dev, |
231 | "NVM section %d read completed\n", section); | ||
181 | return offset; | 232 | return offset; |
182 | } | 233 | } |
183 | 234 | ||
@@ -200,7 +251,130 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) | |||
200 | hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; | 251 | hw = (const __le16 *)sections[NVM_SECTION_TYPE_HW].data; |
201 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; | 252 | sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; |
202 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; | 253 | calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; |
203 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib); | 254 | return iwl_parse_nvm_data(mvm->trans->dev, mvm->cfg, hw, sw, calib, |
255 | iwl_fw_valid_tx_ant(mvm->fw), | ||
256 | iwl_fw_valid_rx_ant(mvm->fw)); | ||
257 | } | ||
258 | |||
259 | #define MAX_NVM_FILE_LEN 16384 | ||
260 | |||
261 | /* | ||
262 | * HOW TO CREATE THE NVM FILE FORMAT: | ||
263 | * ------------------------------ | ||
264 | * 1. create hex file, format: | ||
265 | * 3800 -> header | ||
266 | * 0000 -> header | ||
267 | * 5a40 -> data | ||
268 | * | ||
269 | * rev - 6 bit (word1) | ||
270 | * len - 10 bit (word1) | ||
271 | * id - 4 bit (word2) | ||
272 | * rsv - 12 bit (word2) | ||
273 | * | ||
274 | * 2. flip 8bits with 8 bits per line to get the right NVM file format | ||
275 | * | ||
276 | * 3. create binary file from the hex file | ||
277 | * | ||
278 | * 4. save as "iNVM_xxx.bin" under /lib/firmware | ||
279 | */ | ||
280 | static int iwl_mvm_load_external_nvm(struct iwl_mvm *mvm) | ||
281 | { | ||
282 | int ret, section_id, section_size; | ||
283 | const struct firmware *fw_entry; | ||
284 | const struct { | ||
285 | __le16 word1; | ||
286 | __le16 word2; | ||
287 | u8 data[]; | ||
288 | } *file_sec; | ||
289 | const u8 *eof; | ||
290 | |||
291 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | ||
292 | #define NVM_WORD2_ID(x) (x >> 12) | ||
293 | |||
294 | /* | ||
295 | * Obtain NVM image via request_firmware. Since we already used | ||
296 | * request_firmware_nowait() for the firmware binary load and only | ||
297 | * get here after that we assume the NVM request can be satisfied | ||
298 | * synchronously. | ||
299 | */ | ||
300 | ret = request_firmware(&fw_entry, iwlwifi_mod_params.nvm_file, | ||
301 | mvm->trans->dev); | ||
302 | if (ret) { | ||
303 | IWL_ERR(mvm, "ERROR: %s isn't available %d\n", | ||
304 | iwlwifi_mod_params.nvm_file, ret); | ||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | IWL_INFO(mvm, "Loaded NVM file %s (%zu bytes)\n", | ||
309 | iwlwifi_mod_params.nvm_file, fw_entry->size); | ||
310 | |||
311 | if (fw_entry->size < sizeof(*file_sec)) { | ||
312 | IWL_ERR(mvm, "NVM file too small\n"); | ||
313 | ret = -EINVAL; | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | if (fw_entry->size > MAX_NVM_FILE_LEN) { | ||
318 | IWL_ERR(mvm, "NVM file too large\n"); | ||
319 | ret = -EINVAL; | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | eof = fw_entry->data + fw_entry->size; | ||
324 | |||
325 | file_sec = (void *)fw_entry->data; | ||
326 | |||
327 | while (true) { | ||
328 | if (file_sec->data > eof) { | ||
329 | IWL_ERR(mvm, | ||
330 | "ERROR - NVM file too short for section header\n"); | ||
331 | ret = -EINVAL; | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | /* check for EOF marker */ | ||
336 | if (!file_sec->word1 && !file_sec->word2) { | ||
337 | ret = 0; | ||
338 | break; | ||
339 | } | ||
340 | |||
341 | section_size = 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); | ||
342 | section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); | ||
343 | |||
344 | if (section_size > IWL_MAX_NVM_SECTION_SIZE) { | ||
345 | IWL_ERR(mvm, "ERROR - section too large (%d)\n", | ||
346 | section_size); | ||
347 | ret = -EINVAL; | ||
348 | break; | ||
349 | } | ||
350 | |||
351 | if (!section_size) { | ||
352 | IWL_ERR(mvm, "ERROR - section empty\n"); | ||
353 | ret = -EINVAL; | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | if (file_sec->data + section_size > eof) { | ||
358 | IWL_ERR(mvm, | ||
359 | "ERROR - NVM file too short for section (%d bytes)\n", | ||
360 | section_size); | ||
361 | ret = -EINVAL; | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | ret = iwl_nvm_write_section(mvm, section_id, file_sec->data, | ||
366 | section_size); | ||
367 | if (ret < 0) { | ||
368 | IWL_ERR(mvm, "iwl_mvm_send_cmd failed: %d\n", ret); | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | /* advance to the next section */ | ||
373 | file_sec = (void *)(file_sec->data + section_size); | ||
374 | } | ||
375 | out: | ||
376 | release_firmware(fw_entry); | ||
377 | return ret; | ||
204 | } | 378 | } |
205 | 379 | ||
206 | int iwl_nvm_init(struct iwl_mvm *mvm) | 380 | int iwl_nvm_init(struct iwl_mvm *mvm) |
@@ -208,6 +382,17 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
208 | int ret, i, section; | 382 | int ret, i, section; |
209 | u8 *nvm_buffer, *temp; | 383 | u8 *nvm_buffer, *temp; |
210 | 384 | ||
385 | /* load external NVM if configured */ | ||
386 | if (iwlwifi_mod_params.nvm_file) { | ||
387 | /* move to External NVM flow */ | ||
388 | ret = iwl_mvm_load_external_nvm(mvm); | ||
389 | if (ret) | ||
390 | return ret; | ||
391 | } | ||
392 | |||
393 | /* Read From FW NVM */ | ||
394 | IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); | ||
395 | |||
211 | /* TODO: find correct NVM max size for a section */ | 396 | /* TODO: find correct NVM max size for a section */ |
212 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, | 397 | nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, |
213 | GFP_KERNEL); | 398 | GFP_KERNEL); |
@@ -231,8 +416,9 @@ int iwl_nvm_init(struct iwl_mvm *mvm) | |||
231 | if (ret < 0) | 416 | if (ret < 0) |
232 | return ret; | 417 | return ret; |
233 | 418 | ||
234 | ret = 0; | ||
235 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); | 419 | mvm->nvm_data = iwl_parse_nvm_sections(mvm); |
420 | if (!mvm->nvm_data) | ||
421 | return -ENODATA; | ||
236 | 422 | ||
237 | return ret; | 423 | return 0; |
238 | } | 424 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index fe031d304d1e..d7a199b1cdef 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -222,10 +222,14 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
222 | 222 | ||
223 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | 223 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), |
224 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | 224 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), |
225 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), | ||
225 | 226 | ||
226 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 227 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
227 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 228 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
228 | 229 | ||
230 | RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif, | ||
231 | false), | ||
232 | |||
229 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), | 233 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), |
230 | }; | 234 | }; |
231 | #undef RX_HANDLER | 235 | #undef RX_HANDLER |
@@ -288,10 +292,14 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
288 | CMD(NET_DETECT_HOTSPOTS_CMD), | 292 | CMD(NET_DETECT_HOTSPOTS_CMD), |
289 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | 293 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), |
290 | CMD(CARD_STATE_NOTIFICATION), | 294 | CMD(CARD_STATE_NOTIFICATION), |
295 | CMD(MISSED_BEACONS_NOTIFICATION), | ||
291 | CMD(BT_COEX_PRIO_TABLE), | 296 | CMD(BT_COEX_PRIO_TABLE), |
292 | CMD(BT_COEX_PROT_ENV), | 297 | CMD(BT_COEX_PROT_ENV), |
293 | CMD(BT_PROFILE_NOTIFICATION), | 298 | CMD(BT_PROFILE_NOTIFICATION), |
294 | CMD(BT_CONFIG), | 299 | CMD(BT_CONFIG), |
300 | CMD(MCAST_FILTER_CMD), | ||
301 | CMD(REPLY_BEACON_FILTERING_CMD), | ||
302 | CMD(REPLY_THERMAL_MNG_BACKOFF), | ||
295 | }; | 303 | }; |
296 | #undef CMD | 304 | #undef CMD |
297 | 305 | ||
@@ -392,10 +400,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
392 | if (err) | 400 | if (err) |
393 | goto out_free; | 401 | goto out_free; |
394 | 402 | ||
403 | iwl_mvm_tt_initialize(mvm); | ||
404 | |||
395 | mutex_lock(&mvm->mutex); | 405 | mutex_lock(&mvm->mutex); |
396 | err = iwl_run_init_mvm_ucode(mvm, true); | 406 | err = iwl_run_init_mvm_ucode(mvm, true); |
397 | mutex_unlock(&mvm->mutex); | 407 | mutex_unlock(&mvm->mutex); |
398 | if (err && !iwlmvm_mod_params.init_dbg) { | 408 | /* returns 0 if successful, 1 if success but in rfkill */ |
409 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | ||
399 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); | 410 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); |
400 | goto out_free; | 411 | goto out_free; |
401 | } | 412 | } |
@@ -438,10 +449,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
438 | 449 | ||
439 | iwl_mvm_leds_exit(mvm); | 450 | iwl_mvm_leds_exit(mvm); |
440 | 451 | ||
452 | iwl_mvm_tt_exit(mvm); | ||
453 | |||
441 | ieee80211_unregister_hw(mvm->hw); | 454 | ieee80211_unregister_hw(mvm->hw); |
442 | 455 | ||
443 | kfree(mvm->scan_cmd); | 456 | kfree(mvm->scan_cmd); |
444 | 457 | ||
458 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) | ||
459 | kfree(mvm->d3_resume_sram); | ||
460 | #endif | ||
461 | |||
445 | iwl_trans_stop_hw(mvm->trans, true); | 462 | iwl_trans_stop_hw(mvm->trans, true); |
446 | 463 | ||
447 | iwl_phy_db_free(mvm->phy_db); | 464 | iwl_phy_db_free(mvm->phy_db); |
@@ -588,6 +605,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) | |||
588 | ieee80211_wake_queue(mvm->hw, mq); | 605 | ieee80211_wake_queue(mvm->hw, mq); |
589 | } | 606 | } |
590 | 607 | ||
608 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) | ||
609 | { | ||
610 | if (state) | ||
611 | set_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
612 | else | ||
613 | clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
614 | |||
615 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | ||
616 | } | ||
617 | |||
591 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 618 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
592 | { | 619 | { |
593 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 620 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
@@ -597,7 +624,7 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
597 | else | 624 | else |
598 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | 625 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); |
599 | 626 | ||
600 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); | 627 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
601 | } | 628 | } |
602 | 629 | ||
603 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | 630 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index a28a1d1f23eb..1b4db25d53fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c | |||
@@ -195,21 +195,6 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, | |||
195 | return ret; | 195 | return ret; |
196 | } | 196 | } |
197 | 197 | ||
198 | |||
199 | struct phy_ctx_used_data { | ||
200 | unsigned long used[BITS_TO_LONGS(NUM_PHY_CTX)]; | ||
201 | }; | ||
202 | |||
203 | static void iwl_mvm_phy_ctx_used_iter(struct ieee80211_hw *hw, | ||
204 | struct ieee80211_chanctx_conf *ctx, | ||
205 | void *_data) | ||
206 | { | ||
207 | struct phy_ctx_used_data *data = _data; | ||
208 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | ||
209 | |||
210 | __set_bit(phy_ctxt->id, data->used); | ||
211 | } | ||
212 | |||
213 | /* | 198 | /* |
214 | * Send a command to add a PHY context based on the current HW configuration. | 199 | * Send a command to add a PHY context based on the current HW configuration. |
215 | */ | 200 | */ |
@@ -217,34 +202,27 @@ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | |||
217 | struct cfg80211_chan_def *chandef, | 202 | struct cfg80211_chan_def *chandef, |
218 | u8 chains_static, u8 chains_dynamic) | 203 | u8 chains_static, u8 chains_dynamic) |
219 | { | 204 | { |
220 | struct phy_ctx_used_data data = { | 205 | int ret; |
221 | .used = { }, | ||
222 | }; | ||
223 | |||
224 | /* | ||
225 | * If this is a regular PHY context (not the ROC one) | ||
226 | * skip the ROC PHY context's ID. | ||
227 | */ | ||
228 | if (ctxt != &mvm->phy_ctxt_roc) | ||
229 | __set_bit(mvm->phy_ctxt_roc.id, data.used); | ||
230 | 206 | ||
207 | WARN_ON(ctxt->ref); | ||
231 | lockdep_assert_held(&mvm->mutex); | 208 | lockdep_assert_held(&mvm->mutex); |
232 | ctxt->color++; | ||
233 | 209 | ||
234 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 210 | ctxt->channel = chandef->chan; |
235 | ieee80211_iter_chan_contexts_atomic( | 211 | ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, |
236 | mvm->hw, iwl_mvm_phy_ctx_used_iter, &data); | 212 | chains_static, chains_dynamic, |
213 | FW_CTXT_ACTION_ADD, 0); | ||
237 | 214 | ||
238 | ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX); | 215 | return ret; |
239 | if (WARN_ONCE(ctxt->id == NUM_PHY_CTX, | 216 | } |
240 | "Failed to init PHY context - no free ID!\n")) | ||
241 | return -EIO; | ||
242 | } | ||
243 | 217 | ||
244 | ctxt->channel = chandef->chan; | 218 | /* |
245 | return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, | 219 | * Update the number of references to the given PHY context. This is valid only |
246 | chains_static, chains_dynamic, | 220 | * in case the PHY context was already created, i.e., its reference count > 0. |
247 | FW_CTXT_ACTION_ADD, 0); | 221 | */ |
222 | void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) | ||
223 | { | ||
224 | lockdep_assert_held(&mvm->mutex); | ||
225 | ctxt->ref++; | ||
248 | } | 226 | } |
249 | 227 | ||
250 | /* | 228 | /* |
@@ -264,23 +242,12 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | |||
264 | FW_CTXT_ACTION_MODIFY, 0); | 242 | FW_CTXT_ACTION_MODIFY, 0); |
265 | } | 243 | } |
266 | 244 | ||
267 | /* | 245 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) |
268 | * Send a command to the FW to remove the given phy context. | ||
269 | * Once the command is sent, regardless of success or failure, the context is | ||
270 | * marked as invalid | ||
271 | */ | ||
272 | void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) | ||
273 | { | 246 | { |
274 | struct iwl_phy_context_cmd cmd; | ||
275 | int ret; | ||
276 | |||
277 | lockdep_assert_held(&mvm->mutex); | 247 | lockdep_assert_held(&mvm->mutex); |
278 | 248 | ||
279 | iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0); | 249 | if (WARN_ON_ONCE(!ctxt)) |
280 | ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, | 250 | return; |
281 | sizeof(struct iwl_phy_context_cmd), | 251 | |
282 | &cmd); | 252 | ctxt->ref--; |
283 | if (ret) | ||
284 | IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n", | ||
285 | ctxt->id); | ||
286 | } | 253 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index ed77e437aac4..67cf24aa72f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -75,6 +75,54 @@ | |||
75 | 75 | ||
76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 | 76 | #define POWER_KEEP_ALIVE_PERIOD_SEC 25 |
77 | 77 | ||
78 | static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, | ||
79 | struct iwl_beacon_filter_cmd *cmd) | ||
80 | { | ||
81 | int ret; | ||
82 | |||
83 | ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC, | ||
84 | sizeof(struct iwl_beacon_filter_cmd), cmd); | ||
85 | |||
86 | if (!ret) { | ||
87 | IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", | ||
88 | cmd->ba_enable_beacon_abort); | ||
89 | IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", | ||
90 | cmd->ba_escape_timer); | ||
91 | IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", | ||
92 | cmd->bf_debug_flag); | ||
93 | IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", | ||
94 | cmd->bf_enable_beacon_filter); | ||
95 | IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", | ||
96 | cmd->bf_energy_delta); | ||
97 | IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", | ||
98 | cmd->bf_escape_timer); | ||
99 | IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", | ||
100 | cmd->bf_roaming_energy_delta); | ||
101 | IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", | ||
102 | cmd->bf_roaming_state); | ||
103 | IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n", | ||
104 | cmd->bf_temperature_delta); | ||
105 | } | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm, | ||
110 | struct ieee80211_vif *vif, bool enable) | ||
111 | { | ||
112 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
113 | struct iwl_beacon_filter_cmd cmd = { | ||
114 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
115 | .bf_enable_beacon_filter = 1, | ||
116 | .ba_enable_beacon_abort = enable, | ||
117 | }; | ||
118 | |||
119 | if (!mvmvif->bf_enabled) | ||
120 | return 0; | ||
121 | |||
122 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | ||
123 | return iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | ||
124 | } | ||
125 | |||
78 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, | 126 | static void iwl_mvm_power_log(struct iwl_mvm *mvm, |
79 | struct iwl_powertable_cmd *cmd) | 127 | struct iwl_powertable_cmd *cmd) |
80 | { | 128 | { |
@@ -91,6 +139,9 @@ static void iwl_mvm_power_log(struct iwl_mvm *mvm, | |||
91 | le32_to_cpu(cmd->tx_data_timeout)); | 139 | le32_to_cpu(cmd->tx_data_timeout)); |
92 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", | 140 | IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n", |
93 | cmd->lprx_rssi_threshold); | 141 | cmd->lprx_rssi_threshold); |
142 | if (cmd->flags & cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK)) | ||
143 | IWL_DEBUG_POWER(mvm, "DTIM periods to skip = %u\n", | ||
144 | le32_to_cpu(cmd->skip_dtim_periods)); | ||
94 | } | 145 | } |
95 | } | 146 | } |
96 | 147 | ||
@@ -103,6 +154,8 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
103 | int dtimper, dtimper_msec; | 154 | int dtimper, dtimper_msec; |
104 | int keep_alive; | 155 | int keep_alive; |
105 | bool radar_detect = false; | 156 | bool radar_detect = false; |
157 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
158 | iwl_mvm_vif_from_mac80211(vif); | ||
106 | 159 | ||
107 | /* | 160 | /* |
108 | * Regardless of power management state the driver must set | 161 | * Regardless of power management state the driver must set |
@@ -116,6 +169,11 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
116 | 169 | ||
117 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 170 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
118 | 171 | ||
172 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
173 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
174 | mvmvif->dbgfs_pm.disable_power_off) | ||
175 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
176 | #endif | ||
119 | if (!vif->bss_conf.ps) | 177 | if (!vif->bss_conf.ps) |
120 | return; | 178 | return; |
121 | 179 | ||
@@ -135,8 +193,11 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
135 | 193 | ||
136 | /* Check skip over DTIM conditions */ | 194 | /* Check skip over DTIM conditions */ |
137 | if (!radar_detect && (dtimper <= 10) && | 195 | if (!radar_detect && (dtimper <= 10) && |
138 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) | 196 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
197 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | ||
139 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 198 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); |
199 | cmd->skip_dtim_periods = cpu_to_le32(3); | ||
200 | } | ||
140 | 201 | ||
141 | /* Check that keep alive period is at least 3 * DTIM */ | 202 | /* Check that keep alive period is at least 3 * DTIM */ |
142 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 203 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
@@ -145,12 +206,41 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
145 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); | 206 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); |
146 | cmd->keep_alive_seconds = keep_alive; | 207 | cmd->keep_alive_seconds = keep_alive; |
147 | 208 | ||
148 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 209 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
149 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 210 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
211 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
212 | } else { | ||
213 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
214 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
215 | } | ||
216 | |||
217 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
218 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | ||
219 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | ||
220 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | ||
221 | if (mvmvif->dbgfs_pm.skip_over_dtim) | ||
222 | cmd->flags |= | ||
223 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
224 | else | ||
225 | cmd->flags &= | ||
226 | cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
227 | } | ||
228 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) | ||
229 | cmd->rx_data_timeout = | ||
230 | cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); | ||
231 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) | ||
232 | cmd->tx_data_timeout = | ||
233 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | ||
234 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | ||
235 | cmd->skip_dtim_periods = | ||
236 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
237 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
150 | } | 238 | } |
151 | 239 | ||
152 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 240 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
153 | { | 241 | { |
242 | int ret; | ||
243 | bool ba_enable; | ||
154 | struct iwl_powertable_cmd cmd = {}; | 244 | struct iwl_powertable_cmd cmd = {}; |
155 | 245 | ||
156 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 246 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
@@ -159,13 +249,22 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
159 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 249 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
160 | iwl_mvm_power_log(mvm, &cmd); | 250 | iwl_mvm_power_log(mvm, &cmd); |
161 | 251 | ||
162 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 252 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, |
163 | sizeof(cmd), &cmd); | 253 | sizeof(cmd), &cmd); |
254 | if (ret) | ||
255 | return ret; | ||
256 | |||
257 | ba_enable = !!(cmd.flags & | ||
258 | cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); | ||
259 | |||
260 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | ||
164 | } | 261 | } |
165 | 262 | ||
166 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 263 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
167 | { | 264 | { |
168 | struct iwl_powertable_cmd cmd = {}; | 265 | struct iwl_powertable_cmd cmd = {}; |
266 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
267 | iwl_mvm_vif_from_mac80211(vif); | ||
169 | 268 | ||
170 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 269 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
171 | return 0; | 270 | return 0; |
@@ -173,8 +272,82 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
173 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) | 272 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
174 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 273 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
175 | 274 | ||
275 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
276 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
277 | mvmvif->dbgfs_pm.disable_power_off) | ||
278 | cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
279 | #endif | ||
176 | iwl_mvm_power_log(mvm, &cmd); | 280 | iwl_mvm_power_log(mvm, &cmd); |
177 | 281 | ||
178 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | 282 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
179 | sizeof(cmd), &cmd); | 283 | sizeof(cmd), &cmd); |
180 | } | 284 | } |
285 | |||
286 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
287 | void | ||
288 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
289 | struct iwl_beacon_filter_cmd *cmd) | ||
290 | { | ||
291 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
292 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; | ||
293 | |||
294 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) | ||
295 | cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta; | ||
296 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) | ||
297 | cmd->bf_roaming_energy_delta = | ||
298 | dbgfs_bf->bf_roaming_energy_delta; | ||
299 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) | ||
300 | cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state; | ||
301 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA) | ||
302 | cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta; | ||
303 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) | ||
304 | cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag; | ||
305 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) | ||
306 | cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); | ||
307 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) | ||
308 | cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); | ||
309 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) | ||
310 | cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort; | ||
311 | } | ||
312 | #endif | ||
313 | |||
314 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | ||
315 | struct ieee80211_vif *vif) | ||
316 | { | ||
317 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
318 | struct iwl_beacon_filter_cmd cmd = { | ||
319 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
320 | .bf_enable_beacon_filter = 1, | ||
321 | }; | ||
322 | int ret; | ||
323 | |||
324 | if (mvmvif != mvm->bf_allowed_vif || | ||
325 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
326 | return 0; | ||
327 | |||
328 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | ||
329 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | ||
330 | |||
331 | if (!ret) | ||
332 | mvmvif->bf_enabled = true; | ||
333 | |||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | ||
338 | struct ieee80211_vif *vif) | ||
339 | { | ||
340 | struct iwl_beacon_filter_cmd cmd = {}; | ||
341 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
342 | int ret; | ||
343 | |||
344 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
345 | return 0; | ||
346 | |||
347 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | ||
348 | |||
349 | if (!ret) | ||
350 | mvmvif->bf_enabled = false; | ||
351 | |||
352 | return ret; | ||
353 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 55334d542e26..6a050c69e7d0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -3080,3 +3080,29 @@ void iwl_mvm_rate_control_unregister(void) | |||
3080 | { | 3080 | { |
3081 | ieee80211_rate_control_unregister(&rs_mvm_ops); | 3081 | ieee80211_rate_control_unregister(&rs_mvm_ops); |
3082 | } | 3082 | } |
3083 | |||
3084 | /** | ||
3085 | * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable | ||
3086 | * Tx protection, according to this rquest and previous requests, | ||
3087 | * and send the LQ command. | ||
3088 | * @lq: The LQ command | ||
3089 | * @mvmsta: The station | ||
3090 | * @enable: Enable Tx protection? | ||
3091 | */ | ||
3092 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
3093 | struct iwl_mvm_sta *mvmsta, bool enable) | ||
3094 | { | ||
3095 | lockdep_assert_held(&mvm->mutex); | ||
3096 | |||
3097 | if (enable) { | ||
3098 | if (mvmsta->tx_protection == 0) | ||
3099 | lq->flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; | ||
3100 | mvmsta->tx_protection++; | ||
3101 | } else { | ||
3102 | mvmsta->tx_protection--; | ||
3103 | if (mvmsta->tx_protection == 0) | ||
3104 | lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK; | ||
3105 | } | ||
3106 | |||
3107 | return iwl_mvm_send_lq_cmd(mvm, lq, CMD_ASYNC, false); | ||
3108 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 219c6857cc0f..f66155a57238 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -390,4 +390,9 @@ extern int iwl_mvm_rate_control_register(void); | |||
390 | */ | 390 | */ |
391 | extern void iwl_mvm_rate_control_unregister(void); | 391 | extern void iwl_mvm_rate_control_unregister(void); |
392 | 392 | ||
393 | struct iwl_mvm_sta; | ||
394 | |||
395 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
396 | struct iwl_mvm_sta *mvmsta, bool enable); | ||
397 | |||
393 | #endif /* __rs__ */ | 398 | #endif /* __rs__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 4dfc21a3e83e..e4930d5027d2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -363,3 +363,25 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
363 | rxb, &rx_status); | 363 | rxb, &rx_status); |
364 | return 0; | 364 | return 0; |
365 | } | 365 | } |
366 | |||
367 | /* | ||
368 | * iwl_mvm_rx_statistics - STATISTICS_NOTIFICATION handler | ||
369 | * | ||
370 | * TODO: This handler is implemented partially. | ||
371 | * It only gets the NIC's temperature. | ||
372 | */ | ||
373 | int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, | ||
374 | struct iwl_rx_cmd_buffer *rxb, | ||
375 | struct iwl_device_cmd *cmd) | ||
376 | { | ||
377 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
378 | struct iwl_notif_statistics *stats = (void *)&pkt->data; | ||
379 | struct mvm_statistics_general_common *common = &stats->general.common; | ||
380 | |||
381 | if (mvm->temperature != le32_to_cpu(common->temperature)) { | ||
382 | mvm->temperature = le32_to_cpu(common->temperature); | ||
383 | iwl_mvm_tt_handler(mvm); | ||
384 | } | ||
385 | |||
386 | return 0; | ||
387 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 0fd96e4da461..2278858d5658 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -64,6 +64,7 @@ | |||
64 | 64 | ||
65 | #include "mvm.h" | 65 | #include "mvm.h" |
66 | #include "sta.h" | 66 | #include "sta.h" |
67 | #include "rs.h" | ||
67 | 68 | ||
68 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | 69 | static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) |
69 | { | 70 | { |
@@ -217,9 +218,11 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
217 | mvmvif->color); | 218 | mvmvif->color); |
218 | mvm_sta->vif = vif; | 219 | mvm_sta->vif = vif; |
219 | mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; | 220 | mvm_sta->max_agg_bufsize = LINK_QUAL_AGG_FRAME_LIMIT_DEF; |
221 | mvm_sta->tx_protection = 0; | ||
222 | mvm_sta->tt_tx_protection = false; | ||
220 | 223 | ||
221 | /* HW restart, don't assume the memory has been zeroed */ | 224 | /* HW restart, don't assume the memory has been zeroed */ |
222 | atomic_set(&mvm_sta->pending_frames, 0); | 225 | atomic_set(&mvm->pending_frames[sta_id], 0); |
223 | mvm_sta->tid_disable_agg = 0; | 226 | mvm_sta->tid_disable_agg = 0; |
224 | mvm_sta->tfd_queue_msk = 0; | 227 | mvm_sta->tfd_queue_msk = 0; |
225 | for (i = 0; i < IEEE80211_NUM_ACS; i++) | 228 | for (i = 0; i < IEEE80211_NUM_ACS; i++) |
@@ -407,14 +410,21 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
407 | } | 410 | } |
408 | 411 | ||
409 | /* | 412 | /* |
413 | * Make sure that the tx response code sees the station as -EBUSY and | ||
414 | * calls the drain worker. | ||
415 | */ | ||
416 | spin_lock_bh(&mvm_sta->lock); | ||
417 | /* | ||
410 | * There are frames pending on the AC queues for this station. | 418 | * There are frames pending on the AC queues for this station. |
411 | * We need to wait until all the frames are drained... | 419 | * We need to wait until all the frames are drained... |
412 | */ | 420 | */ |
413 | if (atomic_read(&mvm_sta->pending_frames)) { | 421 | if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) { |
414 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); | ||
415 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], | 422 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], |
416 | ERR_PTR(-EBUSY)); | 423 | ERR_PTR(-EBUSY)); |
424 | spin_unlock_bh(&mvm_sta->lock); | ||
425 | ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); | ||
417 | } else { | 426 | } else { |
427 | spin_unlock_bh(&mvm_sta->lock); | ||
418 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); | 428 | ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); |
419 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); | 429 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); |
420 | } | 430 | } |
@@ -791,21 +801,23 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
791 | min(mvmsta->max_agg_bufsize, buf_size); | 801 | min(mvmsta->max_agg_bufsize, buf_size); |
792 | mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize; | 802 | mvmsta->lq_sta.lq.agg_frame_cnt_limit = mvmsta->max_agg_bufsize; |
793 | 803 | ||
804 | IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", | ||
805 | sta->addr, tid); | ||
806 | |||
794 | if (mvm->cfg->ht_params->use_rts_for_aggregation) { | 807 | if (mvm->cfg->ht_params->use_rts_for_aggregation) { |
795 | /* | 808 | /* |
796 | * switch to RTS/CTS if it is the prefer protection | 809 | * switch to RTS/CTS if it is the prefer protection |
797 | * method for HT traffic | 810 | * method for HT traffic |
811 | * this function also sends the LQ command | ||
798 | */ | 812 | */ |
799 | mvmsta->lq_sta.lq.flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; | 813 | return iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, |
814 | mvmsta, true); | ||
800 | /* | 815 | /* |
801 | * TODO: remove the TLC_RTS flag when we tear down the last | 816 | * TODO: remove the TLC_RTS flag when we tear down the last |
802 | * AGG session (agg_tids_count in DVM) | 817 | * AGG session (agg_tids_count in DVM) |
803 | */ | 818 | */ |
804 | } | 819 | } |
805 | 820 | ||
806 | IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", | ||
807 | sta->addr, tid); | ||
808 | |||
809 | return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); | 821 | return iwl_mvm_send_lq_cmd(mvm, &mvmsta->lq_sta.lq, CMD_ASYNC, false); |
810 | } | 822 | } |
811 | 823 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 12abd2d71835..3efa0a0cc987 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -274,8 +274,9 @@ struct iwl_mvm_tid_data { | |||
274 | * @bt_reduced_txpower: is reduced tx power enabled for this station | 274 | * @bt_reduced_txpower: is reduced tx power enabled for this station |
275 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx | 275 | * @lock: lock to protect the whole struct. Since %tid_data is access from Tx |
276 | * and from Tx response flow, it needs a spinlock. | 276 | * and from Tx response flow, it needs a spinlock. |
277 | * @pending_frames: number of frames for this STA on the shared Tx queues. | ||
278 | * @tid_data: per tid data. Look at %iwl_mvm_tid_data. | 277 | * @tid_data: per tid data. Look at %iwl_mvm_tid_data. |
278 | * @tx_protection: reference counter for controlling the Tx protection. | ||
279 | * @tt_tx_protection: is thermal throttling enable Tx protection? | ||
279 | * | 280 | * |
280 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) | 281 | * When mac80211 creates a station it reserves some space (hw->sta_data_size) |
281 | * in the structure for use by driver. This structure is placed in that | 282 | * in the structure for use by driver. This structure is placed in that |
@@ -290,7 +291,6 @@ struct iwl_mvm_sta { | |||
290 | u8 max_agg_bufsize; | 291 | u8 max_agg_bufsize; |
291 | bool bt_reduced_txpower; | 292 | bool bt_reduced_txpower; |
292 | spinlock_t lock; | 293 | spinlock_t lock; |
293 | atomic_t pending_frames; | ||
294 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; | 294 | struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT]; |
295 | struct iwl_lq_sta lq_sta; | 295 | struct iwl_lq_sta lq_sta; |
296 | struct ieee80211_vif *vif; | 296 | struct ieee80211_vif *vif; |
@@ -298,6 +298,10 @@ struct iwl_mvm_sta { | |||
298 | #ifdef CONFIG_PM_SLEEP | 298 | #ifdef CONFIG_PM_SLEEP |
299 | u16 last_seq_ctl; | 299 | u16 last_seq_ctl; |
300 | #endif | 300 | #endif |
301 | |||
302 | /* Temporary, until the new TLC will control the Tx protection */ | ||
303 | s8 tx_protection; | ||
304 | bool tt_tx_protection; | ||
301 | }; | 305 | }; |
302 | 306 | ||
303 | /** | 307 | /** |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c new file mode 100644 index 000000000000..4665fc033c17 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -0,0 +1,509 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
4 | * redistributing this file, you may do so under either license. | ||
5 | * | ||
6 | * GPL LICENSE SUMMARY | ||
7 | * | ||
8 | * Copyright(c) 2013 Intel Corporation. All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
22 | * USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution | ||
25 | * in the file called COPYING. | ||
26 | * | ||
27 | * Contact Information: | ||
28 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
29 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | * | ||
31 | * BSD LICENSE | ||
32 | * | ||
33 | * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. | ||
34 | * All rights reserved. | ||
35 | * | ||
36 | * Redistribution and use in source and binary forms, with or without | ||
37 | * modification, are permitted provided that the following conditions | ||
38 | * are met: | ||
39 | * | ||
40 | * * Redistributions of source code must retain the above copyright | ||
41 | * notice, this list of conditions and the following disclaimer. | ||
42 | * * Redistributions in binary form must reproduce the above copyright | ||
43 | * notice, this list of conditions and the following disclaimer in | ||
44 | * the documentation and/or other materials provided with the | ||
45 | * distribution. | ||
46 | * * Neither the name Intel Corporation nor the names of its | ||
47 | * contributors may be used to endorse or promote products derived | ||
48 | * from this software without specific prior written permission. | ||
49 | * | ||
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
52 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
53 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
54 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
55 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
56 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
57 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
58 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
59 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
61 | * | ||
62 | *****************************************************************************/ | ||
63 | |||
64 | #include "mvm.h" | ||
65 | #include "iwl-config.h" | ||
66 | #include "iwl-io.h" | ||
67 | #include "iwl-csr.h" | ||
68 | #include "iwl-prph.h" | ||
69 | |||
70 | #define OTP_DTS_DIODE_DEVIATION 96 /*in words*/ | ||
71 | /* VBG - Voltage Band Gap error data (temperature offset) */ | ||
72 | #define OTP_WP_DTS_VBG (OTP_DTS_DIODE_DEVIATION + 2) | ||
73 | #define MEAS_VBG_MIN_VAL 2300 | ||
74 | #define MEAS_VBG_MAX_VAL 3000 | ||
75 | #define MEAS_VBG_DEFAULT_VAL 2700 | ||
76 | #define DTS_DIODE_VALID(flags) (flags & DTS_DIODE_REG_FLAGS_PASS_ONCE) | ||
77 | #define MIN_TEMPERATURE 0 | ||
78 | #define MAX_TEMPERATURE 125 | ||
79 | #define TEMPERATURE_ERROR (MAX_TEMPERATURE + 1) | ||
80 | #define PTAT_DIGITAL_VALUE_MIN_VALUE 0 | ||
81 | #define PTAT_DIGITAL_VALUE_MAX_VALUE 0xFF | ||
82 | #define DTS_VREFS_NUM 5 | ||
83 | static inline u32 DTS_DIODE_GET_VREFS_ID(u32 flags) | ||
84 | { | ||
85 | return (flags & DTS_DIODE_REG_FLAGS_VREFS_ID) >> | ||
86 | DTS_DIODE_REG_FLAGS_VREFS_ID_POS; | ||
87 | } | ||
88 | |||
89 | #define CALC_VREFS_MIN_DIFF 43 | ||
90 | #define CALC_VREFS_MAX_DIFF 51 | ||
91 | #define CALC_LUT_SIZE (1 + CALC_VREFS_MAX_DIFF - CALC_VREFS_MIN_DIFF) | ||
92 | #define CALC_LUT_INDEX_OFFSET CALC_VREFS_MIN_DIFF | ||
93 | #define CALC_TEMPERATURE_RESULT_SHIFT_OFFSET 23 | ||
94 | |||
95 | /* | ||
96 | * @digital_value: The diode's digital-value sampled (temperature/voltage) | ||
97 | * @vref_low: The lower voltage-reference (the vref just below the diode's | ||
98 | * sampled digital-value) | ||
99 | * @vref_high: The higher voltage-reference (the vref just above the diode's | ||
100 | * sampled digital-value) | ||
101 | * @flags: bits[1:0]: The ID of the Vrefs pair (lowVref,highVref) | ||
102 | * bits[6:2]: Reserved. | ||
103 | * bits[7:7]: Indicates completion of at least 1 successful sample | ||
104 | * since last DTS reset. | ||
105 | */ | ||
106 | struct iwl_mvm_dts_diode_bits { | ||
107 | u8 digital_value; | ||
108 | u8 vref_low; | ||
109 | u8 vref_high; | ||
110 | u8 flags; | ||
111 | } __packed; | ||
112 | |||
113 | union dts_diode_results { | ||
114 | u32 reg_value; | ||
115 | struct iwl_mvm_dts_diode_bits bits; | ||
116 | } __packed; | ||
117 | |||
118 | static s16 iwl_mvm_dts_get_volt_band_gap(struct iwl_mvm *mvm) | ||
119 | { | ||
120 | struct iwl_nvm_section calib_sec; | ||
121 | const __le16 *calib; | ||
122 | u16 vbg; | ||
123 | |||
124 | /* TODO: move parsing to NVM code */ | ||
125 | calib_sec = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION]; | ||
126 | calib = (__le16 *)calib_sec.data; | ||
127 | |||
128 | vbg = le16_to_cpu(calib[OTP_WP_DTS_VBG]); | ||
129 | |||
130 | if (vbg < MEAS_VBG_MIN_VAL || vbg > MEAS_VBG_MAX_VAL) | ||
131 | vbg = MEAS_VBG_DEFAULT_VAL; | ||
132 | |||
133 | return vbg; | ||
134 | } | ||
135 | |||
136 | static u16 iwl_mvm_dts_get_ptat_deviation_offset(struct iwl_mvm *mvm) | ||
137 | { | ||
138 | const u8 *calib; | ||
139 | u8 ptat, pa1, pa2, median; | ||
140 | |||
141 | /* TODO: move parsing to NVM code */ | ||
142 | calib = mvm->nvm_sections[NVM_SECTION_TYPE_CALIBRATION].data; | ||
143 | ptat = calib[OTP_DTS_DIODE_DEVIATION]; | ||
144 | pa1 = calib[OTP_DTS_DIODE_DEVIATION + 1]; | ||
145 | pa2 = calib[OTP_DTS_DIODE_DEVIATION + 2]; | ||
146 | |||
147 | /* get the median: */ | ||
148 | if (ptat > pa1) { | ||
149 | if (ptat > pa2) | ||
150 | median = (pa1 > pa2) ? pa1 : pa2; | ||
151 | else | ||
152 | median = ptat; | ||
153 | } else { | ||
154 | if (pa1 > pa2) | ||
155 | median = (ptat > pa2) ? ptat : pa2; | ||
156 | else | ||
157 | median = pa1; | ||
158 | } | ||
159 | |||
160 | return ptat - median; | ||
161 | } | ||
162 | |||
163 | static u8 iwl_mvm_dts_calibrate_ptat_deviation(struct iwl_mvm *mvm, u8 value) | ||
164 | { | ||
165 | /* Calibrate the PTAT digital value, based on PTAT deviation data: */ | ||
166 | s16 new_val = value - iwl_mvm_dts_get_ptat_deviation_offset(mvm); | ||
167 | |||
168 | if (new_val > PTAT_DIGITAL_VALUE_MAX_VALUE) | ||
169 | new_val = PTAT_DIGITAL_VALUE_MAX_VALUE; | ||
170 | else if (new_val < PTAT_DIGITAL_VALUE_MIN_VALUE) | ||
171 | new_val = PTAT_DIGITAL_VALUE_MIN_VALUE; | ||
172 | |||
173 | return new_val; | ||
174 | } | ||
175 | |||
176 | static bool dts_get_adjacent_vrefs(struct iwl_mvm *mvm, | ||
177 | union dts_diode_results *avg_ptat) | ||
178 | { | ||
179 | u8 vrefs_results[DTS_VREFS_NUM]; | ||
180 | u8 low_vref_index = 0, flags; | ||
181 | u32 reg; | ||
182 | |||
183 | reg = iwl_read_prph(mvm->trans, DTSC_VREF_AVG); | ||
184 | memcpy(vrefs_results, ®, sizeof(reg)); | ||
185 | reg = iwl_read_prph(mvm->trans, DTSC_VREF5_AVG); | ||
186 | vrefs_results[4] = reg & 0xff; | ||
187 | |||
188 | if (avg_ptat->bits.digital_value < vrefs_results[0] || | ||
189 | avg_ptat->bits.digital_value > vrefs_results[4]) | ||
190 | return false; | ||
191 | |||
192 | if (avg_ptat->bits.digital_value > vrefs_results[3]) | ||
193 | low_vref_index = 3; | ||
194 | else if (avg_ptat->bits.digital_value > vrefs_results[2]) | ||
195 | low_vref_index = 2; | ||
196 | else if (avg_ptat->bits.digital_value > vrefs_results[1]) | ||
197 | low_vref_index = 1; | ||
198 | |||
199 | avg_ptat->bits.vref_low = vrefs_results[low_vref_index]; | ||
200 | avg_ptat->bits.vref_high = vrefs_results[low_vref_index + 1]; | ||
201 | flags = avg_ptat->bits.flags; | ||
202 | avg_ptat->bits.flags = | ||
203 | (flags & ~DTS_DIODE_REG_FLAGS_VREFS_ID) | | ||
204 | (low_vref_index & DTS_DIODE_REG_FLAGS_VREFS_ID); | ||
205 | return true; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * return true it the results are valid, and false otherwise. | ||
210 | */ | ||
211 | static bool dts_read_ptat_avg_results(struct iwl_mvm *mvm, | ||
212 | union dts_diode_results *avg_ptat) | ||
213 | { | ||
214 | u32 reg; | ||
215 | u8 tmp; | ||
216 | |||
217 | /* fill the diode value and pass_once with avg-reg results */ | ||
218 | reg = iwl_read_prph(mvm->trans, DTSC_PTAT_AVG); | ||
219 | reg &= DTS_DIODE_REG_DIG_VAL | DTS_DIODE_REG_PASS_ONCE; | ||
220 | avg_ptat->reg_value = reg; | ||
221 | |||
222 | /* calibrate the PTAT digital value */ | ||
223 | tmp = avg_ptat->bits.digital_value; | ||
224 | tmp = iwl_mvm_dts_calibrate_ptat_deviation(mvm, tmp); | ||
225 | avg_ptat->bits.digital_value = tmp; | ||
226 | |||
227 | /* | ||
228 | * fill vrefs fields, based on the avgVrefs results | ||
229 | * and the diode value | ||
230 | */ | ||
231 | return dts_get_adjacent_vrefs(mvm, avg_ptat) && | ||
232 | DTS_DIODE_VALID(avg_ptat->bits.flags); | ||
233 | } | ||
234 | |||
235 | static s32 calculate_nic_temperature(union dts_diode_results avg_ptat, | ||
236 | u16 volt_band_gap) | ||
237 | { | ||
238 | u32 tmp_result; | ||
239 | u8 vrefs_diff; | ||
240 | /* | ||
241 | * For temperature calculation (at the end, shift right by 23) | ||
242 | * LUT[(D2-D1)] = ROUND{ 2^23 / ((D2-D1)*9*10) } | ||
243 | * (D2-D1) == 43 44 45 46 47 48 49 50 51 | ||
244 | */ | ||
245 | static const u16 calc_lut[CALC_LUT_SIZE] = { | ||
246 | 2168, 2118, 2071, 2026, 1983, 1942, 1902, 1864, 1828, | ||
247 | }; | ||
248 | |||
249 | /* | ||
250 | * The diff between the high and low voltage-references is assumed | ||
251 | * to be strictly be in range of [60,68] | ||
252 | */ | ||
253 | vrefs_diff = avg_ptat.bits.vref_high - avg_ptat.bits.vref_low; | ||
254 | |||
255 | if (vrefs_diff < CALC_VREFS_MIN_DIFF || | ||
256 | vrefs_diff > CALC_VREFS_MAX_DIFF) | ||
257 | return TEMPERATURE_ERROR; | ||
258 | |||
259 | /* calculate the result: */ | ||
260 | tmp_result = | ||
261 | vrefs_diff * (DTS_DIODE_GET_VREFS_ID(avg_ptat.bits.flags) + 9); | ||
262 | tmp_result += avg_ptat.bits.digital_value; | ||
263 | tmp_result -= avg_ptat.bits.vref_high; | ||
264 | |||
265 | /* multiply by the LUT value (based on the diff) */ | ||
266 | tmp_result *= calc_lut[vrefs_diff - CALC_LUT_INDEX_OFFSET]; | ||
267 | |||
268 | /* | ||
269 | * Get the BandGap (the voltage refereces source) error data | ||
270 | * (temperature offset) | ||
271 | */ | ||
272 | tmp_result *= volt_band_gap; | ||
273 | |||
274 | /* | ||
275 | * here, tmp_result value can be up to 32-bits. We want to right-shift | ||
276 | * it *without* sign-extend. | ||
277 | */ | ||
278 | tmp_result = tmp_result >> CALC_TEMPERATURE_RESULT_SHIFT_OFFSET; | ||
279 | |||
280 | /* | ||
281 | * at this point, tmp_result should be in the range: | ||
282 | * 200 <= tmp_result <= 365 | ||
283 | */ | ||
284 | return (s16)tmp_result - 240; | ||
285 | } | ||
286 | |||
287 | static s32 check_nic_temperature(struct iwl_mvm *mvm) | ||
288 | { | ||
289 | u16 volt_band_gap; | ||
290 | union dts_diode_results avg_ptat; | ||
291 | |||
292 | volt_band_gap = iwl_mvm_dts_get_volt_band_gap(mvm); | ||
293 | |||
294 | /* disable DTS */ | ||
295 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | ||
296 | |||
297 | /* SV initialization */ | ||
298 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 1); | ||
299 | iwl_write_prph(mvm->trans, DTSC_CFG_MODE, | ||
300 | DTSC_CFG_MODE_PERIODIC); | ||
301 | |||
302 | /* wait for results */ | ||
303 | msleep(100); | ||
304 | if (!dts_read_ptat_avg_results(mvm, &avg_ptat)) | ||
305 | return TEMPERATURE_ERROR; | ||
306 | |||
307 | /* disable DTS */ | ||
308 | iwl_write_prph(mvm->trans, SHR_MISC_WFM_DTS_EN, 0); | ||
309 | |||
310 | return calculate_nic_temperature(avg_ptat, volt_band_gap); | ||
311 | } | ||
312 | |||
313 | static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) | ||
314 | { | ||
315 | u32 duration = mvm->thermal_throttle.params->ct_kill_duration; | ||
316 | |||
317 | IWL_ERR(mvm, "Enter CT Kill\n"); | ||
318 | iwl_mvm_set_hw_ctkill_state(mvm, true); | ||
319 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | ||
320 | round_jiffies_relative(duration * HZ)); | ||
321 | } | ||
322 | |||
323 | static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm) | ||
324 | { | ||
325 | IWL_ERR(mvm, "Exit CT Kill\n"); | ||
326 | iwl_mvm_set_hw_ctkill_state(mvm, false); | ||
327 | } | ||
328 | |||
329 | static void check_exit_ctkill(struct work_struct *work) | ||
330 | { | ||
331 | struct iwl_mvm_tt_mgmt *tt; | ||
332 | struct iwl_mvm *mvm; | ||
333 | u32 duration; | ||
334 | s32 temp; | ||
335 | |||
336 | tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work); | ||
337 | mvm = container_of(tt, struct iwl_mvm, thermal_throttle); | ||
338 | |||
339 | duration = tt->params->ct_kill_duration; | ||
340 | |||
341 | iwl_trans_start_hw(mvm->trans); | ||
342 | temp = check_nic_temperature(mvm); | ||
343 | iwl_trans_stop_hw(mvm->trans, false); | ||
344 | |||
345 | if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { | ||
346 | IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); | ||
347 | goto reschedule; | ||
348 | } | ||
349 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp); | ||
350 | |||
351 | if (temp <= tt->params->ct_kill_exit) { | ||
352 | iwl_mvm_exit_ctkill(mvm); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | reschedule: | ||
357 | schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit, | ||
358 | round_jiffies(duration * HZ)); | ||
359 | } | ||
360 | |||
361 | static void iwl_mvm_tt_smps_iterator(void *_data, u8 *mac, | ||
362 | struct ieee80211_vif *vif) | ||
363 | { | ||
364 | struct iwl_mvm *mvm = _data; | ||
365 | enum ieee80211_smps_mode smps_mode; | ||
366 | |||
367 | lockdep_assert_held(&mvm->mutex); | ||
368 | |||
369 | if (mvm->thermal_throttle.dynamic_smps) | ||
370 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
371 | else | ||
372 | smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
373 | |||
374 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode); | ||
375 | } | ||
376 | |||
377 | static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | ||
378 | { | ||
379 | struct ieee80211_sta *sta; | ||
380 | struct iwl_mvm_sta *mvmsta; | ||
381 | int i, err; | ||
382 | |||
383 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
384 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
385 | lockdep_is_held(&mvm->mutex)); | ||
386 | if (IS_ERR_OR_NULL(sta)) | ||
387 | continue; | ||
388 | mvmsta = (void *)sta->drv_priv; | ||
389 | if (enable == mvmsta->tt_tx_protection) | ||
390 | continue; | ||
391 | err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, | ||
392 | mvmsta, enable); | ||
393 | if (err) { | ||
394 | IWL_ERR(mvm, "Failed to %s Tx protection\n", | ||
395 | enable ? "enable" : "disable"); | ||
396 | } else { | ||
397 | IWL_DEBUG_TEMP(mvm, "%s Tx protection\n", | ||
398 | enable ? "Enable" : "Disable"); | ||
399 | mvmsta->tt_tx_protection = enable; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | ||
405 | { | ||
406 | struct iwl_host_cmd cmd = { | ||
407 | .id = REPLY_THERMAL_MNG_BACKOFF, | ||
408 | .len = { sizeof(u32), }, | ||
409 | .data = { &backoff, }, | ||
410 | .flags = CMD_SYNC, | ||
411 | }; | ||
412 | |||
413 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { | ||
414 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", | ||
415 | backoff); | ||
416 | mvm->thermal_throttle.tx_backoff = backoff; | ||
417 | } else { | ||
418 | IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n"); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm) | ||
423 | { | ||
424 | const struct iwl_tt_params *params = mvm->thermal_throttle.params; | ||
425 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
426 | s32 temperature = mvm->temperature; | ||
427 | int i; | ||
428 | u32 tx_backoff; | ||
429 | |||
430 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature); | ||
431 | |||
432 | if (params->support_ct_kill && temperature >= params->ct_kill_entry) { | ||
433 | iwl_mvm_enter_ctkill(mvm); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | if (params->support_dynamic_smps) { | ||
438 | if (!tt->dynamic_smps && | ||
439 | temperature >= params->dynamic_smps_entry) { | ||
440 | IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n"); | ||
441 | tt->dynamic_smps = true; | ||
442 | ieee80211_iterate_active_interfaces_atomic( | ||
443 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
444 | iwl_mvm_tt_smps_iterator, mvm); | ||
445 | } else if (tt->dynamic_smps && | ||
446 | temperature <= params->dynamic_smps_exit) { | ||
447 | IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n"); | ||
448 | tt->dynamic_smps = false; | ||
449 | ieee80211_iterate_active_interfaces_atomic( | ||
450 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
451 | iwl_mvm_tt_smps_iterator, mvm); | ||
452 | } | ||
453 | } | ||
454 | |||
455 | if (params->support_tx_protection) { | ||
456 | if (temperature >= params->tx_protection_entry) | ||
457 | iwl_mvm_tt_tx_protection(mvm, true); | ||
458 | else if (temperature <= params->tx_protection_exit) | ||
459 | iwl_mvm_tt_tx_protection(mvm, false); | ||
460 | } | ||
461 | |||
462 | if (params->support_tx_backoff) { | ||
463 | tx_backoff = 0; | ||
464 | for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { | ||
465 | if (temperature < params->tx_backoff[i].temperature) | ||
466 | break; | ||
467 | tx_backoff = params->tx_backoff[i].backoff; | ||
468 | } | ||
469 | if (tt->tx_backoff != tx_backoff) | ||
470 | iwl_mvm_tt_tx_backoff(mvm, tx_backoff); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static const struct iwl_tt_params iwl7000_tt_params = { | ||
475 | .ct_kill_entry = 118, | ||
476 | .ct_kill_exit = 96, | ||
477 | .ct_kill_duration = 5, | ||
478 | .dynamic_smps_entry = 114, | ||
479 | .dynamic_smps_exit = 110, | ||
480 | .tx_protection_entry = 114, | ||
481 | .tx_protection_exit = 108, | ||
482 | .tx_backoff = { | ||
483 | {.temperature = 112, .backoff = 200}, | ||
484 | {.temperature = 113, .backoff = 600}, | ||
485 | {.temperature = 114, .backoff = 1200}, | ||
486 | {.temperature = 115, .backoff = 2000}, | ||
487 | {.temperature = 116, .backoff = 4000}, | ||
488 | {.temperature = 117, .backoff = 10000}, | ||
489 | }, | ||
490 | .support_ct_kill = true, | ||
491 | .support_dynamic_smps = true, | ||
492 | .support_tx_protection = true, | ||
493 | .support_tx_backoff = true, | ||
494 | }; | ||
495 | |||
496 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | ||
497 | { | ||
498 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
499 | |||
500 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); | ||
501 | tt->params = &iwl7000_tt_params; | ||
502 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | ||
503 | } | ||
504 | |||
505 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm) | ||
506 | { | ||
507 | cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); | ||
508 | IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); | ||
509 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 479074303bd7..f212f16502ff 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -416,9 +416,8 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, | |||
416 | 416 | ||
417 | spin_unlock(&mvmsta->lock); | 417 | spin_unlock(&mvmsta->lock); |
418 | 418 | ||
419 | if (mvmsta->vif->type == NL80211_IFTYPE_AP && | 419 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE) |
420 | txq_id < IWL_MVM_FIRST_AGG_QUEUE) | 420 | atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); |
421 | atomic_inc(&mvmsta->pending_frames); | ||
422 | 421 | ||
423 | return 0; | 422 | return 0; |
424 | 423 | ||
@@ -680,16 +679,41 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
680 | /* | 679 | /* |
681 | * If the txq is not an AMPDU queue, there is no chance we freed | 680 | * If the txq is not an AMPDU queue, there is no chance we freed |
682 | * several skbs. Check that out... | 681 | * several skbs. Check that out... |
683 | * If there are no pending frames for this STA, notify mac80211 that | ||
684 | * this station can go to sleep in its STA table. | ||
685 | */ | 682 | */ |
686 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta && | 683 | if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && !WARN_ON(skb_freed > 1) && |
687 | !WARN_ON(skb_freed > 1) && | 684 | atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) { |
688 | mvmsta->vif->type == NL80211_IFTYPE_AP && | 685 | if (mvmsta) { |
689 | atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) { | 686 | /* |
690 | ieee80211_sta_block_awake(mvm->hw, sta, false); | 687 | * If there are no pending frames for this STA, notify |
691 | set_bit(sta_id, mvm->sta_drained); | 688 | * mac80211 that this station can go to sleep in its |
692 | schedule_work(&mvm->sta_drained_wk); | 689 | * STA table. |
690 | */ | ||
691 | if (mvmsta->vif->type == NL80211_IFTYPE_AP) | ||
692 | ieee80211_sta_block_awake(mvm->hw, sta, false); | ||
693 | /* | ||
694 | * We might very well have taken mvmsta pointer while | ||
695 | * the station was being removed. The remove flow might | ||
696 | * have seen a pending_frame (because we didn't take | ||
697 | * the lock) even if now the queues are drained. So make | ||
698 | * really sure now that this the station is not being | ||
699 | * removed. If it is, run the drain worker to remove it. | ||
700 | */ | ||
701 | spin_lock_bh(&mvmsta->lock); | ||
702 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
703 | if (IS_ERR_OR_NULL(sta)) { | ||
704 | /* | ||
705 | * Station disappeared in the meantime: | ||
706 | * so we are draining. | ||
707 | */ | ||
708 | set_bit(sta_id, mvm->sta_drained); | ||
709 | schedule_work(&mvm->sta_drained_wk); | ||
710 | } | ||
711 | spin_unlock_bh(&mvmsta->lock); | ||
712 | } else if (!mvmsta) { | ||
713 | /* Tx response without STA, so we are draining */ | ||
714 | set_bit(sta_id, mvm->sta_drained); | ||
715 | schedule_work(&mvm->sta_drained_wk); | ||
716 | } | ||
693 | } | 717 | } |
694 | 718 | ||
695 | rcu_read_unlock(); | 719 | rcu_read_unlock(); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 687b34e387ac..c9b44ab4af07 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -471,3 +471,34 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
471 | 471 | ||
472 | return iwl_mvm_send_cmd(mvm, &cmd); | 472 | return iwl_mvm_send_cmd(mvm, &cmd); |
473 | } | 473 | } |
474 | |||
475 | /** | ||
476 | * iwl_mvm_update_smps - Get a requst to change the SMPS mode | ||
477 | * @req_type: The part of the driver who call for a change. | ||
478 | * @smps_requests: The request to change the SMPS mode. | ||
479 | * | ||
480 | * Get a requst to change the SMPS mode, | ||
481 | * and change it according to all other requests in the driver. | ||
482 | */ | ||
483 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
484 | enum iwl_mvm_smps_type_request req_type, | ||
485 | enum ieee80211_smps_mode smps_request) | ||
486 | { | ||
487 | struct iwl_mvm_vif *mvmvif; | ||
488 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
489 | int i; | ||
490 | |||
491 | lockdep_assert_held(&mvm->mutex); | ||
492 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
493 | mvmvif->smps_requests[req_type] = smps_request; | ||
494 | for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { | ||
495 | if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC) { | ||
496 | smps_mode = IEEE80211_SMPS_STATIC; | ||
497 | break; | ||
498 | } | ||
499 | if (mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) | ||
500 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
501 | } | ||
502 | |||
503 | ieee80211_request_smps(vif, smps_mode); | ||
504 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 8cb53ec2b77b..db7bdd35a9c5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c | |||
@@ -256,10 +256,54 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { | |||
256 | 256 | ||
257 | /* 7000 Series */ | 257 | /* 7000 Series */ |
258 | {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, | 258 | {IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)}, |
259 | {IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_2ac_cfg)}, | 259 | {IWL_PCI_DEVICE(0x08B1, 0x4170, iwl7260_2ac_cfg)}, |
260 | {IWL_PCI_DEVICE(0x08B1, 0x4060, iwl7260_2n_cfg)}, | ||
261 | {IWL_PCI_DEVICE(0x08B1, 0x4160, iwl7260_2n_cfg)}, | ||
262 | {IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_n_cfg)}, | ||
263 | {IWL_PCI_DEVICE(0x08B1, 0x4162, iwl7260_n_cfg)}, | ||
264 | {IWL_PCI_DEVICE(0x08B2, 0x4270, iwl7260_2ac_cfg)}, | ||
265 | {IWL_PCI_DEVICE(0x08B2, 0x4260, iwl7260_2n_cfg)}, | ||
266 | {IWL_PCI_DEVICE(0x08B2, 0x4262, iwl7260_n_cfg)}, | ||
267 | {IWL_PCI_DEVICE(0x08B1, 0x4470, iwl7260_2ac_cfg)}, | ||
268 | {IWL_PCI_DEVICE(0x08B1, 0x4460, iwl7260_2n_cfg)}, | ||
269 | {IWL_PCI_DEVICE(0x08B1, 0x4462, iwl7260_n_cfg)}, | ||
270 | {IWL_PCI_DEVICE(0x08B1, 0x4870, iwl7260_2ac_cfg)}, | ||
271 | {IWL_PCI_DEVICE(0x08B1, 0x486E, iwl7260_2ac_cfg)}, | ||
272 | {IWL_PCI_DEVICE(0x08B1, 0x4A70, iwl7260_2ac_cfg)}, | ||
273 | {IWL_PCI_DEVICE(0x08B1, 0x4A6E, iwl7260_2ac_cfg)}, | ||
274 | {IWL_PCI_DEVICE(0x08B1, 0x4A6C, iwl7260_2ac_cfg)}, | ||
275 | {IWL_PCI_DEVICE(0x08B1, 0x4020, iwl7260_2n_cfg)}, | ||
276 | {IWL_PCI_DEVICE(0x08B2, 0x4220, iwl7260_2n_cfg)}, | ||
277 | {IWL_PCI_DEVICE(0x08B1, 0x4420, iwl7260_2n_cfg)}, | ||
260 | {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)}, | 278 | {IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)}, |
261 | {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)}, | 279 | {IWL_PCI_DEVICE(0x08B1, 0xC170, iwl7260_2ac_cfg)}, |
262 | {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)}, | 280 | {IWL_PCI_DEVICE(0x08B1, 0xC060, iwl7260_2n_cfg)}, |
281 | {IWL_PCI_DEVICE(0x08B1, 0xC160, iwl7260_2n_cfg)}, | ||
282 | {IWL_PCI_DEVICE(0x08B1, 0xC062, iwl7260_n_cfg)}, | ||
283 | {IWL_PCI_DEVICE(0x08B1, 0xC162, iwl7260_n_cfg)}, | ||
284 | {IWL_PCI_DEVICE(0x08B2, 0xC270, iwl7260_2ac_cfg)}, | ||
285 | {IWL_PCI_DEVICE(0x08B2, 0xC260, iwl7260_2n_cfg)}, | ||
286 | {IWL_PCI_DEVICE(0x08B2, 0xC262, iwl7260_n_cfg)}, | ||
287 | {IWL_PCI_DEVICE(0x08B1, 0xC470, iwl7260_2ac_cfg)}, | ||
288 | {IWL_PCI_DEVICE(0x08B1, 0xC460, iwl7260_2n_cfg)}, | ||
289 | {IWL_PCI_DEVICE(0x08B1, 0xC462, iwl7260_n_cfg)}, | ||
290 | {IWL_PCI_DEVICE(0x08B1, 0xC020, iwl7260_2n_cfg)}, | ||
291 | {IWL_PCI_DEVICE(0x08B2, 0xC220, iwl7260_2n_cfg)}, | ||
292 | {IWL_PCI_DEVICE(0x08B1, 0xC420, iwl7260_2n_cfg)}, | ||
293 | |||
294 | /* 3160 Series */ | ||
295 | {IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_2ac_cfg)}, | ||
296 | {IWL_PCI_DEVICE(0x08B3, 0x0170, iwl3160_2ac_cfg)}, | ||
297 | {IWL_PCI_DEVICE(0x08B3, 0x0060, iwl3160_2n_cfg)}, | ||
298 | {IWL_PCI_DEVICE(0x08B3, 0x0062, iwl3160_n_cfg)}, | ||
299 | {IWL_PCI_DEVICE(0x08B4, 0x0270, iwl3160_2ac_cfg)}, | ||
300 | {IWL_PCI_DEVICE(0x08B3, 0x0470, iwl3160_2ac_cfg)}, | ||
301 | {IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_2ac_cfg)}, | ||
302 | {IWL_PCI_DEVICE(0x08B3, 0x8170, iwl3160_2ac_cfg)}, | ||
303 | {IWL_PCI_DEVICE(0x08B3, 0x8060, iwl3160_2n_cfg)}, | ||
304 | {IWL_PCI_DEVICE(0x08B3, 0x8062, iwl3160_n_cfg)}, | ||
305 | {IWL_PCI_DEVICE(0x08B4, 0x8270, iwl3160_2ac_cfg)}, | ||
306 | {IWL_PCI_DEVICE(0x08B3, 0x8470, iwl3160_2ac_cfg)}, | ||
263 | 307 | ||
264 | {0} | 308 | {0} |
265 | }; | 309 | }; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 50ba0a468f94..0b021305eedf 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -405,20 +405,27 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
405 | { | 405 | { |
406 | u8 *v_addr; | 406 | u8 *v_addr; |
407 | dma_addr_t p_addr; | 407 | dma_addr_t p_addr; |
408 | u32 offset; | 408 | u32 offset, chunk_sz = section->len; |
409 | int ret = 0; | 409 | int ret = 0; |
410 | 410 | ||
411 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", | 411 | IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n", |
412 | section_num); | 412 | section_num); |
413 | 413 | ||
414 | v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL); | 414 | v_addr = dma_alloc_coherent(trans->dev, chunk_sz, &p_addr, |
415 | if (!v_addr) | 415 | GFP_KERNEL | __GFP_NOWARN); |
416 | return -ENOMEM; | 416 | if (!v_addr) { |
417 | IWL_DEBUG_INFO(trans, "Falling back to small chunks of DMA\n"); | ||
418 | chunk_sz = PAGE_SIZE; | ||
419 | v_addr = dma_alloc_coherent(trans->dev, chunk_sz, | ||
420 | &p_addr, GFP_KERNEL); | ||
421 | if (!v_addr) | ||
422 | return -ENOMEM; | ||
423 | } | ||
417 | 424 | ||
418 | for (offset = 0; offset < section->len; offset += PAGE_SIZE) { | 425 | for (offset = 0; offset < section->len; offset += chunk_sz) { |
419 | u32 copy_size; | 426 | u32 copy_size; |
420 | 427 | ||
421 | copy_size = min_t(u32, PAGE_SIZE, section->len - offset); | 428 | copy_size = min_t(u32, chunk_sz, section->len - offset); |
422 | 429 | ||
423 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); | 430 | memcpy(v_addr, (u8 *)section->data + offset, copy_size); |
424 | ret = iwl_pcie_load_firmware_chunk(trans, | 431 | ret = iwl_pcie_load_firmware_chunk(trans, |
@@ -432,7 +439,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
432 | } | 439 | } |
433 | } | 440 | } |
434 | 441 | ||
435 | dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr); | 442 | dma_free_coherent(trans->dev, chunk_sz, v_addr, p_addr); |
436 | return ret; | 443 | return ret; |
437 | } | 444 | } |
438 | 445 | ||
@@ -573,10 +580,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
573 | 580 | ||
574 | static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) | 581 | static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) |
575 | { | 582 | { |
576 | /* let the ucode operate on its own */ | ||
577 | iwl_write32(trans, CSR_UCODE_DRV_GP1_SET, | ||
578 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
579 | |||
580 | iwl_disable_interrupts(trans); | 583 | iwl_disable_interrupts(trans); |
581 | iwl_pcie_disable_ict(trans); | 584 | iwl_pcie_disable_ict(trans); |
582 | 585 | ||
@@ -636,9 +639,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
636 | return ret; | 639 | return ret; |
637 | } | 640 | } |
638 | 641 | ||
639 | iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, | ||
640 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
641 | |||
642 | *status = IWL_D3_STATUS_ALIVE; | 642 | *status = IWL_D3_STATUS_ALIVE; |
643 | return 0; | 643 | return 0; |
644 | } | 644 | } |
@@ -917,11 +917,11 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, | |||
917 | } | 917 | } |
918 | 918 | ||
919 | static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, | 919 | static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, |
920 | void *buf, int dwords) | 920 | const void *buf, int dwords) |
921 | { | 921 | { |
922 | unsigned long flags; | 922 | unsigned long flags; |
923 | int offs, ret = 0; | 923 | int offs, ret = 0; |
924 | u32 *vals = buf; | 924 | const u32 *vals = buf; |
925 | 925 | ||
926 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { | 926 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
927 | iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); | 927 | iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2878ee99a668..a35c6aefbc3e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -1045,6 +1045,10 @@ static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans, | |||
1045 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); | 1045 | (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); |
1046 | } | 1046 | } |
1047 | 1047 | ||
1048 | /* Receiver address (actually, Rx station's index into station table), | ||
1049 | * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ | ||
1050 | #define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) | ||
1051 | |||
1048 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, | 1052 | void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, |
1049 | int sta_id, int tid, int frame_limit, u16 ssn) | 1053 | int sta_id, int tid, int frame_limit, u16 ssn) |
1050 | { | 1054 | { |
@@ -1518,6 +1522,7 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, | |||
1518 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { | 1522 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) { |
1519 | IWL_ERR(trans, "FW error in SYNC CMD %s\n", | 1523 | IWL_ERR(trans, "FW error in SYNC CMD %s\n", |
1520 | get_cmd_string(trans_pcie, cmd->id)); | 1524 | get_cmd_string(trans_pcie, cmd->id)); |
1525 | dump_stack(); | ||
1521 | ret = -EIO; | 1526 | ret = -EIO; |
1522 | goto cancel; | 1527 | goto cancel; |
1523 | } | 1528 | } |
@@ -1564,7 +1569,8 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) | |||
1564 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) | 1569 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) |
1565 | return -EIO; | 1570 | return -EIO; |
1566 | 1571 | ||
1567 | if (test_bit(STATUS_RFKILL, &trans_pcie->status)) { | 1572 | if (!(cmd->flags & CMD_SEND_IN_RFKILL) && |
1573 | test_bit(STATUS_RFKILL, &trans_pcie->status)) { | ||
1568 | IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", | 1574 | IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", |
1569 | cmd->id); | 1575 | cmd->id); |
1570 | return -ERFKILL; | 1576 | return -ERFKILL; |
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 4f614aad9ded..f7ff4725506a 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig | |||
@@ -3,13 +3,13 @@ config MWIFIEX | |||
3 | depends on CFG80211 | 3 | depends on CFG80211 |
4 | ---help--- | 4 | ---help--- |
5 | This adds support for wireless adapters based on Marvell | 5 | This adds support for wireless adapters based on Marvell |
6 | 802.11n chipsets. | 6 | 802.11n/ac chipsets. |
7 | 7 | ||
8 | If you choose to build it as a module, it will be called | 8 | If you choose to build it as a module, it will be called |
9 | mwifiex. | 9 | mwifiex. |
10 | 10 | ||
11 | config MWIFIEX_SDIO | 11 | config MWIFIEX_SDIO |
12 | tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797" | 12 | tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8897" |
13 | depends on MWIFIEX && MMC | 13 | depends on MWIFIEX && MMC |
14 | select FW_LOADER | 14 | select FW_LOADER |
15 | ---help--- | 15 | ---help--- |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 60077895adff..856aea25052b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -1231,6 +1231,51 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, | |||
1231 | return 0; | 1231 | return 0; |
1232 | } | 1232 | } |
1233 | 1233 | ||
1234 | /* cfg80211 operation handler for del_station. | ||
1235 | * Function deauthenticates station which value is provided in mac parameter. | ||
1236 | * If mac is NULL/broadcast, all stations in associated station list are | ||
1237 | * deauthenticated. If bss is not started or there are no stations in | ||
1238 | * associated stations list, no action is taken. | ||
1239 | */ | ||
1240 | static int | ||
1241 | mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, | ||
1242 | u8 *mac) | ||
1243 | { | ||
1244 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); | ||
1245 | struct mwifiex_sta_node *sta_node; | ||
1246 | unsigned long flags; | ||
1247 | |||
1248 | if (list_empty(&priv->sta_list) || !priv->bss_started) | ||
1249 | return 0; | ||
1250 | |||
1251 | if (!mac || is_broadcast_ether_addr(mac)) { | ||
1252 | wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__); | ||
1253 | list_for_each_entry(sta_node, &priv->sta_list, list) { | ||
1254 | if (mwifiex_send_cmd_sync(priv, | ||
1255 | HostCmd_CMD_UAP_STA_DEAUTH, | ||
1256 | HostCmd_ACT_GEN_SET, 0, | ||
1257 | sta_node->mac_addr)) | ||
1258 | return -1; | ||
1259 | mwifiex_uap_del_sta_data(priv, sta_node); | ||
1260 | } | ||
1261 | } else { | ||
1262 | wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac); | ||
1263 | spin_lock_irqsave(&priv->sta_list_spinlock, flags); | ||
1264 | sta_node = mwifiex_get_sta_entry(priv, mac); | ||
1265 | spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); | ||
1266 | if (sta_node) { | ||
1267 | if (mwifiex_send_cmd_sync(priv, | ||
1268 | HostCmd_CMD_UAP_STA_DEAUTH, | ||
1269 | HostCmd_ACT_GEN_SET, 0, | ||
1270 | sta_node->mac_addr)) | ||
1271 | return -1; | ||
1272 | mwifiex_uap_del_sta_data(priv, sta_node); | ||
1273 | } | ||
1274 | } | ||
1275 | |||
1276 | return 0; | ||
1277 | } | ||
1278 | |||
1234 | static int | 1279 | static int |
1235 | mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) | 1280 | mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) |
1236 | { | 1281 | { |
@@ -1859,6 +1904,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, | |||
1859 | int i, offset, ret; | 1904 | int i, offset, ret; |
1860 | struct ieee80211_channel *chan; | 1905 | struct ieee80211_channel *chan; |
1861 | struct ieee_types_header *ie; | 1906 | struct ieee_types_header *ie; |
1907 | struct mwifiex_user_scan_cfg *user_scan_cfg; | ||
1862 | 1908 | ||
1863 | wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); | 1909 | wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name); |
1864 | 1910 | ||
@@ -1869,20 +1915,22 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, | |||
1869 | return -EBUSY; | 1915 | return -EBUSY; |
1870 | } | 1916 | } |
1871 | 1917 | ||
1872 | if (priv->user_scan_cfg) { | 1918 | /* Block scan request if scan operation or scan cleanup when interface |
1919 | * is disabled is in process | ||
1920 | */ | ||
1921 | if (priv->scan_request || priv->scan_aborting) { | ||
1873 | dev_err(priv->adapter->dev, "cmd: Scan already in process..\n"); | 1922 | dev_err(priv->adapter->dev, "cmd: Scan already in process..\n"); |
1874 | return -EBUSY; | 1923 | return -EBUSY; |
1875 | } | 1924 | } |
1876 | 1925 | ||
1877 | priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), | 1926 | user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); |
1878 | GFP_KERNEL); | 1927 | if (!user_scan_cfg) |
1879 | if (!priv->user_scan_cfg) | ||
1880 | return -ENOMEM; | 1928 | return -ENOMEM; |
1881 | 1929 | ||
1882 | priv->scan_request = request; | 1930 | priv->scan_request = request; |
1883 | 1931 | ||
1884 | priv->user_scan_cfg->num_ssids = request->n_ssids; | 1932 | user_scan_cfg->num_ssids = request->n_ssids; |
1885 | priv->user_scan_cfg->ssid_list = request->ssids; | 1933 | user_scan_cfg->ssid_list = request->ssids; |
1886 | 1934 | ||
1887 | if (request->ie && request->ie_len) { | 1935 | if (request->ie && request->ie_len) { |
1888 | offset = 0; | 1936 | offset = 0; |
@@ -1902,25 +1950,25 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, | |||
1902 | for (i = 0; i < min_t(u32, request->n_channels, | 1950 | for (i = 0; i < min_t(u32, request->n_channels, |
1903 | MWIFIEX_USER_SCAN_CHAN_MAX); i++) { | 1951 | MWIFIEX_USER_SCAN_CHAN_MAX); i++) { |
1904 | chan = request->channels[i]; | 1952 | chan = request->channels[i]; |
1905 | priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value; | 1953 | user_scan_cfg->chan_list[i].chan_number = chan->hw_value; |
1906 | priv->user_scan_cfg->chan_list[i].radio_type = chan->band; | 1954 | user_scan_cfg->chan_list[i].radio_type = chan->band; |
1907 | 1955 | ||
1908 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 1956 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
1909 | priv->user_scan_cfg->chan_list[i].scan_type = | 1957 | user_scan_cfg->chan_list[i].scan_type = |
1910 | MWIFIEX_SCAN_TYPE_PASSIVE; | 1958 | MWIFIEX_SCAN_TYPE_PASSIVE; |
1911 | else | 1959 | else |
1912 | priv->user_scan_cfg->chan_list[i].scan_type = | 1960 | user_scan_cfg->chan_list[i].scan_type = |
1913 | MWIFIEX_SCAN_TYPE_ACTIVE; | 1961 | MWIFIEX_SCAN_TYPE_ACTIVE; |
1914 | 1962 | ||
1915 | priv->user_scan_cfg->chan_list[i].scan_time = 0; | 1963 | user_scan_cfg->chan_list[i].scan_time = 0; |
1916 | } | 1964 | } |
1917 | 1965 | ||
1918 | ret = mwifiex_scan_networks(priv, priv->user_scan_cfg); | 1966 | ret = mwifiex_scan_networks(priv, user_scan_cfg); |
1967 | kfree(user_scan_cfg); | ||
1919 | if (ret) { | 1968 | if (ret) { |
1920 | dev_err(priv->adapter->dev, "scan failed: %d\n", ret); | 1969 | dev_err(priv->adapter->dev, "scan failed: %d\n", ret); |
1970 | priv->scan_aborting = false; | ||
1921 | priv->scan_request = NULL; | 1971 | priv->scan_request = NULL; |
1922 | kfree(priv->user_scan_cfg); | ||
1923 | priv->user_scan_cfg = NULL; | ||
1924 | return ret; | 1972 | return ret; |
1925 | } | 1973 | } |
1926 | 1974 | ||
@@ -2419,6 +2467,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { | |||
2419 | .change_beacon = mwifiex_cfg80211_change_beacon, | 2467 | .change_beacon = mwifiex_cfg80211_change_beacon, |
2420 | .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, | 2468 | .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, |
2421 | .set_antenna = mwifiex_cfg80211_set_antenna, | 2469 | .set_antenna = mwifiex_cfg80211_set_antenna, |
2470 | .del_station = mwifiex_cfg80211_del_station, | ||
2422 | #ifdef CONFIG_PM | 2471 | #ifdef CONFIG_PM |
2423 | .suspend = mwifiex_cfg80211_suspend, | 2472 | .suspend = mwifiex_cfg80211_suspend, |
2424 | .resume = mwifiex_cfg80211_resume, | 2473 | .resume = mwifiex_cfg80211_resume, |
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 26755d9acb55..2d761477d15e 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c | |||
@@ -570,6 +570,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, | |||
570 | case HostCmd_CMD_UAP_SYS_CONFIG: | 570 | case HostCmd_CMD_UAP_SYS_CONFIG: |
571 | case HostCmd_CMD_UAP_BSS_START: | 571 | case HostCmd_CMD_UAP_BSS_START: |
572 | case HostCmd_CMD_UAP_BSS_STOP: | 572 | case HostCmd_CMD_UAP_BSS_STOP: |
573 | case HostCmd_CMD_UAP_STA_DEAUTH: | ||
573 | ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action, | 574 | ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action, |
574 | cmd_oid, data_buf, | 575 | cmd_oid, data_buf, |
575 | cmd_ptr); | 576 | cmd_ptr); |
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 1f7578d553ec..d6ada7354c14 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h | |||
@@ -271,6 +271,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { | |||
271 | #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 | 271 | #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 |
272 | #define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f | 272 | #define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f |
273 | #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 | 273 | #define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083 |
274 | #define HostCmd_CMD_CFG_DATA 0x008f | ||
274 | #define HostCmd_CMD_VERSION_EXT 0x0097 | 275 | #define HostCmd_CMD_VERSION_EXT 0x0097 |
275 | #define HostCmd_CMD_MEF_CFG 0x009a | 276 | #define HostCmd_CMD_MEF_CFG 0x009a |
276 | #define HostCmd_CMD_RSSI_INFO 0x00a4 | 277 | #define HostCmd_CMD_RSSI_INFO 0x00a4 |
@@ -279,6 +280,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { | |||
279 | #define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0 | 280 | #define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0 |
280 | #define HostCmd_CMD_UAP_BSS_START 0x00b1 | 281 | #define HostCmd_CMD_UAP_BSS_START 0x00b1 |
281 | #define HostCmd_CMD_UAP_BSS_STOP 0x00b2 | 282 | #define HostCmd_CMD_UAP_BSS_STOP 0x00b2 |
283 | #define HostCmd_CMD_UAP_STA_DEAUTH 0x00b5 | ||
282 | #define HostCmd_CMD_11N_CFG 0x00cd | 284 | #define HostCmd_CMD_11N_CFG 0x00cd |
283 | #define HostCmd_CMD_11N_ADDBA_REQ 0x00ce | 285 | #define HostCmd_CMD_11N_ADDBA_REQ 0x00ce |
284 | #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf | 286 | #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf |
@@ -464,6 +466,8 @@ enum P2P_MODES { | |||
464 | #define MWIFIEX_CRITERIA_UNICAST BIT(1) | 466 | #define MWIFIEX_CRITERIA_UNICAST BIT(1) |
465 | #define MWIFIEX_CRITERIA_MULTICAST BIT(3) | 467 | #define MWIFIEX_CRITERIA_MULTICAST BIT(3) |
466 | 468 | ||
469 | #define CFG_DATA_TYPE_CAL 2 | ||
470 | |||
467 | struct mwifiex_ie_types_header { | 471 | struct mwifiex_ie_types_header { |
468 | __le16 type; | 472 | __le16 type; |
469 | __le16 len; | 473 | __le16 len; |
@@ -1197,6 +1201,11 @@ struct host_cmd_ds_amsdu_aggr_ctrl { | |||
1197 | __le16 curr_buf_size; | 1201 | __le16 curr_buf_size; |
1198 | } __packed; | 1202 | } __packed; |
1199 | 1203 | ||
1204 | struct host_cmd_ds_sta_deauth { | ||
1205 | u8 mac[ETH_ALEN]; | ||
1206 | __le16 reason; | ||
1207 | } __packed; | ||
1208 | |||
1200 | struct mwifiex_ie_types_wmm_param_set { | 1209 | struct mwifiex_ie_types_wmm_param_set { |
1201 | struct mwifiex_ie_types_header header; | 1210 | struct mwifiex_ie_types_header header; |
1202 | u8 wmm_ie[1]; | 1211 | u8 wmm_ie[1]; |
@@ -1573,6 +1582,12 @@ struct mwifiex_ie_list { | |||
1573 | struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX]; | 1582 | struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX]; |
1574 | } __packed; | 1583 | } __packed; |
1575 | 1584 | ||
1585 | struct host_cmd_ds_802_11_cfg_data { | ||
1586 | __le16 action; | ||
1587 | __le16 type; | ||
1588 | __le16 data_len; | ||
1589 | } __packed; | ||
1590 | |||
1576 | struct host_cmd_ds_command { | 1591 | struct host_cmd_ds_command { |
1577 | __le16 command; | 1592 | __le16 command; |
1578 | __le16 size; | 1593 | __le16 size; |
@@ -1630,7 +1645,9 @@ struct host_cmd_ds_command { | |||
1630 | struct host_cmd_ds_802_11_eeprom_access eeprom; | 1645 | struct host_cmd_ds_802_11_eeprom_access eeprom; |
1631 | struct host_cmd_ds_802_11_subsc_evt subsc_evt; | 1646 | struct host_cmd_ds_802_11_subsc_evt subsc_evt; |
1632 | struct host_cmd_ds_sys_config uap_sys_config; | 1647 | struct host_cmd_ds_sys_config uap_sys_config; |
1648 | struct host_cmd_ds_sta_deauth sta_deauth; | ||
1633 | struct host_cmd_11ac_vht_cfg vht_cfg; | 1649 | struct host_cmd_11ac_vht_cfg vht_cfg; |
1650 | struct host_cmd_ds_802_11_cfg_data cfg_data; | ||
1634 | } params; | 1651 | } params; |
1635 | } __packed; | 1652 | } __packed; |
1636 | 1653 | ||
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 9f44fda19db9..c7f11c0c3bb7 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c | |||
@@ -59,6 +59,9 @@ static void scan_delay_timer_fn(unsigned long data) | |||
59 | struct cmd_ctrl_node *cmd_node, *tmp_node; | 59 | struct cmd_ctrl_node *cmd_node, *tmp_node; |
60 | unsigned long flags; | 60 | unsigned long flags; |
61 | 61 | ||
62 | if (adapter->surprise_removed) | ||
63 | return; | ||
64 | |||
62 | if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) { | 65 | if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) { |
63 | /* | 66 | /* |
64 | * Abort scan operation by cancelling all pending scan | 67 | * Abort scan operation by cancelling all pending scan |
@@ -78,19 +81,13 @@ static void scan_delay_timer_fn(unsigned long data) | |||
78 | adapter->empty_tx_q_cnt = 0; | 81 | adapter->empty_tx_q_cnt = 0; |
79 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); | 82 | spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); |
80 | 83 | ||
81 | if (priv->user_scan_cfg) { | 84 | if (priv->scan_request) { |
82 | if (priv->scan_request) { | 85 | dev_dbg(adapter->dev, "info: aborting scan\n"); |
83 | dev_dbg(priv->adapter->dev, | 86 | cfg80211_scan_done(priv->scan_request, 1); |
84 | "info: aborting scan\n"); | 87 | priv->scan_request = NULL; |
85 | cfg80211_scan_done(priv->scan_request, 1); | 88 | } else { |
86 | priv->scan_request = NULL; | 89 | priv->scan_aborting = false; |
87 | } else { | 90 | dev_dbg(adapter->dev, "info: scan already aborted\n"); |
88 | dev_dbg(priv->adapter->dev, | ||
89 | "info: scan already aborted\n"); | ||
90 | } | ||
91 | |||
92 | kfree(priv->user_scan_cfg); | ||
93 | priv->user_scan_cfg = NULL; | ||
94 | } | 91 | } |
95 | goto done; | 92 | goto done; |
96 | } | 93 | } |
@@ -447,23 +444,29 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) | |||
447 | } | 444 | } |
448 | 445 | ||
449 | /* | 446 | /* |
450 | * This function frees the adapter structure. | 447 | * This function performs cleanup for adapter structure. |
451 | * | 448 | * |
452 | * The freeing operation is done recursively, by canceling all | 449 | * The cleanup is done recursively, by canceling all pending |
453 | * pending commands, freeing the member buffers previously | 450 | * commands, freeing the member buffers previously allocated |
454 | * allocated (command buffers, scan table buffer, sleep confirm | 451 | * (command buffers, scan table buffer, sleep confirm command |
455 | * command buffer), stopping the timers and calling the cleanup | 452 | * buffer), stopping the timers and calling the cleanup routines |
456 | * routines for every interface, before the actual adapter | 453 | * for every interface. |
457 | * structure is freed. | ||
458 | */ | 454 | */ |
459 | static void | 455 | static void |
460 | mwifiex_free_adapter(struct mwifiex_adapter *adapter) | 456 | mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) |
461 | { | 457 | { |
458 | int i; | ||
459 | |||
462 | if (!adapter) { | 460 | if (!adapter) { |
463 | pr_err("%s: adapter is NULL\n", __func__); | 461 | pr_err("%s: adapter is NULL\n", __func__); |
464 | return; | 462 | return; |
465 | } | 463 | } |
466 | 464 | ||
465 | for (i = 0; i < adapter->priv_num; i++) { | ||
466 | if (adapter->priv[i]) | ||
467 | del_timer_sync(&adapter->priv[i]->scan_delay_timer); | ||
468 | } | ||
469 | |||
467 | mwifiex_cancel_all_pending_cmd(adapter); | 470 | mwifiex_cancel_all_pending_cmd(adapter); |
468 | 471 | ||
469 | /* Free lock variables */ | 472 | /* Free lock variables */ |
@@ -684,7 +687,6 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
684 | int ret = -EINPROGRESS; | 687 | int ret = -EINPROGRESS; |
685 | struct mwifiex_private *priv; | 688 | struct mwifiex_private *priv; |
686 | s32 i; | 689 | s32 i; |
687 | unsigned long flags; | ||
688 | struct sk_buff *skb; | 690 | struct sk_buff *skb; |
689 | 691 | ||
690 | /* mwifiex already shutdown */ | 692 | /* mwifiex already shutdown */ |
@@ -719,7 +721,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
719 | } | 721 | } |
720 | } | 722 | } |
721 | 723 | ||
722 | spin_lock_irqsave(&adapter->mwifiex_lock, flags); | 724 | spin_lock(&adapter->mwifiex_lock); |
723 | 725 | ||
724 | if (adapter->if_ops.data_complete) { | 726 | if (adapter->if_ops.data_complete) { |
725 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) { | 727 | while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) { |
@@ -733,10 +735,9 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) | |||
733 | } | 735 | } |
734 | } | 736 | } |
735 | 737 | ||
736 | /* Free adapter structure */ | 738 | mwifiex_adapter_cleanup(adapter); |
737 | mwifiex_free_adapter(adapter); | ||
738 | 739 | ||
739 | spin_unlock_irqrestore(&adapter->mwifiex_lock, flags); | 740 | spin_unlock(&adapter->mwifiex_lock); |
740 | 741 | ||
741 | /* Notify completion */ | 742 | /* Notify completion */ |
742 | ret = mwifiex_shutdown_fw_complete(adapter); | 743 | ret = mwifiex_shutdown_fw_complete(adapter); |
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 6bcb66e6e97c..122175af18c6 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c | |||
@@ -919,9 +919,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, | |||
919 | memcpy(&priv->curr_bss_params.data_rates, | 919 | memcpy(&priv->curr_bss_params.data_rates, |
920 | &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); | 920 | &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); |
921 | 921 | ||
922 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n", | 922 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%4ph\n", |
923 | adhoc_start->data_rate[0], adhoc_start->data_rate[1], | 923 | adhoc_start->data_rate); |
924 | adhoc_start->data_rate[2], adhoc_start->data_rate[3]); | ||
925 | 924 | ||
926 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); | 925 | dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); |
927 | 926 | ||
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2eb88ea9acf7..5bc7ef8d04d6 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #define VERSION "1.0" | 25 | #define VERSION "1.0" |
26 | 26 | ||
27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; | 27 | const char driver_version[] = "mwifiex " VERSION " (%s) "; |
28 | static char *cal_data_cfg; | ||
29 | module_param(cal_data_cfg, charp, 0); | ||
28 | 30 | ||
29 | /* | 31 | /* |
30 | * This function registers the device and performs all the necessary | 32 | * This function registers the device and performs all the necessary |
@@ -336,6 +338,13 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) | |||
336 | 338 | ||
337 | dev_notice(adapter->dev, "WLAN FW is active\n"); | 339 | dev_notice(adapter->dev, "WLAN FW is active\n"); |
338 | 340 | ||
341 | if (cal_data_cfg) { | ||
342 | if ((request_firmware(&adapter->cal_data, cal_data_cfg, | ||
343 | adapter->dev)) < 0) | ||
344 | dev_err(adapter->dev, | ||
345 | "Cal data request_firmware() failed\n"); | ||
346 | } | ||
347 | |||
339 | adapter->init_wait_q_woken = false; | 348 | adapter->init_wait_q_woken = false; |
340 | ret = mwifiex_init_fw(adapter); | 349 | ret = mwifiex_init_fw(adapter); |
341 | if (ret == -1) { | 350 | if (ret == -1) { |
@@ -390,6 +399,10 @@ err_init_fw: | |||
390 | pr_debug("info: %s: unregister device\n", __func__); | 399 | pr_debug("info: %s: unregister device\n", __func__); |
391 | adapter->if_ops.unregister_dev(adapter); | 400 | adapter->if_ops.unregister_dev(adapter); |
392 | done: | 401 | done: |
402 | if (adapter->cal_data) { | ||
403 | release_firmware(adapter->cal_data); | ||
404 | adapter->cal_data = NULL; | ||
405 | } | ||
393 | release_firmware(adapter->firmware); | 406 | release_firmware(adapter->firmware); |
394 | complete(&adapter->fw_load); | 407 | complete(&adapter->fw_load); |
395 | return; | 408 | return; |
@@ -436,6 +449,7 @@ mwifiex_close(struct net_device *dev) | |||
436 | dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); | 449 | dev_dbg(priv->adapter->dev, "aborting scan on ndo_stop\n"); |
437 | cfg80211_scan_done(priv->scan_request, 1); | 450 | cfg80211_scan_done(priv->scan_request, 1); |
438 | priv->scan_request = NULL; | 451 | priv->scan_request = NULL; |
452 | priv->scan_aborting = true; | ||
439 | } | 453 | } |
440 | 454 | ||
441 | return 0; | 455 | return 0; |
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 4ef67fca06d3..0832c2437daf 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h | |||
@@ -492,7 +492,6 @@ struct mwifiex_private { | |||
492 | struct semaphore async_sem; | 492 | struct semaphore async_sem; |
493 | u8 report_scan_result; | 493 | u8 report_scan_result; |
494 | struct cfg80211_scan_request *scan_request; | 494 | struct cfg80211_scan_request *scan_request; |
495 | struct mwifiex_user_scan_cfg *user_scan_cfg; | ||
496 | u8 cfg_bssid[6]; | 495 | u8 cfg_bssid[6]; |
497 | struct wps wps; | 496 | struct wps wps; |
498 | u8 scan_block; | 497 | u8 scan_block; |
@@ -510,6 +509,7 @@ struct mwifiex_private { | |||
510 | u8 ap_11ac_enabled; | 509 | u8 ap_11ac_enabled; |
511 | u32 mgmt_frame_mask; | 510 | u32 mgmt_frame_mask; |
512 | struct mwifiex_roc_cfg roc_cfg; | 511 | struct mwifiex_roc_cfg roc_cfg; |
512 | bool scan_aborting; | ||
513 | }; | 513 | }; |
514 | 514 | ||
515 | enum mwifiex_ba_status { | 515 | enum mwifiex_ba_status { |
@@ -730,6 +730,7 @@ struct mwifiex_adapter { | |||
730 | u16 max_mgmt_ie_index; | 730 | u16 max_mgmt_ie_index; |
731 | u8 scan_delay_cnt; | 731 | u8 scan_delay_cnt; |
732 | u8 empty_tx_q_cnt; | 732 | u8 empty_tx_q_cnt; |
733 | const struct firmware *cal_data; | ||
733 | 734 | ||
734 | /* 11AC */ | 735 | /* 11AC */ |
735 | u32 is_hw_11ac_capable; | 736 | u32 is_hw_11ac_capable; |
@@ -1115,6 +1116,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, | |||
1115 | struct cfg80211_beacon_data *data); | 1116 | struct cfg80211_beacon_data *data); |
1116 | int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); | 1117 | int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); |
1117 | u8 *mwifiex_11d_code_2_region(u8 code); | 1118 | u8 *mwifiex_11d_code_2_region(u8 code); |
1119 | void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, | ||
1120 | struct mwifiex_sta_node *node); | ||
1118 | 1121 | ||
1119 | extern const struct ethtool_ops mwifiex_ethtool_ops; | 1122 | extern const struct ethtool_ops mwifiex_ethtool_ops; |
1120 | 1123 | ||
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 9cf5d8f07df8..801b6b728379 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c | |||
@@ -1784,22 +1784,17 @@ check_next_scan: | |||
1784 | if (priv->report_scan_result) | 1784 | if (priv->report_scan_result) |
1785 | priv->report_scan_result = false; | 1785 | priv->report_scan_result = false; |
1786 | 1786 | ||
1787 | if (priv->user_scan_cfg) { | 1787 | if (priv->scan_request) { |
1788 | if (priv->scan_request) { | 1788 | dev_dbg(adapter->dev, "info: notifying scan done\n"); |
1789 | dev_dbg(priv->adapter->dev, | 1789 | cfg80211_scan_done(priv->scan_request, 0); |
1790 | "info: notifying scan done\n"); | 1790 | priv->scan_request = NULL; |
1791 | cfg80211_scan_done(priv->scan_request, 0); | 1791 | } else { |
1792 | priv->scan_request = NULL; | 1792 | priv->scan_aborting = false; |
1793 | } else { | 1793 | dev_dbg(adapter->dev, "info: scan already aborted\n"); |
1794 | dev_dbg(priv->adapter->dev, | ||
1795 | "info: scan already aborted\n"); | ||
1796 | } | ||
1797 | |||
1798 | kfree(priv->user_scan_cfg); | ||
1799 | priv->user_scan_cfg = NULL; | ||
1800 | } | 1794 | } |
1801 | } else { | 1795 | } else { |
1802 | if (priv->user_scan_cfg && !priv->scan_request) { | 1796 | if ((priv->scan_aborting && !priv->scan_request) || |
1797 | priv->scan_block) { | ||
1803 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, | 1798 | spin_unlock_irqrestore(&adapter->scan_pending_q_lock, |
1804 | flags); | 1799 | flags); |
1805 | adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; | 1800 | adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT; |
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 363ba31b58bf..5ee5ed02eccd 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c | |||
@@ -77,6 +77,17 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) | |||
77 | 77 | ||
78 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; | 78 | func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; |
79 | 79 | ||
80 | if (id->driver_data) { | ||
81 | struct mwifiex_sdio_device *data = (void *)id->driver_data; | ||
82 | |||
83 | card->firmware = data->firmware; | ||
84 | card->reg = data->reg; | ||
85 | card->max_ports = data->max_ports; | ||
86 | card->mp_agg_pkt_limit = data->mp_agg_pkt_limit; | ||
87 | card->supports_sdio_new_mode = data->supports_sdio_new_mode; | ||
88 | card->has_control_mask = data->has_control_mask; | ||
89 | } | ||
90 | |||
80 | sdio_claim_host(func); | 91 | sdio_claim_host(func); |
81 | ret = sdio_enable_func(func); | 92 | ret = sdio_enable_func(func); |
82 | sdio_release_host(func); | 93 | sdio_release_host(func); |
@@ -251,12 +262,19 @@ static int mwifiex_sdio_resume(struct device *dev) | |||
251 | #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) | 262 | #define SDIO_DEVICE_ID_MARVELL_8787 (0x9119) |
252 | /* Device ID for SD8797 */ | 263 | /* Device ID for SD8797 */ |
253 | #define SDIO_DEVICE_ID_MARVELL_8797 (0x9129) | 264 | #define SDIO_DEVICE_ID_MARVELL_8797 (0x9129) |
265 | /* Device ID for SD8897 */ | ||
266 | #define SDIO_DEVICE_ID_MARVELL_8897 (0x912d) | ||
254 | 267 | ||
255 | /* WLAN IDs */ | 268 | /* WLAN IDs */ |
256 | static const struct sdio_device_id mwifiex_ids[] = { | 269 | static const struct sdio_device_id mwifiex_ids[] = { |
257 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786)}, | 270 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8786), |
258 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)}, | 271 | .driver_data = (unsigned long) &mwifiex_sdio_sd8786}, |
259 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797)}, | 272 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787), |
273 | .driver_data = (unsigned long) &mwifiex_sdio_sd8787}, | ||
274 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797), | ||
275 | .driver_data = (unsigned long) &mwifiex_sdio_sd8797}, | ||
276 | {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8897), | ||
277 | .driver_data = (unsigned long) &mwifiex_sdio_sd8897}, | ||
260 | {}, | 278 | {}, |
261 | }; | 279 | }; |
262 | 280 | ||
@@ -282,13 +300,13 @@ static struct sdio_driver mwifiex_sdio = { | |||
282 | * This function writes data into SDIO card register. | 300 | * This function writes data into SDIO card register. |
283 | */ | 301 | */ |
284 | static int | 302 | static int |
285 | mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) | 303 | mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data) |
286 | { | 304 | { |
287 | struct sdio_mmc_card *card = adapter->card; | 305 | struct sdio_mmc_card *card = adapter->card; |
288 | int ret = -1; | 306 | int ret = -1; |
289 | 307 | ||
290 | sdio_claim_host(card->func); | 308 | sdio_claim_host(card->func); |
291 | sdio_writeb(card->func, (u8) data, reg, &ret); | 309 | sdio_writeb(card->func, data, reg, &ret); |
292 | sdio_release_host(card->func); | 310 | sdio_release_host(card->func); |
293 | 311 | ||
294 | return ret; | 312 | return ret; |
@@ -298,7 +316,7 @@ mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data) | |||
298 | * This function reads data from SDIO card register. | 316 | * This function reads data from SDIO card register. |
299 | */ | 317 | */ |
300 | static int | 318 | static int |
301 | mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data) | 319 | mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u8 *data) |
302 | { | 320 | { |
303 | struct sdio_mmc_card *card = adapter->card; | 321 | struct sdio_mmc_card *card = adapter->card; |
304 | int ret = -1; | 322 | int ret = -1; |
@@ -400,7 +418,40 @@ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) | |||
400 | } | 418 | } |
401 | 419 | ||
402 | /* | 420 | /* |
403 | * This function initializes the IO ports. | 421 | * This function is used to initialize IO ports for the |
422 | * chipsets supporting SDIO new mode eg SD8897. | ||
423 | */ | ||
424 | static int mwifiex_init_sdio_new_mode(struct mwifiex_adapter *adapter) | ||
425 | { | ||
426 | u8 reg; | ||
427 | |||
428 | adapter->ioport = MEM_PORT; | ||
429 | |||
430 | /* enable sdio new mode */ | ||
431 | if (mwifiex_read_reg(adapter, CARD_CONFIG_2_1_REG, ®)) | ||
432 | return -1; | ||
433 | if (mwifiex_write_reg(adapter, CARD_CONFIG_2_1_REG, | ||
434 | reg | CMD53_NEW_MODE)) | ||
435 | return -1; | ||
436 | |||
437 | /* Configure cmd port and enable reading rx length from the register */ | ||
438 | if (mwifiex_read_reg(adapter, CMD_CONFIG_0, ®)) | ||
439 | return -1; | ||
440 | if (mwifiex_write_reg(adapter, CMD_CONFIG_0, reg | CMD_PORT_RD_LEN_EN)) | ||
441 | return -1; | ||
442 | |||
443 | /* Enable Dnld/Upld ready auto reset for cmd port after cmd53 is | ||
444 | * completed | ||
445 | */ | ||
446 | if (mwifiex_read_reg(adapter, CMD_CONFIG_1, ®)) | ||
447 | return -1; | ||
448 | if (mwifiex_write_reg(adapter, CMD_CONFIG_1, reg | CMD_PORT_AUTO_EN)) | ||
449 | return -1; | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /* This function initializes the IO ports. | ||
404 | * | 455 | * |
405 | * The following operations are performed - | 456 | * The following operations are performed - |
406 | * - Read the IO ports (0, 1 and 2) | 457 | * - Read the IO ports (0, 1 and 2) |
@@ -409,10 +460,17 @@ static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) | |||
409 | */ | 460 | */ |
410 | static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) | 461 | static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) |
411 | { | 462 | { |
412 | u32 reg; | 463 | u8 reg; |
464 | struct sdio_mmc_card *card = adapter->card; | ||
413 | 465 | ||
414 | adapter->ioport = 0; | 466 | adapter->ioport = 0; |
415 | 467 | ||
468 | if (card->supports_sdio_new_mode) { | ||
469 | if (mwifiex_init_sdio_new_mode(adapter)) | ||
470 | return -1; | ||
471 | goto cont; | ||
472 | } | ||
473 | |||
416 | /* Read the IO port */ | 474 | /* Read the IO port */ |
417 | if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) | 475 | if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, ®)) |
418 | adapter->ioport |= (reg & 0xff); | 476 | adapter->ioport |= (reg & 0xff); |
@@ -428,19 +486,19 @@ static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter) | |||
428 | adapter->ioport |= ((reg & 0xff) << 16); | 486 | adapter->ioport |= ((reg & 0xff) << 16); |
429 | else | 487 | else |
430 | return -1; | 488 | return -1; |
431 | 489 | cont: | |
432 | pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); | 490 | pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport); |
433 | 491 | ||
434 | /* Set Host interrupt reset to read to clear */ | 492 | /* Set Host interrupt reset to read to clear */ |
435 | if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) | 493 | if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, ®)) |
436 | mwifiex_write_reg(adapter, HOST_INT_RSR_REG, | 494 | mwifiex_write_reg(adapter, HOST_INT_RSR_REG, |
437 | reg | SDIO_INT_MASK); | 495 | reg | card->reg->sdio_int_mask); |
438 | else | 496 | else |
439 | return -1; | 497 | return -1; |
440 | 498 | ||
441 | /* Dnld/Upld ready set to auto reset */ | 499 | /* Dnld/Upld ready set to auto reset */ |
442 | if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, ®)) | 500 | if (!mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, ®)) |
443 | mwifiex_write_reg(adapter, CARD_MISC_CFG_REG, | 501 | mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg, |
444 | reg | AUTO_RE_ENABLE_INT); | 502 | reg | AUTO_RE_ENABLE_INT); |
445 | else | 503 | else |
446 | return -1; | 504 | return -1; |
@@ -486,34 +544,42 @@ static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter, | |||
486 | static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) | 544 | static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) |
487 | { | 545 | { |
488 | struct sdio_mmc_card *card = adapter->card; | 546 | struct sdio_mmc_card *card = adapter->card; |
489 | u16 rd_bitmap = card->mp_rd_bitmap; | 547 | const struct mwifiex_sdio_card_reg *reg = card->reg; |
548 | u32 rd_bitmap = card->mp_rd_bitmap; | ||
490 | 549 | ||
491 | dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap); | 550 | dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%08x\n", rd_bitmap); |
492 | 551 | ||
493 | if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK))) | 552 | if (card->supports_sdio_new_mode) { |
494 | return -1; | 553 | if (!(rd_bitmap & reg->data_port_mask)) |
554 | return -1; | ||
555 | } else { | ||
556 | if (!(rd_bitmap & (CTRL_PORT_MASK | reg->data_port_mask))) | ||
557 | return -1; | ||
558 | } | ||
495 | 559 | ||
496 | if (card->mp_rd_bitmap & CTRL_PORT_MASK) { | 560 | if ((card->has_control_mask) && |
497 | card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK); | 561 | (card->mp_rd_bitmap & CTRL_PORT_MASK)) { |
562 | card->mp_rd_bitmap &= (u32) (~CTRL_PORT_MASK); | ||
498 | *port = CTRL_PORT; | 563 | *port = CTRL_PORT; |
499 | dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n", | 564 | dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%08x\n", |
500 | *port, card->mp_rd_bitmap); | 565 | *port, card->mp_rd_bitmap); |
501 | } else { | 566 | return 0; |
502 | if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) { | 567 | } |
503 | card->mp_rd_bitmap &= (u16) | ||
504 | (~(1 << card->curr_rd_port)); | ||
505 | *port = card->curr_rd_port; | ||
506 | 568 | ||
507 | if (++card->curr_rd_port == MAX_PORT) | 569 | if (!(card->mp_rd_bitmap & (1 << card->curr_rd_port))) |
508 | card->curr_rd_port = 1; | 570 | return -1; |
509 | } else { | 571 | |
510 | return -1; | 572 | /* We are now handling the SDIO data ports */ |
511 | } | 573 | card->mp_rd_bitmap &= (u32)(~(1 << card->curr_rd_port)); |
574 | *port = card->curr_rd_port; | ||
575 | |||
576 | if (++card->curr_rd_port == card->max_ports) | ||
577 | card->curr_rd_port = reg->start_rd_port; | ||
578 | |||
579 | dev_dbg(adapter->dev, | ||
580 | "data: port=%d mp_rd_bitmap=0x%08x -> 0x%08x\n", | ||
581 | *port, rd_bitmap, card->mp_rd_bitmap); | ||
512 | 582 | ||
513 | dev_dbg(adapter->dev, | ||
514 | "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n", | ||
515 | *port, rd_bitmap, card->mp_rd_bitmap); | ||
516 | } | ||
517 | return 0; | 583 | return 0; |
518 | } | 584 | } |
519 | 585 | ||
@@ -524,35 +590,45 @@ static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port) | |||
524 | * increased (provided it does not reach the maximum limit, in which | 590 | * increased (provided it does not reach the maximum limit, in which |
525 | * case it is reset to 1) | 591 | * case it is reset to 1) |
526 | */ | 592 | */ |
527 | static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) | 593 | static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u32 *port) |
528 | { | 594 | { |
529 | struct sdio_mmc_card *card = adapter->card; | 595 | struct sdio_mmc_card *card = adapter->card; |
530 | u16 wr_bitmap = card->mp_wr_bitmap; | 596 | const struct mwifiex_sdio_card_reg *reg = card->reg; |
597 | u32 wr_bitmap = card->mp_wr_bitmap; | ||
531 | 598 | ||
532 | dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap); | 599 | dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%08x\n", wr_bitmap); |
533 | 600 | ||
534 | if (!(wr_bitmap & card->mp_data_port_mask)) | 601 | if (card->supports_sdio_new_mode && |
602 | !(wr_bitmap & reg->data_port_mask)) { | ||
603 | adapter->data_sent = true; | ||
604 | return -EBUSY; | ||
605 | } else if (!card->supports_sdio_new_mode && | ||
606 | !(wr_bitmap & card->mp_data_port_mask)) { | ||
535 | return -1; | 607 | return -1; |
608 | } | ||
536 | 609 | ||
537 | if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { | 610 | if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) { |
538 | card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port)); | 611 | card->mp_wr_bitmap &= (u32) (~(1 << card->curr_wr_port)); |
539 | *port = card->curr_wr_port; | 612 | *port = card->curr_wr_port; |
540 | if (++card->curr_wr_port == card->mp_end_port) | 613 | if (((card->supports_sdio_new_mode) && |
541 | card->curr_wr_port = 1; | 614 | (++card->curr_wr_port == card->max_ports)) || |
615 | ((!card->supports_sdio_new_mode) && | ||
616 | (++card->curr_wr_port == card->mp_end_port))) | ||
617 | card->curr_wr_port = reg->start_wr_port; | ||
542 | } else { | 618 | } else { |
543 | adapter->data_sent = true; | 619 | adapter->data_sent = true; |
544 | return -EBUSY; | 620 | return -EBUSY; |
545 | } | 621 | } |
546 | 622 | ||
547 | if (*port == CTRL_PORT) { | 623 | if ((card->has_control_mask) && (*port == CTRL_PORT)) { |
548 | dev_err(adapter->dev, "invalid data port=%d cur port=%d" | 624 | dev_err(adapter->dev, |
549 | " mp_wr_bitmap=0x%04x -> 0x%04x\n", | 625 | "invalid data port=%d cur port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", |
550 | *port, card->curr_wr_port, wr_bitmap, | 626 | *port, card->curr_wr_port, wr_bitmap, |
551 | card->mp_wr_bitmap); | 627 | card->mp_wr_bitmap); |
552 | return -1; | 628 | return -1; |
553 | } | 629 | } |
554 | 630 | ||
555 | dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n", | 631 | dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%08x -> 0x%08x\n", |
556 | *port, wr_bitmap, card->mp_wr_bitmap); | 632 | *port, wr_bitmap, card->mp_wr_bitmap); |
557 | 633 | ||
558 | return 0; | 634 | return 0; |
@@ -564,11 +640,12 @@ static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port) | |||
564 | static int | 640 | static int |
565 | mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) | 641 | mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) |
566 | { | 642 | { |
643 | struct sdio_mmc_card *card = adapter->card; | ||
567 | u32 tries; | 644 | u32 tries; |
568 | u32 cs; | 645 | u8 cs; |
569 | 646 | ||
570 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | 647 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { |
571 | if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs)) | 648 | if (mwifiex_read_reg(adapter, card->reg->poll_reg, &cs)) |
572 | break; | 649 | break; |
573 | else if ((cs & bits) == bits) | 650 | else if ((cs & bits) == bits) |
574 | return 0; | 651 | return 0; |
@@ -587,12 +664,14 @@ mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits) | |||
587 | static int | 664 | static int |
588 | mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) | 665 | mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) |
589 | { | 666 | { |
590 | u32 fws0, fws1; | 667 | struct sdio_mmc_card *card = adapter->card; |
668 | const struct mwifiex_sdio_card_reg *reg = card->reg; | ||
669 | u8 fws0, fws1; | ||
591 | 670 | ||
592 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0)) | 671 | if (mwifiex_read_reg(adapter, reg->status_reg_0, &fws0)) |
593 | return -1; | 672 | return -1; |
594 | 673 | ||
595 | if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1)) | 674 | if (mwifiex_read_reg(adapter, reg->status_reg_1, &fws1)) |
596 | return -1; | 675 | return -1; |
597 | 676 | ||
598 | *dat = (u16) ((fws1 << 8) | fws0); | 677 | *dat = (u16) ((fws1 << 8) | fws0); |
@@ -608,14 +687,14 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat) | |||
608 | */ | 687 | */ |
609 | static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) | 688 | static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) |
610 | { | 689 | { |
611 | u32 host_int_mask; | 690 | u8 host_int_mask, host_int_disable = HOST_INT_DISABLE; |
612 | 691 | ||
613 | /* Read back the host_int_mask register */ | 692 | /* Read back the host_int_mask register */ |
614 | if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) | 693 | if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask)) |
615 | return -1; | 694 | return -1; |
616 | 695 | ||
617 | /* Update with the mask and write back to the register */ | 696 | /* Update with the mask and write back to the register */ |
618 | host_int_mask &= ~HOST_INT_DISABLE; | 697 | host_int_mask &= ~host_int_disable; |
619 | 698 | ||
620 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { | 699 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) { |
621 | dev_err(adapter->dev, "disable host interrupt failed\n"); | 700 | dev_err(adapter->dev, "disable host interrupt failed\n"); |
@@ -633,8 +712,11 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter) | |||
633 | */ | 712 | */ |
634 | static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) | 713 | static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter) |
635 | { | 714 | { |
715 | struct sdio_mmc_card *card = adapter->card; | ||
716 | |||
636 | /* Simply write the mask to the register */ | 717 | /* Simply write the mask to the register */ |
637 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) { | 718 | if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, |
719 | card->reg->host_int_enable)) { | ||
638 | dev_err(adapter->dev, "enable host interrupt failed\n"); | 720 | dev_err(adapter->dev, "enable host interrupt failed\n"); |
639 | return -1; | 721 | return -1; |
640 | } | 722 | } |
@@ -686,11 +768,13 @@ static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter, | |||
686 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | 768 | static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, |
687 | struct mwifiex_fw_image *fw) | 769 | struct mwifiex_fw_image *fw) |
688 | { | 770 | { |
771 | struct sdio_mmc_card *card = adapter->card; | ||
772 | const struct mwifiex_sdio_card_reg *reg = card->reg; | ||
689 | int ret; | 773 | int ret; |
690 | u8 *firmware = fw->fw_buf; | 774 | u8 *firmware = fw->fw_buf; |
691 | u32 firmware_len = fw->fw_len; | 775 | u32 firmware_len = fw->fw_len; |
692 | u32 offset = 0; | 776 | u32 offset = 0; |
693 | u32 base0, base1; | 777 | u8 base0, base1; |
694 | u8 *fwbuf; | 778 | u8 *fwbuf; |
695 | u16 len = 0; | 779 | u16 len = 0; |
696 | u32 txlen, tx_blocks = 0, tries; | 780 | u32 txlen, tx_blocks = 0, tries; |
@@ -727,7 +811,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | |||
727 | break; | 811 | break; |
728 | 812 | ||
729 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { | 813 | for (tries = 0; tries < MAX_POLL_TRIES; tries++) { |
730 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0, | 814 | ret = mwifiex_read_reg(adapter, reg->base_0_reg, |
731 | &base0); | 815 | &base0); |
732 | if (ret) { | 816 | if (ret) { |
733 | dev_err(adapter->dev, | 817 | dev_err(adapter->dev, |
@@ -736,7 +820,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, | |||
736 | base0, base0); | 820 | base0, base0); |
737 | goto done; | 821 | goto done; |
738 | } | 822 | } |
739 | ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1, | 823 | ret = mwifiex_read_reg(adapter, reg->base_1_reg, |
740 | &base1); | 824 | &base1); |
741 | if (ret) { | 825 | if (ret) { |
742 | dev_err(adapter->dev, | 826 | dev_err(adapter->dev, |
@@ -828,10 +912,11 @@ done: | |||
828 | static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, | 912 | static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, |
829 | u32 poll_num) | 913 | u32 poll_num) |
830 | { | 914 | { |
915 | struct sdio_mmc_card *card = adapter->card; | ||
831 | int ret = 0; | 916 | int ret = 0; |
832 | u16 firmware_stat; | 917 | u16 firmware_stat; |
833 | u32 tries; | 918 | u32 tries; |
834 | u32 winner_status; | 919 | u8 winner_status; |
835 | 920 | ||
836 | /* Wait for firmware initialization event */ | 921 | /* Wait for firmware initialization event */ |
837 | for (tries = 0; tries < poll_num; tries++) { | 922 | for (tries = 0; tries < poll_num; tries++) { |
@@ -849,7 +934,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, | |||
849 | 934 | ||
850 | if (ret) { | 935 | if (ret) { |
851 | if (mwifiex_read_reg | 936 | if (mwifiex_read_reg |
852 | (adapter, CARD_FW_STATUS0_REG, &winner_status)) | 937 | (adapter, card->reg->status_reg_0, &winner_status)) |
853 | winner_status = 0; | 938 | winner_status = 0; |
854 | 939 | ||
855 | if (winner_status) | 940 | if (winner_status) |
@@ -866,12 +951,12 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, | |||
866 | static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) | 951 | static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) |
867 | { | 952 | { |
868 | struct sdio_mmc_card *card = adapter->card; | 953 | struct sdio_mmc_card *card = adapter->card; |
869 | u32 sdio_ireg; | 954 | u8 sdio_ireg; |
870 | unsigned long flags; | 955 | unsigned long flags; |
871 | 956 | ||
872 | if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS, | 957 | if (mwifiex_read_data_sync(adapter, card->mp_regs, |
873 | REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, | 958 | card->reg->max_mp_regs, |
874 | 0)) { | 959 | REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) { |
875 | dev_err(adapter->dev, "read mp_regs failed\n"); | 960 | dev_err(adapter->dev, "read mp_regs failed\n"); |
876 | return; | 961 | return; |
877 | } | 962 | } |
@@ -880,6 +965,9 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) | |||
880 | if (sdio_ireg) { | 965 | if (sdio_ireg) { |
881 | /* | 966 | /* |
882 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS | 967 | * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS |
968 | * For SDIO new mode CMD port interrupts | ||
969 | * DN_LD_CMD_PORT_HOST_INT_STATUS and/or | ||
970 | * UP_LD_CMD_PORT_HOST_INT_STATUS | ||
883 | * Clear the interrupt status register | 971 | * Clear the interrupt status register |
884 | */ | 972 | */ |
885 | dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); | 973 | dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg); |
@@ -1003,11 +1091,11 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | |||
1003 | s32 f_aggr_cur = 0; | 1091 | s32 f_aggr_cur = 0; |
1004 | struct sk_buff *skb_deaggr; | 1092 | struct sk_buff *skb_deaggr; |
1005 | u32 pind; | 1093 | u32 pind; |
1006 | u32 pkt_len, pkt_type = 0; | 1094 | u32 pkt_len, pkt_type, mport; |
1007 | u8 *curr_ptr; | 1095 | u8 *curr_ptr; |
1008 | u32 rx_len = skb->len; | 1096 | u32 rx_len = skb->len; |
1009 | 1097 | ||
1010 | if (port == CTRL_PORT) { | 1098 | if ((card->has_control_mask) && (port == CTRL_PORT)) { |
1011 | /* Read the command Resp without aggr */ | 1099 | /* Read the command Resp without aggr */ |
1012 | dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " | 1100 | dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " |
1013 | "response\n", __func__); | 1101 | "response\n", __func__); |
@@ -1024,7 +1112,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | |||
1024 | goto rx_curr_single; | 1112 | goto rx_curr_single; |
1025 | } | 1113 | } |
1026 | 1114 | ||
1027 | if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { | 1115 | if ((!card->has_control_mask && (card->mp_rd_bitmap & |
1116 | card->reg->data_port_mask)) || | ||
1117 | (card->has_control_mask && (card->mp_rd_bitmap & | ||
1118 | (~((u32) CTRL_PORT_MASK))))) { | ||
1028 | /* Some more data RX pending */ | 1119 | /* Some more data RX pending */ |
1029 | dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); | 1120 | dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); |
1030 | 1121 | ||
@@ -1060,10 +1151,10 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | |||
1060 | if (f_aggr_cur) { | 1151 | if (f_aggr_cur) { |
1061 | dev_dbg(adapter->dev, "info: current packet aggregation\n"); | 1152 | dev_dbg(adapter->dev, "info: current packet aggregation\n"); |
1062 | /* Curr pkt can be aggregated */ | 1153 | /* Curr pkt can be aggregated */ |
1063 | MP_RX_AGGR_SETUP(card, skb, port); | 1154 | mp_rx_aggr_setup(card, skb, port); |
1064 | 1155 | ||
1065 | if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || | 1156 | if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || |
1066 | MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { | 1157 | mp_rx_aggr_port_limit_reached(card)) { |
1067 | dev_dbg(adapter->dev, "info: %s: aggregated packet " | 1158 | dev_dbg(adapter->dev, "info: %s: aggregated packet " |
1068 | "limit reached\n", __func__); | 1159 | "limit reached\n", __func__); |
1069 | /* No more pkts allowed in Aggr buf, rx it */ | 1160 | /* No more pkts allowed in Aggr buf, rx it */ |
@@ -1076,11 +1167,28 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, | |||
1076 | dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", | 1167 | dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", |
1077 | card->mpa_rx.pkt_cnt); | 1168 | card->mpa_rx.pkt_cnt); |
1078 | 1169 | ||
1170 | if (card->supports_sdio_new_mode) { | ||
1171 | int i; | ||
1172 | u32 port_count; | ||
1173 | |||
1174 | for (i = 0, port_count = 0; i < card->max_ports; i++) | ||
1175 | if (card->mpa_rx.ports & BIT(i)) | ||
1176 | port_count++; | ||
1177 | |||
1178 | /* Reading data from "start_port + 0" to "start_port + | ||
1179 | * port_count -1", so decrease the count by 1 | ||
1180 | */ | ||
1181 | port_count--; | ||
1182 | mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | | ||
1183 | (port_count << 8)) + card->mpa_rx.start_port; | ||
1184 | } else { | ||
1185 | mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | | ||
1186 | (card->mpa_rx.ports << 4)) + | ||
1187 | card->mpa_rx.start_port; | ||
1188 | } | ||
1189 | |||
1079 | if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, | 1190 | if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, |
1080 | card->mpa_rx.buf_len, | 1191 | card->mpa_rx.buf_len, mport, 1)) |
1081 | (adapter->ioport | 0x1000 | | ||
1082 | (card->mpa_rx.ports << 4)) + | ||
1083 | card->mpa_rx.start_port, 1)) | ||
1084 | goto error; | 1192 | goto error; |
1085 | 1193 | ||
1086 | curr_ptr = card->mpa_rx.buf; | 1194 | curr_ptr = card->mpa_rx.buf; |
@@ -1167,6 +1275,7 @@ error: | |||
1167 | static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | 1275 | static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) |
1168 | { | 1276 | { |
1169 | struct sdio_mmc_card *card = adapter->card; | 1277 | struct sdio_mmc_card *card = adapter->card; |
1278 | const struct mwifiex_sdio_card_reg *reg = card->reg; | ||
1170 | int ret = 0; | 1279 | int ret = 0; |
1171 | u8 sdio_ireg; | 1280 | u8 sdio_ireg; |
1172 | struct sk_buff *skb; | 1281 | struct sk_buff *skb; |
@@ -1175,6 +1284,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1175 | u32 rx_blocks; | 1284 | u32 rx_blocks; |
1176 | u16 rx_len; | 1285 | u16 rx_len; |
1177 | unsigned long flags; | 1286 | unsigned long flags; |
1287 | u32 bitmap; | ||
1288 | u8 cr; | ||
1178 | 1289 | ||
1179 | spin_lock_irqsave(&adapter->int_lock, flags); | 1290 | spin_lock_irqsave(&adapter->int_lock, flags); |
1180 | sdio_ireg = adapter->int_status; | 1291 | sdio_ireg = adapter->int_status; |
@@ -1184,10 +1295,60 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1184 | if (!sdio_ireg) | 1295 | if (!sdio_ireg) |
1185 | return ret; | 1296 | return ret; |
1186 | 1297 | ||
1298 | /* Following interrupt is only for SDIO new mode */ | ||
1299 | if (sdio_ireg & DN_LD_CMD_PORT_HOST_INT_STATUS && adapter->cmd_sent) | ||
1300 | adapter->cmd_sent = false; | ||
1301 | |||
1302 | /* Following interrupt is only for SDIO new mode */ | ||
1303 | if (sdio_ireg & UP_LD_CMD_PORT_HOST_INT_STATUS) { | ||
1304 | u32 pkt_type; | ||
1305 | |||
1306 | /* read the len of control packet */ | ||
1307 | rx_len = card->mp_regs[CMD_RD_LEN_1] << 8; | ||
1308 | rx_len |= (u16) card->mp_regs[CMD_RD_LEN_0]; | ||
1309 | rx_blocks = DIV_ROUND_UP(rx_len, MWIFIEX_SDIO_BLOCK_SIZE); | ||
1310 | if (rx_len <= INTF_HEADER_LEN || | ||
1311 | (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) > | ||
1312 | MWIFIEX_RX_DATA_BUF_SIZE) | ||
1313 | return -1; | ||
1314 | rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE); | ||
1315 | |||
1316 | skb = dev_alloc_skb(rx_len); | ||
1317 | if (!skb) | ||
1318 | return -1; | ||
1319 | |||
1320 | skb_put(skb, rx_len); | ||
1321 | |||
1322 | if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, | ||
1323 | skb->len, adapter->ioport | | ||
1324 | CMD_PORT_SLCT)) { | ||
1325 | dev_err(adapter->dev, | ||
1326 | "%s: failed to card_to_host", __func__); | ||
1327 | dev_kfree_skb_any(skb); | ||
1328 | goto term_cmd; | ||
1329 | } | ||
1330 | |||
1331 | if ((pkt_type != MWIFIEX_TYPE_CMD) && | ||
1332 | (pkt_type != MWIFIEX_TYPE_EVENT)) | ||
1333 | dev_err(adapter->dev, | ||
1334 | "%s:Received wrong packet on cmd port", | ||
1335 | __func__); | ||
1336 | |||
1337 | mwifiex_decode_rx_packet(adapter, skb, pkt_type); | ||
1338 | } | ||
1339 | |||
1187 | if (sdio_ireg & DN_LD_HOST_INT_STATUS) { | 1340 | if (sdio_ireg & DN_LD_HOST_INT_STATUS) { |
1188 | card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8; | 1341 | bitmap = (u32) card->mp_regs[reg->wr_bitmap_l]; |
1189 | card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L]; | 1342 | bitmap |= ((u32) card->mp_regs[reg->wr_bitmap_u]) << 8; |
1190 | dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n", | 1343 | if (card->supports_sdio_new_mode) { |
1344 | bitmap |= | ||
1345 | ((u32) card->mp_regs[reg->wr_bitmap_1l]) << 16; | ||
1346 | bitmap |= | ||
1347 | ((u32) card->mp_regs[reg->wr_bitmap_1u]) << 24; | ||
1348 | } | ||
1349 | card->mp_wr_bitmap = bitmap; | ||
1350 | |||
1351 | dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%x\n", | ||
1191 | card->mp_wr_bitmap); | 1352 | card->mp_wr_bitmap); |
1192 | if (adapter->data_sent && | 1353 | if (adapter->data_sent && |
1193 | (card->mp_wr_bitmap & card->mp_data_port_mask)) { | 1354 | (card->mp_wr_bitmap & card->mp_data_port_mask)) { |
@@ -1200,11 +1361,11 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1200 | /* As firmware will not generate download ready interrupt if the port | 1361 | /* As firmware will not generate download ready interrupt if the port |
1201 | updated is command port only, cmd_sent should be done for any SDIO | 1362 | updated is command port only, cmd_sent should be done for any SDIO |
1202 | interrupt. */ | 1363 | interrupt. */ |
1203 | if (adapter->cmd_sent) { | 1364 | if (card->has_control_mask && adapter->cmd_sent) { |
1204 | /* Check if firmware has attach buffer at command port and | 1365 | /* Check if firmware has attach buffer at command port and |
1205 | update just that in wr_bit_map. */ | 1366 | update just that in wr_bit_map. */ |
1206 | card->mp_wr_bitmap |= | 1367 | card->mp_wr_bitmap |= |
1207 | (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK; | 1368 | (u32) card->mp_regs[reg->wr_bitmap_l] & CTRL_PORT_MASK; |
1208 | if (card->mp_wr_bitmap & CTRL_PORT_MASK) | 1369 | if (card->mp_wr_bitmap & CTRL_PORT_MASK) |
1209 | adapter->cmd_sent = false; | 1370 | adapter->cmd_sent = false; |
1210 | } | 1371 | } |
@@ -1212,9 +1373,16 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1212 | dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", | 1373 | dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", |
1213 | adapter->cmd_sent, adapter->data_sent); | 1374 | adapter->cmd_sent, adapter->data_sent); |
1214 | if (sdio_ireg & UP_LD_HOST_INT_STATUS) { | 1375 | if (sdio_ireg & UP_LD_HOST_INT_STATUS) { |
1215 | card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8; | 1376 | bitmap = (u32) card->mp_regs[reg->rd_bitmap_l]; |
1216 | card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L]; | 1377 | bitmap |= ((u32) card->mp_regs[reg->rd_bitmap_u]) << 8; |
1217 | dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n", | 1378 | if (card->supports_sdio_new_mode) { |
1379 | bitmap |= | ||
1380 | ((u32) card->mp_regs[reg->rd_bitmap_1l]) << 16; | ||
1381 | bitmap |= | ||
1382 | ((u32) card->mp_regs[reg->rd_bitmap_1u]) << 24; | ||
1383 | } | ||
1384 | card->mp_rd_bitmap = bitmap; | ||
1385 | dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%x\n", | ||
1218 | card->mp_rd_bitmap); | 1386 | card->mp_rd_bitmap); |
1219 | 1387 | ||
1220 | while (true) { | 1388 | while (true) { |
@@ -1224,8 +1392,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1224 | "info: no more rd_port available\n"); | 1392 | "info: no more rd_port available\n"); |
1225 | break; | 1393 | break; |
1226 | } | 1394 | } |
1227 | len_reg_l = RD_LEN_P0_L + (port << 1); | 1395 | len_reg_l = reg->rd_len_p0_l + (port << 1); |
1228 | len_reg_u = RD_LEN_P0_U + (port << 1); | 1396 | len_reg_u = reg->rd_len_p0_u + (port << 1); |
1229 | rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; | 1397 | rx_len = ((u16) card->mp_regs[len_reg_u]) << 8; |
1230 | rx_len |= (u16) card->mp_regs[len_reg_l]; | 1398 | rx_len |= (u16) card->mp_regs[len_reg_l]; |
1231 | dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", | 1399 | dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n", |
@@ -1257,37 +1425,33 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1257 | 1425 | ||
1258 | if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, | 1426 | if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb, |
1259 | port)) { | 1427 | port)) { |
1260 | u32 cr = 0; | ||
1261 | |||
1262 | dev_err(adapter->dev, "card_to_host_mpa failed:" | 1428 | dev_err(adapter->dev, "card_to_host_mpa failed:" |
1263 | " int status=%#x\n", sdio_ireg); | 1429 | " int status=%#x\n", sdio_ireg); |
1264 | if (mwifiex_read_reg(adapter, | 1430 | goto term_cmd; |
1265 | CONFIGURATION_REG, &cr)) | ||
1266 | dev_err(adapter->dev, | ||
1267 | "read CFG reg failed\n"); | ||
1268 | |||
1269 | dev_dbg(adapter->dev, | ||
1270 | "info: CFG reg val = %d\n", cr); | ||
1271 | if (mwifiex_write_reg(adapter, | ||
1272 | CONFIGURATION_REG, | ||
1273 | (cr | 0x04))) | ||
1274 | dev_err(adapter->dev, | ||
1275 | "write CFG reg failed\n"); | ||
1276 | |||
1277 | dev_dbg(adapter->dev, "info: write success\n"); | ||
1278 | if (mwifiex_read_reg(adapter, | ||
1279 | CONFIGURATION_REG, &cr)) | ||
1280 | dev_err(adapter->dev, | ||
1281 | "read CFG reg failed\n"); | ||
1282 | |||
1283 | dev_dbg(adapter->dev, | ||
1284 | "info: CFG reg val =%x\n", cr); | ||
1285 | return -1; | ||
1286 | } | 1431 | } |
1287 | } | 1432 | } |
1288 | } | 1433 | } |
1289 | 1434 | ||
1290 | return 0; | 1435 | return 0; |
1436 | |||
1437 | term_cmd: | ||
1438 | /* terminate cmd */ | ||
1439 | if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) | ||
1440 | dev_err(adapter->dev, "read CFG reg failed\n"); | ||
1441 | else | ||
1442 | dev_dbg(adapter->dev, "info: CFG reg val = %d\n", cr); | ||
1443 | |||
1444 | if (mwifiex_write_reg(adapter, CONFIGURATION_REG, (cr | 0x04))) | ||
1445 | dev_err(adapter->dev, "write CFG reg failed\n"); | ||
1446 | else | ||
1447 | dev_dbg(adapter->dev, "info: write success\n"); | ||
1448 | |||
1449 | if (mwifiex_read_reg(adapter, CONFIGURATION_REG, &cr)) | ||
1450 | dev_err(adapter->dev, "read CFG reg failed\n"); | ||
1451 | else | ||
1452 | dev_dbg(adapter->dev, "info: CFG reg val =%x\n", cr); | ||
1453 | |||
1454 | return -1; | ||
1291 | } | 1455 | } |
1292 | 1456 | ||
1293 | /* | 1457 | /* |
@@ -1305,7 +1469,7 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) | |||
1305 | * and return. | 1469 | * and return. |
1306 | */ | 1470 | */ |
1307 | static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | 1471 | static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, |
1308 | u8 *payload, u32 pkt_len, u8 port, | 1472 | u8 *payload, u32 pkt_len, u32 port, |
1309 | u32 next_pkt_len) | 1473 | u32 next_pkt_len) |
1310 | { | 1474 | { |
1311 | struct sdio_mmc_card *card = adapter->card; | 1475 | struct sdio_mmc_card *card = adapter->card; |
@@ -1314,8 +1478,11 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | |||
1314 | s32 f_send_cur_buf = 0; | 1478 | s32 f_send_cur_buf = 0; |
1315 | s32 f_precopy_cur_buf = 0; | 1479 | s32 f_precopy_cur_buf = 0; |
1316 | s32 f_postcopy_cur_buf = 0; | 1480 | s32 f_postcopy_cur_buf = 0; |
1481 | u32 mport; | ||
1317 | 1482 | ||
1318 | if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) { | 1483 | if (!card->mpa_tx.enabled || |
1484 | (card->has_control_mask && (port == CTRL_PORT)) || | ||
1485 | (card->supports_sdio_new_mode && (port == CMD_PORT_SLCT))) { | ||
1319 | dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", | 1486 | dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n", |
1320 | __func__); | 1487 | __func__); |
1321 | 1488 | ||
@@ -1329,7 +1496,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | |||
1329 | __func__); | 1496 | __func__); |
1330 | 1497 | ||
1331 | if (MP_TX_AGGR_IN_PROGRESS(card)) { | 1498 | if (MP_TX_AGGR_IN_PROGRESS(card)) { |
1332 | if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) && | 1499 | if (!mp_tx_aggr_port_limit_reached(card) && |
1333 | MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { | 1500 | MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) { |
1334 | f_precopy_cur_buf = 1; | 1501 | f_precopy_cur_buf = 1; |
1335 | 1502 | ||
@@ -1342,7 +1509,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | |||
1342 | /* No room in Aggr buf, send it */ | 1509 | /* No room in Aggr buf, send it */ |
1343 | f_send_aggr_buf = 1; | 1510 | f_send_aggr_buf = 1; |
1344 | 1511 | ||
1345 | if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) || | 1512 | if (mp_tx_aggr_port_limit_reached(card) || |
1346 | !(card->mp_wr_bitmap & | 1513 | !(card->mp_wr_bitmap & |
1347 | (1 << card->curr_wr_port))) | 1514 | (1 << card->curr_wr_port))) |
1348 | f_send_cur_buf = 1; | 1515 | f_send_cur_buf = 1; |
@@ -1381,7 +1548,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | |||
1381 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); | 1548 | MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port); |
1382 | 1549 | ||
1383 | if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || | 1550 | if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) || |
1384 | MP_TX_AGGR_PORT_LIMIT_REACHED(card)) | 1551 | mp_tx_aggr_port_limit_reached(card)) |
1385 | /* No more pkts allowed in Aggr buf, send it */ | 1552 | /* No more pkts allowed in Aggr buf, send it */ |
1386 | f_send_aggr_buf = 1; | 1553 | f_send_aggr_buf = 1; |
1387 | } | 1554 | } |
@@ -1390,11 +1557,28 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, | |||
1390 | dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", | 1557 | dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n", |
1391 | __func__, | 1558 | __func__, |
1392 | card->mpa_tx.start_port, card->mpa_tx.ports); | 1559 | card->mpa_tx.start_port, card->mpa_tx.ports); |
1560 | if (card->supports_sdio_new_mode) { | ||
1561 | u32 port_count; | ||
1562 | int i; | ||
1563 | |||
1564 | for (i = 0, port_count = 0; i < card->max_ports; i++) | ||
1565 | if (card->mpa_tx.ports & BIT(i)) | ||
1566 | port_count++; | ||
1567 | |||
1568 | /* Writing data from "start_port + 0" to "start_port + | ||
1569 | * port_count -1", so decrease the count by 1 | ||
1570 | */ | ||
1571 | port_count--; | ||
1572 | mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | | ||
1573 | (port_count << 8)) + card->mpa_tx.start_port; | ||
1574 | } else { | ||
1575 | mport = (adapter->ioport | SDIO_MPA_ADDR_BASE | | ||
1576 | (card->mpa_tx.ports << 4)) + | ||
1577 | card->mpa_tx.start_port; | ||
1578 | } | ||
1579 | |||
1393 | ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, | 1580 | ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, |
1394 | card->mpa_tx.buf_len, | 1581 | card->mpa_tx.buf_len, mport); |
1395 | (adapter->ioport | 0x1000 | | ||
1396 | (card->mpa_tx.ports << 4)) + | ||
1397 | card->mpa_tx.start_port); | ||
1398 | 1582 | ||
1399 | MP_TX_AGGR_BUF_RESET(card); | 1583 | MP_TX_AGGR_BUF_RESET(card); |
1400 | } | 1584 | } |
@@ -1434,7 +1618,7 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, | |||
1434 | int ret; | 1618 | int ret; |
1435 | u32 buf_block_len; | 1619 | u32 buf_block_len; |
1436 | u32 blk_size; | 1620 | u32 blk_size; |
1437 | u8 port = CTRL_PORT; | 1621 | u32 port = CTRL_PORT; |
1438 | u8 *payload = (u8 *)skb->data; | 1622 | u8 *payload = (u8 *)skb->data; |
1439 | u32 pkt_len = skb->len; | 1623 | u32 pkt_len = skb->len; |
1440 | 1624 | ||
@@ -1465,6 +1649,9 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, | |||
1465 | pkt_len > MWIFIEX_UPLD_SIZE) | 1649 | pkt_len > MWIFIEX_UPLD_SIZE) |
1466 | dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", | 1650 | dev_err(adapter->dev, "%s: payload=%p, nb=%d\n", |
1467 | __func__, payload, pkt_len); | 1651 | __func__, payload, pkt_len); |
1652 | |||
1653 | if (card->supports_sdio_new_mode) | ||
1654 | port = CMD_PORT_SLCT; | ||
1468 | } | 1655 | } |
1469 | 1656 | ||
1470 | /* Transfer data to card */ | 1657 | /* Transfer data to card */ |
@@ -1586,18 +1773,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) | |||
1586 | 1773 | ||
1587 | adapter->dev = &func->dev; | 1774 | adapter->dev = &func->dev; |
1588 | 1775 | ||
1589 | switch (func->device) { | 1776 | strcpy(adapter->fw_name, card->firmware); |
1590 | case SDIO_DEVICE_ID_MARVELL_8786: | ||
1591 | strcpy(adapter->fw_name, SD8786_DEFAULT_FW_NAME); | ||
1592 | break; | ||
1593 | case SDIO_DEVICE_ID_MARVELL_8797: | ||
1594 | strcpy(adapter->fw_name, SD8797_DEFAULT_FW_NAME); | ||
1595 | break; | ||
1596 | case SDIO_DEVICE_ID_MARVELL_8787: | ||
1597 | default: | ||
1598 | strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME); | ||
1599 | break; | ||
1600 | } | ||
1601 | 1777 | ||
1602 | return 0; | 1778 | return 0; |
1603 | 1779 | ||
@@ -1626,8 +1802,9 @@ disable_func: | |||
1626 | static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) | 1802 | static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) |
1627 | { | 1803 | { |
1628 | struct sdio_mmc_card *card = adapter->card; | 1804 | struct sdio_mmc_card *card = adapter->card; |
1805 | const struct mwifiex_sdio_card_reg *reg = card->reg; | ||
1629 | int ret; | 1806 | int ret; |
1630 | u32 sdio_ireg; | 1807 | u8 sdio_ireg; |
1631 | 1808 | ||
1632 | /* | 1809 | /* |
1633 | * Read the HOST_INT_STATUS_REG for ACK the first interrupt got | 1810 | * Read the HOST_INT_STATUS_REG for ACK the first interrupt got |
@@ -1645,30 +1822,35 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter) | |||
1645 | /* Initialize SDIO variables in card */ | 1822 | /* Initialize SDIO variables in card */ |
1646 | card->mp_rd_bitmap = 0; | 1823 | card->mp_rd_bitmap = 0; |
1647 | card->mp_wr_bitmap = 0; | 1824 | card->mp_wr_bitmap = 0; |
1648 | card->curr_rd_port = 1; | 1825 | card->curr_rd_port = reg->start_rd_port; |
1649 | card->curr_wr_port = 1; | 1826 | card->curr_wr_port = reg->start_wr_port; |
1650 | 1827 | ||
1651 | card->mp_data_port_mask = DATA_PORT_MASK; | 1828 | card->mp_data_port_mask = reg->data_port_mask; |
1652 | 1829 | ||
1653 | card->mpa_tx.buf_len = 0; | 1830 | card->mpa_tx.buf_len = 0; |
1654 | card->mpa_tx.pkt_cnt = 0; | 1831 | card->mpa_tx.pkt_cnt = 0; |
1655 | card->mpa_tx.start_port = 0; | 1832 | card->mpa_tx.start_port = 0; |
1656 | 1833 | ||
1657 | card->mpa_tx.enabled = 1; | 1834 | card->mpa_tx.enabled = 1; |
1658 | card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | 1835 | card->mpa_tx.pkt_aggr_limit = card->mp_agg_pkt_limit; |
1659 | 1836 | ||
1660 | card->mpa_rx.buf_len = 0; | 1837 | card->mpa_rx.buf_len = 0; |
1661 | card->mpa_rx.pkt_cnt = 0; | 1838 | card->mpa_rx.pkt_cnt = 0; |
1662 | card->mpa_rx.start_port = 0; | 1839 | card->mpa_rx.start_port = 0; |
1663 | 1840 | ||
1664 | card->mpa_rx.enabled = 1; | 1841 | card->mpa_rx.enabled = 1; |
1665 | card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT; | 1842 | card->mpa_rx.pkt_aggr_limit = card->mp_agg_pkt_limit; |
1666 | 1843 | ||
1667 | /* Allocate buffers for SDIO MP-A */ | 1844 | /* Allocate buffers for SDIO MP-A */ |
1668 | card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL); | 1845 | card->mp_regs = kzalloc(reg->max_mp_regs, GFP_KERNEL); |
1669 | if (!card->mp_regs) | 1846 | if (!card->mp_regs) |
1670 | return -ENOMEM; | 1847 | return -ENOMEM; |
1671 | 1848 | ||
1849 | /* Allocate skb pointer buffers */ | ||
1850 | card->mpa_rx.skb_arr = kzalloc((sizeof(void *)) * | ||
1851 | card->mp_agg_pkt_limit, GFP_KERNEL); | ||
1852 | card->mpa_rx.len_arr = kzalloc(sizeof(*card->mpa_rx.len_arr) * | ||
1853 | card->mp_agg_pkt_limit, GFP_KERNEL); | ||
1672 | ret = mwifiex_alloc_sdio_mpa_buffers(adapter, | 1854 | ret = mwifiex_alloc_sdio_mpa_buffers(adapter, |
1673 | SDIO_MP_TX_AGGR_DEF_BUF_SIZE, | 1855 | SDIO_MP_TX_AGGR_DEF_BUF_SIZE, |
1674 | SDIO_MP_RX_AGGR_DEF_BUF_SIZE); | 1856 | SDIO_MP_RX_AGGR_DEF_BUF_SIZE); |
@@ -1705,6 +1887,8 @@ static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter) | |||
1705 | struct sdio_mmc_card *card = adapter->card; | 1887 | struct sdio_mmc_card *card = adapter->card; |
1706 | 1888 | ||
1707 | kfree(card->mp_regs); | 1889 | kfree(card->mp_regs); |
1890 | kfree(card->mpa_rx.skb_arr); | ||
1891 | kfree(card->mpa_rx.len_arr); | ||
1708 | kfree(card->mpa_tx.buf); | 1892 | kfree(card->mpa_tx.buf); |
1709 | kfree(card->mpa_rx.buf); | 1893 | kfree(card->mpa_rx.buf); |
1710 | } | 1894 | } |
@@ -1716,16 +1900,20 @@ static void | |||
1716 | mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) | 1900 | mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) |
1717 | { | 1901 | { |
1718 | struct sdio_mmc_card *card = adapter->card; | 1902 | struct sdio_mmc_card *card = adapter->card; |
1903 | const struct mwifiex_sdio_card_reg *reg = card->reg; | ||
1719 | int i; | 1904 | int i; |
1720 | 1905 | ||
1721 | card->mp_end_port = port; | 1906 | card->mp_end_port = port; |
1722 | 1907 | ||
1723 | card->mp_data_port_mask = DATA_PORT_MASK; | 1908 | card->mp_data_port_mask = reg->data_port_mask; |
1724 | 1909 | ||
1725 | for (i = 1; i <= MAX_PORT - card->mp_end_port; i++) | 1910 | if (reg->start_wr_port) { |
1726 | card->mp_data_port_mask &= ~(1 << (MAX_PORT - i)); | 1911 | for (i = 1; i <= card->max_ports - card->mp_end_port; i++) |
1912 | card->mp_data_port_mask &= | ||
1913 | ~(1 << (card->max_ports - i)); | ||
1914 | } | ||
1727 | 1915 | ||
1728 | card->curr_wr_port = 1; | 1916 | card->curr_wr_port = reg->start_wr_port; |
1729 | 1917 | ||
1730 | dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", | 1918 | dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n", |
1731 | port, card->mp_data_port_mask); | 1919 | port, card->mp_data_port_mask); |
@@ -1831,3 +2019,4 @@ MODULE_LICENSE("GPL v2"); | |||
1831 | MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); | 2019 | MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); |
1832 | MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); | 2020 | MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); |
1833 | MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); | 2021 | MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); |
2022 | MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME); | ||
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 8cc5468654b4..6d51dfdd8251 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h | |||
@@ -32,30 +32,37 @@ | |||
32 | #define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin" | 32 | #define SD8786_DEFAULT_FW_NAME "mrvl/sd8786_uapsta.bin" |
33 | #define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" | 33 | #define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin" |
34 | #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" | 34 | #define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" |
35 | #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin" | ||
35 | 36 | ||
36 | #define BLOCK_MODE 1 | 37 | #define BLOCK_MODE 1 |
37 | #define BYTE_MODE 0 | 38 | #define BYTE_MODE 0 |
38 | 39 | ||
39 | #define REG_PORT 0 | 40 | #define REG_PORT 0 |
40 | #define RD_BITMAP_L 0x04 | ||
41 | #define RD_BITMAP_U 0x05 | ||
42 | #define WR_BITMAP_L 0x06 | ||
43 | #define WR_BITMAP_U 0x07 | ||
44 | #define RD_LEN_P0_L 0x08 | ||
45 | #define RD_LEN_P0_U 0x09 | ||
46 | 41 | ||
47 | #define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff | 42 | #define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff |
48 | 43 | ||
49 | #define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 | 44 | #define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000 |
50 | 45 | ||
46 | #define SDIO_MPA_ADDR_BASE 0x1000 | ||
51 | #define CTRL_PORT 0 | 47 | #define CTRL_PORT 0 |
52 | #define CTRL_PORT_MASK 0x0001 | 48 | #define CTRL_PORT_MASK 0x0001 |
53 | #define DATA_PORT_MASK 0xfffe | ||
54 | 49 | ||
55 | #define MAX_MP_REGS 64 | 50 | #define CMD_PORT_UPLD_INT_MASK (0x1U<<6) |
56 | #define MAX_PORT 16 | 51 | #define CMD_PORT_DNLD_INT_MASK (0x1U<<7) |
57 | 52 | #define HOST_TERM_CMD53 (0x1U << 2) | |
58 | #define SDIO_MP_AGGR_DEF_PKT_LIMIT 8 | 53 | #define REG_PORT 0 |
54 | #define MEM_PORT 0x10000 | ||
55 | #define CMD_RD_LEN_0 0xB4 | ||
56 | #define CMD_RD_LEN_1 0xB5 | ||
57 | #define CARD_CONFIG_2_1_REG 0xCD | ||
58 | #define CMD53_NEW_MODE (0x1U << 0) | ||
59 | #define CMD_CONFIG_0 0xB8 | ||
60 | #define CMD_PORT_RD_LEN_EN (0x1U << 2) | ||
61 | #define CMD_CONFIG_1 0xB9 | ||
62 | #define CMD_PORT_AUTO_EN (0x1U << 0) | ||
63 | #define CMD_PORT_SLCT 0x8000 | ||
64 | #define UP_LD_CMD_PORT_HOST_INT_STATUS (0x40U) | ||
65 | #define DN_LD_CMD_PORT_HOST_INT_STATUS (0x80U) | ||
59 | 66 | ||
60 | #define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */ | 67 | #define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (8192) /* 8K */ |
61 | 68 | ||
@@ -75,14 +82,8 @@ | |||
75 | 82 | ||
76 | /* Host Control Registers : Configuration */ | 83 | /* Host Control Registers : Configuration */ |
77 | #define CONFIGURATION_REG 0x00 | 84 | #define CONFIGURATION_REG 0x00 |
78 | /* Host Control Registers : Host without Command 53 finish host*/ | ||
79 | #define HOST_TO_CARD_EVENT (0x1U << 3) | ||
80 | /* Host Control Registers : Host without Command 53 finish host */ | ||
81 | #define HOST_WO_CMD53_FINISH_HOST (0x1U << 2) | ||
82 | /* Host Control Registers : Host power up */ | 85 | /* Host Control Registers : Host power up */ |
83 | #define HOST_POWER_UP (0x1U << 1) | 86 | #define HOST_POWER_UP (0x1U << 1) |
84 | /* Host Control Registers : Host power down */ | ||
85 | #define HOST_POWER_DOWN (0x1U << 0) | ||
86 | 87 | ||
87 | /* Host Control Registers : Host interrupt mask */ | 88 | /* Host Control Registers : Host interrupt mask */ |
88 | #define HOST_INT_MASK_REG 0x02 | 89 | #define HOST_INT_MASK_REG 0x02 |
@@ -90,8 +91,7 @@ | |||
90 | #define UP_LD_HOST_INT_MASK (0x1U) | 91 | #define UP_LD_HOST_INT_MASK (0x1U) |
91 | /* Host Control Registers : Download host interrupt mask */ | 92 | /* Host Control Registers : Download host interrupt mask */ |
92 | #define DN_LD_HOST_INT_MASK (0x2U) | 93 | #define DN_LD_HOST_INT_MASK (0x2U) |
93 | /* Enable Host interrupt mask */ | 94 | |
94 | #define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK) | ||
95 | /* Disable Host interrupt mask */ | 95 | /* Disable Host interrupt mask */ |
96 | #define HOST_INT_DISABLE 0xff | 96 | #define HOST_INT_DISABLE 0xff |
97 | 97 | ||
@@ -104,74 +104,15 @@ | |||
104 | 104 | ||
105 | /* Host Control Registers : Host interrupt RSR */ | 105 | /* Host Control Registers : Host interrupt RSR */ |
106 | #define HOST_INT_RSR_REG 0x01 | 106 | #define HOST_INT_RSR_REG 0x01 |
107 | /* Host Control Registers : Upload host interrupt RSR */ | ||
108 | #define UP_LD_HOST_INT_RSR (0x1U) | ||
109 | #define SDIO_INT_MASK 0x3F | ||
110 | 107 | ||
111 | /* Host Control Registers : Host interrupt status */ | 108 | /* Host Control Registers : Host interrupt status */ |
112 | #define HOST_INT_STATUS_REG 0x28 | 109 | #define HOST_INT_STATUS_REG 0x28 |
113 | /* Host Control Registers : Upload CRC error */ | 110 | |
114 | #define UP_LD_CRC_ERR (0x1U << 2) | ||
115 | /* Host Control Registers : Upload restart */ | ||
116 | #define UP_LD_RESTART (0x1U << 1) | ||
117 | /* Host Control Registers : Download restart */ | ||
118 | #define DN_LD_RESTART (0x1U << 0) | ||
119 | |||
120 | /* Card Control Registers : Card status register */ | ||
121 | #define CARD_STATUS_REG 0x30 | ||
122 | /* Card Control Registers : Card I/O ready */ | 111 | /* Card Control Registers : Card I/O ready */ |
123 | #define CARD_IO_READY (0x1U << 3) | 112 | #define CARD_IO_READY (0x1U << 3) |
124 | /* Card Control Registers : CIS card ready */ | ||
125 | #define CIS_CARD_RDY (0x1U << 2) | ||
126 | /* Card Control Registers : Upload card ready */ | ||
127 | #define UP_LD_CARD_RDY (0x1U << 1) | ||
128 | /* Card Control Registers : Download card ready */ | 113 | /* Card Control Registers : Download card ready */ |
129 | #define DN_LD_CARD_RDY (0x1U << 0) | 114 | #define DN_LD_CARD_RDY (0x1U << 0) |
130 | 115 | ||
131 | /* Card Control Registers : Host interrupt mask register */ | ||
132 | #define HOST_INTERRUPT_MASK_REG 0x34 | ||
133 | /* Card Control Registers : Host power interrupt mask */ | ||
134 | #define HOST_POWER_INT_MASK (0x1U << 3) | ||
135 | /* Card Control Registers : Abort card interrupt mask */ | ||
136 | #define ABORT_CARD_INT_MASK (0x1U << 2) | ||
137 | /* Card Control Registers : Upload card interrupt mask */ | ||
138 | #define UP_LD_CARD_INT_MASK (0x1U << 1) | ||
139 | /* Card Control Registers : Download card interrupt mask */ | ||
140 | #define DN_LD_CARD_INT_MASK (0x1U << 0) | ||
141 | |||
142 | /* Card Control Registers : Card interrupt status register */ | ||
143 | #define CARD_INTERRUPT_STATUS_REG 0x38 | ||
144 | /* Card Control Registers : Power up interrupt */ | ||
145 | #define POWER_UP_INT (0x1U << 4) | ||
146 | /* Card Control Registers : Power down interrupt */ | ||
147 | #define POWER_DOWN_INT (0x1U << 3) | ||
148 | |||
149 | /* Card Control Registers : Card interrupt RSR register */ | ||
150 | #define CARD_INTERRUPT_RSR_REG 0x3c | ||
151 | /* Card Control Registers : Power up RSR */ | ||
152 | #define POWER_UP_RSR (0x1U << 4) | ||
153 | /* Card Control Registers : Power down RSR */ | ||
154 | #define POWER_DOWN_RSR (0x1U << 3) | ||
155 | |||
156 | /* Card Control Registers : Miscellaneous Configuration Register */ | ||
157 | #define CARD_MISC_CFG_REG 0x6C | ||
158 | |||
159 | /* Host F1 read base 0 */ | ||
160 | #define HOST_F1_RD_BASE_0 0x0040 | ||
161 | /* Host F1 read base 1 */ | ||
162 | #define HOST_F1_RD_BASE_1 0x0041 | ||
163 | /* Host F1 card ready */ | ||
164 | #define HOST_F1_CARD_RDY 0x0020 | ||
165 | |||
166 | /* Firmware status 0 register */ | ||
167 | #define CARD_FW_STATUS0_REG 0x60 | ||
168 | /* Firmware status 1 register */ | ||
169 | #define CARD_FW_STATUS1_REG 0x61 | ||
170 | /* Rx length register */ | ||
171 | #define CARD_RX_LEN_REG 0x62 | ||
172 | /* Rx unit register */ | ||
173 | #define CARD_RX_UNIT_REG 0x63 | ||
174 | |||
175 | /* Max retry number of CMD53 write */ | 116 | /* Max retry number of CMD53 write */ |
176 | #define MAX_WRITE_IOMEM_RETRY 2 | 117 | #define MAX_WRITE_IOMEM_RETRY 2 |
177 | 118 | ||
@@ -192,7 +133,8 @@ | |||
192 | if (a->mpa_tx.start_port <= port) \ | 133 | if (a->mpa_tx.start_port <= port) \ |
193 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ | 134 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \ |
194 | else \ | 135 | else \ |
195 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \ | 136 | a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+ \ |
137 | (a->max_ports - \ | ||
196 | a->mp_end_port))); \ | 138 | a->mp_end_port))); \ |
197 | a->mpa_tx.pkt_cnt++; \ | 139 | a->mpa_tx.pkt_cnt++; \ |
198 | } while (0) | 140 | } while (0) |
@@ -201,12 +143,6 @@ | |||
201 | #define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ | 143 | #define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \ |
202 | (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) | 144 | (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit) |
203 | 145 | ||
204 | /* SDIO Tx aggregation port limit ? */ | ||
205 | #define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \ | ||
206 | a->mpa_tx.start_port) && (((MAX_PORT - \ | ||
207 | a->mpa_tx.start_port) + a->curr_wr_port) >= \ | ||
208 | SDIO_MP_AGGR_DEF_PKT_LIMIT)) | ||
209 | |||
210 | /* Reset SDIO Tx aggregation buffer parameters */ | 146 | /* Reset SDIO Tx aggregation buffer parameters */ |
211 | #define MP_TX_AGGR_BUF_RESET(a) do { \ | 147 | #define MP_TX_AGGR_BUF_RESET(a) do { \ |
212 | a->mpa_tx.pkt_cnt = 0; \ | 148 | a->mpa_tx.pkt_cnt = 0; \ |
@@ -219,12 +155,6 @@ | |||
219 | #define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ | 155 | #define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \ |
220 | (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) | 156 | (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit) |
221 | 157 | ||
222 | /* SDIO Tx aggregation port limit ? */ | ||
223 | #define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \ | ||
224 | a->mpa_rx.start_port) && (((MAX_PORT - \ | ||
225 | a->mpa_rx.start_port) + a->curr_rd_port) >= \ | ||
226 | SDIO_MP_AGGR_DEF_PKT_LIMIT)) | ||
227 | |||
228 | /* SDIO Rx aggregation in progress ? */ | 158 | /* SDIO Rx aggregation in progress ? */ |
229 | #define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) | 159 | #define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0) |
230 | 160 | ||
@@ -232,20 +162,6 @@ | |||
232 | #define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ | 162 | #define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \ |
233 | ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) | 163 | ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size) |
234 | 164 | ||
235 | /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ | ||
236 | #define MP_RX_AGGR_SETUP(a, skb, port) do { \ | ||
237 | a->mpa_rx.buf_len += skb->len; \ | ||
238 | if (!a->mpa_rx.pkt_cnt) \ | ||
239 | a->mpa_rx.start_port = port; \ | ||
240 | if (a->mpa_rx.start_port <= port) \ | ||
241 | a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \ | ||
242 | else \ | ||
243 | a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \ | ||
244 | a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \ | ||
245 | a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \ | ||
246 | a->mpa_rx.pkt_cnt++; \ | ||
247 | } while (0) | ||
248 | |||
249 | /* Reset SDIO Rx aggregation buffer parameters */ | 165 | /* Reset SDIO Rx aggregation buffer parameters */ |
250 | #define MP_RX_AGGR_BUF_RESET(a) do { \ | 166 | #define MP_RX_AGGR_BUF_RESET(a) do { \ |
251 | a->mpa_rx.pkt_cnt = 0; \ | 167 | a->mpa_rx.pkt_cnt = 0; \ |
@@ -254,14 +170,13 @@ | |||
254 | a->mpa_rx.start_port = 0; \ | 170 | a->mpa_rx.start_port = 0; \ |
255 | } while (0) | 171 | } while (0) |
256 | 172 | ||
257 | |||
258 | /* data structure for SDIO MPA TX */ | 173 | /* data structure for SDIO MPA TX */ |
259 | struct mwifiex_sdio_mpa_tx { | 174 | struct mwifiex_sdio_mpa_tx { |
260 | /* multiport tx aggregation buffer pointer */ | 175 | /* multiport tx aggregation buffer pointer */ |
261 | u8 *buf; | 176 | u8 *buf; |
262 | u32 buf_len; | 177 | u32 buf_len; |
263 | u32 pkt_cnt; | 178 | u32 pkt_cnt; |
264 | u16 ports; | 179 | u32 ports; |
265 | u16 start_port; | 180 | u16 start_port; |
266 | u8 enabled; | 181 | u8 enabled; |
267 | u32 buf_size; | 182 | u32 buf_size; |
@@ -272,11 +187,11 @@ struct mwifiex_sdio_mpa_rx { | |||
272 | u8 *buf; | 187 | u8 *buf; |
273 | u32 buf_len; | 188 | u32 buf_len; |
274 | u32 pkt_cnt; | 189 | u32 pkt_cnt; |
275 | u16 ports; | 190 | u32 ports; |
276 | u16 start_port; | 191 | u16 start_port; |
277 | 192 | ||
278 | struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; | 193 | struct sk_buff **skb_arr; |
279 | u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT]; | 194 | u32 *len_arr; |
280 | 195 | ||
281 | u8 enabled; | 196 | u8 enabled; |
282 | u32 buf_size; | 197 | u32 buf_size; |
@@ -286,15 +201,47 @@ struct mwifiex_sdio_mpa_rx { | |||
286 | int mwifiex_bus_register(void); | 201 | int mwifiex_bus_register(void); |
287 | void mwifiex_bus_unregister(void); | 202 | void mwifiex_bus_unregister(void); |
288 | 203 | ||
204 | struct mwifiex_sdio_card_reg { | ||
205 | u8 start_rd_port; | ||
206 | u8 start_wr_port; | ||
207 | u8 base_0_reg; | ||
208 | u8 base_1_reg; | ||
209 | u8 poll_reg; | ||
210 | u8 host_int_enable; | ||
211 | u8 status_reg_0; | ||
212 | u8 status_reg_1; | ||
213 | u8 sdio_int_mask; | ||
214 | u32 data_port_mask; | ||
215 | u8 max_mp_regs; | ||
216 | u8 rd_bitmap_l; | ||
217 | u8 rd_bitmap_u; | ||
218 | u8 rd_bitmap_1l; | ||
219 | u8 rd_bitmap_1u; | ||
220 | u8 wr_bitmap_l; | ||
221 | u8 wr_bitmap_u; | ||
222 | u8 wr_bitmap_1l; | ||
223 | u8 wr_bitmap_1u; | ||
224 | u8 rd_len_p0_l; | ||
225 | u8 rd_len_p0_u; | ||
226 | u8 card_misc_cfg_reg; | ||
227 | }; | ||
228 | |||
289 | struct sdio_mmc_card { | 229 | struct sdio_mmc_card { |
290 | struct sdio_func *func; | 230 | struct sdio_func *func; |
291 | struct mwifiex_adapter *adapter; | 231 | struct mwifiex_adapter *adapter; |
292 | 232 | ||
293 | u16 mp_rd_bitmap; | 233 | const char *firmware; |
294 | u16 mp_wr_bitmap; | 234 | const struct mwifiex_sdio_card_reg *reg; |
235 | u8 max_ports; | ||
236 | u8 mp_agg_pkt_limit; | ||
237 | bool supports_sdio_new_mode; | ||
238 | bool has_control_mask; | ||
239 | |||
240 | u32 mp_rd_bitmap; | ||
241 | u32 mp_wr_bitmap; | ||
295 | 242 | ||
296 | u16 mp_end_port; | 243 | u16 mp_end_port; |
297 | u16 mp_data_port_mask; | 244 | u32 mp_data_port_mask; |
298 | 245 | ||
299 | u8 curr_rd_port; | 246 | u8 curr_rd_port; |
300 | u8 curr_wr_port; | 247 | u8 curr_wr_port; |
@@ -305,6 +252,98 @@ struct sdio_mmc_card { | |||
305 | struct mwifiex_sdio_mpa_rx mpa_rx; | 252 | struct mwifiex_sdio_mpa_rx mpa_rx; |
306 | }; | 253 | }; |
307 | 254 | ||
255 | struct mwifiex_sdio_device { | ||
256 | const char *firmware; | ||
257 | const struct mwifiex_sdio_card_reg *reg; | ||
258 | u8 max_ports; | ||
259 | u8 mp_agg_pkt_limit; | ||
260 | bool supports_sdio_new_mode; | ||
261 | bool has_control_mask; | ||
262 | }; | ||
263 | |||
264 | static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = { | ||
265 | .start_rd_port = 1, | ||
266 | .start_wr_port = 1, | ||
267 | .base_0_reg = 0x0040, | ||
268 | .base_1_reg = 0x0041, | ||
269 | .poll_reg = 0x30, | ||
270 | .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK, | ||
271 | .status_reg_0 = 0x60, | ||
272 | .status_reg_1 = 0x61, | ||
273 | .sdio_int_mask = 0x3f, | ||
274 | .data_port_mask = 0x0000fffe, | ||
275 | .max_mp_regs = 64, | ||
276 | .rd_bitmap_l = 0x04, | ||
277 | .rd_bitmap_u = 0x05, | ||
278 | .wr_bitmap_l = 0x06, | ||
279 | .wr_bitmap_u = 0x07, | ||
280 | .rd_len_p0_l = 0x08, | ||
281 | .rd_len_p0_u = 0x09, | ||
282 | .card_misc_cfg_reg = 0x6c, | ||
283 | }; | ||
284 | |||
285 | static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = { | ||
286 | .start_rd_port = 0, | ||
287 | .start_wr_port = 0, | ||
288 | .base_0_reg = 0x60, | ||
289 | .base_1_reg = 0x61, | ||
290 | .poll_reg = 0x50, | ||
291 | .host_int_enable = UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK | | ||
292 | CMD_PORT_UPLD_INT_MASK | CMD_PORT_DNLD_INT_MASK, | ||
293 | .status_reg_0 = 0xc0, | ||
294 | .status_reg_1 = 0xc1, | ||
295 | .sdio_int_mask = 0xff, | ||
296 | .data_port_mask = 0xffffffff, | ||
297 | .max_mp_regs = 184, | ||
298 | .rd_bitmap_l = 0x04, | ||
299 | .rd_bitmap_u = 0x05, | ||
300 | .rd_bitmap_1l = 0x06, | ||
301 | .rd_bitmap_1u = 0x07, | ||
302 | .wr_bitmap_l = 0x08, | ||
303 | .wr_bitmap_u = 0x09, | ||
304 | .wr_bitmap_1l = 0x0a, | ||
305 | .wr_bitmap_1u = 0x0b, | ||
306 | .rd_len_p0_l = 0x0c, | ||
307 | .rd_len_p0_u = 0x0d, | ||
308 | .card_misc_cfg_reg = 0xcc, | ||
309 | }; | ||
310 | |||
311 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { | ||
312 | .firmware = SD8786_DEFAULT_FW_NAME, | ||
313 | .reg = &mwifiex_reg_sd87xx, | ||
314 | .max_ports = 16, | ||
315 | .mp_agg_pkt_limit = 8, | ||
316 | .supports_sdio_new_mode = false, | ||
317 | .has_control_mask = true, | ||
318 | }; | ||
319 | |||
320 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { | ||
321 | .firmware = SD8787_DEFAULT_FW_NAME, | ||
322 | .reg = &mwifiex_reg_sd87xx, | ||
323 | .max_ports = 16, | ||
324 | .mp_agg_pkt_limit = 8, | ||
325 | .supports_sdio_new_mode = false, | ||
326 | .has_control_mask = true, | ||
327 | }; | ||
328 | |||
329 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { | ||
330 | .firmware = SD8797_DEFAULT_FW_NAME, | ||
331 | .reg = &mwifiex_reg_sd87xx, | ||
332 | .max_ports = 16, | ||
333 | .mp_agg_pkt_limit = 8, | ||
334 | .supports_sdio_new_mode = false, | ||
335 | .has_control_mask = true, | ||
336 | }; | ||
337 | |||
338 | static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { | ||
339 | .firmware = SD8897_DEFAULT_FW_NAME, | ||
340 | .reg = &mwifiex_reg_sd8897, | ||
341 | .max_ports = 32, | ||
342 | .mp_agg_pkt_limit = 16, | ||
343 | .supports_sdio_new_mode = true, | ||
344 | .has_control_mask = false, | ||
345 | }; | ||
346 | |||
308 | /* | 347 | /* |
309 | * .cmdrsp_complete handler | 348 | * .cmdrsp_complete handler |
310 | */ | 349 | */ |
@@ -325,4 +364,77 @@ static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter, | |||
325 | return 0; | 364 | return 0; |
326 | } | 365 | } |
327 | 366 | ||
367 | static inline bool | ||
368 | mp_rx_aggr_port_limit_reached(struct sdio_mmc_card *card) | ||
369 | { | ||
370 | u8 tmp; | ||
371 | |||
372 | if (card->curr_rd_port < card->mpa_rx.start_port) { | ||
373 | if (card->supports_sdio_new_mode) | ||
374 | tmp = card->mp_end_port >> 1; | ||
375 | else | ||
376 | tmp = card->mp_agg_pkt_limit; | ||
377 | |||
378 | if (((card->max_ports - card->mpa_rx.start_port) + | ||
379 | card->curr_rd_port) >= tmp) | ||
380 | return true; | ||
381 | } | ||
382 | |||
383 | if (!card->supports_sdio_new_mode) | ||
384 | return false; | ||
385 | |||
386 | if ((card->curr_rd_port - card->mpa_rx.start_port) >= | ||
387 | (card->mp_end_port >> 1)) | ||
388 | return true; | ||
389 | |||
390 | return false; | ||
391 | } | ||
392 | |||
393 | static inline bool | ||
394 | mp_tx_aggr_port_limit_reached(struct sdio_mmc_card *card) | ||
395 | { | ||
396 | u16 tmp; | ||
397 | |||
398 | if (card->curr_wr_port < card->mpa_tx.start_port) { | ||
399 | if (card->supports_sdio_new_mode) | ||
400 | tmp = card->mp_end_port >> 1; | ||
401 | else | ||
402 | tmp = card->mp_agg_pkt_limit; | ||
403 | |||
404 | if (((card->max_ports - card->mpa_tx.start_port) + | ||
405 | card->curr_wr_port) >= tmp) | ||
406 | return true; | ||
407 | } | ||
408 | |||
409 | if (!card->supports_sdio_new_mode) | ||
410 | return false; | ||
411 | |||
412 | if ((card->curr_wr_port - card->mpa_tx.start_port) >= | ||
413 | (card->mp_end_port >> 1)) | ||
414 | return true; | ||
415 | |||
416 | return false; | ||
417 | } | ||
418 | |||
419 | /* Prepare to copy current packet from card to SDIO Rx aggregation buffer */ | ||
420 | static inline void mp_rx_aggr_setup(struct sdio_mmc_card *card, | ||
421 | struct sk_buff *skb, u8 port) | ||
422 | { | ||
423 | card->mpa_rx.buf_len += skb->len; | ||
424 | |||
425 | if (!card->mpa_rx.pkt_cnt) | ||
426 | card->mpa_rx.start_port = port; | ||
427 | |||
428 | if (card->supports_sdio_new_mode) { | ||
429 | card->mpa_rx.ports |= (1 << port); | ||
430 | } else { | ||
431 | if (card->mpa_rx.start_port <= port) | ||
432 | card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt); | ||
433 | else | ||
434 | card->mpa_rx.ports |= 1 << (card->mpa_rx.pkt_cnt + 1); | ||
435 | } | ||
436 | card->mpa_rx.skb_arr[card->mpa_rx.pkt_cnt] = skb; | ||
437 | card->mpa_rx.len_arr[card->mpa_rx.pkt_cnt] = skb->len; | ||
438 | card->mpa_rx.pkt_cnt++; | ||
439 | } | ||
328 | #endif /* _MWIFIEX_SDIO_H */ | 440 | #endif /* _MWIFIEX_SDIO_H */ |
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index b193e25977d2..8ece48580642 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c | |||
@@ -1134,6 +1134,55 @@ mwifiex_cmd_mef_cfg(struct mwifiex_private *priv, | |||
1134 | return 0; | 1134 | return 0; |
1135 | } | 1135 | } |
1136 | 1136 | ||
1137 | /* This function parse cal data from ASCII to hex */ | ||
1138 | static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst) | ||
1139 | { | ||
1140 | u8 *s = src, *d = dst; | ||
1141 | |||
1142 | while (s - src < len) { | ||
1143 | if (*s && (isspace(*s) || *s == '\t')) { | ||
1144 | s++; | ||
1145 | continue; | ||
1146 | } | ||
1147 | if (isxdigit(*s)) { | ||
1148 | *d++ = simple_strtol(s, NULL, 16); | ||
1149 | s += 2; | ||
1150 | } else { | ||
1151 | s++; | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | return d - dst; | ||
1156 | } | ||
1157 | |||
1158 | /* This function prepares command of set_cfg_data. */ | ||
1159 | static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, | ||
1160 | struct host_cmd_ds_command *cmd, | ||
1161 | u16 cmd_action) | ||
1162 | { | ||
1163 | struct host_cmd_ds_802_11_cfg_data *cfg_data = &cmd->params.cfg_data; | ||
1164 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1165 | u32 len, cal_data_offset; | ||
1166 | u8 *tmp_cmd = (u8 *)cmd; | ||
1167 | |||
1168 | cal_data_offset = S_DS_GEN + sizeof(*cfg_data); | ||
1169 | if ((adapter->cal_data->data) && (adapter->cal_data->size > 0)) | ||
1170 | len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data, | ||
1171 | adapter->cal_data->size, | ||
1172 | (u8 *)(tmp_cmd + cal_data_offset)); | ||
1173 | else | ||
1174 | return -1; | ||
1175 | |||
1176 | cfg_data->action = cpu_to_le16(cmd_action); | ||
1177 | cfg_data->type = cpu_to_le16(CFG_DATA_TYPE_CAL); | ||
1178 | cfg_data->data_len = cpu_to_le16(len); | ||
1179 | |||
1180 | cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA); | ||
1181 | cmd->size = cpu_to_le16(S_DS_GEN + sizeof(*cfg_data) + len); | ||
1182 | |||
1183 | return 0; | ||
1184 | } | ||
1185 | |||
1137 | /* | 1186 | /* |
1138 | * This function prepares the commands before sending them to the firmware. | 1187 | * This function prepares the commands before sending them to the firmware. |
1139 | * | 1188 | * |
@@ -1152,6 +1201,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | |||
1152 | case HostCmd_CMD_GET_HW_SPEC: | 1201 | case HostCmd_CMD_GET_HW_SPEC: |
1153 | ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); | 1202 | ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); |
1154 | break; | 1203 | break; |
1204 | case HostCmd_CMD_CFG_DATA: | ||
1205 | ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, cmd_action); | ||
1206 | break; | ||
1155 | case HostCmd_CMD_MAC_CONTROL: | 1207 | case HostCmd_CMD_MAC_CONTROL: |
1156 | ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, | 1208 | ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, |
1157 | data_buf); | 1209 | data_buf); |
@@ -1384,6 +1436,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, | |||
1384 | */ | 1436 | */ |
1385 | int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) | 1437 | int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) |
1386 | { | 1438 | { |
1439 | struct mwifiex_adapter *adapter = priv->adapter; | ||
1387 | int ret; | 1440 | int ret; |
1388 | u16 enable = true; | 1441 | u16 enable = true; |
1389 | struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; | 1442 | struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; |
@@ -1404,6 +1457,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) | |||
1404 | HostCmd_ACT_GEN_SET, 0, NULL); | 1457 | HostCmd_ACT_GEN_SET, 0, NULL); |
1405 | if (ret) | 1458 | if (ret) |
1406 | return -1; | 1459 | return -1; |
1460 | |||
1461 | /* Download calibration data to firmware */ | ||
1462 | if (adapter->cal_data) { | ||
1463 | ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA, | ||
1464 | HostCmd_ACT_GEN_SET, 0, NULL); | ||
1465 | if (ret) | ||
1466 | return -1; | ||
1467 | } | ||
1468 | |||
1407 | /* Read MAC address from HW */ | 1469 | /* Read MAC address from HW */ |
1408 | ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC, | 1470 | ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_GET_HW_SPEC, |
1409 | HostCmd_ACT_GEN_GET, 0, NULL); | 1471 | HostCmd_ACT_GEN_GET, 0, NULL); |
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 9f990e14966e..d85df158cc6c 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c | |||
@@ -818,6 +818,18 @@ static int mwifiex_ret_subsc_evt(struct mwifiex_private *priv, | |||
818 | return 0; | 818 | return 0; |
819 | } | 819 | } |
820 | 820 | ||
821 | /* This function handles the command response of set_cfg_data */ | ||
822 | static int mwifiex_ret_cfg_data(struct mwifiex_private *priv, | ||
823 | struct host_cmd_ds_command *resp) | ||
824 | { | ||
825 | if (resp->result != HostCmd_RESULT_OK) { | ||
826 | dev_err(priv->adapter->dev, "Cal data cmd resp failed\n"); | ||
827 | return -1; | ||
828 | } | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
821 | /* | 833 | /* |
822 | * This function handles the command responses. | 834 | * This function handles the command responses. |
823 | * | 835 | * |
@@ -841,6 +853,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, | |||
841 | case HostCmd_CMD_GET_HW_SPEC: | 853 | case HostCmd_CMD_GET_HW_SPEC: |
842 | ret = mwifiex_ret_get_hw_spec(priv, resp); | 854 | ret = mwifiex_ret_get_hw_spec(priv, resp); |
843 | break; | 855 | break; |
856 | case HostCmd_CMD_CFG_DATA: | ||
857 | ret = mwifiex_ret_cfg_data(priv, resp); | ||
858 | break; | ||
844 | case HostCmd_CMD_MAC_CONTROL: | 859 | case HostCmd_CMD_MAC_CONTROL: |
845 | break; | 860 | break; |
846 | case HostCmd_CMD_802_11_MAC_ADDRESS: | 861 | case HostCmd_CMD_802_11_MAC_ADDRESS: |
@@ -978,6 +993,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, | |||
978 | case HostCmd_CMD_UAP_BSS_STOP: | 993 | case HostCmd_CMD_UAP_BSS_STOP: |
979 | priv->bss_started = 0; | 994 | priv->bss_started = 0; |
980 | break; | 995 | break; |
996 | case HostCmd_CMD_UAP_STA_DEAUTH: | ||
997 | break; | ||
981 | case HostCmd_CMD_MEF_CFG: | 998 | case HostCmd_CMD_MEF_CFG: |
982 | break; | 999 | break; |
983 | default: | 1000 | default: |
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index b04b1db29100..2de882dead0f 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c | |||
@@ -689,6 +689,23 @@ mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, | |||
689 | return 0; | 689 | return 0; |
690 | } | 690 | } |
691 | 691 | ||
692 | /* This function prepares AP specific deauth command with mac supplied in | ||
693 | * function parameter. | ||
694 | */ | ||
695 | static int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv, | ||
696 | struct host_cmd_ds_command *cmd, u8 *mac) | ||
697 | { | ||
698 | struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth; | ||
699 | |||
700 | cmd->command = cpu_to_le16(HostCmd_CMD_UAP_STA_DEAUTH); | ||
701 | memcpy(sta_deauth->mac, mac, ETH_ALEN); | ||
702 | sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); | ||
703 | |||
704 | cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) + | ||
705 | S_DS_GEN); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
692 | /* This function prepares the AP specific commands before sending them | 709 | /* This function prepares the AP specific commands before sending them |
693 | * to the firmware. | 710 | * to the firmware. |
694 | * This is a generic function which calls specific command preparation | 711 | * This is a generic function which calls specific command preparation |
@@ -710,6 +727,10 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, | |||
710 | cmd->command = cpu_to_le16(cmd_no); | 727 | cmd->command = cpu_to_le16(cmd_no); |
711 | cmd->size = cpu_to_le16(S_DS_GEN); | 728 | cmd->size = cpu_to_le16(S_DS_GEN); |
712 | break; | 729 | break; |
730 | case HostCmd_CMD_UAP_STA_DEAUTH: | ||
731 | if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf)) | ||
732 | return -1; | ||
733 | break; | ||
713 | default: | 734 | default: |
714 | dev_err(priv->adapter->dev, | 735 | dev_err(priv->adapter->dev, |
715 | "PREP_CMD: unknown cmd %#x\n", cmd_no); | 736 | "PREP_CMD: unknown cmd %#x\n", cmd_no); |
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 21c640d3b579..718066577c6c 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c | |||
@@ -107,18 +107,15 @@ mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies, | |||
107 | */ | 107 | */ |
108 | static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac) | 108 | static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac) |
109 | { | 109 | { |
110 | struct mwifiex_sta_node *node, *tmp; | 110 | struct mwifiex_sta_node *node; |
111 | unsigned long flags; | 111 | unsigned long flags; |
112 | 112 | ||
113 | spin_lock_irqsave(&priv->sta_list_spinlock, flags); | 113 | spin_lock_irqsave(&priv->sta_list_spinlock, flags); |
114 | 114 | ||
115 | node = mwifiex_get_sta_entry(priv, mac); | 115 | node = mwifiex_get_sta_entry(priv, mac); |
116 | if (node) { | 116 | if (node) { |
117 | list_for_each_entry_safe(node, tmp, &priv->sta_list, | 117 | list_del(&node->list); |
118 | list) { | 118 | kfree(node); |
119 | list_del(&node->list); | ||
120 | kfree(node); | ||
121 | } | ||
122 | } | 119 | } |
123 | 120 | ||
124 | spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); | 121 | spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); |
@@ -295,3 +292,19 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) | |||
295 | 292 | ||
296 | return 0; | 293 | return 0; |
297 | } | 294 | } |
295 | |||
296 | /* This function deletes station entry from associated station list. | ||
297 | * Also if both AP and STA are 11n enabled, RxReorder tables and TxBA stream | ||
298 | * tables created for this station are deleted. | ||
299 | */ | ||
300 | void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, | ||
301 | struct mwifiex_sta_node *node) | ||
302 | { | ||
303 | if (priv->ap_11n_enabled && node->is_11n_enabled) { | ||
304 | mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, node->mac_addr); | ||
305 | mwifiex_del_tx_ba_stream_tbl_by_ra(priv, node->mac_addr); | ||
306 | } | ||
307 | mwifiex_del_sta_entry(priv, node->mac_addr); | ||
308 | |||
309 | return; | ||
310 | } | ||
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 6820fce4016b..a3707fd4ef62 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -1548,7 +1548,7 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1548 | if (!priv->pending_tx_pkts) | 1548 | if (!priv->pending_tx_pkts) |
1549 | return 0; | 1549 | return 0; |
1550 | 1550 | ||
1551 | retry = 0; | 1551 | retry = 1; |
1552 | rc = 0; | 1552 | rc = 0; |
1553 | 1553 | ||
1554 | spin_lock_bh(&priv->tx_lock); | 1554 | spin_lock_bh(&priv->tx_lock); |
@@ -1572,13 +1572,19 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw) | |||
1572 | 1572 | ||
1573 | spin_lock_bh(&priv->tx_lock); | 1573 | spin_lock_bh(&priv->tx_lock); |
1574 | 1574 | ||
1575 | if (timeout) { | 1575 | if (timeout || !priv->pending_tx_pkts) { |
1576 | WARN_ON(priv->pending_tx_pkts); | 1576 | WARN_ON(priv->pending_tx_pkts); |
1577 | if (retry) | 1577 | if (retry) |
1578 | wiphy_notice(hw->wiphy, "tx rings drained\n"); | 1578 | wiphy_notice(hw->wiphy, "tx rings drained\n"); |
1579 | break; | 1579 | break; |
1580 | } | 1580 | } |
1581 | 1581 | ||
1582 | if (retry) { | ||
1583 | mwl8k_tx_start(priv); | ||
1584 | retry = 0; | ||
1585 | continue; | ||
1586 | } | ||
1587 | |||
1582 | if (priv->pending_tx_pkts < oldcount) { | 1588 | if (priv->pending_tx_pkts < oldcount) { |
1583 | wiphy_notice(hw->wiphy, | 1589 | wiphy_notice(hw->wiphy, |
1584 | "waiting for tx rings to drain (%d -> %d pkts)\n", | 1590 | "waiting for tx rings to drain (%d -> %d pkts)\n", |
@@ -2055,6 +2061,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, | |||
2055 | mwl8k_remove_stream(hw, stream); | 2061 | mwl8k_remove_stream(hw, stream); |
2056 | spin_unlock(&priv->stream_lock); | 2062 | spin_unlock(&priv->stream_lock); |
2057 | } | 2063 | } |
2064 | mwl8k_tx_start(priv); | ||
2058 | spin_unlock_bh(&priv->tx_lock); | 2065 | spin_unlock_bh(&priv->tx_lock); |
2059 | pci_unmap_single(priv->pdev, dma, skb->len, | 2066 | pci_unmap_single(priv->pdev, dma, skb->len, |
2060 | PCI_DMA_TODEVICE); | 2067 | PCI_DMA_TODEVICE); |
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 978e7eb26567..7fc46f26cf2b 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c | |||
@@ -42,8 +42,7 @@ | |||
42 | 42 | ||
43 | MODULE_FIRMWARE("3826.arm"); | 43 | MODULE_FIRMWARE("3826.arm"); |
44 | 44 | ||
45 | /* | 45 | /* gpios should be handled in board files and provided via platform data, |
46 | * gpios should be handled in board files and provided via platform data, | ||
47 | * but because it's currently impossible for p54spi to have a header file | 46 | * but because it's currently impossible for p54spi to have a header file |
48 | * in include/linux, let's use module paramaters for now | 47 | * in include/linux, let's use module paramaters for now |
49 | */ | 48 | */ |
@@ -191,8 +190,7 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) | |||
191 | const struct firmware *eeprom; | 190 | const struct firmware *eeprom; |
192 | int ret; | 191 | int ret; |
193 | 192 | ||
194 | /* | 193 | /* allow users to customize their eeprom. |
195 | * allow users to customize their eeprom. | ||
196 | */ | 194 | */ |
197 | 195 | ||
198 | ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev); | 196 | ret = request_firmware(&eeprom, "3826.eeprom", &priv->spi->dev); |
@@ -285,8 +283,7 @@ static void p54spi_power_on(struct p54s_priv *priv) | |||
285 | gpio_set_value(p54spi_gpio_power, 1); | 283 | gpio_set_value(p54spi_gpio_power, 1); |
286 | enable_irq(gpio_to_irq(p54spi_gpio_irq)); | 284 | enable_irq(gpio_to_irq(p54spi_gpio_irq)); |
287 | 285 | ||
288 | /* | 286 | /* need to wait a while before device can be accessed, the length |
289 | * need to wait a while before device can be accessed, the length | ||
290 | * is just a guess | 287 | * is just a guess |
291 | */ | 288 | */ |
292 | msleep(10); | 289 | msleep(10); |
@@ -365,7 +362,8 @@ static int p54spi_rx(struct p54s_priv *priv) | |||
365 | /* Firmware may insert up to 4 padding bytes after the lmac header, | 362 | /* Firmware may insert up to 4 padding bytes after the lmac header, |
366 | * but it does not amend the size of SPI data transfer. | 363 | * but it does not amend the size of SPI data transfer. |
367 | * Such packets has correct data size in header, thus referencing | 364 | * Such packets has correct data size in header, thus referencing |
368 | * past the end of allocated skb. Reserve extra 4 bytes for this case */ | 365 | * past the end of allocated skb. Reserve extra 4 bytes for this case |
366 | */ | ||
369 | skb = dev_alloc_skb(len + 4); | 367 | skb = dev_alloc_skb(len + 4); |
370 | if (!skb) { | 368 | if (!skb) { |
371 | p54spi_sleep(priv); | 369 | p54spi_sleep(priv); |
@@ -383,7 +381,8 @@ static int p54spi_rx(struct p54s_priv *priv) | |||
383 | } | 381 | } |
384 | p54spi_sleep(priv); | 382 | p54spi_sleep(priv); |
385 | /* Put additional bytes to compensate for the possible | 383 | /* Put additional bytes to compensate for the possible |
386 | * alignment-caused truncation */ | 384 | * alignment-caused truncation |
385 | */ | ||
387 | skb_put(skb, 4); | 386 | skb_put(skb, 4); |
388 | 387 | ||
389 | if (p54_rx(priv->hw, skb) == 0) | 388 | if (p54_rx(priv->hw, skb) == 0) |
@@ -713,27 +712,7 @@ static struct spi_driver p54spi_driver = { | |||
713 | .remove = p54spi_remove, | 712 | .remove = p54spi_remove, |
714 | }; | 713 | }; |
715 | 714 | ||
716 | static int __init p54spi_init(void) | 715 | module_spi_driver(p54spi_driver); |
717 | { | ||
718 | int ret; | ||
719 | |||
720 | ret = spi_register_driver(&p54spi_driver); | ||
721 | if (ret < 0) { | ||
722 | printk(KERN_ERR "failed to register SPI driver: %d", ret); | ||
723 | goto out; | ||
724 | } | ||
725 | |||
726 | out: | ||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | static void __exit p54spi_exit(void) | ||
731 | { | ||
732 | spi_unregister_driver(&p54spi_driver); | ||
733 | } | ||
734 | |||
735 | module_init(p54spi_init); | ||
736 | module_exit(p54spi_exit); | ||
737 | 716 | ||
738 | MODULE_LICENSE("GPL"); | 717 | MODULE_LICENSE("GPL"); |
739 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); | 718 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); |
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b52d70c75e1a..ead3a3e746a2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c | |||
@@ -840,7 +840,7 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev, | |||
840 | unsigned int beacon_base) | 840 | unsigned int beacon_base) |
841 | { | 841 | { |
842 | int i; | 842 | int i; |
843 | const int txwi_desc_size = rt2x00dev->ops->bcn->winfo_size; | 843 | const int txwi_desc_size = rt2x00dev->bcn->winfo_size; |
844 | 844 | ||
845 | /* | 845 | /* |
846 | * For the Beacon base registers we only need to clear | 846 | * For the Beacon base registers we only need to clear |
@@ -3953,379 +3953,577 @@ static void rt2800_init_bbp_early(struct rt2x00_dev *rt2x00dev) | |||
3953 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | 3953 | rt2800_bbp_write(rt2x00dev, 106, 0x35); |
3954 | } | 3954 | } |
3955 | 3955 | ||
3956 | static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) | 3956 | static void rt2800_disable_unused_dac_adc(struct rt2x00_dev *rt2x00dev) |
3957 | { | 3957 | { |
3958 | int ant, div_mode; | ||
3959 | u16 eeprom; | 3958 | u16 eeprom; |
3960 | u8 value; | 3959 | u8 value; |
3961 | 3960 | ||
3962 | rt2800_init_bbp_early(rt2x00dev); | 3961 | rt2800_bbp_read(rt2x00dev, 138, &value); |
3962 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); | ||
3963 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) | ||
3964 | value |= 0x20; | ||
3965 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) | ||
3966 | value &= ~0x02; | ||
3967 | rt2800_bbp_write(rt2x00dev, 138, value); | ||
3968 | } | ||
3963 | 3969 | ||
3964 | rt2800_bbp_read(rt2x00dev, 105, &value); | 3970 | static void rt2800_init_bbp_305x_soc(struct rt2x00_dev *rt2x00dev) |
3965 | rt2x00_set_field8(&value, BBP105_MLD, | 3971 | { |
3966 | rt2x00dev->default_ant.rx_chain_num == 2); | 3972 | rt2800_bbp_write(rt2x00dev, 31, 0x08); |
3967 | rt2800_bbp_write(rt2x00dev, 105, value); | 3973 | |
3974 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | ||
3975 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | ||
3976 | |||
3977 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
3978 | rt2800_bbp_write(rt2x00dev, 73, 0x10); | ||
3979 | |||
3980 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
3981 | |||
3982 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | ||
3983 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | ||
3984 | |||
3985 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
3986 | |||
3987 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
3988 | |||
3989 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
3990 | |||
3991 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
3992 | |||
3993 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
3994 | |||
3995 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
3996 | |||
3997 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | ||
3998 | |||
3999 | rt2800_bbp_write(rt2x00dev, 105, 0x01); | ||
4000 | |||
4001 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4002 | } | ||
4003 | |||
4004 | static void rt2800_init_bbp_28xx(struct rt2x00_dev *rt2x00dev) | ||
4005 | { | ||
4006 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | ||
4007 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | ||
4008 | |||
4009 | if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) { | ||
4010 | rt2800_bbp_write(rt2x00dev, 69, 0x16); | ||
4011 | rt2800_bbp_write(rt2x00dev, 73, 0x12); | ||
4012 | } else { | ||
4013 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
4014 | rt2800_bbp_write(rt2x00dev, 73, 0x10); | ||
4015 | } | ||
4016 | |||
4017 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
4018 | |||
4019 | rt2800_bbp_write(rt2x00dev, 81, 0x37); | ||
4020 | |||
4021 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
4022 | |||
4023 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
4024 | |||
4025 | if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D)) | ||
4026 | rt2800_bbp_write(rt2x00dev, 84, 0x19); | ||
4027 | else | ||
4028 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4029 | |||
4030 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
4031 | |||
4032 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4033 | |||
4034 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
4035 | |||
4036 | rt2800_bbp_write(rt2x00dev, 103, 0x00); | ||
4037 | |||
4038 | rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||
4039 | |||
4040 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4041 | } | ||
4042 | |||
4043 | static void rt2800_init_bbp_30xx(struct rt2x00_dev *rt2x00dev) | ||
4044 | { | ||
4045 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | ||
4046 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | ||
4047 | |||
4048 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
4049 | rt2800_bbp_write(rt2x00dev, 73, 0x10); | ||
4050 | |||
4051 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
4052 | |||
4053 | rt2800_bbp_write(rt2x00dev, 79, 0x13); | ||
4054 | rt2800_bbp_write(rt2x00dev, 80, 0x05); | ||
4055 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
4056 | |||
4057 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
4058 | |||
4059 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
4060 | |||
4061 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4062 | |||
4063 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
4064 | |||
4065 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4066 | |||
4067 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
4068 | |||
4069 | if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) || | ||
4070 | rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) || | ||
4071 | rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E)) | ||
4072 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | ||
4073 | else | ||
4074 | rt2800_bbp_write(rt2x00dev, 103, 0x00); | ||
4075 | |||
4076 | rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||
4077 | |||
4078 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4079 | |||
4080 | if (rt2x00_rt(rt2x00dev, RT3071) || | ||
4081 | rt2x00_rt(rt2x00dev, RT3090)) | ||
4082 | rt2800_disable_unused_dac_adc(rt2x00dev); | ||
4083 | } | ||
4084 | |||
4085 | static void rt2800_init_bbp_3290(struct rt2x00_dev *rt2x00dev) | ||
4086 | { | ||
4087 | u8 value; | ||
3968 | 4088 | ||
3969 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | 4089 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); |
3970 | 4090 | ||
3971 | rt2800_bbp_write(rt2x00dev, 20, 0x06); | ||
3972 | rt2800_bbp_write(rt2x00dev, 31, 0x08); | 4091 | rt2800_bbp_write(rt2x00dev, 31, 0x08); |
3973 | rt2800_bbp_write(rt2x00dev, 65, 0x2C); | 4092 | |
3974 | rt2800_bbp_write(rt2x00dev, 68, 0xDD); | 4093 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); |
3975 | rt2800_bbp_write(rt2x00dev, 69, 0x1A); | 4094 | rt2800_bbp_write(rt2x00dev, 66, 0x38); |
3976 | rt2800_bbp_write(rt2x00dev, 70, 0x05); | 4095 | |
4096 | rt2800_bbp_write(rt2x00dev, 68, 0x0b); | ||
4097 | |||
4098 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
3977 | rt2800_bbp_write(rt2x00dev, 73, 0x13); | 4099 | rt2800_bbp_write(rt2x00dev, 73, 0x13); |
3978 | rt2800_bbp_write(rt2x00dev, 74, 0x0F); | 4100 | rt2800_bbp_write(rt2x00dev, 75, 0x46); |
3979 | rt2800_bbp_write(rt2x00dev, 75, 0x4F); | ||
3980 | rt2800_bbp_write(rt2x00dev, 76, 0x28); | 4101 | rt2800_bbp_write(rt2x00dev, 76, 0x28); |
4102 | |||
4103 | rt2800_bbp_write(rt2x00dev, 77, 0x58); | ||
4104 | |||
4105 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
4106 | |||
4107 | rt2800_bbp_write(rt2x00dev, 74, 0x0b); | ||
4108 | rt2800_bbp_write(rt2x00dev, 79, 0x18); | ||
4109 | rt2800_bbp_write(rt2x00dev, 80, 0x09); | ||
4110 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
4111 | |||
4112 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
4113 | |||
4114 | rt2800_bbp_write(rt2x00dev, 83, 0x7a); | ||
4115 | |||
4116 | rt2800_bbp_write(rt2x00dev, 84, 0x9a); | ||
4117 | |||
4118 | rt2800_bbp_write(rt2x00dev, 86, 0x38); | ||
4119 | |||
4120 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4121 | |||
4122 | rt2800_bbp_write(rt2x00dev, 92, 0x02); | ||
4123 | |||
4124 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | ||
4125 | |||
4126 | rt2800_bbp_write(rt2x00dev, 104, 0x92); | ||
4127 | |||
4128 | rt2800_bbp_write(rt2x00dev, 105, 0x1c); | ||
4129 | |||
4130 | rt2800_bbp_write(rt2x00dev, 106, 0x03); | ||
4131 | |||
4132 | rt2800_bbp_write(rt2x00dev, 128, 0x12); | ||
4133 | |||
4134 | rt2800_bbp_write(rt2x00dev, 67, 0x24); | ||
4135 | rt2800_bbp_write(rt2x00dev, 143, 0x04); | ||
4136 | rt2800_bbp_write(rt2x00dev, 142, 0x99); | ||
4137 | rt2800_bbp_write(rt2x00dev, 150, 0x30); | ||
4138 | rt2800_bbp_write(rt2x00dev, 151, 0x2e); | ||
4139 | rt2800_bbp_write(rt2x00dev, 152, 0x20); | ||
4140 | rt2800_bbp_write(rt2x00dev, 153, 0x34); | ||
4141 | rt2800_bbp_write(rt2x00dev, 154, 0x40); | ||
4142 | rt2800_bbp_write(rt2x00dev, 155, 0x3b); | ||
4143 | rt2800_bbp_write(rt2x00dev, 253, 0x04); | ||
4144 | |||
4145 | rt2800_bbp_read(rt2x00dev, 47, &value); | ||
4146 | rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1); | ||
4147 | rt2800_bbp_write(rt2x00dev, 47, value); | ||
4148 | |||
4149 | /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */ | ||
4150 | rt2800_bbp_read(rt2x00dev, 3, &value); | ||
4151 | rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1); | ||
4152 | rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1); | ||
4153 | rt2800_bbp_write(rt2x00dev, 3, value); | ||
4154 | } | ||
4155 | |||
4156 | static void rt2800_init_bbp_3352(struct rt2x00_dev *rt2x00dev) | ||
4157 | { | ||
4158 | rt2800_bbp_write(rt2x00dev, 3, 0x00); | ||
4159 | rt2800_bbp_write(rt2x00dev, 4, 0x50); | ||
4160 | |||
4161 | rt2800_bbp_write(rt2x00dev, 31, 0x08); | ||
4162 | |||
4163 | rt2800_bbp_write(rt2x00dev, 47, 0x48); | ||
4164 | |||
4165 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | ||
4166 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | ||
4167 | |||
4168 | rt2800_bbp_write(rt2x00dev, 68, 0x0b); | ||
4169 | |||
4170 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
4171 | rt2800_bbp_write(rt2x00dev, 73, 0x13); | ||
4172 | rt2800_bbp_write(rt2x00dev, 75, 0x46); | ||
4173 | rt2800_bbp_write(rt2x00dev, 76, 0x28); | ||
4174 | |||
3981 | rt2800_bbp_write(rt2x00dev, 77, 0x59); | 4175 | rt2800_bbp_write(rt2x00dev, 77, 0x59); |
3982 | rt2800_bbp_write(rt2x00dev, 84, 0x9A); | 4176 | |
4177 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||
4178 | |||
4179 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | ||
4180 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | ||
4181 | rt2800_bbp_write(rt2x00dev, 81, 0x37); | ||
4182 | |||
4183 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | ||
4184 | |||
4185 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
4186 | |||
4187 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4188 | |||
3983 | rt2800_bbp_write(rt2x00dev, 86, 0x38); | 4189 | rt2800_bbp_write(rt2x00dev, 86, 0x38); |
4190 | |||
3984 | rt2800_bbp_write(rt2x00dev, 88, 0x90); | 4191 | rt2800_bbp_write(rt2x00dev, 88, 0x90); |
4192 | |||
3985 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | 4193 | rt2800_bbp_write(rt2x00dev, 91, 0x04); |
4194 | |||
3986 | rt2800_bbp_write(rt2x00dev, 92, 0x02); | 4195 | rt2800_bbp_write(rt2x00dev, 92, 0x02); |
3987 | rt2800_bbp_write(rt2x00dev, 95, 0x9a); | 4196 | |
3988 | rt2800_bbp_write(rt2x00dev, 98, 0x12); | 4197 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); |
3989 | rt2800_bbp_write(rt2x00dev, 103, 0xC0); | 4198 | |
3990 | rt2800_bbp_write(rt2x00dev, 104, 0x92); | 4199 | rt2800_bbp_write(rt2x00dev, 104, 0x92); |
3991 | /* FIXME BBP105 owerwrite */ | ||
3992 | rt2800_bbp_write(rt2x00dev, 105, 0x3C); | ||
3993 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
3994 | rt2800_bbp_write(rt2x00dev, 128, 0x12); | ||
3995 | rt2800_bbp_write(rt2x00dev, 134, 0xD0); | ||
3996 | rt2800_bbp_write(rt2x00dev, 135, 0xF6); | ||
3997 | rt2800_bbp_write(rt2x00dev, 137, 0x0F); | ||
3998 | 4200 | ||
3999 | /* Initialize GLRT (Generalized Likehood Radio Test) */ | 4201 | rt2800_bbp_write(rt2x00dev, 105, 0x34); |
4000 | rt2800_init_bbp_5592_glrt(rt2x00dev); | 4202 | |
4203 | rt2800_bbp_write(rt2x00dev, 106, 0x05); | ||
4204 | |||
4205 | rt2800_bbp_write(rt2x00dev, 120, 0x50); | ||
4206 | |||
4207 | rt2800_bbp_write(rt2x00dev, 137, 0x0f); | ||
4208 | |||
4209 | rt2800_bbp_write(rt2x00dev, 163, 0xbd); | ||
4210 | /* Set ITxBF timeout to 0x9c40=1000msec */ | ||
4211 | rt2800_bbp_write(rt2x00dev, 179, 0x02); | ||
4212 | rt2800_bbp_write(rt2x00dev, 180, 0x00); | ||
4213 | rt2800_bbp_write(rt2x00dev, 182, 0x40); | ||
4214 | rt2800_bbp_write(rt2x00dev, 180, 0x01); | ||
4215 | rt2800_bbp_write(rt2x00dev, 182, 0x9c); | ||
4216 | rt2800_bbp_write(rt2x00dev, 179, 0x00); | ||
4217 | /* Reprogram the inband interface to put right values in RXWI */ | ||
4218 | rt2800_bbp_write(rt2x00dev, 142, 0x04); | ||
4219 | rt2800_bbp_write(rt2x00dev, 143, 0x3b); | ||
4220 | rt2800_bbp_write(rt2x00dev, 142, 0x06); | ||
4221 | rt2800_bbp_write(rt2x00dev, 143, 0xa0); | ||
4222 | rt2800_bbp_write(rt2x00dev, 142, 0x07); | ||
4223 | rt2800_bbp_write(rt2x00dev, 143, 0xa1); | ||
4224 | rt2800_bbp_write(rt2x00dev, 142, 0x08); | ||
4225 | rt2800_bbp_write(rt2x00dev, 143, 0xa2); | ||
4226 | |||
4227 | rt2800_bbp_write(rt2x00dev, 148, 0xc8); | ||
4228 | } | ||
4001 | 4229 | ||
4002 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | 4230 | static void rt2800_init_bbp_3390(struct rt2x00_dev *rt2x00dev) |
4231 | { | ||
4232 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | ||
4233 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | ||
4003 | 4234 | ||
4004 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | 4235 | rt2800_bbp_write(rt2x00dev, 69, 0x12); |
4005 | div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); | 4236 | rt2800_bbp_write(rt2x00dev, 73, 0x10); |
4006 | ant = (div_mode == 3) ? 1 : 0; | ||
4007 | rt2800_bbp_read(rt2x00dev, 152, &value); | ||
4008 | if (ant == 0) { | ||
4009 | /* Main antenna */ | ||
4010 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); | ||
4011 | } else { | ||
4012 | /* Auxiliary antenna */ | ||
4013 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0); | ||
4014 | } | ||
4015 | rt2800_bbp_write(rt2x00dev, 152, value); | ||
4016 | 4237 | ||
4017 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) { | 4238 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); |
4018 | rt2800_bbp_read(rt2x00dev, 254, &value); | ||
4019 | rt2x00_set_field8(&value, BBP254_BIT7, 1); | ||
4020 | rt2800_bbp_write(rt2x00dev, 254, value); | ||
4021 | } | ||
4022 | 4239 | ||
4023 | rt2800_init_freq_calibration(rt2x00dev); | 4240 | rt2800_bbp_write(rt2x00dev, 79, 0x13); |
4241 | rt2800_bbp_write(rt2x00dev, 80, 0x05); | ||
4242 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
4024 | 4243 | ||
4025 | rt2800_bbp_write(rt2x00dev, 84, 0x19); | 4244 | rt2800_bbp_write(rt2x00dev, 82, 0x62); |
4026 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) | 4245 | |
4246 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
4247 | |||
4248 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4249 | |||
4250 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
4251 | |||
4252 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4253 | |||
4254 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
4255 | |||
4256 | if (rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E)) | ||
4027 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | 4257 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); |
4258 | else | ||
4259 | rt2800_bbp_write(rt2x00dev, 103, 0x00); | ||
4260 | |||
4261 | rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||
4262 | |||
4263 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4264 | |||
4265 | rt2800_disable_unused_dac_adc(rt2x00dev); | ||
4028 | } | 4266 | } |
4029 | 4267 | ||
4030 | static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | 4268 | static void rt2800_init_bbp_3572(struct rt2x00_dev *rt2x00dev) |
4031 | { | 4269 | { |
4032 | unsigned int i; | 4270 | rt2800_bbp_write(rt2x00dev, 31, 0x08); |
4033 | u16 eeprom; | ||
4034 | u8 reg_id; | ||
4035 | u8 value; | ||
4036 | 4271 | ||
4037 | if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) || | 4272 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); |
4038 | rt2800_wait_bbp_ready(rt2x00dev))) | 4273 | rt2800_bbp_write(rt2x00dev, 66, 0x38); |
4039 | return -EACCES; | ||
4040 | 4274 | ||
4041 | if (rt2x00_rt(rt2x00dev, RT5592)) { | 4275 | rt2800_bbp_write(rt2x00dev, 69, 0x12); |
4042 | rt2800_init_bbp_5592(rt2x00dev); | 4276 | rt2800_bbp_write(rt2x00dev, 73, 0x10); |
4043 | return 0; | ||
4044 | } | ||
4045 | 4277 | ||
4046 | if (rt2x00_rt(rt2x00dev, RT3352)) { | 4278 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); |
4047 | rt2800_bbp_write(rt2x00dev, 3, 0x00); | ||
4048 | rt2800_bbp_write(rt2x00dev, 4, 0x50); | ||
4049 | } | ||
4050 | 4279 | ||
4051 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4280 | rt2800_bbp_write(rt2x00dev, 79, 0x13); |
4052 | rt2x00_rt(rt2x00dev, RT5390) || | 4281 | rt2800_bbp_write(rt2x00dev, 80, 0x05); |
4053 | rt2x00_rt(rt2x00dev, RT5392)) | 4282 | rt2800_bbp_write(rt2x00dev, 81, 0x33); |
4054 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | ||
4055 | 4283 | ||
4056 | if (rt2800_is_305x_soc(rt2x00dev) || | 4284 | rt2800_bbp_write(rt2x00dev, 82, 0x62); |
4057 | rt2x00_rt(rt2x00dev, RT3290) || | ||
4058 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4059 | rt2x00_rt(rt2x00dev, RT3572) || | ||
4060 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4061 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4062 | rt2800_bbp_write(rt2x00dev, 31, 0x08); | ||
4063 | 4285 | ||
4064 | if (rt2x00_rt(rt2x00dev, RT3352)) | 4286 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); |
4065 | rt2800_bbp_write(rt2x00dev, 47, 0x48); | 4287 | |
4288 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4289 | |||
4290 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
4291 | |||
4292 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4293 | |||
4294 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
4295 | |||
4296 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | ||
4297 | |||
4298 | rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||
4299 | |||
4300 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4301 | |||
4302 | rt2800_disable_unused_dac_adc(rt2x00dev); | ||
4303 | } | ||
4304 | |||
4305 | static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev) | ||
4306 | { | ||
4307 | int ant, div_mode; | ||
4308 | u16 eeprom; | ||
4309 | u8 value; | ||
4310 | |||
4311 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | ||
4312 | |||
4313 | rt2800_bbp_write(rt2x00dev, 31, 0x08); | ||
4066 | 4314 | ||
4067 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); | 4315 | rt2800_bbp_write(rt2x00dev, 65, 0x2c); |
4068 | rt2800_bbp_write(rt2x00dev, 66, 0x38); | 4316 | rt2800_bbp_write(rt2x00dev, 66, 0x38); |
4069 | 4317 | ||
4070 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4318 | rt2800_bbp_write(rt2x00dev, 68, 0x0b); |
4071 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4072 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4073 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4074 | rt2800_bbp_write(rt2x00dev, 68, 0x0b); | ||
4075 | 4319 | ||
4076 | if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) { | 4320 | rt2800_bbp_write(rt2x00dev, 69, 0x12); |
4077 | rt2800_bbp_write(rt2x00dev, 69, 0x16); | 4321 | rt2800_bbp_write(rt2x00dev, 73, 0x13); |
4078 | rt2800_bbp_write(rt2x00dev, 73, 0x12); | 4322 | rt2800_bbp_write(rt2x00dev, 75, 0x46); |
4079 | } else if (rt2x00_rt(rt2x00dev, RT3290) || | 4323 | rt2800_bbp_write(rt2x00dev, 76, 0x28); |
4080 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4081 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4082 | rt2x00_rt(rt2x00dev, RT5392)) { | ||
4083 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
4084 | rt2800_bbp_write(rt2x00dev, 73, 0x13); | ||
4085 | rt2800_bbp_write(rt2x00dev, 75, 0x46); | ||
4086 | rt2800_bbp_write(rt2x00dev, 76, 0x28); | ||
4087 | 4324 | ||
4088 | if (rt2x00_rt(rt2x00dev, RT3290)) | 4325 | rt2800_bbp_write(rt2x00dev, 77, 0x59); |
4089 | rt2800_bbp_write(rt2x00dev, 77, 0x58); | ||
4090 | else | ||
4091 | rt2800_bbp_write(rt2x00dev, 77, 0x59); | ||
4092 | } else { | ||
4093 | rt2800_bbp_write(rt2x00dev, 69, 0x12); | ||
4094 | rt2800_bbp_write(rt2x00dev, 73, 0x10); | ||
4095 | } | ||
4096 | 4326 | ||
4097 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); | 4327 | rt2800_bbp_write(rt2x00dev, 70, 0x0a); |
4098 | 4328 | ||
4099 | if (rt2x00_rt(rt2x00dev, RT3070) || | 4329 | rt2800_bbp_write(rt2x00dev, 79, 0x13); |
4100 | rt2x00_rt(rt2x00dev, RT3071) || | 4330 | rt2800_bbp_write(rt2x00dev, 80, 0x05); |
4101 | rt2x00_rt(rt2x00dev, RT3090) || | 4331 | rt2800_bbp_write(rt2x00dev, 81, 0x33); |
4102 | rt2x00_rt(rt2x00dev, RT3390) || | ||
4103 | rt2x00_rt(rt2x00dev, RT3572) || | ||
4104 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4105 | rt2x00_rt(rt2x00dev, RT5392)) { | ||
4106 | rt2800_bbp_write(rt2x00dev, 79, 0x13); | ||
4107 | rt2800_bbp_write(rt2x00dev, 80, 0x05); | ||
4108 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
4109 | } else if (rt2800_is_305x_soc(rt2x00dev)) { | ||
4110 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | ||
4111 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | ||
4112 | } else if (rt2x00_rt(rt2x00dev, RT3290)) { | ||
4113 | rt2800_bbp_write(rt2x00dev, 74, 0x0b); | ||
4114 | rt2800_bbp_write(rt2x00dev, 79, 0x18); | ||
4115 | rt2800_bbp_write(rt2x00dev, 80, 0x09); | ||
4116 | rt2800_bbp_write(rt2x00dev, 81, 0x33); | ||
4117 | } else if (rt2x00_rt(rt2x00dev, RT3352)) { | ||
4118 | rt2800_bbp_write(rt2x00dev, 78, 0x0e); | ||
4119 | rt2800_bbp_write(rt2x00dev, 80, 0x08); | ||
4120 | rt2800_bbp_write(rt2x00dev, 81, 0x37); | ||
4121 | } else { | ||
4122 | rt2800_bbp_write(rt2x00dev, 81, 0x37); | ||
4123 | } | ||
4124 | 4332 | ||
4125 | rt2800_bbp_write(rt2x00dev, 82, 0x62); | 4333 | rt2800_bbp_write(rt2x00dev, 82, 0x62); |
4126 | if (rt2x00_rt(rt2x00dev, RT3290) || | ||
4127 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4128 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4129 | rt2800_bbp_write(rt2x00dev, 83, 0x7a); | ||
4130 | else | ||
4131 | rt2800_bbp_write(rt2x00dev, 83, 0x6a); | ||
4132 | 4334 | ||
4133 | if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D)) | 4335 | rt2800_bbp_write(rt2x00dev, 83, 0x7a); |
4134 | rt2800_bbp_write(rt2x00dev, 84, 0x19); | ||
4135 | else if (rt2x00_rt(rt2x00dev, RT3290) || | ||
4136 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4137 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4138 | rt2800_bbp_write(rt2x00dev, 84, 0x9a); | ||
4139 | else | ||
4140 | rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||
4141 | 4336 | ||
4142 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4337 | rt2800_bbp_write(rt2x00dev, 84, 0x9a); |
4143 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4144 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4145 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4146 | rt2800_bbp_write(rt2x00dev, 86, 0x38); | ||
4147 | else | ||
4148 | rt2800_bbp_write(rt2x00dev, 86, 0x00); | ||
4149 | 4338 | ||
4150 | if (rt2x00_rt(rt2x00dev, RT3352) || | 4339 | rt2800_bbp_write(rt2x00dev, 86, 0x38); |
4151 | rt2x00_rt(rt2x00dev, RT5392)) | 4340 | |
4341 | if (rt2x00_rt(rt2x00dev, RT5392)) | ||
4152 | rt2800_bbp_write(rt2x00dev, 88, 0x90); | 4342 | rt2800_bbp_write(rt2x00dev, 88, 0x90); |
4153 | 4343 | ||
4154 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | 4344 | rt2800_bbp_write(rt2x00dev, 91, 0x04); |
4155 | 4345 | ||
4156 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4346 | rt2800_bbp_write(rt2x00dev, 92, 0x02); |
4157 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4158 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4159 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4160 | rt2800_bbp_write(rt2x00dev, 92, 0x02); | ||
4161 | else | ||
4162 | rt2800_bbp_write(rt2x00dev, 92, 0x00); | ||
4163 | 4347 | ||
4164 | if (rt2x00_rt(rt2x00dev, RT5392)) { | 4348 | if (rt2x00_rt(rt2x00dev, RT5392)) { |
4165 | rt2800_bbp_write(rt2x00dev, 95, 0x9a); | 4349 | rt2800_bbp_write(rt2x00dev, 95, 0x9a); |
4166 | rt2800_bbp_write(rt2x00dev, 98, 0x12); | 4350 | rt2800_bbp_write(rt2x00dev, 98, 0x12); |
4167 | } | 4351 | } |
4168 | 4352 | ||
4169 | if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) || | 4353 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); |
4170 | rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) || | ||
4171 | rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) || | ||
4172 | rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) || | ||
4173 | rt2x00_rt(rt2x00dev, RT3290) || | ||
4174 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4175 | rt2x00_rt(rt2x00dev, RT3572) || | ||
4176 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4177 | rt2x00_rt(rt2x00dev, RT5392) || | ||
4178 | rt2800_is_305x_soc(rt2x00dev)) | ||
4179 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); | ||
4180 | else | ||
4181 | rt2800_bbp_write(rt2x00dev, 103, 0x00); | ||
4182 | 4354 | ||
4183 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4355 | rt2800_bbp_write(rt2x00dev, 104, 0x92); |
4184 | rt2x00_rt(rt2x00dev, RT3352) || | ||
4185 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4186 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4187 | rt2800_bbp_write(rt2x00dev, 104, 0x92); | ||
4188 | 4356 | ||
4189 | if (rt2800_is_305x_soc(rt2x00dev)) | 4357 | rt2800_bbp_write(rt2x00dev, 105, 0x3c); |
4190 | rt2800_bbp_write(rt2x00dev, 105, 0x01); | ||
4191 | else if (rt2x00_rt(rt2x00dev, RT3290)) | ||
4192 | rt2800_bbp_write(rt2x00dev, 105, 0x1c); | ||
4193 | else if (rt2x00_rt(rt2x00dev, RT3352)) | ||
4194 | rt2800_bbp_write(rt2x00dev, 105, 0x34); | ||
4195 | else if (rt2x00_rt(rt2x00dev, RT5390) || | ||
4196 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4197 | rt2800_bbp_write(rt2x00dev, 105, 0x3c); | ||
4198 | else | ||
4199 | rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||
4200 | 4358 | ||
4201 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4359 | if (rt2x00_rt(rt2x00dev, RT5390)) |
4202 | rt2x00_rt(rt2x00dev, RT5390)) | ||
4203 | rt2800_bbp_write(rt2x00dev, 106, 0x03); | 4360 | rt2800_bbp_write(rt2x00dev, 106, 0x03); |
4204 | else if (rt2x00_rt(rt2x00dev, RT3352)) | ||
4205 | rt2800_bbp_write(rt2x00dev, 106, 0x05); | ||
4206 | else if (rt2x00_rt(rt2x00dev, RT5392)) | 4361 | else if (rt2x00_rt(rt2x00dev, RT5392)) |
4207 | rt2800_bbp_write(rt2x00dev, 106, 0x12); | 4362 | rt2800_bbp_write(rt2x00dev, 106, 0x12); |
4208 | else | 4363 | else |
4209 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | 4364 | WARN_ON(1); |
4210 | |||
4211 | if (rt2x00_rt(rt2x00dev, RT3352)) | ||
4212 | rt2800_bbp_write(rt2x00dev, 120, 0x50); | ||
4213 | 4365 | ||
4214 | if (rt2x00_rt(rt2x00dev, RT3290) || | 4366 | rt2800_bbp_write(rt2x00dev, 128, 0x12); |
4215 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4216 | rt2x00_rt(rt2x00dev, RT5392)) | ||
4217 | rt2800_bbp_write(rt2x00dev, 128, 0x12); | ||
4218 | 4367 | ||
4219 | if (rt2x00_rt(rt2x00dev, RT5392)) { | 4368 | if (rt2x00_rt(rt2x00dev, RT5392)) { |
4220 | rt2800_bbp_write(rt2x00dev, 134, 0xd0); | 4369 | rt2800_bbp_write(rt2x00dev, 134, 0xd0); |
4221 | rt2800_bbp_write(rt2x00dev, 135, 0xf6); | 4370 | rt2800_bbp_write(rt2x00dev, 135, 0xf6); |
4222 | } | 4371 | } |
4223 | 4372 | ||
4224 | if (rt2x00_rt(rt2x00dev, RT3352)) | 4373 | rt2800_disable_unused_dac_adc(rt2x00dev); |
4225 | rt2800_bbp_write(rt2x00dev, 137, 0x0f); | ||
4226 | 4374 | ||
4227 | if (rt2x00_rt(rt2x00dev, RT3071) || | 4375 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); |
4228 | rt2x00_rt(rt2x00dev, RT3090) || | 4376 | div_mode = rt2x00_get_field16(eeprom, |
4229 | rt2x00_rt(rt2x00dev, RT3390) || | 4377 | EEPROM_NIC_CONF1_ANT_DIVERSITY); |
4230 | rt2x00_rt(rt2x00dev, RT3572) || | 4378 | ant = (div_mode == 3) ? 1 : 0; |
4231 | rt2x00_rt(rt2x00dev, RT5390) || | ||
4232 | rt2x00_rt(rt2x00dev, RT5392)) { | ||
4233 | rt2800_bbp_read(rt2x00dev, 138, &value); | ||
4234 | 4379 | ||
4235 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom); | 4380 | /* check if this is a Bluetooth combo card */ |
4236 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1) | 4381 | if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { |
4237 | value |= 0x20; | 4382 | u32 reg; |
4238 | if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1) | ||
4239 | value &= ~0x02; | ||
4240 | 4383 | ||
4241 | rt2800_bbp_write(rt2x00dev, 138, value); | 4384 | rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); |
4385 | rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); | ||
4386 | rt2x00_set_field32(®, GPIO_CTRL_DIR6, 0); | ||
4387 | rt2x00_set_field32(®, GPIO_CTRL_VAL3, 0); | ||
4388 | rt2x00_set_field32(®, GPIO_CTRL_VAL6, 0); | ||
4389 | if (ant == 0) | ||
4390 | rt2x00_set_field32(®, GPIO_CTRL_VAL3, 1); | ||
4391 | else if (ant == 1) | ||
4392 | rt2x00_set_field32(®, GPIO_CTRL_VAL6, 1); | ||
4393 | rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); | ||
4242 | } | 4394 | } |
4243 | 4395 | ||
4244 | if (rt2x00_rt(rt2x00dev, RT3290)) { | 4396 | /* This chip has hardware antenna diversity*/ |
4245 | rt2800_bbp_write(rt2x00dev, 67, 0x24); | 4397 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { |
4246 | rt2800_bbp_write(rt2x00dev, 143, 0x04); | 4398 | rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ |
4247 | rt2800_bbp_write(rt2x00dev, 142, 0x99); | 4399 | rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ |
4248 | rt2800_bbp_write(rt2x00dev, 150, 0x30); | 4400 | rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ |
4249 | rt2800_bbp_write(rt2x00dev, 151, 0x2e); | ||
4250 | rt2800_bbp_write(rt2x00dev, 152, 0x20); | ||
4251 | rt2800_bbp_write(rt2x00dev, 153, 0x34); | ||
4252 | rt2800_bbp_write(rt2x00dev, 154, 0x40); | ||
4253 | rt2800_bbp_write(rt2x00dev, 155, 0x3b); | ||
4254 | rt2800_bbp_write(rt2x00dev, 253, 0x04); | ||
4255 | |||
4256 | rt2800_bbp_read(rt2x00dev, 47, &value); | ||
4257 | rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1); | ||
4258 | rt2800_bbp_write(rt2x00dev, 47, value); | ||
4259 | |||
4260 | /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */ | ||
4261 | rt2800_bbp_read(rt2x00dev, 3, &value); | ||
4262 | rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1); | ||
4263 | rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1); | ||
4264 | rt2800_bbp_write(rt2x00dev, 3, value); | ||
4265 | } | 4401 | } |
4266 | 4402 | ||
4267 | if (rt2x00_rt(rt2x00dev, RT3352)) { | 4403 | rt2800_bbp_read(rt2x00dev, 152, &value); |
4268 | rt2800_bbp_write(rt2x00dev, 163, 0xbd); | 4404 | if (ant == 0) |
4269 | /* Set ITxBF timeout to 0x9c40=1000msec */ | 4405 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); |
4270 | rt2800_bbp_write(rt2x00dev, 179, 0x02); | 4406 | else |
4271 | rt2800_bbp_write(rt2x00dev, 180, 0x00); | 4407 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0); |
4272 | rt2800_bbp_write(rt2x00dev, 182, 0x40); | 4408 | rt2800_bbp_write(rt2x00dev, 152, value); |
4273 | rt2800_bbp_write(rt2x00dev, 180, 0x01); | 4409 | |
4274 | rt2800_bbp_write(rt2x00dev, 182, 0x9c); | 4410 | rt2800_init_freq_calibration(rt2x00dev); |
4275 | rt2800_bbp_write(rt2x00dev, 179, 0x00); | 4411 | } |
4276 | /* Reprogram the inband interface to put right values in RXWI */ | 4412 | |
4277 | rt2800_bbp_write(rt2x00dev, 142, 0x04); | 4413 | static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev) |
4278 | rt2800_bbp_write(rt2x00dev, 143, 0x3b); | 4414 | { |
4279 | rt2800_bbp_write(rt2x00dev, 142, 0x06); | 4415 | int ant, div_mode; |
4280 | rt2800_bbp_write(rt2x00dev, 143, 0xa0); | 4416 | u16 eeprom; |
4281 | rt2800_bbp_write(rt2x00dev, 142, 0x07); | 4417 | u8 value; |
4282 | rt2800_bbp_write(rt2x00dev, 143, 0xa1); | 4418 | |
4283 | rt2800_bbp_write(rt2x00dev, 142, 0x08); | 4419 | rt2800_init_bbp_early(rt2x00dev); |
4284 | rt2800_bbp_write(rt2x00dev, 143, 0xa2); | 4420 | |
4285 | 4421 | rt2800_bbp_read(rt2x00dev, 105, &value); | |
4286 | rt2800_bbp_write(rt2x00dev, 148, 0xc8); | 4422 | rt2x00_set_field8(&value, BBP105_MLD, |
4423 | rt2x00dev->default_ant.rx_chain_num == 2); | ||
4424 | rt2800_bbp_write(rt2x00dev, 105, value); | ||
4425 | |||
4426 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | ||
4427 | |||
4428 | rt2800_bbp_write(rt2x00dev, 20, 0x06); | ||
4429 | rt2800_bbp_write(rt2x00dev, 31, 0x08); | ||
4430 | rt2800_bbp_write(rt2x00dev, 65, 0x2C); | ||
4431 | rt2800_bbp_write(rt2x00dev, 68, 0xDD); | ||
4432 | rt2800_bbp_write(rt2x00dev, 69, 0x1A); | ||
4433 | rt2800_bbp_write(rt2x00dev, 70, 0x05); | ||
4434 | rt2800_bbp_write(rt2x00dev, 73, 0x13); | ||
4435 | rt2800_bbp_write(rt2x00dev, 74, 0x0F); | ||
4436 | rt2800_bbp_write(rt2x00dev, 75, 0x4F); | ||
4437 | rt2800_bbp_write(rt2x00dev, 76, 0x28); | ||
4438 | rt2800_bbp_write(rt2x00dev, 77, 0x59); | ||
4439 | rt2800_bbp_write(rt2x00dev, 84, 0x9A); | ||
4440 | rt2800_bbp_write(rt2x00dev, 86, 0x38); | ||
4441 | rt2800_bbp_write(rt2x00dev, 88, 0x90); | ||
4442 | rt2800_bbp_write(rt2x00dev, 91, 0x04); | ||
4443 | rt2800_bbp_write(rt2x00dev, 92, 0x02); | ||
4444 | rt2800_bbp_write(rt2x00dev, 95, 0x9a); | ||
4445 | rt2800_bbp_write(rt2x00dev, 98, 0x12); | ||
4446 | rt2800_bbp_write(rt2x00dev, 103, 0xC0); | ||
4447 | rt2800_bbp_write(rt2x00dev, 104, 0x92); | ||
4448 | /* FIXME BBP105 owerwrite */ | ||
4449 | rt2800_bbp_write(rt2x00dev, 105, 0x3C); | ||
4450 | rt2800_bbp_write(rt2x00dev, 106, 0x35); | ||
4451 | rt2800_bbp_write(rt2x00dev, 128, 0x12); | ||
4452 | rt2800_bbp_write(rt2x00dev, 134, 0xD0); | ||
4453 | rt2800_bbp_write(rt2x00dev, 135, 0xF6); | ||
4454 | rt2800_bbp_write(rt2x00dev, 137, 0x0F); | ||
4455 | |||
4456 | /* Initialize GLRT (Generalized Likehood Radio Test) */ | ||
4457 | rt2800_init_bbp_5592_glrt(rt2x00dev); | ||
4458 | |||
4459 | rt2800_bbp4_mac_if_ctrl(rt2x00dev); | ||
4460 | |||
4461 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | ||
4462 | div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY); | ||
4463 | ant = (div_mode == 3) ? 1 : 0; | ||
4464 | rt2800_bbp_read(rt2x00dev, 152, &value); | ||
4465 | if (ant == 0) { | ||
4466 | /* Main antenna */ | ||
4467 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); | ||
4468 | } else { | ||
4469 | /* Auxiliary antenna */ | ||
4470 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0); | ||
4287 | } | 4471 | } |
4472 | rt2800_bbp_write(rt2x00dev, 152, value); | ||
4288 | 4473 | ||
4289 | if (rt2x00_rt(rt2x00dev, RT5390) || | 4474 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) { |
4290 | rt2x00_rt(rt2x00dev, RT5392)) { | 4475 | rt2800_bbp_read(rt2x00dev, 254, &value); |
4291 | int ant, div_mode; | 4476 | rt2x00_set_field8(&value, BBP254_BIT7, 1); |
4477 | rt2800_bbp_write(rt2x00dev, 254, value); | ||
4478 | } | ||
4292 | 4479 | ||
4293 | rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); | 4480 | rt2800_init_freq_calibration(rt2x00dev); |
4294 | div_mode = rt2x00_get_field16(eeprom, | ||
4295 | EEPROM_NIC_CONF1_ANT_DIVERSITY); | ||
4296 | ant = (div_mode == 3) ? 1 : 0; | ||
4297 | 4481 | ||
4298 | /* check if this is a Bluetooth combo card */ | 4482 | rt2800_bbp_write(rt2x00dev, 84, 0x19); |
4299 | if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { | 4483 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) |
4300 | u32 reg; | 4484 | rt2800_bbp_write(rt2x00dev, 103, 0xc0); |
4301 | 4485 | } | |
4302 | rt2800_register_read(rt2x00dev, GPIO_CTRL, ®); | ||
4303 | rt2x00_set_field32(®, GPIO_CTRL_DIR3, 0); | ||
4304 | rt2x00_set_field32(®, GPIO_CTRL_DIR6, 0); | ||
4305 | rt2x00_set_field32(®, GPIO_CTRL_VAL3, 0); | ||
4306 | rt2x00_set_field32(®, GPIO_CTRL_VAL6, 0); | ||
4307 | if (ant == 0) | ||
4308 | rt2x00_set_field32(®, GPIO_CTRL_VAL3, 1); | ||
4309 | else if (ant == 1) | ||
4310 | rt2x00_set_field32(®, GPIO_CTRL_VAL6, 1); | ||
4311 | rt2800_register_write(rt2x00dev, GPIO_CTRL, reg); | ||
4312 | } | ||
4313 | 4486 | ||
4314 | /* This chip has hardware antenna diversity*/ | 4487 | static void rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) |
4315 | if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390R)) { | 4488 | { |
4316 | rt2800_bbp_write(rt2x00dev, 150, 0); /* Disable Antenna Software OFDM */ | 4489 | unsigned int i; |
4317 | rt2800_bbp_write(rt2x00dev, 151, 0); /* Disable Antenna Software CCK */ | 4490 | u16 eeprom; |
4318 | rt2800_bbp_write(rt2x00dev, 154, 0); /* Clear previously selected antenna */ | 4491 | u8 reg_id; |
4319 | } | 4492 | u8 value; |
4320 | 4493 | ||
4321 | rt2800_bbp_read(rt2x00dev, 152, &value); | 4494 | if (rt2800_is_305x_soc(rt2x00dev)) |
4322 | if (ant == 0) | 4495 | rt2800_init_bbp_305x_soc(rt2x00dev); |
4323 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1); | ||
4324 | else | ||
4325 | rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0); | ||
4326 | rt2800_bbp_write(rt2x00dev, 152, value); | ||
4327 | 4496 | ||
4328 | rt2800_init_freq_calibration(rt2x00dev); | 4497 | switch (rt2x00dev->chip.rt) { |
4498 | case RT2860: | ||
4499 | case RT2872: | ||
4500 | case RT2883: | ||
4501 | rt2800_init_bbp_28xx(rt2x00dev); | ||
4502 | break; | ||
4503 | case RT3070: | ||
4504 | case RT3071: | ||
4505 | case RT3090: | ||
4506 | rt2800_init_bbp_30xx(rt2x00dev); | ||
4507 | break; | ||
4508 | case RT3290: | ||
4509 | rt2800_init_bbp_3290(rt2x00dev); | ||
4510 | break; | ||
4511 | case RT3352: | ||
4512 | rt2800_init_bbp_3352(rt2x00dev); | ||
4513 | break; | ||
4514 | case RT3390: | ||
4515 | rt2800_init_bbp_3390(rt2x00dev); | ||
4516 | break; | ||
4517 | case RT3572: | ||
4518 | rt2800_init_bbp_3572(rt2x00dev); | ||
4519 | break; | ||
4520 | case RT5390: | ||
4521 | case RT5392: | ||
4522 | rt2800_init_bbp_53xx(rt2x00dev); | ||
4523 | break; | ||
4524 | case RT5592: | ||
4525 | rt2800_init_bbp_5592(rt2x00dev); | ||
4526 | return; | ||
4329 | } | 4527 | } |
4330 | 4528 | ||
4331 | for (i = 0; i < EEPROM_BBP_SIZE; i++) { | 4529 | for (i = 0; i < EEPROM_BBP_SIZE; i++) { |
@@ -4337,8 +4535,6 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
4337 | rt2800_bbp_write(rt2x00dev, reg_id, value); | 4535 | rt2800_bbp_write(rt2x00dev, reg_id, value); |
4338 | } | 4536 | } |
4339 | } | 4537 | } |
4340 | |||
4341 | return 0; | ||
4342 | } | 4538 | } |
4343 | 4539 | ||
4344 | static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev) | 4540 | static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev) |
@@ -5189,9 +5385,11 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
5189 | } | 5385 | } |
5190 | msleep(1); | 5386 | msleep(1); |
5191 | 5387 | ||
5192 | if (unlikely(rt2800_init_bbp(rt2x00dev))) | 5388 | if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev) || |
5389 | rt2800_wait_bbp_ready(rt2x00dev))) | ||
5193 | return -EIO; | 5390 | return -EIO; |
5194 | 5391 | ||
5392 | rt2800_init_bbp(rt2x00dev); | ||
5195 | rt2800_init_rfcsr(rt2x00dev); | 5393 | rt2800_init_rfcsr(rt2x00dev); |
5196 | 5394 | ||
5197 | if (rt2x00_is_usb(rt2x00dev) && | 5395 | if (rt2x00_is_usb(rt2x00dev) && |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6f4a861af336..330f1d25726d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -1014,7 +1014,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) | |||
1014 | * Since we have only one producer and one consumer we don't | 1014 | * Since we have only one producer and one consumer we don't |
1015 | * need to lock the kfifo. | 1015 | * need to lock the kfifo. |
1016 | */ | 1016 | */ |
1017 | for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { | 1017 | for (i = 0; i < rt2x00dev->tx->limit; i++) { |
1018 | rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); | 1018 | rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status); |
1019 | 1019 | ||
1020 | if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) | 1020 | if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index ac854d75bd6c..c71a48da9a31 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -327,7 +327,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
327 | * this limit so reduce the number to prevent errors. | 327 | * this limit so reduce the number to prevent errors. |
328 | */ | 328 | */ |
329 | rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, | 329 | rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, |
330 | ((rt2x00dev->ops->rx->entry_num * DATA_FRAME_SIZE) | 330 | ((rt2x00dev->rx->limit * DATA_FRAME_SIZE) |
331 | / 1024) - 3); | 331 | / 1024) - 3); |
332 | rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); | 332 | rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); |
333 | rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); | 333 | rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 90dc14336980..6a201725bc50 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -1077,7 +1077,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1077 | */ | 1077 | */ |
1078 | int kfifo_size = | 1078 | int kfifo_size = |
1079 | roundup_pow_of_two(rt2x00dev->ops->tx_queues * | 1079 | roundup_pow_of_two(rt2x00dev->ops->tx_queues * |
1080 | rt2x00dev->ops->tx->entry_num * | 1080 | rt2x00dev->tx->limit * |
1081 | sizeof(u32)); | 1081 | sizeof(u32)); |
1082 | 1082 | ||
1083 | status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, | 1083 | status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size, |
@@ -1301,23 +1301,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1301 | (rt2x00dev->ops->max_ap_intf - 1); | 1301 | (rt2x00dev->ops->max_ap_intf - 1); |
1302 | 1302 | ||
1303 | /* | 1303 | /* |
1304 | * Determine which operating modes are supported, all modes | ||
1305 | * which require beaconing, depend on the availability of | ||
1306 | * beacon entries. | ||
1307 | */ | ||
1308 | rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1309 | if (rt2x00dev->ops->bcn->entry_num > 0) | ||
1310 | rt2x00dev->hw->wiphy->interface_modes |= | ||
1311 | BIT(NL80211_IFTYPE_ADHOC) | | ||
1312 | BIT(NL80211_IFTYPE_AP) | | ||
1313 | #ifdef CONFIG_MAC80211_MESH | ||
1314 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
1315 | #endif | ||
1316 | BIT(NL80211_IFTYPE_WDS); | ||
1317 | |||
1318 | rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | ||
1319 | |||
1320 | /* | ||
1321 | * Initialize work. | 1304 | * Initialize work. |
1322 | */ | 1305 | */ |
1323 | rt2x00dev->workqueue = | 1306 | rt2x00dev->workqueue = |
@@ -1348,6 +1331,23 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1348 | goto exit; | 1331 | goto exit; |
1349 | 1332 | ||
1350 | /* | 1333 | /* |
1334 | * Determine which operating modes are supported, all modes | ||
1335 | * which require beaconing, depend on the availability of | ||
1336 | * beacon entries. | ||
1337 | */ | ||
1338 | rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
1339 | if (rt2x00dev->ops->bcn->entry_num > 0) | ||
1340 | rt2x00dev->hw->wiphy->interface_modes |= | ||
1341 | BIT(NL80211_IFTYPE_ADHOC) | | ||
1342 | BIT(NL80211_IFTYPE_AP) | | ||
1343 | #ifdef CONFIG_MAC80211_MESH | ||
1344 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
1345 | #endif | ||
1346 | BIT(NL80211_IFTYPE_WDS); | ||
1347 | |||
1348 | rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | ||
1349 | |||
1350 | /* | ||
1351 | * Initialize ieee80211 structure. | 1351 | * Initialize ieee80211 structure. |
1352 | */ | 1352 | */ |
1353 | retval = rt2x00lib_probe_hw(rt2x00dev); | 1353 | retval = rt2x00lib_probe_hw(rt2x00dev); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index dc49e525ae5e..76d95deb274b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c | |||
@@ -105,11 +105,13 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) | |||
105 | goto exit_release_regions; | 105 | goto exit_release_regions; |
106 | } | 106 | } |
107 | 107 | ||
108 | pci_enable_msi(pci_dev); | ||
109 | |||
108 | hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); | 110 | hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); |
109 | if (!hw) { | 111 | if (!hw) { |
110 | rt2x00_probe_err("Failed to allocate hardware\n"); | 112 | rt2x00_probe_err("Failed to allocate hardware\n"); |
111 | retval = -ENOMEM; | 113 | retval = -ENOMEM; |
112 | goto exit_release_regions; | 114 | goto exit_disable_msi; |
113 | } | 115 | } |
114 | 116 | ||
115 | pci_set_drvdata(pci_dev, hw); | 117 | pci_set_drvdata(pci_dev, hw); |
@@ -150,6 +152,9 @@ exit_free_reg: | |||
150 | exit_free_device: | 152 | exit_free_device: |
151 | ieee80211_free_hw(hw); | 153 | ieee80211_free_hw(hw); |
152 | 154 | ||
155 | exit_disable_msi: | ||
156 | pci_disable_msi(pci_dev); | ||
157 | |||
153 | exit_release_regions: | 158 | exit_release_regions: |
154 | pci_release_regions(pci_dev); | 159 | pci_release_regions(pci_dev); |
155 | 160 | ||
@@ -174,6 +179,8 @@ void rt2x00pci_remove(struct pci_dev *pci_dev) | |||
174 | rt2x00pci_free_reg(rt2x00dev); | 179 | rt2x00pci_free_reg(rt2x00dev); |
175 | ieee80211_free_hw(hw); | 180 | ieee80211_free_hw(hw); |
176 | 181 | ||
182 | pci_disable_msi(pci_dev); | ||
183 | |||
177 | /* | 184 | /* |
178 | * Free the PCI device data. | 185 | * Free the PCI device data. |
179 | */ | 186 | */ |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0dc8180e251b..7e1759b3e49a 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -2175,7 +2175,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) | |||
2175 | * that the TX_STA_FIFO stack has a size of 16. We stick to our | 2175 | * that the TX_STA_FIFO stack has a size of 16. We stick to our |
2176 | * tx ring size for now. | 2176 | * tx ring size for now. |
2177 | */ | 2177 | */ |
2178 | for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { | 2178 | for (i = 0; i < rt2x00dev->tx->limit; i++) { |
2179 | rt2x00mmio_register_read(rt2x00dev, STA_CSR4, ®); | 2179 | rt2x00mmio_register_read(rt2x00dev, STA_CSR4, ®); |
2180 | if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) | 2180 | if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) |
2181 | break; | 2181 | break; |
diff --git a/include/linux/platform_data/net-cw1200.h b/include/linux/platform_data/net-cw1200.h new file mode 100644 index 000000000000..c6fbc3ce4ab0 --- /dev/null +++ b/include/linux/platform_data/net-cw1200.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2011 | ||
3 | * | ||
4 | * Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | */ | ||
7 | |||
8 | #ifndef CW1200_PLAT_H_INCLUDED | ||
9 | #define CW1200_PLAT_H_INCLUDED | ||
10 | |||
11 | struct cw1200_platform_data_spi { | ||
12 | u8 spi_bits_per_word; /* REQUIRED */ | ||
13 | u16 ref_clk; /* REQUIRED (in KHz) */ | ||
14 | |||
15 | /* All others are optional */ | ||
16 | bool have_5ghz; | ||
17 | int reset; /* GPIO to RSTn signal (0 disables) */ | ||
18 | int powerup; /* GPIO to POWERUP signal (0 disables) */ | ||
19 | int (*power_ctrl)(const struct cw1200_platform_data_spi *pdata, | ||
20 | bool enable); /* Control 3v3 / 1v8 supply */ | ||
21 | int (*clk_ctrl)(const struct cw1200_platform_data_spi *pdata, | ||
22 | bool enable); /* Control CLK32K */ | ||
23 | const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */ | ||
24 | const char *sdd_file; /* if NULL, will use default for detected hw type */ | ||
25 | }; | ||
26 | |||
27 | struct cw1200_platform_data_sdio { | ||
28 | u16 ref_clk; /* REQUIRED (in KHz) */ | ||
29 | |||
30 | /* All others are optional */ | ||
31 | bool have_5ghz; | ||
32 | bool no_nptb; /* SDIO hardware does not support non-power-of-2-blocksizes */ | ||
33 | int reset; /* GPIO to RSTn signal (0 disables) */ | ||
34 | int powerup; /* GPIO to POWERUP signal (0 disables) */ | ||
35 | int irq; /* IRQ line or 0 to use SDIO IRQ */ | ||
36 | int (*power_ctrl)(const struct cw1200_platform_data_sdio *pdata, | ||
37 | bool enable); /* Control 3v3 / 1v8 supply */ | ||
38 | int (*clk_ctrl)(const struct cw1200_platform_data_sdio *pdata, | ||
39 | bool enable); /* Control CLK32K */ | ||
40 | const u8 *macaddr; /* if NULL, use cw1200_mac_template module parameter */ | ||
41 | const char *sdd_file; /* if NULL, will use default for detected hw type */ | ||
42 | }; | ||
43 | |||
44 | |||
45 | /* An example of SPI support in your board setup file: | ||
46 | |||
47 | static struct cw1200_platform_data_spi cw1200_platform_data = { | ||
48 | .ref_clk = 38400, | ||
49 | .spi_bits_per_word = 16, | ||
50 | .reset = GPIO_RF_RESET, | ||
51 | .powerup = GPIO_RF_POWERUP, | ||
52 | .macaddr = wifi_mac_addr, | ||
53 | .sdd_file = "sdd_sagrad_1091_1098.bin", | ||
54 | }; | ||
55 | static struct spi_board_info myboard_spi_devices[] __initdata = { | ||
56 | { | ||
57 | .modalias = "cw1200_wlan_spi", | ||
58 | .max_speed_hz = 52000000, | ||
59 | .bus_num = 0, | ||
60 | .irq = WIFI_IRQ, | ||
61 | .platform_data = &cw1200_platform_data, | ||
62 | .chip_select = 0, | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | */ | ||
67 | |||
68 | /* An example of SDIO support in your board setup file: | ||
69 | |||
70 | static struct cw1200_platform_data_sdio my_cw1200_platform_data = { | ||
71 | .ref_clk = 38400, | ||
72 | .have_5ghz = false, | ||
73 | .sdd_file = "sdd_myplatform.bin", | ||
74 | }; | ||
75 | cw1200_sdio_set_platform_data(&my_cw1200_platform_data); | ||
76 | |||
77 | */ | ||
78 | |||
79 | void __init cw1200_sdio_set_platform_data(struct cw1200_platform_data_sdio *pdata); | ||
80 | |||
81 | #endif /* CW1200_PLAT_H_INCLUDED */ | ||
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 3a7256955b10..f9f931c89e3e 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h | |||
@@ -172,6 +172,7 @@ | |||
172 | #define SSB_SPROMSIZE_WORDS_R4 220 | 172 | #define SSB_SPROMSIZE_WORDS_R4 220 |
173 | #define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16)) | 173 | #define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16)) |
174 | #define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16)) | 174 | #define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16)) |
175 | #define SSB_SPROMSIZE_WORDS_R10 230 | ||
175 | #define SSB_SPROM_BASE1 0x1000 | 176 | #define SSB_SPROM_BASE1 0x1000 |
176 | #define SSB_SPROM_BASE31 0x0800 | 177 | #define SSB_SPROM_BASE31 0x0800 |
177 | #define SSB_SPROM_REVISION 0x007E | 178 | #define SSB_SPROM_REVISION 0x007E |