diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-06-11 14:48:32 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-06-11 14:48:32 -0400 |
commit | 3899ba90a4ab2f3cab8e0f91a76c14ff131c8293 (patch) | |
tree | ae82b469f8a7ceb42547d11dd1fe5c73abc8635b | |
parent | 45203a3b380cee28f570475c0d28c169f908c209 (diff) | |
parent | 8b3e7be437a6b62118d0485ad971e724afe23fdf (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/ath/ath9k/debug.c
net/mac80211/iface.c
206 files changed, 19923 insertions, 3391 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index 0f6a3edcd44b..ebe89694cf81 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl | |||
@@ -132,9 +132,7 @@ | |||
132 | !Finclude/net/cfg80211.h cfg80211_send_rx_assoc | 132 | !Finclude/net/cfg80211.h cfg80211_send_rx_assoc |
133 | !Finclude/net/cfg80211.h cfg80211_send_assoc_timeout | 133 | !Finclude/net/cfg80211.h cfg80211_send_assoc_timeout |
134 | !Finclude/net/cfg80211.h cfg80211_send_deauth | 134 | !Finclude/net/cfg80211.h cfg80211_send_deauth |
135 | !Finclude/net/cfg80211.h __cfg80211_send_deauth | ||
136 | !Finclude/net/cfg80211.h cfg80211_send_disassoc | 135 | !Finclude/net/cfg80211.h cfg80211_send_disassoc |
137 | !Finclude/net/cfg80211.h __cfg80211_send_disassoc | ||
138 | !Finclude/net/cfg80211.h cfg80211_ibss_joined | 136 | !Finclude/net/cfg80211.h cfg80211_ibss_joined |
139 | !Finclude/net/cfg80211.h cfg80211_connect_result | 137 | !Finclude/net/cfg80211.h cfg80211_connect_result |
140 | !Finclude/net/cfg80211.h cfg80211_roamed | 138 | !Finclude/net/cfg80211.h cfg80211_roamed |
diff --git a/MAINTAINERS b/MAINTAINERS index f35a259a6564..0518ec49467b 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 f3dc124c60c7..3b078515b422 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 e1714d7c9eeb..83e03857c014 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | |||
@@ -905,7 +905,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, | |||
905 | { | 905 | { |
906 | struct ath_common *common = ath9k_hw_common(ah); | 906 | struct ath_common *common = ath9k_hw_common(ah); |
907 | struct ath9k_channel *chan = ah->curchan; | 907 | struct ath9k_channel *chan = ah->curchan; |
908 | struct ar5416AniState *aniState = &chan->ani; | 908 | struct ar5416AniState *aniState = &ah->ani; |
909 | s32 value, value2; | 909 | s32 value, value2; |
910 | 910 | ||
911 | switch (cmd & ah->ani_function) { | 911 | switch (cmd & ah->ani_function) { |
@@ -1173,7 +1173,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1173 | struct ath9k_ani_default *iniDef; | 1173 | struct ath9k_ani_default *iniDef; |
1174 | u32 val; | 1174 | u32 val; |
1175 | 1175 | ||
1176 | aniState = &ah->curchan->ani; | 1176 | aniState = &ah->ani; |
1177 | iniDef = &aniState->iniDef; | 1177 | iniDef = &aniState->iniDef; |
1178 | 1178 | ||
1179 | ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", | 1179 | ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n", |
@@ -1214,7 +1214,7 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) | |||
1214 | /* these levels just got reset to defaults by the INI */ | 1214 | /* these levels just got reset to defaults by the INI */ |
1215 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; | 1215 | aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; |
1216 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; | 1216 | aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; |
1217 | aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; | 1217 | aniState->ofdmWeakSigDetect = true; |
1218 | aniState->mrcCCK = true; | 1218 | aniState->mrcCCK = true; |
1219 | } | 1219 | } |
1220 | 1220 | ||
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 42b03dc39d14..18fcee4e9d68 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -642,6 +642,7 @@ enum sc_op_flags { | |||
642 | SC_OP_ANI_RUN, | 642 | SC_OP_ANI_RUN, |
643 | SC_OP_PRIM_STA_VIF, | 643 | SC_OP_PRIM_STA_VIF, |
644 | SC_OP_HW_RESET, | 644 | SC_OP_HW_RESET, |
645 | SC_OP_SCANNING, | ||
645 | }; | 646 | }; |
646 | 647 | ||
647 | /* Powersave flags */ | 648 | /* Powersave flags */ |
@@ -755,7 +756,6 @@ struct ath_softc { | |||
755 | struct rchan *rfs_chan_spec_scan; | 756 | struct rchan *rfs_chan_spec_scan; |
756 | enum spectral_mode spectral_mode; | 757 | enum spectral_mode spectral_mode; |
757 | struct ath_spec_scan spec_config; | 758 | struct ath_spec_scan spec_config; |
758 | int scanning; | ||
759 | 759 | ||
760 | #ifdef CONFIG_PM_SLEEP | 760 | #ifdef CONFIG_PM_SLEEP |
761 | atomic_t wow_got_bmiss_intr; | 761 | 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 51cc0fa5cd3e..87454f6c7b4f 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 (kstrtoul(buf, 0, &disable_ani)) | 247 | if (kstrtoul(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) |
@@ -2059,8 +1774,8 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
2059 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask); | 1774 | sc->debug.debugfs_phy, sc, &fops_rx_chainmask); |
2060 | debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, | 1775 | debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR, |
2061 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); | 1776 | sc->debug.debugfs_phy, sc, &fops_tx_chainmask); |
2062 | debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR, | 1777 | debugfs_create_file("ani", S_IRUSR | S_IWUSR, |
2063 | sc->debug.debugfs_phy, sc, &fops_disable_ani); | 1778 | sc->debug.debugfs_phy, sc, &fops_ani); |
2064 | debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1779 | debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
2065 | &sc->sc_ah->config.enable_paprd); | 1780 | &sc->sc_ah->config.enable_paprd); |
2066 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, | 1781 | debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, |
@@ -2095,11 +1810,6 @@ int ath9k_init_debug(struct ath_hw *ah) | |||
2095 | debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, | 1810 | debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, |
2096 | sc->debug.debugfs_phy, sc, | 1811 | sc->debug.debugfs_phy, sc, |
2097 | &fops_spectral_fft_period); | 1812 | &fops_spectral_fft_period); |
2098 | |||
2099 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
2100 | debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, | ||
2101 | &fops_samps); | ||
2102 | #endif | ||
2103 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, | 1813 | debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, |
2104 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); | 1814 | sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); |
2105 | debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, | 1815 | 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 9d49aab8b989..fc679198a0f3 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); |
@@ -364,17 +318,4 @@ static inline void ath_debug_stat_rx(struct ath_softc *sc, | |||
364 | 318 | ||
365 | #endif /* CONFIG_ATH9K_DEBUGFS */ | 319 | #endif /* CONFIG_ATH9K_DEBUGFS */ |
366 | 320 | ||
367 | #ifdef CONFIG_ATH9K_MAC_DEBUG | ||
368 | |||
369 | void ath9k_debug_samp_bb_mac(struct ath_softc *sc); | ||
370 | |||
371 | #else | ||
372 | |||
373 | static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) | ||
374 | { | ||
375 | } | ||
376 | |||
377 | #endif | ||
378 | |||
379 | |||
380 | #endif /* DEBUG_H */ | 321 | #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 15dfefcf2d0f..d813ab8104d6 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 | } |
@@ -1250,10 +1248,10 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) | |||
1250 | 1248 | ||
1251 | switch (opmode) { | 1249 | switch (opmode) { |
1252 | case NL80211_IFTYPE_ADHOC: | 1250 | case NL80211_IFTYPE_ADHOC: |
1253 | case NL80211_IFTYPE_MESH_POINT: | ||
1254 | set |= AR_STA_ID1_ADHOC; | 1251 | set |= AR_STA_ID1_ADHOC; |
1255 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | 1252 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
1256 | break; | 1253 | break; |
1254 | case NL80211_IFTYPE_MESH_POINT: | ||
1257 | case NL80211_IFTYPE_AP: | 1255 | case NL80211_IFTYPE_AP: |
1258 | set |= AR_STA_ID1_STA_AP; | 1256 | set |= AR_STA_ID1_STA_AP; |
1259 | /* fall through */ | 1257 | /* fall through */ |
@@ -2255,12 +2253,12 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | |||
2255 | 2253 | ||
2256 | switch (ah->opmode) { | 2254 | switch (ah->opmode) { |
2257 | case NL80211_IFTYPE_ADHOC: | 2255 | case NL80211_IFTYPE_ADHOC: |
2258 | case NL80211_IFTYPE_MESH_POINT: | ||
2259 | REG_SET_BIT(ah, AR_TXCFG, | 2256 | REG_SET_BIT(ah, AR_TXCFG, |
2260 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); | 2257 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); |
2261 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + | 2258 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon + |
2262 | TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); | 2259 | TU_TO_USEC(ah->atim_window ? ah->atim_window : 1)); |
2263 | flags |= AR_NDP_TIMER_EN; | 2260 | flags |= AR_NDP_TIMER_EN; |
2261 | case NL80211_IFTYPE_MESH_POINT: | ||
2264 | case NL80211_IFTYPE_AP: | 2262 | case NL80211_IFTYPE_AP: |
2265 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); | 2263 | REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon); |
2266 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - | 2264 | REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon - |
@@ -2604,13 +2602,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
2604 | pCap->hw_caps |= ATH9K_HW_CAP_RTT; | 2602 | pCap->hw_caps |= ATH9K_HW_CAP_RTT; |
2605 | } | 2603 | } |
2606 | 2604 | ||
2607 | if (AR_SREV_9280_20_OR_LATER(ah)) { | 2605 | if (AR_SREV_9462(ah)) |
2608 | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | | 2606 | pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE; |
2609 | ATH9K_HW_WOW_PATTERN_MATCH_EXACT; | ||
2610 | |||
2611 | if (AR_SREV_9280(ah)) | ||
2612 | pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD; | ||
2613 | } | ||
2614 | 2607 | ||
2615 | if (AR_SREV_9300_20_OR_LATER(ah) && | 2608 | if (AR_SREV_9300_20_OR_LATER(ah) && |
2616 | ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) | 2609 | 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 aba415103f94..daba841808cf 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); |
@@ -769,12 +767,19 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
769 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | 767 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | |
770 | IEEE80211_HW_SUPPORTS_RC_TABLE; | 768 | IEEE80211_HW_SUPPORTS_RC_TABLE; |
771 | 769 | ||
772 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) | 770 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { |
773 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; | 771 | hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION; |
772 | |||
773 | if (AR_SREV_9280_20_OR_LATER(ah)) | ||
774 | hw->radiotap_mcs_details |= | ||
775 | IEEE80211_RADIOTAP_MCS_HAVE_STBC; | ||
776 | } | ||
774 | 777 | ||
775 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) | 778 | if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) |
776 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; | 779 | hw->flags |= IEEE80211_HW_MFP_CAPABLE; |
777 | 780 | ||
781 | hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; | ||
782 | |||
778 | hw->wiphy->interface_modes = | 783 | hw->wiphy->interface_modes = |
779 | BIT(NL80211_IFTYPE_P2P_GO) | | 784 | BIT(NL80211_IFTYPE_P2P_GO) | |
780 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | 785 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
@@ -795,21 +800,17 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
795 | hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 800 | hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
796 | 801 | ||
797 | #ifdef CONFIG_PM_SLEEP | 802 | #ifdef CONFIG_PM_SLEEP |
798 | |||
799 | if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && | 803 | if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && |
800 | device_can_wakeup(sc->dev)) { | 804 | device_can_wakeup(sc->dev)) { |
801 | |||
802 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | | 805 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | |
803 | WIPHY_WOWLAN_DISCONNECT; | 806 | WIPHY_WOWLAN_DISCONNECT; |
804 | hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN; | 807 | hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN; |
805 | hw->wiphy->wowlan.pattern_min_len = 1; | 808 | hw->wiphy->wowlan.pattern_min_len = 1; |
806 | hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE; | 809 | hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE; |
807 | |||
808 | } | 810 | } |
809 | 811 | ||
810 | atomic_set(&sc->wow_sleep_proc_intr, -1); | 812 | atomic_set(&sc->wow_sleep_proc_intr, -1); |
811 | atomic_set(&sc->wow_got_bmiss_intr, -1); | 813 | atomic_set(&sc->wow_got_bmiss_intr, -1); |
812 | |||
813 | #endif | 814 | #endif |
814 | 815 | ||
815 | hw->queues = 4; | 816 | 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 566109a40fb3..2ef05ebffbcf 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 5092ecae7706..e5b186b04b29 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 | } |
@@ -1690,7 +1689,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1690 | bool flush = false; | 1689 | bool flush = false; |
1691 | int ret = 0; | 1690 | int ret = 0; |
1692 | 1691 | ||
1693 | local_bh_disable(); | 1692 | mutex_lock(&sc->mutex); |
1694 | 1693 | ||
1695 | switch (action) { | 1694 | switch (action) { |
1696 | case IEEE80211_AMPDU_RX_START: | 1695 | case IEEE80211_AMPDU_RX_START: |
@@ -1723,7 +1722,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1723 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); | 1722 | ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); |
1724 | } | 1723 | } |
1725 | 1724 | ||
1726 | local_bh_enable(); | 1725 | mutex_unlock(&sc->mutex); |
1727 | 1726 | ||
1728 | return ret; | 1727 | return ret; |
1729 | } | 1728 | } |
@@ -2007,7 +2006,6 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
2007 | { | 2006 | { |
2008 | struct ath_hw *ah = sc->sc_ah; | 2007 | struct ath_hw *ah = sc->sc_ah; |
2009 | struct ath_common *common = ath9k_hw_common(ah); | 2008 | struct ath_common *common = ath9k_hw_common(ah); |
2010 | struct ath9k_hw_capabilities *pcaps = &ah->caps; | ||
2011 | int pattern_count = 0; | 2009 | int pattern_count = 0; |
2012 | int i, byte_cnt; | 2010 | int i, byte_cnt; |
2013 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; | 2011 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; |
@@ -2077,36 +2075,9 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | |||
2077 | 2075 | ||
2078 | /* Create Disassociate pattern mask */ | 2076 | /* Create Disassociate pattern mask */ |
2079 | 2077 | ||
2080 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { | 2078 | dis_deauth_mask[0] = 0xfe; |
2081 | 2079 | dis_deauth_mask[1] = 0x03; | |
2082 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { | 2080 | dis_deauth_mask[2] = 0xc0; |
2083 | /* | ||
2084 | * for AR9280, because of hardware limitation, the | ||
2085 | * first 4 bytes have to be matched for all patterns. | ||
2086 | * the mask for disassociation and de-auth pattern | ||
2087 | * matching need to enable the first 4 bytes. | ||
2088 | * also the duration field needs to be filled. | ||
2089 | */ | ||
2090 | dis_deauth_mask[0] = 0xf0; | ||
2091 | |||
2092 | /* | ||
2093 | * fill in duration field | ||
2094 | FIXME: what is the exact value ? | ||
2095 | */ | ||
2096 | dis_deauth_pattern[2] = 0xff; | ||
2097 | dis_deauth_pattern[3] = 0xff; | ||
2098 | } else { | ||
2099 | dis_deauth_mask[0] = 0xfe; | ||
2100 | } | ||
2101 | |||
2102 | dis_deauth_mask[1] = 0x03; | ||
2103 | dis_deauth_mask[2] = 0xc0; | ||
2104 | } else { | ||
2105 | dis_deauth_mask[0] = 0xef; | ||
2106 | dis_deauth_mask[1] = 0x3f; | ||
2107 | dis_deauth_mask[2] = 0x00; | ||
2108 | dis_deauth_mask[3] = 0xfc; | ||
2109 | } | ||
2110 | 2081 | ||
2111 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); | 2082 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); |
2112 | 2083 | ||
@@ -2342,15 +2313,13 @@ static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) | |||
2342 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | 2313 | static void ath9k_sw_scan_start(struct ieee80211_hw *hw) |
2343 | { | 2314 | { |
2344 | struct ath_softc *sc = hw->priv; | 2315 | struct ath_softc *sc = hw->priv; |
2345 | 2316 | set_bit(SC_OP_SCANNING, &sc->sc_flags); | |
2346 | sc->scanning = 1; | ||
2347 | } | 2317 | } |
2348 | 2318 | ||
2349 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) | 2319 | static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) |
2350 | { | 2320 | { |
2351 | struct ath_softc *sc = hw->priv; | 2321 | struct ath_softc *sc = hw->priv; |
2352 | 2322 | clear_bit(SC_OP_SCANNING, &sc->sc_flags); | |
2353 | sc->scanning = 0; | ||
2354 | } | 2323 | } |
2355 | 2324 | ||
2356 | struct ieee80211_ops ath9k_ops = { | 2325 | 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..0880742eab17 --- /dev/null +++ b/drivers/net/wireless/cw1200/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
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 | endif | ||
diff --git a/drivers/net/wireless/cw1200/Makefile b/drivers/net/wireless/cw1200/Makefile new file mode 100644 index 000000000000..b086aac6547a --- /dev/null +++ b/drivers/net/wireless/cw1200/Makefile | |||
@@ -0,0 +1,21 @@ | |||
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_PM) += pm.o | ||
13 | |||
14 | # CFLAGS_sta.o += -DDEBUG | ||
15 | |||
16 | cw1200_wlan_sdio-y := cw1200_sdio.o | ||
17 | cw1200_wlan_spi-y := cw1200_spi.o | ||
18 | |||
19 | obj-$(CONFIG_CW1200) += cw1200_core.o | ||
20 | obj-$(CONFIG_CW1200_WLAN_SDIO) += cw1200_wlan_sdio.o | ||
21 | 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..c1ec2a4dd8c0 --- /dev/null +++ b/drivers/net/wireless/cw1200/bh.c | |||
@@ -0,0 +1,619 @@ | |||
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 | */ | ||
36 | #define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) | ||
37 | #define PIGGYBACK_CTRL_REG (2) | ||
38 | #define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) | ||
39 | |||
40 | /* Suspend state privates */ | ||
41 | enum cw1200_bh_pm_state { | ||
42 | CW1200_BH_RESUMED = 0, | ||
43 | CW1200_BH_SUSPEND, | ||
44 | CW1200_BH_SUSPENDED, | ||
45 | CW1200_BH_RESUME, | ||
46 | }; | ||
47 | |||
48 | typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv, | ||
49 | u8 *data, size_t size); | ||
50 | |||
51 | static void cw1200_bh_work(struct work_struct *work) | ||
52 | { | ||
53 | struct cw1200_common *priv = | ||
54 | container_of(work, struct cw1200_common, bh_work); | ||
55 | cw1200_bh(priv); | ||
56 | } | ||
57 | |||
58 | int cw1200_register_bh(struct cw1200_common *priv) | ||
59 | { | ||
60 | int err = 0; | ||
61 | /* Realtime workqueue */ | ||
62 | priv->bh_workqueue = alloc_workqueue("cw1200_bh", | ||
63 | WQ_MEM_RECLAIM | WQ_HIGHPRI | ||
64 | | WQ_CPU_INTENSIVE, 1); | ||
65 | |||
66 | if (!priv->bh_workqueue) | ||
67 | return -ENOMEM; | ||
68 | |||
69 | INIT_WORK(&priv->bh_work, cw1200_bh_work); | ||
70 | |||
71 | pr_debug("[BH] register.\n"); | ||
72 | |||
73 | atomic_set(&priv->bh_rx, 0); | ||
74 | atomic_set(&priv->bh_tx, 0); | ||
75 | atomic_set(&priv->bh_term, 0); | ||
76 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); | ||
77 | priv->bh_error = 0; | ||
78 | priv->hw_bufs_used = 0; | ||
79 | priv->buf_id_tx = 0; | ||
80 | priv->buf_id_rx = 0; | ||
81 | init_waitqueue_head(&priv->bh_wq); | ||
82 | init_waitqueue_head(&priv->bh_evt_wq); | ||
83 | |||
84 | err = !queue_work(priv->bh_workqueue, &priv->bh_work); | ||
85 | WARN_ON(err); | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | void cw1200_unregister_bh(struct cw1200_common *priv) | ||
90 | { | ||
91 | atomic_add(1, &priv->bh_term); | ||
92 | wake_up(&priv->bh_wq); | ||
93 | |||
94 | flush_workqueue(priv->bh_workqueue); | ||
95 | |||
96 | destroy_workqueue(priv->bh_workqueue); | ||
97 | priv->bh_workqueue = NULL; | ||
98 | |||
99 | pr_debug("[BH] unregistered.\n"); | ||
100 | } | ||
101 | |||
102 | void cw1200_irq_handler(struct cw1200_common *priv) | ||
103 | { | ||
104 | pr_debug("[BH] irq.\n"); | ||
105 | |||
106 | /* Disable Interrupts! */ | ||
107 | /* NOTE: hwbus_ops->lock already held */ | ||
108 | __cw1200_irq_enable(priv, 0); | ||
109 | |||
110 | if (/* WARN_ON */(priv->bh_error)) | ||
111 | return; | ||
112 | |||
113 | if (atomic_add_return(1, &priv->bh_rx) == 1) | ||
114 | wake_up(&priv->bh_wq); | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(cw1200_irq_handler); | ||
117 | |||
118 | void cw1200_bh_wakeup(struct cw1200_common *priv) | ||
119 | { | ||
120 | pr_debug("[BH] wakeup.\n"); | ||
121 | if (priv->bh_error) { | ||
122 | pr_err("[BH] wakeup failed (BH error)\n"); | ||
123 | return; | ||
124 | } | ||
125 | |||
126 | if (atomic_add_return(1, &priv->bh_tx) == 1) | ||
127 | wake_up(&priv->bh_wq); | ||
128 | } | ||
129 | |||
130 | int cw1200_bh_suspend(struct cw1200_common *priv) | ||
131 | { | ||
132 | pr_debug("[BH] suspend.\n"); | ||
133 | if (priv->bh_error) { | ||
134 | wiphy_warn(priv->hw->wiphy, "BH error -- can't suspend\n"); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | atomic_set(&priv->bh_suspend, CW1200_BH_SUSPEND); | ||
139 | wake_up(&priv->bh_wq); | ||
140 | return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || | ||
141 | (CW1200_BH_SUSPENDED == atomic_read(&priv->bh_suspend)), | ||
142 | 1 * HZ) ? 0 : -ETIMEDOUT; | ||
143 | } | ||
144 | |||
145 | int cw1200_bh_resume(struct cw1200_common *priv) | ||
146 | { | ||
147 | pr_debug("[BH] resume.\n"); | ||
148 | if (priv->bh_error) { | ||
149 | wiphy_warn(priv->hw->wiphy, "BH error -- can't resume\n"); | ||
150 | return -EINVAL; | ||
151 | } | ||
152 | |||
153 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUME); | ||
154 | wake_up(&priv->bh_wq); | ||
155 | return wait_event_timeout(priv->bh_evt_wq, priv->bh_error || | ||
156 | (CW1200_BH_RESUMED == atomic_read(&priv->bh_suspend)), | ||
157 | 1 * HZ) ? 0 : -ETIMEDOUT; | ||
158 | } | ||
159 | |||
160 | static inline void wsm_alloc_tx_buffer(struct cw1200_common *priv) | ||
161 | { | ||
162 | ++priv->hw_bufs_used; | ||
163 | } | ||
164 | |||
165 | int wsm_release_tx_buffer(struct cw1200_common *priv, int count) | ||
166 | { | ||
167 | int ret = 0; | ||
168 | int hw_bufs_used = priv->hw_bufs_used; | ||
169 | |||
170 | priv->hw_bufs_used -= count; | ||
171 | if (WARN_ON(priv->hw_bufs_used < 0)) | ||
172 | ret = -1; | ||
173 | else if (hw_bufs_used >= priv->wsm_caps.input_buffers) | ||
174 | ret = 1; | ||
175 | if (!priv->hw_bufs_used) | ||
176 | wake_up(&priv->bh_evt_wq); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static int cw1200_bh_read_ctrl_reg(struct cw1200_common *priv, | ||
181 | u16 *ctrl_reg) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | ret = cw1200_reg_read_16(priv, | ||
186 | ST90TDS_CONTROL_REG_ID, ctrl_reg); | ||
187 | if (ret) { | ||
188 | ret = cw1200_reg_read_16(priv, | ||
189 | ST90TDS_CONTROL_REG_ID, ctrl_reg); | ||
190 | if (ret) | ||
191 | pr_err("[BH] Failed to read control register.\n"); | ||
192 | } | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static int cw1200_device_wakeup(struct cw1200_common *priv) | ||
198 | { | ||
199 | u16 ctrl_reg; | ||
200 | int ret; | ||
201 | |||
202 | pr_debug("[BH] Device wakeup.\n"); | ||
203 | |||
204 | /* First, set the dpll register */ | ||
205 | ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, | ||
206 | cw1200_dpll_from_clk(priv->hw_refclk)); | ||
207 | if (WARN_ON(ret)) | ||
208 | return ret; | ||
209 | |||
210 | /* To force the device to be always-on, the host sets WLAN_UP to 1 */ | ||
211 | ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, | ||
212 | ST90TDS_CONT_WUP_BIT); | ||
213 | if (WARN_ON(ret)) | ||
214 | return ret; | ||
215 | |||
216 | ret = cw1200_bh_read_ctrl_reg(priv, &ctrl_reg); | ||
217 | if (WARN_ON(ret)) | ||
218 | return ret; | ||
219 | |||
220 | /* If the device returns WLAN_RDY as 1, the device is active and will | ||
221 | * remain active. | ||
222 | */ | ||
223 | if (ctrl_reg & ST90TDS_CONT_RDY_BIT) { | ||
224 | pr_debug("[BH] Device awake.\n"); | ||
225 | return 1; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* Must be called from BH thraed. */ | ||
232 | void cw1200_enable_powersave(struct cw1200_common *priv, | ||
233 | bool enable) | ||
234 | { | ||
235 | pr_debug("[BH] Powerave is %s.\n", | ||
236 | enable ? "enabled" : "disabled"); | ||
237 | priv->powersave_enabled = enable; | ||
238 | } | ||
239 | |||
240 | static int cw1200_bh_rx_helper(struct cw1200_common *priv, | ||
241 | uint16_t *ctrl_reg, | ||
242 | int *tx) | ||
243 | { | ||
244 | size_t read_len = 0; | ||
245 | struct sk_buff *skb_rx = NULL; | ||
246 | struct wsm_hdr *wsm; | ||
247 | size_t wsm_len; | ||
248 | u16 wsm_id; | ||
249 | u8 wsm_seq; | ||
250 | int rx_resync = 1; | ||
251 | |||
252 | size_t alloc_len; | ||
253 | u8 *data; | ||
254 | |||
255 | read_len = (*ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) * 2; | ||
256 | if (!read_len) | ||
257 | return 0; /* No more work */ | ||
258 | |||
259 | if (WARN_ON((read_len < sizeof(struct wsm_hdr)) || | ||
260 | (read_len > EFFECTIVE_BUF_SIZE))) { | ||
261 | pr_debug("Invalid read len: %zu (%04x)", | ||
262 | read_len, *ctrl_reg); | ||
263 | goto err; | ||
264 | } | ||
265 | |||
266 | /* Add SIZE of PIGGYBACK reg (CONTROL Reg) | ||
267 | * to the NEXT Message length + 2 Bytes for SKB | ||
268 | */ | ||
269 | read_len = read_len + 2; | ||
270 | |||
271 | alloc_len = priv->hwbus_ops->align_size( | ||
272 | priv->hwbus_priv, read_len); | ||
273 | |||
274 | /* Check if not exceeding CW1200 capabilities */ | ||
275 | if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { | ||
276 | pr_debug("Read aligned len: %zu\n", | ||
277 | alloc_len); | ||
278 | } | ||
279 | |||
280 | skb_rx = dev_alloc_skb(alloc_len); | ||
281 | if (WARN_ON(!skb_rx)) | ||
282 | goto err; | ||
283 | |||
284 | skb_trim(skb_rx, 0); | ||
285 | skb_put(skb_rx, read_len); | ||
286 | data = skb_rx->data; | ||
287 | if (WARN_ON(!data)) | ||
288 | goto err; | ||
289 | |||
290 | if (WARN_ON(cw1200_data_read(priv, data, alloc_len))) { | ||
291 | pr_err("rx blew up, len %zu\n", alloc_len); | ||
292 | goto err; | ||
293 | } | ||
294 | |||
295 | /* Piggyback */ | ||
296 | *ctrl_reg = __le16_to_cpu( | ||
297 | ((__le16 *)data)[alloc_len / 2 - 1]); | ||
298 | |||
299 | wsm = (struct wsm_hdr *)data; | ||
300 | wsm_len = __le16_to_cpu(wsm->len); | ||
301 | if (WARN_ON(wsm_len > read_len)) | ||
302 | goto err; | ||
303 | |||
304 | if (priv->wsm_enable_wsm_dumps) | ||
305 | print_hex_dump_bytes("<-- ", | ||
306 | DUMP_PREFIX_NONE, | ||
307 | data, wsm_len); | ||
308 | |||
309 | wsm_id = __le16_to_cpu(wsm->id) & 0xFFF; | ||
310 | wsm_seq = (__le16_to_cpu(wsm->id) >> 13) & 7; | ||
311 | |||
312 | skb_trim(skb_rx, wsm_len); | ||
313 | |||
314 | if (wsm_id == 0x0800) { | ||
315 | wsm_handle_exception(priv, | ||
316 | &data[sizeof(*wsm)], | ||
317 | wsm_len - sizeof(*wsm)); | ||
318 | goto err; | ||
319 | } else if (!rx_resync) { | ||
320 | if (WARN_ON(wsm_seq != priv->wsm_rx_seq)) | ||
321 | goto err; | ||
322 | } | ||
323 | priv->wsm_rx_seq = (wsm_seq + 1) & 7; | ||
324 | rx_resync = 0; | ||
325 | |||
326 | if (wsm_id & 0x0400) { | ||
327 | int rc = wsm_release_tx_buffer(priv, 1); | ||
328 | if (WARN_ON(rc < 0)) | ||
329 | return rc; | ||
330 | else if (rc > 0) | ||
331 | *tx = 1; | ||
332 | } | ||
333 | |||
334 | /* cw1200_wsm_rx takes care on SKB livetime */ | ||
335 | if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx))) | ||
336 | goto err; | ||
337 | |||
338 | if (skb_rx) { | ||
339 | dev_kfree_skb(skb_rx); | ||
340 | skb_rx = NULL; | ||
341 | } | ||
342 | |||
343 | return 0; | ||
344 | |||
345 | err: | ||
346 | if (skb_rx) { | ||
347 | dev_kfree_skb(skb_rx); | ||
348 | skb_rx = NULL; | ||
349 | } | ||
350 | return -1; | ||
351 | } | ||
352 | |||
353 | static int cw1200_bh_tx_helper(struct cw1200_common *priv, | ||
354 | int *pending_tx, | ||
355 | int *tx_burst) | ||
356 | { | ||
357 | size_t tx_len; | ||
358 | u8 *data; | ||
359 | int ret; | ||
360 | struct wsm_hdr *wsm; | ||
361 | |||
362 | if (priv->device_can_sleep) { | ||
363 | ret = cw1200_device_wakeup(priv); | ||
364 | if (WARN_ON(ret < 0)) { /* Error in wakeup */ | ||
365 | *pending_tx = 1; | ||
366 | return 0; | ||
367 | } else if (ret) { /* Woke up */ | ||
368 | priv->device_can_sleep = false; | ||
369 | } else { /* Did not awake */ | ||
370 | *pending_tx = 1; | ||
371 | return 0; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | wsm_alloc_tx_buffer(priv); | ||
376 | ret = wsm_get_tx(priv, &data, &tx_len, tx_burst); | ||
377 | if (ret <= 0) { | ||
378 | wsm_release_tx_buffer(priv, 1); | ||
379 | if (WARN_ON(ret < 0)) | ||
380 | return ret; /* Error */ | ||
381 | return 0; /* No work */ | ||
382 | } | ||
383 | |||
384 | wsm = (struct wsm_hdr *)data; | ||
385 | BUG_ON(tx_len < sizeof(*wsm)); | ||
386 | BUG_ON(__le16_to_cpu(wsm->len) != tx_len); | ||
387 | |||
388 | atomic_add(1, &priv->bh_tx); | ||
389 | |||
390 | tx_len = priv->hwbus_ops->align_size( | ||
391 | priv->hwbus_priv, tx_len); | ||
392 | |||
393 | /* Check if not exceeding CW1200 capabilities */ | ||
394 | if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE)) | ||
395 | pr_debug("Write aligned len: %zu\n", tx_len); | ||
396 | |||
397 | wsm->id &= __cpu_to_le16(0xffff ^ WSM_TX_SEQ(WSM_TX_SEQ_MAX)); | ||
398 | wsm->id |= __cpu_to_le16(WSM_TX_SEQ(priv->wsm_tx_seq)); | ||
399 | |||
400 | if (WARN_ON(cw1200_data_write(priv, data, tx_len))) { | ||
401 | pr_err("tx blew up, len %zu\n", tx_len); | ||
402 | wsm_release_tx_buffer(priv, 1); | ||
403 | return -1; /* Error */ | ||
404 | } | ||
405 | |||
406 | if (priv->wsm_enable_wsm_dumps) | ||
407 | print_hex_dump_bytes("--> ", | ||
408 | DUMP_PREFIX_NONE, | ||
409 | data, | ||
410 | __le16_to_cpu(wsm->len)); | ||
411 | |||
412 | wsm_txed(priv, data); | ||
413 | priv->wsm_tx_seq = (priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; | ||
414 | |||
415 | if (*tx_burst > 1) { | ||
416 | cw1200_debug_tx_burst(priv); | ||
417 | return 1; /* Work remains */ | ||
418 | } | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int cw1200_bh(void *arg) | ||
424 | { | ||
425 | struct cw1200_common *priv = arg; | ||
426 | int rx, tx, term, suspend; | ||
427 | u16 ctrl_reg = 0; | ||
428 | int tx_allowed; | ||
429 | int pending_tx = 0; | ||
430 | int tx_burst; | ||
431 | long status; | ||
432 | u32 dummy; | ||
433 | int ret; | ||
434 | |||
435 | for (;;) { | ||
436 | if (!priv->hw_bufs_used && | ||
437 | priv->powersave_enabled && | ||
438 | !priv->device_can_sleep && | ||
439 | !atomic_read(&priv->recent_scan)) { | ||
440 | status = 1 * HZ; | ||
441 | pr_debug("[BH] Device wakedown. No data.\n"); | ||
442 | cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, 0); | ||
443 | priv->device_can_sleep = true; | ||
444 | } else if (priv->hw_bufs_used) { | ||
445 | /* Interrupt loss detection */ | ||
446 | status = 1 * HZ; | ||
447 | } else { | ||
448 | status = MAX_SCHEDULE_TIMEOUT; | ||
449 | } | ||
450 | |||
451 | /* Dummy Read for SDIO retry mechanism*/ | ||
452 | if ((priv->hw_type != -1) && | ||
453 | (atomic_read(&priv->bh_rx) == 0) && | ||
454 | (atomic_read(&priv->bh_tx) == 0)) | ||
455 | cw1200_reg_read(priv, ST90TDS_CONFIG_REG_ID, | ||
456 | &dummy, sizeof(dummy)); | ||
457 | |||
458 | pr_debug("[BH] waiting ...\n"); | ||
459 | status = wait_event_interruptible_timeout(priv->bh_wq, ({ | ||
460 | rx = atomic_xchg(&priv->bh_rx, 0); | ||
461 | tx = atomic_xchg(&priv->bh_tx, 0); | ||
462 | term = atomic_xchg(&priv->bh_term, 0); | ||
463 | suspend = pending_tx ? | ||
464 | 0 : atomic_read(&priv->bh_suspend); | ||
465 | (rx || tx || term || suspend || priv->bh_error); | ||
466 | }), status); | ||
467 | |||
468 | pr_debug("[BH] - rx: %d, tx: %d, term: %d, suspend: %d, status: %ld\n", | ||
469 | rx, tx, term, suspend, status); | ||
470 | |||
471 | /* Did an error occur? */ | ||
472 | if ((status < 0 && status != -ERESTARTSYS) || | ||
473 | term || priv->bh_error) { | ||
474 | break; | ||
475 | } | ||
476 | if (!status) { /* wait_event timed out */ | ||
477 | unsigned long timestamp = jiffies; | ||
478 | long timeout; | ||
479 | int pending = 0; | ||
480 | int i; | ||
481 | |||
482 | /* Check to see if we have any outstanding frames */ | ||
483 | if (priv->hw_bufs_used && (!rx || !tx)) { | ||
484 | wiphy_warn(priv->hw->wiphy, | ||
485 | "Missed interrupt? (%d frames outstanding)\n", | ||
486 | priv->hw_bufs_used); | ||
487 | rx = 1; | ||
488 | |||
489 | /* Get a timestamp of "oldest" frame */ | ||
490 | for (i = 0; i < 4; ++i) | ||
491 | pending += cw1200_queue_get_xmit_timestamp( | ||
492 | &priv->tx_queue[i], | ||
493 | ×tamp, | ||
494 | priv->pending_frame_id); | ||
495 | |||
496 | /* Check if frame transmission is timed out. | ||
497 | * Add an extra second with respect to possible | ||
498 | * interrupt loss. | ||
499 | */ | ||
500 | timeout = timestamp + | ||
501 | WSM_CMD_LAST_CHANCE_TIMEOUT + | ||
502 | 1 * HZ - | ||
503 | jiffies; | ||
504 | |||
505 | /* And terminate BH thread if the frame is "stuck" */ | ||
506 | if (pending && timeout < 0) { | ||
507 | wiphy_warn(priv->hw->wiphy, | ||
508 | "Timeout waiting for TX confirm (%d/%d pending, %ld vs %lu).\n", | ||
509 | priv->hw_bufs_used, pending, | ||
510 | timestamp, jiffies); | ||
511 | break; | ||
512 | } | ||
513 | } else if (!priv->device_can_sleep && | ||
514 | !atomic_read(&priv->recent_scan)) { | ||
515 | pr_debug("[BH] Device wakedown. Timeout.\n"); | ||
516 | cw1200_reg_write_16(priv, | ||
517 | ST90TDS_CONTROL_REG_ID, 0); | ||
518 | priv->device_can_sleep = true; | ||
519 | } | ||
520 | goto done; | ||
521 | } else if (suspend) { | ||
522 | pr_debug("[BH] Device suspend.\n"); | ||
523 | if (priv->powersave_enabled) { | ||
524 | pr_debug("[BH] Device wakedown. Suspend.\n"); | ||
525 | cw1200_reg_write_16(priv, | ||
526 | ST90TDS_CONTROL_REG_ID, 0); | ||
527 | priv->device_can_sleep = true; | ||
528 | } | ||
529 | |||
530 | atomic_set(&priv->bh_suspend, CW1200_BH_SUSPENDED); | ||
531 | wake_up(&priv->bh_evt_wq); | ||
532 | status = wait_event_interruptible(priv->bh_wq, | ||
533 | CW1200_BH_RESUME == atomic_read(&priv->bh_suspend)); | ||
534 | if (status < 0) { | ||
535 | wiphy_err(priv->hw->wiphy, | ||
536 | "Failed to wait for resume: %ld.\n", | ||
537 | status); | ||
538 | break; | ||
539 | } | ||
540 | pr_debug("[BH] Device resume.\n"); | ||
541 | atomic_set(&priv->bh_suspend, CW1200_BH_RESUMED); | ||
542 | wake_up(&priv->bh_evt_wq); | ||
543 | atomic_add(1, &priv->bh_rx); | ||
544 | goto done; | ||
545 | } | ||
546 | |||
547 | rx: | ||
548 | tx += pending_tx; | ||
549 | pending_tx = 0; | ||
550 | |||
551 | if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) | ||
552 | break; | ||
553 | |||
554 | /* Don't bother trying to rx unless we have data to read */ | ||
555 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { | ||
556 | ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); | ||
557 | if (ret < 0) | ||
558 | break; | ||
559 | /* Double up here if there's more data.. */ | ||
560 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) { | ||
561 | ret = cw1200_bh_rx_helper(priv, &ctrl_reg, &tx); | ||
562 | if (ret < 0) | ||
563 | break; | ||
564 | } | ||
565 | } | ||
566 | |||
567 | tx: | ||
568 | if (tx) { | ||
569 | tx = 0; | ||
570 | |||
571 | BUG_ON(priv->hw_bufs_used > priv->wsm_caps.input_buffers); | ||
572 | tx_burst = priv->wsm_caps.input_buffers - priv->hw_bufs_used; | ||
573 | tx_allowed = tx_burst > 0; | ||
574 | |||
575 | if (!tx_allowed) { | ||
576 | /* Buffers full. Ensure we process tx | ||
577 | * after we handle rx.. | ||
578 | */ | ||
579 | pending_tx = tx; | ||
580 | goto done_rx; | ||
581 | } | ||
582 | ret = cw1200_bh_tx_helper(priv, &pending_tx, &tx_burst); | ||
583 | if (ret < 0) | ||
584 | break; | ||
585 | if (ret > 0) /* More to transmit */ | ||
586 | tx = ret; | ||
587 | |||
588 | /* Re-read ctrl reg */ | ||
589 | if (cw1200_bh_read_ctrl_reg(priv, &ctrl_reg)) | ||
590 | break; | ||
591 | } | ||
592 | |||
593 | done_rx: | ||
594 | if (priv->bh_error) | ||
595 | break; | ||
596 | if (ctrl_reg & ST90TDS_CONT_NEXT_LEN_MASK) | ||
597 | goto rx; | ||
598 | if (tx) | ||
599 | goto tx; | ||
600 | |||
601 | done: | ||
602 | /* Re-enable device interrupts */ | ||
603 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
604 | __cw1200_irq_enable(priv, 1); | ||
605 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
606 | } | ||
607 | |||
608 | /* Explicitly disable device interrupts */ | ||
609 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
610 | __cw1200_irq_enable(priv, 0); | ||
611 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
612 | |||
613 | if (!term) { | ||
614 | pr_err("[BH] Fatal error, exiting.\n"); | ||
615 | priv->bh_error = 1; | ||
616 | /* TODO: schedule_work(recovery) */ | ||
617 | } | ||
618 | return 0; | ||
619 | } | ||
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..243e96353d13 --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200.h | |||
@@ -0,0 +1,323 @@ | |||
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 | #define CW1200_MAX_CTRL_FRAME_LEN (0x1000) | ||
39 | |||
40 | #define CW1200_MAX_STA_IN_AP_MODE (5) | ||
41 | #define CW1200_LINK_ID_AFTER_DTIM (CW1200_MAX_STA_IN_AP_MODE + 1) | ||
42 | #define CW1200_LINK_ID_UAPSD (CW1200_MAX_STA_IN_AP_MODE + 2) | ||
43 | #define CW1200_LINK_ID_MAX (CW1200_MAX_STA_IN_AP_MODE + 3) | ||
44 | #define CW1200_MAX_REQUEUE_ATTEMPTS (5) | ||
45 | |||
46 | #define CW1200_MAX_TID (8) | ||
47 | |||
48 | #define CW1200_BLOCK_ACK_CNT (30) | ||
49 | #define CW1200_BLOCK_ACK_THLD (800) | ||
50 | #define CW1200_BLOCK_ACK_HIST (3) | ||
51 | #define CW1200_BLOCK_ACK_INTERVAL (1 * HZ / CW1200_BLOCK_ACK_HIST) | ||
52 | |||
53 | #define CW1200_JOIN_TIMEOUT (1 * HZ) | ||
54 | #define CW1200_AUTH_TIMEOUT (5 * HZ) | ||
55 | |||
56 | struct cw1200_ht_info { | ||
57 | struct ieee80211_sta_ht_cap ht_cap; | ||
58 | enum nl80211_channel_type channel_type; | ||
59 | u16 operation_mode; | ||
60 | }; | ||
61 | |||
62 | /* Please keep order */ | ||
63 | enum cw1200_join_status { | ||
64 | CW1200_JOIN_STATUS_PASSIVE = 0, | ||
65 | CW1200_JOIN_STATUS_MONITOR, | ||
66 | CW1200_JOIN_STATUS_JOINING, | ||
67 | CW1200_JOIN_STATUS_PRE_STA, | ||
68 | CW1200_JOIN_STATUS_STA, | ||
69 | CW1200_JOIN_STATUS_IBSS, | ||
70 | CW1200_JOIN_STATUS_AP, | ||
71 | }; | ||
72 | |||
73 | enum cw1200_link_status { | ||
74 | CW1200_LINK_OFF, | ||
75 | CW1200_LINK_RESERVE, | ||
76 | CW1200_LINK_SOFT, | ||
77 | CW1200_LINK_HARD, | ||
78 | CW1200_LINK_RESET, | ||
79 | CW1200_LINK_RESET_REMAP, | ||
80 | }; | ||
81 | |||
82 | extern int cw1200_power_mode; | ||
83 | extern const char * const cw1200_fw_types[]; | ||
84 | |||
85 | struct cw1200_link_entry { | ||
86 | unsigned long timestamp; | ||
87 | enum cw1200_link_status status; | ||
88 | enum cw1200_link_status prev_status; | ||
89 | u8 mac[ETH_ALEN]; | ||
90 | u8 buffered[CW1200_MAX_TID]; | ||
91 | struct sk_buff_head rx_queue; | ||
92 | }; | ||
93 | |||
94 | struct cw1200_common { | ||
95 | /* interfaces to the rest of the stack */ | ||
96 | struct ieee80211_hw *hw; | ||
97 | struct ieee80211_vif *vif; | ||
98 | struct device *pdev; | ||
99 | |||
100 | /* Statistics */ | ||
101 | struct ieee80211_low_level_stats stats; | ||
102 | |||
103 | /* Our macaddr */ | ||
104 | u8 mac_addr[ETH_ALEN]; | ||
105 | |||
106 | /* Hardware interface */ | ||
107 | const struct hwbus_ops *hwbus_ops; | ||
108 | struct hwbus_priv *hwbus_priv; | ||
109 | |||
110 | /* Hardware information */ | ||
111 | enum { | ||
112 | HIF_9000_SILICON_VERSATILE = 0, | ||
113 | HIF_8601_VERSATILE, | ||
114 | HIF_8601_SILICON, | ||
115 | } hw_type; | ||
116 | enum { | ||
117 | CW1200_HW_REV_CUT10 = 10, | ||
118 | CW1200_HW_REV_CUT11 = 11, | ||
119 | CW1200_HW_REV_CUT20 = 20, | ||
120 | CW1200_HW_REV_CUT22 = 22, | ||
121 | CW1X60_HW_REV = 40, | ||
122 | } hw_revision; | ||
123 | int hw_refclk; | ||
124 | bool hw_have_5ghz; | ||
125 | const struct firmware *sdd; | ||
126 | char *sdd_path; | ||
127 | |||
128 | struct cw1200_debug_priv *debug; | ||
129 | |||
130 | struct workqueue_struct *workqueue; | ||
131 | struct mutex conf_mutex; | ||
132 | |||
133 | struct cw1200_queue tx_queue[4]; | ||
134 | struct cw1200_queue_stats tx_queue_stats; | ||
135 | int tx_burst_idx; | ||
136 | |||
137 | /* firmware/hardware info */ | ||
138 | unsigned int tx_hdr_len; | ||
139 | |||
140 | /* Radio data */ | ||
141 | int output_power; | ||
142 | |||
143 | /* BBP/MAC state */ | ||
144 | struct ieee80211_rate *rates; | ||
145 | struct ieee80211_rate *mcs_rates; | ||
146 | struct ieee80211_channel *channel; | ||
147 | struct wsm_edca_params edca; | ||
148 | struct wsm_tx_queue_params tx_queue_params; | ||
149 | struct wsm_mib_association_mode association_mode; | ||
150 | struct wsm_set_bss_params bss_params; | ||
151 | struct cw1200_ht_info ht_info; | ||
152 | struct wsm_set_pm powersave_mode; | ||
153 | struct wsm_set_pm firmware_ps_mode; | ||
154 | int cqm_rssi_thold; | ||
155 | unsigned cqm_rssi_hyst; | ||
156 | bool cqm_use_rssi; | ||
157 | int cqm_beacon_loss_count; | ||
158 | int channel_switch_in_progress; | ||
159 | wait_queue_head_t channel_switch_done; | ||
160 | u8 long_frame_max_tx_count; | ||
161 | u8 short_frame_max_tx_count; | ||
162 | int mode; | ||
163 | bool enable_beacon; | ||
164 | int beacon_int; | ||
165 | bool listening; | ||
166 | struct wsm_rx_filter rx_filter; | ||
167 | struct wsm_mib_multicast_filter multicast_filter; | ||
168 | bool has_multicast_subscription; | ||
169 | bool disable_beacon_filter; | ||
170 | struct work_struct update_filtering_work; | ||
171 | struct work_struct set_beacon_wakeup_period_work; | ||
172 | |||
173 | u8 ba_rx_tid_mask; | ||
174 | u8 ba_tx_tid_mask; | ||
175 | |||
176 | struct cw1200_pm_state pm_state; | ||
177 | |||
178 | struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; | ||
179 | struct wsm_uapsd_info uapsd_info; | ||
180 | bool setbssparams_done; | ||
181 | bool bt_present; | ||
182 | u8 conf_listen_interval; | ||
183 | u32 listen_interval; | ||
184 | u32 erp_info; | ||
185 | u32 rts_threshold; | ||
186 | |||
187 | /* BH */ | ||
188 | atomic_t bh_rx; | ||
189 | atomic_t bh_tx; | ||
190 | atomic_t bh_term; | ||
191 | atomic_t bh_suspend; | ||
192 | |||
193 | struct workqueue_struct *bh_workqueue; | ||
194 | struct work_struct bh_work; | ||
195 | |||
196 | int bh_error; | ||
197 | wait_queue_head_t bh_wq; | ||
198 | wait_queue_head_t bh_evt_wq; | ||
199 | u8 buf_id_tx; | ||
200 | u8 buf_id_rx; | ||
201 | u8 wsm_rx_seq; | ||
202 | u8 wsm_tx_seq; | ||
203 | int hw_bufs_used; | ||
204 | bool powersave_enabled; | ||
205 | bool device_can_sleep; | ||
206 | |||
207 | /* Scan status */ | ||
208 | struct cw1200_scan scan; | ||
209 | /* Keep cw1200 awake (WUP = 1) 1 second after each scan to avoid | ||
210 | * FW issue with sleeping/waking up. | ||
211 | */ | ||
212 | atomic_t recent_scan; | ||
213 | struct delayed_work clear_recent_scan_work; | ||
214 | |||
215 | /* WSM */ | ||
216 | struct wsm_startup_ind wsm_caps; | ||
217 | struct mutex wsm_cmd_mux; | ||
218 | struct wsm_buf wsm_cmd_buf; | ||
219 | struct wsm_cmd wsm_cmd; | ||
220 | wait_queue_head_t wsm_cmd_wq; | ||
221 | wait_queue_head_t wsm_startup_done; | ||
222 | int firmware_ready; | ||
223 | atomic_t tx_lock; | ||
224 | |||
225 | /* WSM debug */ | ||
226 | int wsm_enable_wsm_dumps; | ||
227 | |||
228 | /* WSM Join */ | ||
229 | enum cw1200_join_status join_status; | ||
230 | u32 pending_frame_id; | ||
231 | bool join_pending; | ||
232 | struct delayed_work join_timeout; | ||
233 | struct work_struct unjoin_work; | ||
234 | struct work_struct join_complete_work; | ||
235 | int join_complete_status; | ||
236 | int join_dtim_period; | ||
237 | bool delayed_unjoin; | ||
238 | |||
239 | /* TX/RX and security */ | ||
240 | s8 wep_default_key_id; | ||
241 | struct work_struct wep_key_work; | ||
242 | u32 key_map; | ||
243 | struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; | ||
244 | |||
245 | /* AP powersave */ | ||
246 | u32 link_id_map; | ||
247 | struct cw1200_link_entry link_id_db[CW1200_MAX_STA_IN_AP_MODE]; | ||
248 | struct work_struct link_id_work; | ||
249 | struct delayed_work link_id_gc_work; | ||
250 | u32 sta_asleep_mask; | ||
251 | u32 pspoll_mask; | ||
252 | bool aid0_bit_set; | ||
253 | spinlock_t ps_state_lock; /* Protect power save state */ | ||
254 | bool buffered_multicasts; | ||
255 | bool tx_multicast; | ||
256 | struct work_struct set_tim_work; | ||
257 | struct work_struct set_cts_work; | ||
258 | struct work_struct multicast_start_work; | ||
259 | struct work_struct multicast_stop_work; | ||
260 | struct timer_list mcast_timeout; | ||
261 | |||
262 | /* WSM events and CQM implementation */ | ||
263 | spinlock_t event_queue_lock; /* Protect event queue */ | ||
264 | struct list_head event_queue; | ||
265 | struct work_struct event_handler; | ||
266 | |||
267 | struct delayed_work bss_loss_work; | ||
268 | spinlock_t bss_loss_lock; /* Protect BSS loss state */ | ||
269 | int bss_loss_state; | ||
270 | int bss_loss_confirm_id; | ||
271 | int delayed_link_loss; | ||
272 | struct work_struct bss_params_work; | ||
273 | |||
274 | /* TX rate policy cache */ | ||
275 | struct tx_policy_cache tx_policy_cache; | ||
276 | struct work_struct tx_policy_upload_work; | ||
277 | |||
278 | /* legacy PS mode switch in suspend */ | ||
279 | int ps_mode_switch_in_progress; | ||
280 | wait_queue_head_t ps_mode_switch_done; | ||
281 | |||
282 | /* Workaround for WFD testcase 6.1.10*/ | ||
283 | struct work_struct linkid_reset_work; | ||
284 | u8 action_frame_sa[ETH_ALEN]; | ||
285 | u8 action_linkid; | ||
286 | }; | ||
287 | |||
288 | struct cw1200_sta_priv { | ||
289 | int link_id; | ||
290 | }; | ||
291 | |||
292 | /* interfaces for the drivers */ | ||
293 | int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, | ||
294 | struct hwbus_priv *hwbus, | ||
295 | struct device *pdev, | ||
296 | struct cw1200_common **pself, | ||
297 | int ref_clk, const u8 *macaddr, | ||
298 | const char *sdd_path, bool have_5ghz); | ||
299 | void cw1200_core_release(struct cw1200_common *self); | ||
300 | |||
301 | #define FWLOAD_BLOCK_SIZE (1024) | ||
302 | |||
303 | static inline int cw1200_is_ht(const struct cw1200_ht_info *ht_info) | ||
304 | { | ||
305 | return ht_info->channel_type != NL80211_CHAN_NO_HT; | ||
306 | } | ||
307 | |||
308 | static inline int cw1200_ht_greenfield(const struct cw1200_ht_info *ht_info) | ||
309 | { | ||
310 | return cw1200_is_ht(ht_info) && | ||
311 | (ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && | ||
312 | !(ht_info->operation_mode & | ||
313 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||
314 | } | ||
315 | |||
316 | static inline int cw1200_ht_ampdu_density(const struct cw1200_ht_info *ht_info) | ||
317 | { | ||
318 | if (!cw1200_is_ht(ht_info)) | ||
319 | return 0; | ||
320 | return ht_info->ht_cap.ampdu_density; | ||
321 | } | ||
322 | |||
323 | #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..ebdcdf44f155 --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200_sdio.c | |||
@@ -0,0 +1,425 @@ | |||
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 | */ | ||
328 | static void cw1200_sdio_disconnect(struct sdio_func *func) | ||
329 | { | ||
330 | struct hwbus_priv *self = sdio_get_drvdata(func); | ||
331 | |||
332 | if (self) { | ||
333 | cw1200_sdio_irq_unsubscribe(self); | ||
334 | if (self->core) { | ||
335 | cw1200_core_release(self->core); | ||
336 | self->core = NULL; | ||
337 | } | ||
338 | sdio_claim_host(func); | ||
339 | sdio_disable_func(func); | ||
340 | sdio_release_host(func); | ||
341 | sdio_set_drvdata(func, NULL); | ||
342 | kfree(self); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | #ifdef CONFIG_PM | ||
347 | static int cw1200_sdio_suspend(struct device *dev) | ||
348 | { | ||
349 | int ret; | ||
350 | struct sdio_func *func = dev_to_sdio_func(dev); | ||
351 | struct hwbus_priv *self = sdio_get_drvdata(func); | ||
352 | |||
353 | if (!cw1200_can_suspend(self->core)) | ||
354 | return -EAGAIN; | ||
355 | |||
356 | /* Notify SDIO that CW1200 will remain powered during suspend */ | ||
357 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); | ||
358 | if (ret) | ||
359 | pr_err("Error setting SDIO pm flags: %i\n", ret); | ||
360 | |||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | static int cw1200_sdio_resume(struct device *dev) | ||
365 | { | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static const struct dev_pm_ops cw1200_pm_ops = { | ||
370 | .suspend = cw1200_sdio_suspend, | ||
371 | .resume = cw1200_sdio_resume, | ||
372 | }; | ||
373 | #endif | ||
374 | |||
375 | static struct sdio_driver sdio_driver = { | ||
376 | .name = "cw1200_wlan_sdio", | ||
377 | .id_table = cw1200_sdio_ids, | ||
378 | .probe = cw1200_sdio_probe, | ||
379 | .remove = cw1200_sdio_disconnect, | ||
380 | #ifdef CONFIG_PM | ||
381 | .drv = { | ||
382 | .pm = &cw1200_pm_ops, | ||
383 | } | ||
384 | #endif | ||
385 | }; | ||
386 | |||
387 | /* Init Module function -> Called by insmod */ | ||
388 | static int __init cw1200_sdio_init(void) | ||
389 | { | ||
390 | const struct cw1200_platform_data_sdio *pdata; | ||
391 | int ret; | ||
392 | |||
393 | /* FIXME -- this won't support multiple devices */ | ||
394 | pdata = global_plat_data; | ||
395 | |||
396 | if (cw1200_sdio_on(pdata)) { | ||
397 | ret = -1; | ||
398 | goto err; | ||
399 | } | ||
400 | |||
401 | ret = sdio_register_driver(&sdio_driver); | ||
402 | if (ret) | ||
403 | goto err; | ||
404 | |||
405 | return 0; | ||
406 | |||
407 | err: | ||
408 | cw1200_sdio_off(pdata); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | /* Called at Driver Unloading */ | ||
413 | static void __exit cw1200_sdio_exit(void) | ||
414 | { | ||
415 | const struct cw1200_platform_data_sdio *pdata; | ||
416 | |||
417 | /* FIXME -- this won't support multiple devices */ | ||
418 | pdata = global_plat_data; | ||
419 | sdio_unregister_driver(&sdio_driver); | ||
420 | cw1200_sdio_off(pdata); | ||
421 | } | ||
422 | |||
423 | |||
424 | module_init(cw1200_sdio_init); | ||
425 | 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..953bd1904d3d --- /dev/null +++ b/drivers/net/wireless/cw1200/cw1200_spi.c | |||
@@ -0,0 +1,463 @@ | |||
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 | /* Notes on byte ordering: | ||
51 | LE: B0 B1 B2 B3 | ||
52 | BE: B3 B2 B1 B0 | ||
53 | |||
54 | Hardware expects 32-bit data to be written as 16-bit BE words: | ||
55 | |||
56 | B1 B0 B3 B2 | ||
57 | */ | ||
58 | |||
59 | static int cw1200_spi_memcpy_fromio(struct hwbus_priv *self, | ||
60 | unsigned int addr, | ||
61 | void *dst, int count) | ||
62 | { | ||
63 | int ret, i; | ||
64 | uint16_t regaddr; | ||
65 | struct spi_message m; | ||
66 | |||
67 | struct spi_transfer t_addr = { | ||
68 | .tx_buf = ®addr, | ||
69 | .len = sizeof(regaddr), | ||
70 | }; | ||
71 | struct spi_transfer t_msg = { | ||
72 | .rx_buf = dst, | ||
73 | .len = count, | ||
74 | }; | ||
75 | |||
76 | regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; | ||
77 | regaddr |= SET_READ; | ||
78 | regaddr |= (count>>1); | ||
79 | regaddr = cpu_to_le16(regaddr); | ||
80 | |||
81 | #ifdef SPI_DEBUG | ||
82 | pr_info("READ : %04d from 0x%02x (%04x)\n", count, addr, | ||
83 | le16_to_cpu(regaddr)); | ||
84 | #endif | ||
85 | |||
86 | #if defined(__LITTLE_ENDIAN) | ||
87 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
88 | if (self->func->bits_per_word == 8) | ||
89 | #endif | ||
90 | regaddr = swab16(regaddr); | ||
91 | |||
92 | spi_message_init(&m); | ||
93 | spi_message_add_tail(&t_addr, &m); | ||
94 | spi_message_add_tail(&t_msg, &m); | ||
95 | ret = spi_sync(self->func, &m); | ||
96 | |||
97 | #ifdef SPI_DEBUG | ||
98 | pr_info("READ : "); | ||
99 | for (i = 0; i < t_addr.len; i++) | ||
100 | printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); | ||
101 | printk(" : "); | ||
102 | for (i = 0; i < t_msg.len; i++) | ||
103 | printk("%02x ", ((u8 *)t_msg.rx_buf)[i]); | ||
104 | printk("\n"); | ||
105 | #endif | ||
106 | |||
107 | #if defined(__LITTLE_ENDIAN) | ||
108 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
109 | if (self->func->bits_per_word == 8) | ||
110 | #endif | ||
111 | { | ||
112 | uint16_t *buf = (uint16_t *)dst; | ||
113 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
114 | buf[i] = swab16(buf[i]); | ||
115 | } | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int cw1200_spi_memcpy_toio(struct hwbus_priv *self, | ||
121 | unsigned int addr, | ||
122 | const void *src, int count) | ||
123 | { | ||
124 | int rval, i; | ||
125 | uint16_t regaddr; | ||
126 | struct spi_transfer t_addr = { | ||
127 | .tx_buf = ®addr, | ||
128 | .len = sizeof(regaddr), | ||
129 | }; | ||
130 | struct spi_transfer t_msg = { | ||
131 | .tx_buf = src, | ||
132 | .len = count, | ||
133 | }; | ||
134 | struct spi_message m; | ||
135 | |||
136 | regaddr = (SDIO_TO_SPI_ADDR(addr))<<12; | ||
137 | regaddr &= SET_WRITE; | ||
138 | regaddr |= (count>>1); | ||
139 | regaddr = cpu_to_le16(regaddr); | ||
140 | |||
141 | #ifdef SPI_DEBUG | ||
142 | pr_info("WRITE: %04d to 0x%02x (%04x)\n", count, addr, | ||
143 | le16_to_cpu(regaddr)); | ||
144 | #endif | ||
145 | |||
146 | #if defined(__LITTLE_ENDIAN) | ||
147 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
148 | if (self->func->bits_per_word == 8) | ||
149 | #endif | ||
150 | { | ||
151 | uint16_t *buf = (uint16_t *)src; | ||
152 | regaddr = swab16(regaddr); | ||
153 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
154 | buf[i] = swab16(buf[i]); | ||
155 | } | ||
156 | |||
157 | #ifdef SPI_DEBUG | ||
158 | pr_info("WRITE: "); | ||
159 | for (i = 0; i < t_addr.len; i++) | ||
160 | printk("%02x ", ((u8 *)t_addr.tx_buf)[i]); | ||
161 | printk(" : "); | ||
162 | for (i = 0; i < t_msg.len; i++) | ||
163 | printk("%02x ", ((u8 *)t_msg.tx_buf)[i]); | ||
164 | printk("\n"); | ||
165 | #endif | ||
166 | |||
167 | spi_message_init(&m); | ||
168 | spi_message_add_tail(&t_addr, &m); | ||
169 | spi_message_add_tail(&t_msg, &m); | ||
170 | rval = spi_sync(self->func, &m); | ||
171 | |||
172 | #ifdef SPI_DEBUG | ||
173 | pr_info("WROTE: %d\n", m.actual_length); | ||
174 | #endif | ||
175 | |||
176 | #if defined(__LITTLE_ENDIAN) | ||
177 | /* We have to byteswap if the SPI bus is limited to 8b operation */ | ||
178 | if (self->func->bits_per_word == 8) | ||
179 | #endif | ||
180 | { | ||
181 | uint16_t *buf = (uint16_t *)src; | ||
182 | for (i = 0; i < ((count + 1) >> 1); i++) | ||
183 | buf[i] = swab16(buf[i]); | ||
184 | } | ||
185 | return rval; | ||
186 | } | ||
187 | |||
188 | static void cw1200_spi_lock(struct hwbus_priv *self) | ||
189 | { | ||
190 | unsigned long flags; | ||
191 | |||
192 | might_sleep(); | ||
193 | |||
194 | spin_lock_irqsave(&self->lock, flags); | ||
195 | while (1) { | ||
196 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
197 | if (!self->claimed) | ||
198 | break; | ||
199 | spin_unlock_irqrestore(&self->lock, flags); | ||
200 | schedule(); | ||
201 | spin_lock_irqsave(&self->lock, flags); | ||
202 | } | ||
203 | set_current_state(TASK_RUNNING); | ||
204 | self->claimed = 1; | ||
205 | spin_unlock_irqrestore(&self->lock, flags); | ||
206 | |||
207 | return; | ||
208 | } | ||
209 | |||
210 | static void cw1200_spi_unlock(struct hwbus_priv *self) | ||
211 | { | ||
212 | unsigned long flags; | ||
213 | |||
214 | spin_lock_irqsave(&self->lock, flags); | ||
215 | self->claimed = 0; | ||
216 | spin_unlock_irqrestore(&self->lock, flags); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | static irqreturn_t cw1200_spi_irq_handler(int irq, void *dev_id) | ||
221 | { | ||
222 | struct hwbus_priv *self = dev_id; | ||
223 | |||
224 | if (self->core) { | ||
225 | cw1200_irq_handler(self->core); | ||
226 | return IRQ_HANDLED; | ||
227 | } else { | ||
228 | return IRQ_NONE; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | static int cw1200_spi_irq_subscribe(struct hwbus_priv *self) | ||
233 | { | ||
234 | int ret; | ||
235 | |||
236 | pr_debug("SW IRQ subscribe\n"); | ||
237 | |||
238 | ret = request_any_context_irq(self->func->irq, cw1200_spi_irq_handler, | ||
239 | IRQF_TRIGGER_HIGH, | ||
240 | "cw1200_wlan_irq", self); | ||
241 | if (WARN_ON(ret < 0)) | ||
242 | goto exit; | ||
243 | |||
244 | ret = enable_irq_wake(self->func->irq); | ||
245 | if (WARN_ON(ret)) | ||
246 | goto free_irq; | ||
247 | |||
248 | return 0; | ||
249 | |||
250 | free_irq: | ||
251 | free_irq(self->func->irq, self); | ||
252 | exit: | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | static int cw1200_spi_irq_unsubscribe(struct hwbus_priv *self) | ||
257 | { | ||
258 | int ret = 0; | ||
259 | |||
260 | pr_debug("SW IRQ unsubscribe\n"); | ||
261 | disable_irq_wake(self->func->irq); | ||
262 | free_irq(self->func->irq, self); | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static int cw1200_spi_off(const struct cw1200_platform_data_spi *pdata) | ||
268 | { | ||
269 | if (pdata->reset) { | ||
270 | gpio_set_value(pdata->reset, 0); | ||
271 | msleep(30); /* Min is 2 * CLK32K cycles */ | ||
272 | gpio_free(pdata->reset); | ||
273 | } | ||
274 | |||
275 | if (pdata->power_ctrl) | ||
276 | pdata->power_ctrl(pdata, false); | ||
277 | if (pdata->clk_ctrl) | ||
278 | pdata->clk_ctrl(pdata, false); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int cw1200_spi_on(const struct cw1200_platform_data_spi *pdata) | ||
284 | { | ||
285 | /* Ensure I/Os are pulled low */ | ||
286 | if (pdata->reset) { | ||
287 | gpio_request(pdata->reset, "cw1200_wlan_reset"); | ||
288 | gpio_direction_output(pdata->reset, 0); | ||
289 | } | ||
290 | if (pdata->powerup) { | ||
291 | gpio_request(pdata->powerup, "cw1200_wlan_powerup"); | ||
292 | gpio_direction_output(pdata->powerup, 0); | ||
293 | } | ||
294 | if (pdata->reset || pdata->powerup) | ||
295 | msleep(10); /* Settle time? */ | ||
296 | |||
297 | /* Enable 3v3 and 1v8 to hardware */ | ||
298 | if (pdata->power_ctrl) { | ||
299 | if (pdata->power_ctrl(pdata, true)) { | ||
300 | pr_err("power_ctrl() failed!\n"); | ||
301 | return -1; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | /* Enable CLK32K */ | ||
306 | if (pdata->clk_ctrl) { | ||
307 | if (pdata->clk_ctrl(pdata, true)) { | ||
308 | pr_err("clk_ctrl() failed!\n"); | ||
309 | return -1; | ||
310 | } | ||
311 | msleep(10); /* Delay until clock is stable for 2 cycles */ | ||
312 | } | ||
313 | |||
314 | /* Enable POWERUP signal */ | ||
315 | if (pdata->powerup) { | ||
316 | gpio_set_value(pdata->powerup, 1); | ||
317 | msleep(250); /* or more..? */ | ||
318 | } | ||
319 | /* Enable RSTn signal */ | ||
320 | if (pdata->reset) { | ||
321 | gpio_set_value(pdata->reset, 1); | ||
322 | msleep(50); /* Or more..? */ | ||
323 | } | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static size_t cw1200_spi_align_size(struct hwbus_priv *self, size_t size) | ||
328 | { | ||
329 | return size & 1 ? size + 1 : size; | ||
330 | } | ||
331 | |||
332 | static int cw1200_spi_pm(struct hwbus_priv *self, bool suspend) | ||
333 | { | ||
334 | return irq_set_irq_wake(self->func->irq, suspend); | ||
335 | } | ||
336 | |||
337 | static struct hwbus_ops cw1200_spi_hwbus_ops = { | ||
338 | .hwbus_memcpy_fromio = cw1200_spi_memcpy_fromio, | ||
339 | .hwbus_memcpy_toio = cw1200_spi_memcpy_toio, | ||
340 | .lock = cw1200_spi_lock, | ||
341 | .unlock = cw1200_spi_unlock, | ||
342 | .align_size = cw1200_spi_align_size, | ||
343 | .power_mgmt = cw1200_spi_pm, | ||
344 | }; | ||
345 | |||
346 | /* Probe Function to be called by SPI stack when device is discovered */ | ||
347 | static int cw1200_spi_probe(struct spi_device *func) | ||
348 | { | ||
349 | const struct cw1200_platform_data_spi *plat_data = | ||
350 | func->dev.platform_data; | ||
351 | struct hwbus_priv *self; | ||
352 | int status; | ||
353 | |||
354 | /* Sanity check speed */ | ||
355 | if (func->max_speed_hz > 52000000) | ||
356 | func->max_speed_hz = 52000000; | ||
357 | if (func->max_speed_hz < 1000000) | ||
358 | func->max_speed_hz = 1000000; | ||
359 | |||
360 | /* Fix up transfer size */ | ||
361 | if (plat_data->spi_bits_per_word) | ||
362 | func->bits_per_word = plat_data->spi_bits_per_word; | ||
363 | if (!func->bits_per_word) | ||
364 | func->bits_per_word = 16; | ||
365 | |||
366 | /* And finally.. */ | ||
367 | func->mode = SPI_MODE_0; | ||
368 | |||
369 | pr_info("cw1200_wlan_spi: Probe called (CS %d M %d BPW %d CLK %d)\n", | ||
370 | func->chip_select, func->mode, func->bits_per_word, | ||
371 | func->max_speed_hz); | ||
372 | |||
373 | if (cw1200_spi_on(plat_data)) { | ||
374 | pr_err("spi_on() failed!\n"); | ||
375 | return -1; | ||
376 | } | ||
377 | |||
378 | if (spi_setup(func)) { | ||
379 | pr_err("spi_setup() failed!\n"); | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | self = kzalloc(sizeof(*self), GFP_KERNEL); | ||
384 | if (!self) { | ||
385 | pr_err("Can't allocate SPI hwbus_priv."); | ||
386 | return -ENOMEM; | ||
387 | } | ||
388 | |||
389 | self->pdata = plat_data; | ||
390 | self->func = func; | ||
391 | spin_lock_init(&self->lock); | ||
392 | |||
393 | spi_set_drvdata(func, self); | ||
394 | |||
395 | status = cw1200_spi_irq_subscribe(self); | ||
396 | |||
397 | status = cw1200_core_probe(&cw1200_spi_hwbus_ops, | ||
398 | self, &func->dev, &self->core, | ||
399 | self->pdata->ref_clk, | ||
400 | self->pdata->macaddr, | ||
401 | self->pdata->sdd_file, | ||
402 | self->pdata->have_5ghz); | ||
403 | |||
404 | if (status) { | ||
405 | cw1200_spi_irq_unsubscribe(self); | ||
406 | cw1200_spi_off(plat_data); | ||
407 | kfree(self); | ||
408 | } | ||
409 | |||
410 | return status; | ||
411 | } | ||
412 | |||
413 | /* Disconnect Function to be called by SPI stack when device is disconnected */ | ||
414 | static int cw1200_spi_disconnect(struct spi_device *func) | ||
415 | { | ||
416 | struct hwbus_priv *self = spi_get_drvdata(func); | ||
417 | |||
418 | if (self) { | ||
419 | cw1200_spi_irq_unsubscribe(self); | ||
420 | if (self->core) { | ||
421 | cw1200_core_release(self->core); | ||
422 | self->core = NULL; | ||
423 | } | ||
424 | kfree(self); | ||
425 | } | ||
426 | cw1200_spi_off(func->dev.platform_data); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | #ifdef CONFIG_PM | ||
432 | static int cw1200_spi_suspend(struct device *dev, pm_message_t state) | ||
433 | { | ||
434 | struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); | ||
435 | |||
436 | if (!cw1200_can_suspend(self->core)) | ||
437 | return -EAGAIN; | ||
438 | |||
439 | /* XXX notify host that we have to keep CW1200 powered on? */ | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int cw1200_spi_resume(struct device *dev) | ||
444 | { | ||
445 | return 0; | ||
446 | } | ||
447 | #endif | ||
448 | |||
449 | static struct spi_driver spi_driver = { | ||
450 | .probe = cw1200_spi_probe, | ||
451 | .remove = cw1200_spi_disconnect, | ||
452 | .driver = { | ||
453 | .name = "cw1200_wlan_spi", | ||
454 | .bus = &spi_bus_type, | ||
455 | .owner = THIS_MODULE, | ||
456 | #ifdef CONFIG_PM | ||
457 | .suspend = cw1200_spi_suspend, | ||
458 | .resume = cw1200_spi_resume, | ||
459 | #endif | ||
460 | }, | ||
461 | }; | ||
462 | |||
463 | 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..e323b4d54338 --- /dev/null +++ b/drivers/net/wireless/cw1200/debug.c | |||
@@ -0,0 +1,428 @@ | |||
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 | static ssize_t cw1200_wsm_dumps(struct file *file, | ||
361 | const char __user *user_buf, size_t count, loff_t *ppos) | ||
362 | { | ||
363 | struct cw1200_common *priv = file->private_data; | ||
364 | char buf[1]; | ||
365 | |||
366 | if (!count) | ||
367 | return -EINVAL; | ||
368 | if (copy_from_user(buf, user_buf, 1)) | ||
369 | return -EFAULT; | ||
370 | |||
371 | if (buf[0] == '1') | ||
372 | priv->wsm_enable_wsm_dumps = 1; | ||
373 | else | ||
374 | priv->wsm_enable_wsm_dumps = 0; | ||
375 | |||
376 | return count; | ||
377 | } | ||
378 | |||
379 | static const struct file_operations fops_wsm_dumps = { | ||
380 | .open = simple_open, | ||
381 | .write = cw1200_wsm_dumps, | ||
382 | .llseek = default_llseek, | ||
383 | }; | ||
384 | |||
385 | int cw1200_debug_init(struct cw1200_common *priv) | ||
386 | { | ||
387 | int ret = -ENOMEM; | ||
388 | struct cw1200_debug_priv *d = kzalloc(sizeof(struct cw1200_debug_priv), | ||
389 | GFP_KERNEL); | ||
390 | priv->debug = d; | ||
391 | if (!d) | ||
392 | return ret; | ||
393 | |||
394 | d->debugfs_phy = debugfs_create_dir("cw1200", | ||
395 | priv->hw->wiphy->debugfsdir); | ||
396 | if (!d->debugfs_phy) | ||
397 | goto err; | ||
398 | |||
399 | if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy, | ||
400 | priv, &fops_status)) | ||
401 | goto err; | ||
402 | |||
403 | if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy, | ||
404 | priv, &fops_counters)) | ||
405 | goto err; | ||
406 | |||
407 | if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy, | ||
408 | priv, &fops_wsm_dumps)) | ||
409 | goto err; | ||
410 | |||
411 | return 0; | ||
412 | |||
413 | err: | ||
414 | priv->debug = NULL; | ||
415 | debugfs_remove_recursive(d->debugfs_phy); | ||
416 | kfree(d); | ||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | void cw1200_debug_release(struct cw1200_common *priv) | ||
421 | { | ||
422 | struct cw1200_debug_priv *d = priv->debug; | ||
423 | if (d) { | ||
424 | debugfs_remove_recursive(d->debugfs_phy); | ||
425 | priv->debug = NULL; | ||
426 | kfree(d); | ||
427 | } | ||
428 | } | ||
diff --git a/drivers/net/wireless/cw1200/debug.h b/drivers/net/wireless/cw1200/debug.h new file mode 100644 index 000000000000..b525aba53bfc --- /dev/null +++ b/drivers/net/wireless/cw1200/debug.h | |||
@@ -0,0 +1,93 @@ | |||
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 | struct cw1200_debug_priv { | ||
16 | struct dentry *debugfs_phy; | ||
17 | int tx; | ||
18 | int tx_agg; | ||
19 | int rx; | ||
20 | int rx_agg; | ||
21 | int tx_multi; | ||
22 | int tx_multi_frames; | ||
23 | int tx_cache_miss; | ||
24 | int tx_align; | ||
25 | int tx_ttl; | ||
26 | int tx_burst; | ||
27 | int ba_cnt; | ||
28 | int ba_acc; | ||
29 | int ba_cnt_rx; | ||
30 | int ba_acc_rx; | ||
31 | }; | ||
32 | |||
33 | int cw1200_debug_init(struct cw1200_common *priv); | ||
34 | void cw1200_debug_release(struct cw1200_common *priv); | ||
35 | |||
36 | static inline void cw1200_debug_txed(struct cw1200_common *priv) | ||
37 | { | ||
38 | ++priv->debug->tx; | ||
39 | } | ||
40 | |||
41 | static inline void cw1200_debug_txed_agg(struct cw1200_common *priv) | ||
42 | { | ||
43 | ++priv->debug->tx_agg; | ||
44 | } | ||
45 | |||
46 | static inline void cw1200_debug_txed_multi(struct cw1200_common *priv, | ||
47 | int count) | ||
48 | { | ||
49 | ++priv->debug->tx_multi; | ||
50 | priv->debug->tx_multi_frames += count; | ||
51 | } | ||
52 | |||
53 | static inline void cw1200_debug_rxed(struct cw1200_common *priv) | ||
54 | { | ||
55 | ++priv->debug->rx; | ||
56 | } | ||
57 | |||
58 | static inline void cw1200_debug_rxed_agg(struct cw1200_common *priv) | ||
59 | { | ||
60 | ++priv->debug->rx_agg; | ||
61 | } | ||
62 | |||
63 | static inline void cw1200_debug_tx_cache_miss(struct cw1200_common *priv) | ||
64 | { | ||
65 | ++priv->debug->tx_cache_miss; | ||
66 | } | ||
67 | |||
68 | static inline void cw1200_debug_tx_align(struct cw1200_common *priv) | ||
69 | { | ||
70 | ++priv->debug->tx_align; | ||
71 | } | ||
72 | |||
73 | static inline void cw1200_debug_tx_ttl(struct cw1200_common *priv) | ||
74 | { | ||
75 | ++priv->debug->tx_ttl; | ||
76 | } | ||
77 | |||
78 | static inline void cw1200_debug_tx_burst(struct cw1200_common *priv) | ||
79 | { | ||
80 | ++priv->debug->tx_burst; | ||
81 | } | ||
82 | |||
83 | static inline void cw1200_debug_ba(struct cw1200_common *priv, | ||
84 | int ba_cnt, int ba_acc, | ||
85 | int ba_cnt_rx, int ba_acc_rx) | ||
86 | { | ||
87 | priv->debug->ba_cnt = ba_cnt; | ||
88 | priv->debug->ba_acc = ba_acc; | ||
89 | priv->debug->ba_cnt_rx = ba_cnt_rx; | ||
90 | priv->debug->ba_acc_rx = ba_acc_rx; | ||
91 | } | ||
92 | |||
93 | #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..acdff0f7f952 --- /dev/null +++ b/drivers/net/wireless/cw1200/fwio.c | |||
@@ -0,0 +1,520 @@ | |||
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 | /* Load a firmware file */ | ||
143 | ret = request_firmware(&firmware, fw_path, priv->pdev); | ||
144 | if (ret) { | ||
145 | pr_err("Can't load firmware file %s.\n", fw_path); | ||
146 | goto error; | ||
147 | } | ||
148 | |||
149 | buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); | ||
150 | if (!buf) { | ||
151 | pr_err("Can't allocate firmware load buffer.\n"); | ||
152 | ret = -ENOMEM; | ||
153 | goto error; | ||
154 | } | ||
155 | |||
156 | /* Check if the bootloader is ready */ | ||
157 | for (i = 0; i < 100; i += 1 + i / 2) { | ||
158 | APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); | ||
159 | if (val32 == DOWNLOAD_I_AM_HERE) | ||
160 | break; | ||
161 | mdelay(i); | ||
162 | } /* End of for loop */ | ||
163 | |||
164 | if (val32 != DOWNLOAD_I_AM_HERE) { | ||
165 | pr_err("Bootloader is not ready.\n"); | ||
166 | ret = -ETIMEDOUT; | ||
167 | goto error; | ||
168 | } | ||
169 | |||
170 | /* Calculcate number of download blocks */ | ||
171 | num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; | ||
172 | |||
173 | /* Updating the length in Download Ctrl Area */ | ||
174 | val32 = firmware->size; /* Explicit cast from size_t to u32 */ | ||
175 | APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); | ||
176 | |||
177 | /* Firmware downloading loop */ | ||
178 | for (block = 0; block < num_blocks; block++) { | ||
179 | size_t tx_size; | ||
180 | size_t block_size; | ||
181 | |||
182 | /* check the download status */ | ||
183 | APB_READ(DOWNLOAD_STATUS_REG, val32); | ||
184 | if (val32 != DOWNLOAD_PENDING) { | ||
185 | pr_err("Bootloader reported error %d.\n", val32); | ||
186 | ret = -EIO; | ||
187 | goto error; | ||
188 | } | ||
189 | |||
190 | /* loop until put - get <= 24K */ | ||
191 | for (i = 0; i < 100; i++) { | ||
192 | APB_READ(DOWNLOAD_GET_REG, get); | ||
193 | if ((put - get) <= | ||
194 | (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) | ||
195 | break; | ||
196 | mdelay(i); | ||
197 | } | ||
198 | |||
199 | if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { | ||
200 | pr_err("Timeout waiting for FIFO.\n"); | ||
201 | ret = -ETIMEDOUT; | ||
202 | goto error; | ||
203 | } | ||
204 | |||
205 | /* calculate the block size */ | ||
206 | tx_size = block_size = min((size_t)(firmware->size - put), | ||
207 | (size_t)DOWNLOAD_BLOCK_SIZE); | ||
208 | |||
209 | memcpy(buf, &firmware->data[put], block_size); | ||
210 | if (block_size < DOWNLOAD_BLOCK_SIZE) { | ||
211 | memset(&buf[block_size], 0, | ||
212 | DOWNLOAD_BLOCK_SIZE - block_size); | ||
213 | tx_size = DOWNLOAD_BLOCK_SIZE; | ||
214 | } | ||
215 | |||
216 | /* send the block to sram */ | ||
217 | ret = cw1200_apb_write(priv, | ||
218 | CW1200_APB(DOWNLOAD_FIFO_OFFSET + | ||
219 | (put & (DOWNLOAD_FIFO_SIZE - 1))), | ||
220 | buf, tx_size); | ||
221 | if (ret < 0) { | ||
222 | pr_err("Can't write firmware block @ %d!\n", | ||
223 | put & (DOWNLOAD_FIFO_SIZE - 1)); | ||
224 | goto error; | ||
225 | } | ||
226 | |||
227 | /* update the put register */ | ||
228 | put += block_size; | ||
229 | APB_WRITE(DOWNLOAD_PUT_REG, put); | ||
230 | } /* End of firmware download loop */ | ||
231 | |||
232 | /* Wait for the download completion */ | ||
233 | for (i = 0; i < 300; i += 1 + i / 2) { | ||
234 | APB_READ(DOWNLOAD_STATUS_REG, val32); | ||
235 | if (val32 != DOWNLOAD_PENDING) | ||
236 | break; | ||
237 | mdelay(i); | ||
238 | } | ||
239 | if (val32 != DOWNLOAD_SUCCESS) { | ||
240 | pr_err("Wait for download completion failed: 0x%.8X\n", val32); | ||
241 | ret = -ETIMEDOUT; | ||
242 | goto error; | ||
243 | } else { | ||
244 | pr_info("Firmware download completed.\n"); | ||
245 | ret = 0; | ||
246 | } | ||
247 | |||
248 | error: | ||
249 | kfree(buf); | ||
250 | if (firmware) | ||
251 | release_firmware(firmware); | ||
252 | return ret; | ||
253 | |||
254 | #undef APB_WRITE | ||
255 | #undef APB_READ | ||
256 | #undef REG_WRITE | ||
257 | #undef REG_READ | ||
258 | } | ||
259 | |||
260 | |||
261 | static int config_reg_read(struct cw1200_common *priv, u32 *val) | ||
262 | { | ||
263 | switch (priv->hw_type) { | ||
264 | case HIF_9000_SILICON_VERSATILE: { | ||
265 | u16 val16; | ||
266 | int ret = cw1200_reg_read_16(priv, | ||
267 | ST90TDS_CONFIG_REG_ID, | ||
268 | &val16); | ||
269 | if (ret < 0) | ||
270 | return ret; | ||
271 | *val = val16; | ||
272 | return 0; | ||
273 | } | ||
274 | case HIF_8601_VERSATILE: | ||
275 | case HIF_8601_SILICON: | ||
276 | default: | ||
277 | cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, val); | ||
278 | break; | ||
279 | } | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int config_reg_write(struct cw1200_common *priv, u32 val) | ||
284 | { | ||
285 | switch (priv->hw_type) { | ||
286 | case HIF_9000_SILICON_VERSATILE: | ||
287 | return cw1200_reg_write_16(priv, | ||
288 | ST90TDS_CONFIG_REG_ID, | ||
289 | (u16)val); | ||
290 | case HIF_8601_VERSATILE: | ||
291 | case HIF_8601_SILICON: | ||
292 | default: | ||
293 | return cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val); | ||
294 | break; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | int cw1200_load_firmware(struct cw1200_common *priv) | ||
300 | { | ||
301 | int ret; | ||
302 | int i; | ||
303 | u32 val32; | ||
304 | u16 val16; | ||
305 | int major_revision = -1; | ||
306 | |||
307 | /* Read CONFIG Register */ | ||
308 | ret = cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
309 | if (ret < 0) { | ||
310 | pr_err("Can't read config register.\n"); | ||
311 | goto out; | ||
312 | } | ||
313 | |||
314 | if (val32 == 0 || val32 == 0xffffffff) { | ||
315 | pr_err("Bad config register value (0x%08x)\n", val32); | ||
316 | ret = -EIO; | ||
317 | goto out; | ||
318 | } | ||
319 | |||
320 | priv->hw_type = cw1200_get_hw_type(val32, &major_revision); | ||
321 | if (priv->hw_type < 0) { | ||
322 | pr_err("Can't deduce hardware type.\n"); | ||
323 | ret = -ENOTSUPP; | ||
324 | goto out; | ||
325 | } | ||
326 | |||
327 | /* Set DPLL Reg value, and read back to confirm writes work */ | ||
328 | ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, | ||
329 | cw1200_dpll_from_clk(priv->hw_refclk)); | ||
330 | if (ret < 0) { | ||
331 | pr_err("Can't write DPLL register.\n"); | ||
332 | goto out; | ||
333 | } | ||
334 | |||
335 | msleep(20); | ||
336 | |||
337 | ret = cw1200_reg_read_32(priv, | ||
338 | ST90TDS_TSET_GEN_R_W_REG_ID, &val32); | ||
339 | if (ret < 0) { | ||
340 | pr_err("Can't read DPLL register.\n"); | ||
341 | goto out; | ||
342 | } | ||
343 | |||
344 | if (val32 != cw1200_dpll_from_clk(priv->hw_refclk)) { | ||
345 | pr_err("Unable to initialise DPLL register. Wrote 0x%.8X, Read 0x%.8X.\n", | ||
346 | cw1200_dpll_from_clk(priv->hw_refclk), val32); | ||
347 | ret = -EIO; | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | /* Set wakeup bit in device */ | ||
352 | ret = cw1200_reg_read_16(priv, ST90TDS_CONTROL_REG_ID, &val16); | ||
353 | if (ret < 0) { | ||
354 | pr_err("set_wakeup: can't read control register.\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | |||
358 | ret = cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID, | ||
359 | val16 | ST90TDS_CONT_WUP_BIT); | ||
360 | if (ret < 0) { | ||
361 | pr_err("set_wakeup: can't write control register.\n"); | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | /* Wait for wakeup */ | ||
366 | for (i = 0; i < 300; i += (1 + i / 2)) { | ||
367 | ret = cw1200_reg_read_16(priv, | ||
368 | ST90TDS_CONTROL_REG_ID, &val16); | ||
369 | if (ret < 0) { | ||
370 | pr_err("wait_for_wakeup: can't read control register.\n"); | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | if (val16 & ST90TDS_CONT_RDY_BIT) | ||
375 | break; | ||
376 | |||
377 | msleep(i); | ||
378 | } | ||
379 | |||
380 | if ((val16 & ST90TDS_CONT_RDY_BIT) == 0) { | ||
381 | pr_err("wait_for_wakeup: device is not responding.\n"); | ||
382 | ret = -ETIMEDOUT; | ||
383 | goto out; | ||
384 | } | ||
385 | |||
386 | switch (major_revision) { | ||
387 | case 1: | ||
388 | /* CW1200 Hardware detection logic : Check for CUT1.1 */ | ||
389 | ret = cw1200_ahb_read_32(priv, CW1200_CUT_ID_ADDR, &val32); | ||
390 | if (ret) { | ||
391 | pr_err("HW detection: can't read CUT ID.\n"); | ||
392 | goto out; | ||
393 | } | ||
394 | |||
395 | switch (val32) { | ||
396 | case CW1200_CUT_11_ID_STR: | ||
397 | pr_info("CW1x00 Cut 1.1 silicon detected.\n"); | ||
398 | priv->hw_revision = CW1200_HW_REV_CUT11; | ||
399 | break; | ||
400 | default: | ||
401 | pr_info("CW1x00 Cut 1.0 silicon detected.\n"); | ||
402 | priv->hw_revision = CW1200_HW_REV_CUT10; | ||
403 | break; | ||
404 | } | ||
405 | |||
406 | /* According to ST-E, CUT<2.0 has busted BA TID0-3. | ||
407 | Just disable it entirely... | ||
408 | */ | ||
409 | priv->ba_rx_tid_mask = 0; | ||
410 | priv->ba_tx_tid_mask = 0; | ||
411 | break; | ||
412 | case 2: { | ||
413 | u32 ar1, ar2, ar3; | ||
414 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR, &ar1); | ||
415 | if (ret) { | ||
416 | pr_err("(1) HW detection: can't read CUT ID\n"); | ||
417 | goto out; | ||
418 | } | ||
419 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 4, &ar2); | ||
420 | if (ret) { | ||
421 | pr_err("(2) HW detection: can't read CUT ID.\n"); | ||
422 | goto out; | ||
423 | } | ||
424 | |||
425 | ret = cw1200_ahb_read_32(priv, CW1200_CUT2_ID_ADDR + 8, &ar3); | ||
426 | if (ret) { | ||
427 | pr_err("(3) HW detection: can't read CUT ID.\n"); | ||
428 | goto out; | ||
429 | } | ||
430 | |||
431 | if (ar1 == CW1200_CUT_22_ID_STR1 && | ||
432 | ar2 == CW1200_CUT_22_ID_STR2 && | ||
433 | ar3 == CW1200_CUT_22_ID_STR3) { | ||
434 | pr_info("CW1x00 Cut 2.2 silicon detected.\n"); | ||
435 | priv->hw_revision = CW1200_HW_REV_CUT22; | ||
436 | } else { | ||
437 | pr_info("CW1x00 Cut 2.0 silicon detected.\n"); | ||
438 | priv->hw_revision = CW1200_HW_REV_CUT20; | ||
439 | } | ||
440 | break; | ||
441 | } | ||
442 | case 4: | ||
443 | pr_info("CW1x60 silicon detected.\n"); | ||
444 | priv->hw_revision = CW1X60_HW_REV; | ||
445 | break; | ||
446 | default: | ||
447 | pr_err("Unsupported silicon major revision %d.\n", | ||
448 | major_revision); | ||
449 | ret = -ENOTSUPP; | ||
450 | goto out; | ||
451 | } | ||
452 | |||
453 | /* Checking for access mode */ | ||
454 | ret = config_reg_read(priv, &val32); | ||
455 | if (ret < 0) { | ||
456 | pr_err("Can't read config register.\n"); | ||
457 | goto out; | ||
458 | } | ||
459 | |||
460 | if (!(val32 & ST90TDS_CONFIG_ACCESS_MODE_BIT)) { | ||
461 | pr_err("Device is already in QUEUE mode!\n"); | ||
462 | ret = -EINVAL; | ||
463 | goto out; | ||
464 | } | ||
465 | |||
466 | switch (priv->hw_type) { | ||
467 | case HIF_8601_SILICON: | ||
468 | if (priv->hw_revision == CW1X60_HW_REV) { | ||
469 | pr_err("Can't handle CW1160/1260 firmware load yet.\n"); | ||
470 | ret = -ENOTSUPP; | ||
471 | goto out; | ||
472 | } | ||
473 | ret = cw1200_load_firmware_cw1200(priv); | ||
474 | break; | ||
475 | default: | ||
476 | pr_err("Can't perform firmware load for hw type %d.\n", | ||
477 | priv->hw_type); | ||
478 | ret = -ENOTSUPP; | ||
479 | goto out; | ||
480 | } | ||
481 | if (ret < 0) { | ||
482 | pr_err("Firmware load error.\n"); | ||
483 | goto out; | ||
484 | } | ||
485 | |||
486 | /* Enable interrupt signalling */ | ||
487 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
488 | ret = __cw1200_irq_enable(priv, 1); | ||
489 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
490 | if (ret < 0) | ||
491 | goto unsubscribe; | ||
492 | |||
493 | /* Configure device for MESSSAGE MODE */ | ||
494 | ret = config_reg_read(priv, &val32); | ||
495 | if (ret < 0) { | ||
496 | pr_err("Can't read config register.\n"); | ||
497 | goto unsubscribe; | ||
498 | } | ||
499 | ret = config_reg_write(priv, val32 & ~ST90TDS_CONFIG_ACCESS_MODE_BIT); | ||
500 | if (ret < 0) { | ||
501 | pr_err("Can't write config register.\n"); | ||
502 | goto unsubscribe; | ||
503 | } | ||
504 | |||
505 | /* Unless we read the CONFIG Register we are | ||
506 | * not able to get an interrupt | ||
507 | */ | ||
508 | mdelay(10); | ||
509 | config_reg_read(priv, &val32); | ||
510 | |||
511 | out: | ||
512 | return ret; | ||
513 | |||
514 | unsubscribe: | ||
515 | /* Disable interrupt signalling */ | ||
516 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
517 | ret = __cw1200_irq_enable(priv, 0); | ||
518 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
519 | return ret; | ||
520 | } | ||
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..dad3fb331818 --- /dev/null +++ b/drivers/net/wireless/cw1200/hwio.c | |||
@@ -0,0 +1,310 @@ | |||
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 | } | ||
182 | |||
183 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
184 | /* Write address */ | ||
185 | ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); | ||
186 | if (ret < 0) { | ||
187 | pr_err("Can't write address register.\n"); | ||
188 | goto out; | ||
189 | } | ||
190 | |||
191 | /* Read CONFIG Register Value - We will read 32 bits */ | ||
192 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
193 | if (ret < 0) { | ||
194 | pr_err("Can't read config register.\n"); | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | /* Set PREFETCH bit */ | ||
199 | ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, | ||
200 | val32 | prefetch); | ||
201 | if (ret < 0) { | ||
202 | pr_err("Can't write prefetch bit.\n"); | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | /* Check for PRE-FETCH bit to be cleared */ | ||
207 | for (i = 0; i < 20; i++) { | ||
208 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
209 | if (ret < 0) { | ||
210 | pr_err("Can't check prefetch bit.\n"); | ||
211 | goto out; | ||
212 | } | ||
213 | if (!(val32 & prefetch)) | ||
214 | break; | ||
215 | |||
216 | mdelay(i); | ||
217 | } | ||
218 | |||
219 | if (val32 & prefetch) { | ||
220 | pr_err("Prefetch bit is not cleared.\n"); | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | /* Read data port */ | ||
225 | ret = __cw1200_reg_read(priv, port_addr, buf, buf_len, 0); | ||
226 | if (ret < 0) { | ||
227 | pr_err("Can't read data port.\n"); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | out: | ||
232 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, | ||
237 | size_t buf_len) | ||
238 | { | ||
239 | int ret; | ||
240 | |||
241 | if ((buf_len / 2) >= 0x1000) { | ||
242 | pr_err("Can't write more than 0xfff words.\n"); | ||
243 | return -EINVAL; | ||
244 | } | ||
245 | |||
246 | priv->hwbus_ops->lock(priv->hwbus_priv); | ||
247 | |||
248 | /* Write address */ | ||
249 | ret = __cw1200_reg_write_32(priv, ST90TDS_SRAM_BASE_ADDR_REG_ID, addr); | ||
250 | if (ret < 0) { | ||
251 | pr_err("Can't write address register.\n"); | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | /* Write data port */ | ||
256 | ret = __cw1200_reg_write(priv, ST90TDS_SRAM_DPORT_REG_ID, | ||
257 | buf, buf_len, 0); | ||
258 | if (ret < 0) { | ||
259 | pr_err("Can't write data port.\n"); | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | out: | ||
264 | priv->hwbus_ops->unlock(priv->hwbus_priv); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | int __cw1200_irq_enable(struct cw1200_common *priv, int enable) | ||
269 | { | ||
270 | u32 val32; | ||
271 | u16 val16; | ||
272 | int ret; | ||
273 | |||
274 | if (HIF_8601_SILICON == priv->hw_type) { | ||
275 | ret = __cw1200_reg_read_32(priv, ST90TDS_CONFIG_REG_ID, &val32); | ||
276 | if (ret < 0) { | ||
277 | pr_err("Can't read config register.\n"); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | if (enable) | ||
282 | val32 |= ST90TDS_CONF_IRQ_RDY_ENABLE; | ||
283 | else | ||
284 | val32 &= ~ST90TDS_CONF_IRQ_RDY_ENABLE; | ||
285 | |||
286 | ret = __cw1200_reg_write_32(priv, ST90TDS_CONFIG_REG_ID, val32); | ||
287 | if (ret < 0) { | ||
288 | pr_err("Can't write config register.\n"); | ||
289 | return ret; | ||
290 | } | ||
291 | } else { | ||
292 | ret = __cw1200_reg_read_16(priv, ST90TDS_CONFIG_REG_ID, &val16); | ||
293 | if (ret < 0) { | ||
294 | pr_err("Can't read control register.\n"); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | if (enable) | ||
299 | val16 |= ST90TDS_CONT_IRQ_RDY_ENABLE; | ||
300 | else | ||
301 | val16 &= ~ST90TDS_CONT_IRQ_RDY_ENABLE; | ||
302 | |||
303 | ret = __cw1200_reg_write_16(priv, ST90TDS_CONFIG_REG_ID, val16); | ||
304 | if (ret < 0) { | ||
305 | pr_err("Can't write control register.\n"); | ||
306 | return ret; | ||
307 | } | ||
308 | } | ||
309 | return 0; | ||
310 | } | ||
diff --git a/drivers/net/wireless/cw1200/hwio.h b/drivers/net/wireless/cw1200/hwio.h new file mode 100644 index 000000000000..563329cfead6 --- /dev/null +++ b/drivers/net/wireless/cw1200/hwio.h | |||
@@ -0,0 +1,246 @@ | |||
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 | /* Device register definitions */ | ||
101 | |||
102 | /* WBF - SPI Register Addresses */ | ||
103 | #define ST90TDS_ADDR_ID_BASE (0x0000) | ||
104 | /* 16/32 bits */ | ||
105 | #define ST90TDS_CONFIG_REG_ID (0x0000) | ||
106 | /* 16/32 bits */ | ||
107 | #define ST90TDS_CONTROL_REG_ID (0x0001) | ||
108 | /* 16 bits, Q mode W/R */ | ||
109 | #define ST90TDS_IN_OUT_QUEUE_REG_ID (0x0002) | ||
110 | /* 32 bits, AHB bus R/W */ | ||
111 | #define ST90TDS_AHB_DPORT_REG_ID (0x0003) | ||
112 | /* 16/32 bits */ | ||
113 | #define ST90TDS_SRAM_BASE_ADDR_REG_ID (0x0004) | ||
114 | /* 32 bits, APB bus R/W */ | ||
115 | #define ST90TDS_SRAM_DPORT_REG_ID (0x0005) | ||
116 | /* 32 bits, t_settle/general */ | ||
117 | #define ST90TDS_TSET_GEN_R_W_REG_ID (0x0006) | ||
118 | /* 16 bits, Q mode read, no length */ | ||
119 | #define ST90TDS_FRAME_OUT_REG_ID (0x0007) | ||
120 | #define ST90TDS_ADDR_ID_MAX (ST90TDS_FRAME_OUT_REG_ID) | ||
121 | |||
122 | /* WBF - Control register bit set */ | ||
123 | /* next o/p length, bit 11 to 0 */ | ||
124 | #define ST90TDS_CONT_NEXT_LEN_MASK (0x0FFF) | ||
125 | #define ST90TDS_CONT_WUP_BIT (BIT(12)) | ||
126 | #define ST90TDS_CONT_RDY_BIT (BIT(13)) | ||
127 | #define ST90TDS_CONT_IRQ_ENABLE (BIT(14)) | ||
128 | #define ST90TDS_CONT_RDY_ENABLE (BIT(15)) | ||
129 | #define ST90TDS_CONT_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) | ||
130 | |||
131 | /* SPI Config register bit set */ | ||
132 | #define ST90TDS_CONFIG_FRAME_BIT (BIT(2)) | ||
133 | #define ST90TDS_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) | ||
134 | #define ST90TDS_CONFIG_WORD_MODE_1 (BIT(3)) | ||
135 | #define ST90TDS_CONFIG_WORD_MODE_2 (BIT(4)) | ||
136 | #define ST90TDS_CONFIG_ERROR_0_BIT (BIT(5)) | ||
137 | #define ST90TDS_CONFIG_ERROR_1_BIT (BIT(6)) | ||
138 | #define ST90TDS_CONFIG_ERROR_2_BIT (BIT(7)) | ||
139 | /* TBD: Sure??? */ | ||
140 | #define ST90TDS_CONFIG_CSN_FRAME_BIT (BIT(7)) | ||
141 | #define ST90TDS_CONFIG_ERROR_3_BIT (BIT(8)) | ||
142 | #define ST90TDS_CONFIG_ERROR_4_BIT (BIT(9)) | ||
143 | /* QueueM */ | ||
144 | #define ST90TDS_CONFIG_ACCESS_MODE_BIT (BIT(10)) | ||
145 | /* AHB bus */ | ||
146 | #define ST90TDS_CONFIG_AHB_PRFETCH_BIT (BIT(11)) | ||
147 | #define ST90TDS_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) | ||
148 | /* APB bus */ | ||
149 | #define ST90TDS_CONFIG_PRFETCH_BIT (BIT(13)) | ||
150 | /* cpu reset */ | ||
151 | #define ST90TDS_CONFIG_CPU_RESET_BIT (BIT(14)) | ||
152 | #define ST90TDS_CONFIG_CLEAR_INT_BIT (BIT(15)) | ||
153 | |||
154 | /* For CW1200 the IRQ Enable and Ready Bits are in CONFIG register */ | ||
155 | #define ST90TDS_CONF_IRQ_ENABLE (BIT(16)) | ||
156 | #define ST90TDS_CONF_RDY_ENABLE (BIT(17)) | ||
157 | #define ST90TDS_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) | ||
158 | |||
159 | int cw1200_data_read(struct cw1200_common *priv, | ||
160 | void *buf, size_t buf_len); | ||
161 | int cw1200_data_write(struct cw1200_common *priv, | ||
162 | const void *buf, size_t buf_len); | ||
163 | |||
164 | int cw1200_reg_read(struct cw1200_common *priv, u16 addr, | ||
165 | void *buf, size_t buf_len); | ||
166 | int cw1200_reg_write(struct cw1200_common *priv, u16 addr, | ||
167 | const void *buf, size_t buf_len); | ||
168 | |||
169 | static inline int cw1200_reg_read_16(struct cw1200_common *priv, | ||
170 | u16 addr, u16 *val) | ||
171 | { | ||
172 | u32 tmp; | ||
173 | int i; | ||
174 | i = cw1200_reg_read(priv, addr, &tmp, sizeof(tmp)); | ||
175 | tmp = le32_to_cpu(tmp); | ||
176 | *val = tmp & 0xffff; | ||
177 | return i; | ||
178 | } | ||
179 | |||
180 | static inline int cw1200_reg_write_16(struct cw1200_common *priv, | ||
181 | u16 addr, u16 val) | ||
182 | { | ||
183 | u32 tmp = val; | ||
184 | tmp = cpu_to_le32(tmp); | ||
185 | return cw1200_reg_write(priv, addr, &tmp, sizeof(tmp)); | ||
186 | } | ||
187 | |||
188 | static inline int cw1200_reg_read_32(struct cw1200_common *priv, | ||
189 | u16 addr, u32 *val) | ||
190 | { | ||
191 | int i = cw1200_reg_read(priv, addr, val, sizeof(*val)); | ||
192 | *val = le32_to_cpu(*val); | ||
193 | return i; | ||
194 | } | ||
195 | |||
196 | static inline int cw1200_reg_write_32(struct cw1200_common *priv, | ||
197 | u16 addr, u32 val) | ||
198 | { | ||
199 | val = cpu_to_le32(val); | ||
200 | return cw1200_reg_write(priv, addr, &val, sizeof(val)); | ||
201 | } | ||
202 | |||
203 | int cw1200_indirect_read(struct cw1200_common *priv, u32 addr, void *buf, | ||
204 | size_t buf_len, u32 prefetch, u16 port_addr); | ||
205 | int cw1200_apb_write(struct cw1200_common *priv, u32 addr, const void *buf, | ||
206 | size_t buf_len); | ||
207 | |||
208 | static inline int cw1200_apb_read(struct cw1200_common *priv, u32 addr, | ||
209 | void *buf, size_t buf_len) | ||
210 | { | ||
211 | return cw1200_indirect_read(priv, addr, buf, buf_len, | ||
212 | ST90TDS_CONFIG_PRFETCH_BIT, | ||
213 | ST90TDS_SRAM_DPORT_REG_ID); | ||
214 | } | ||
215 | |||
216 | static inline int cw1200_ahb_read(struct cw1200_common *priv, u32 addr, | ||
217 | void *buf, size_t buf_len) | ||
218 | { | ||
219 | return cw1200_indirect_read(priv, addr, buf, buf_len, | ||
220 | ST90TDS_CONFIG_AHB_PRFETCH_BIT, | ||
221 | ST90TDS_AHB_DPORT_REG_ID); | ||
222 | } | ||
223 | |||
224 | static inline int cw1200_apb_read_32(struct cw1200_common *priv, | ||
225 | u32 addr, u32 *val) | ||
226 | { | ||
227 | int i = cw1200_apb_read(priv, addr, val, sizeof(*val)); | ||
228 | *val = le32_to_cpu(*val); | ||
229 | return i; | ||
230 | } | ||
231 | |||
232 | static inline int cw1200_apb_write_32(struct cw1200_common *priv, | ||
233 | u32 addr, u32 val) | ||
234 | { | ||
235 | val = cpu_to_le32(val); | ||
236 | return cw1200_apb_write(priv, addr, &val, sizeof(val)); | ||
237 | } | ||
238 | static inline int cw1200_ahb_read_32(struct cw1200_common *priv, | ||
239 | u32 addr, u32 *val) | ||
240 | { | ||
241 | int i = cw1200_ahb_read(priv, addr, val, sizeof(*val)); | ||
242 | *val = le32_to_cpu(*val); | ||
243 | return i; | ||
244 | } | ||
245 | |||
246 | #endif /* CW1200_HWIO_H_INCLUDED */ | ||
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c new file mode 100644 index 000000000000..9f9adb4fbfb8 --- /dev/null +++ b/drivers/net/wireless/cw1200/main.c | |||
@@ -0,0 +1,600 @@ | |||
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 | #define RATETAB_ENT(_rate, _rateid, _flags) \ | ||
65 | { \ | ||
66 | .bitrate = (_rate), \ | ||
67 | .hw_value = (_rateid), \ | ||
68 | .flags = (_flags), \ | ||
69 | } | ||
70 | |||
71 | static struct ieee80211_rate cw1200_rates[] = { | ||
72 | RATETAB_ENT(10, 0, 0), | ||
73 | RATETAB_ENT(20, 1, 0), | ||
74 | RATETAB_ENT(55, 2, 0), | ||
75 | RATETAB_ENT(110, 3, 0), | ||
76 | RATETAB_ENT(60, 6, 0), | ||
77 | RATETAB_ENT(90, 7, 0), | ||
78 | RATETAB_ENT(120, 8, 0), | ||
79 | RATETAB_ENT(180, 9, 0), | ||
80 | RATETAB_ENT(240, 10, 0), | ||
81 | RATETAB_ENT(360, 11, 0), | ||
82 | RATETAB_ENT(480, 12, 0), | ||
83 | RATETAB_ENT(540, 13, 0), | ||
84 | }; | ||
85 | |||
86 | static struct ieee80211_rate cw1200_mcs_rates[] = { | ||
87 | RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), | ||
88 | RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), | ||
89 | RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), | ||
90 | RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), | ||
91 | RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), | ||
92 | RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), | ||
93 | RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), | ||
94 | RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), | ||
95 | }; | ||
96 | |||
97 | #define cw1200_a_rates (cw1200_rates + 4) | ||
98 | #define cw1200_a_rates_size (ARRAY_SIZE(cw1200_rates) - 4) | ||
99 | #define cw1200_g_rates (cw1200_rates + 0) | ||
100 | #define cw1200_g_rates_size (ARRAY_SIZE(cw1200_rates)) | ||
101 | #define cw1200_n_rates (cw1200_mcs_rates) | ||
102 | #define cw1200_n_rates_size (ARRAY_SIZE(cw1200_mcs_rates)) | ||
103 | |||
104 | |||
105 | #define CHAN2G(_channel, _freq, _flags) { \ | ||
106 | .band = IEEE80211_BAND_2GHZ, \ | ||
107 | .center_freq = (_freq), \ | ||
108 | .hw_value = (_channel), \ | ||
109 | .flags = (_flags), \ | ||
110 | .max_antenna_gain = 0, \ | ||
111 | .max_power = 30, \ | ||
112 | } | ||
113 | |||
114 | #define CHAN5G(_channel, _flags) { \ | ||
115 | .band = IEEE80211_BAND_5GHZ, \ | ||
116 | .center_freq = 5000 + (5 * (_channel)), \ | ||
117 | .hw_value = (_channel), \ | ||
118 | .flags = (_flags), \ | ||
119 | .max_antenna_gain = 0, \ | ||
120 | .max_power = 30, \ | ||
121 | } | ||
122 | |||
123 | static struct ieee80211_channel cw1200_2ghz_chantable[] = { | ||
124 | CHAN2G(1, 2412, 0), | ||
125 | CHAN2G(2, 2417, 0), | ||
126 | CHAN2G(3, 2422, 0), | ||
127 | CHAN2G(4, 2427, 0), | ||
128 | CHAN2G(5, 2432, 0), | ||
129 | CHAN2G(6, 2437, 0), | ||
130 | CHAN2G(7, 2442, 0), | ||
131 | CHAN2G(8, 2447, 0), | ||
132 | CHAN2G(9, 2452, 0), | ||
133 | CHAN2G(10, 2457, 0), | ||
134 | CHAN2G(11, 2462, 0), | ||
135 | CHAN2G(12, 2467, 0), | ||
136 | CHAN2G(13, 2472, 0), | ||
137 | CHAN2G(14, 2484, 0), | ||
138 | }; | ||
139 | |||
140 | static struct ieee80211_channel cw1200_5ghz_chantable[] = { | ||
141 | CHAN5G(34, 0), CHAN5G(36, 0), | ||
142 | CHAN5G(38, 0), CHAN5G(40, 0), | ||
143 | CHAN5G(42, 0), CHAN5G(44, 0), | ||
144 | CHAN5G(46, 0), CHAN5G(48, 0), | ||
145 | CHAN5G(52, 0), CHAN5G(56, 0), | ||
146 | CHAN5G(60, 0), CHAN5G(64, 0), | ||
147 | CHAN5G(100, 0), CHAN5G(104, 0), | ||
148 | CHAN5G(108, 0), CHAN5G(112, 0), | ||
149 | CHAN5G(116, 0), CHAN5G(120, 0), | ||
150 | CHAN5G(124, 0), CHAN5G(128, 0), | ||
151 | CHAN5G(132, 0), CHAN5G(136, 0), | ||
152 | CHAN5G(140, 0), CHAN5G(149, 0), | ||
153 | CHAN5G(153, 0), CHAN5G(157, 0), | ||
154 | CHAN5G(161, 0), CHAN5G(165, 0), | ||
155 | CHAN5G(184, 0), CHAN5G(188, 0), | ||
156 | CHAN5G(192, 0), CHAN5G(196, 0), | ||
157 | CHAN5G(200, 0), CHAN5G(204, 0), | ||
158 | CHAN5G(208, 0), CHAN5G(212, 0), | ||
159 | CHAN5G(216, 0), | ||
160 | }; | ||
161 | |||
162 | static struct ieee80211_supported_band cw1200_band_2ghz = { | ||
163 | .channels = cw1200_2ghz_chantable, | ||
164 | .n_channels = ARRAY_SIZE(cw1200_2ghz_chantable), | ||
165 | .bitrates = cw1200_g_rates, | ||
166 | .n_bitrates = cw1200_g_rates_size, | ||
167 | .ht_cap = { | ||
168 | .cap = IEEE80211_HT_CAP_GRN_FLD | | ||
169 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | | ||
170 | IEEE80211_HT_CAP_MAX_AMSDU, | ||
171 | .ht_supported = 1, | ||
172 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, | ||
173 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, | ||
174 | .mcs = { | ||
175 | .rx_mask[0] = 0xFF, | ||
176 | .rx_highest = __cpu_to_le16(0x41), | ||
177 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
178 | }, | ||
179 | }, | ||
180 | }; | ||
181 | |||
182 | static struct ieee80211_supported_band cw1200_band_5ghz = { | ||
183 | .channels = cw1200_5ghz_chantable, | ||
184 | .n_channels = ARRAY_SIZE(cw1200_5ghz_chantable), | ||
185 | .bitrates = cw1200_a_rates, | ||
186 | .n_bitrates = cw1200_a_rates_size, | ||
187 | .ht_cap = { | ||
188 | .cap = IEEE80211_HT_CAP_GRN_FLD | | ||
189 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | | ||
190 | IEEE80211_HT_CAP_MAX_AMSDU, | ||
191 | .ht_supported = 1, | ||
192 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, | ||
193 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, | ||
194 | .mcs = { | ||
195 | .rx_mask[0] = 0xFF, | ||
196 | .rx_highest = __cpu_to_le16(0x41), | ||
197 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, | ||
198 | }, | ||
199 | }, | ||
200 | }; | ||
201 | |||
202 | static const unsigned long cw1200_ttl[] = { | ||
203 | 1 * HZ, /* VO */ | ||
204 | 2 * HZ, /* VI */ | ||
205 | 5 * HZ, /* BE */ | ||
206 | 10 * HZ /* BK */ | ||
207 | }; | ||
208 | |||
209 | static const struct ieee80211_ops cw1200_ops = { | ||
210 | .start = cw1200_start, | ||
211 | .stop = cw1200_stop, | ||
212 | .add_interface = cw1200_add_interface, | ||
213 | .remove_interface = cw1200_remove_interface, | ||
214 | .change_interface = cw1200_change_interface, | ||
215 | .tx = cw1200_tx, | ||
216 | .hw_scan = cw1200_hw_scan, | ||
217 | .set_tim = cw1200_set_tim, | ||
218 | .sta_notify = cw1200_sta_notify, | ||
219 | .sta_add = cw1200_sta_add, | ||
220 | .sta_remove = cw1200_sta_remove, | ||
221 | .set_key = cw1200_set_key, | ||
222 | .set_rts_threshold = cw1200_set_rts_threshold, | ||
223 | .config = cw1200_config, | ||
224 | .bss_info_changed = cw1200_bss_info_changed, | ||
225 | .prepare_multicast = cw1200_prepare_multicast, | ||
226 | .configure_filter = cw1200_configure_filter, | ||
227 | .conf_tx = cw1200_conf_tx, | ||
228 | .get_stats = cw1200_get_stats, | ||
229 | .ampdu_action = cw1200_ampdu_action, | ||
230 | .flush = cw1200_flush, | ||
231 | #ifdef CONFIG_PM | ||
232 | .suspend = cw1200_wow_suspend, | ||
233 | .resume = cw1200_wow_resume, | ||
234 | #endif | ||
235 | /* Intentionally not offloaded: */ | ||
236 | /*.channel_switch = cw1200_channel_switch, */ | ||
237 | /*.remain_on_channel = cw1200_remain_on_channel, */ | ||
238 | /*.cancel_remain_on_channel = cw1200_cancel_remain_on_channel, */ | ||
239 | }; | ||
240 | |||
241 | int cw1200_ba_rx_tids = -1; | ||
242 | int cw1200_ba_tx_tids = -1; | ||
243 | module_param(cw1200_ba_rx_tids, int, 0644); | ||
244 | module_param(cw1200_ba_tx_tids, int, 0644); | ||
245 | MODULE_PARM_DESC(cw1200_ba_rx_tids, "Block ACK RX TIDs"); | ||
246 | MODULE_PARM_DESC(cw1200_ba_tx_tids, "Block ACK TX TIDs"); | ||
247 | |||
248 | static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr, | ||
249 | const bool have_5ghz) | ||
250 | { | ||
251 | int i, band; | ||
252 | struct ieee80211_hw *hw; | ||
253 | struct cw1200_common *priv; | ||
254 | |||
255 | hw = ieee80211_alloc_hw(sizeof(struct cw1200_common), &cw1200_ops); | ||
256 | if (!hw) | ||
257 | return NULL; | ||
258 | |||
259 | priv = hw->priv; | ||
260 | priv->hw = hw; | ||
261 | priv->hw_type = -1; | ||
262 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||
263 | priv->rates = cw1200_rates; /* TODO: fetch from FW */ | ||
264 | priv->mcs_rates = cw1200_n_rates; | ||
265 | if (cw1200_ba_rx_tids != -1) | ||
266 | priv->ba_rx_tid_mask = cw1200_ba_rx_tids; | ||
267 | else | ||
268 | priv->ba_rx_tid_mask = 0xFF; /* Enable RX BLKACK for all TIDs */ | ||
269 | if (cw1200_ba_tx_tids != -1) | ||
270 | priv->ba_tx_tid_mask = cw1200_ba_tx_tids; | ||
271 | else | ||
272 | priv->ba_tx_tid_mask = 0xff; /* Enable TX BLKACK for all TIDs */ | ||
273 | |||
274 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | ||
275 | IEEE80211_HW_SUPPORTS_PS | | ||
276 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | | ||
277 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | | ||
278 | IEEE80211_HW_SUPPORTS_UAPSD | | ||
279 | IEEE80211_HW_CONNECTION_MONITOR | | ||
280 | IEEE80211_HW_AMPDU_AGGREGATION | | ||
281 | IEEE80211_HW_TX_AMPDU_SETUP_IN_HW | | ||
282 | IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC; | ||
283 | |||
284 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
285 | BIT(NL80211_IFTYPE_ADHOC) | | ||
286 | BIT(NL80211_IFTYPE_AP) | | ||
287 | BIT(NL80211_IFTYPE_MESH_POINT) | | ||
288 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
289 | BIT(NL80211_IFTYPE_P2P_GO); | ||
290 | |||
291 | #ifdef CONFIG_PM | ||
292 | /* Support only for limited wowlan functionalities */ | ||
293 | hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | | ||
294 | WIPHY_WOWLAN_DISCONNECT; | ||
295 | hw->wiphy->wowlan.n_patterns = 0; | ||
296 | #endif | ||
297 | |||
298 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | ||
299 | |||
300 | hw->channel_change_time = 1000; /* TODO: find actual value */ | ||
301 | hw->queues = 4; | ||
302 | |||
303 | priv->rts_threshold = -1; | ||
304 | |||
305 | hw->max_rates = 8; | ||
306 | hw->max_rate_tries = 15; | ||
307 | hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + | ||
308 | 8; /* TKIP IV */ | ||
309 | |||
310 | hw->sta_data_size = sizeof(struct cw1200_sta_priv); | ||
311 | |||
312 | hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &cw1200_band_2ghz; | ||
313 | if (have_5ghz) | ||
314 | hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &cw1200_band_5ghz; | ||
315 | |||
316 | /* Channel params have to be cleared before registering wiphy again */ | ||
317 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
318 | struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; | ||
319 | if (!sband) | ||
320 | continue; | ||
321 | for (i = 0; i < sband->n_channels; i++) { | ||
322 | sband->channels[i].flags = 0; | ||
323 | sband->channels[i].max_antenna_gain = 0; | ||
324 | sband->channels[i].max_power = 30; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | hw->wiphy->max_scan_ssids = 2; | ||
329 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | ||
330 | |||
331 | if (macaddr) | ||
332 | SET_IEEE80211_PERM_ADDR(hw, (u8 *)macaddr); | ||
333 | else | ||
334 | SET_IEEE80211_PERM_ADDR(hw, cw1200_mac_template); | ||
335 | |||
336 | /* Fix up mac address if necessary */ | ||
337 | if (hw->wiphy->perm_addr[3] == 0 && | ||
338 | hw->wiphy->perm_addr[4] == 0 && | ||
339 | hw->wiphy->perm_addr[5] == 0) { | ||
340 | get_random_bytes(&hw->wiphy->perm_addr[3], 3); | ||
341 | } | ||
342 | |||
343 | mutex_init(&priv->wsm_cmd_mux); | ||
344 | mutex_init(&priv->conf_mutex); | ||
345 | priv->workqueue = create_singlethread_workqueue("cw1200_wq"); | ||
346 | sema_init(&priv->scan.lock, 1); | ||
347 | INIT_WORK(&priv->scan.work, cw1200_scan_work); | ||
348 | INIT_DELAYED_WORK(&priv->scan.probe_work, cw1200_probe_work); | ||
349 | INIT_DELAYED_WORK(&priv->scan.timeout, cw1200_scan_timeout); | ||
350 | INIT_DELAYED_WORK(&priv->clear_recent_scan_work, | ||
351 | cw1200_clear_recent_scan_work); | ||
352 | INIT_DELAYED_WORK(&priv->join_timeout, cw1200_join_timeout); | ||
353 | INIT_WORK(&priv->unjoin_work, cw1200_unjoin_work); | ||
354 | INIT_WORK(&priv->join_complete_work, cw1200_join_complete_work); | ||
355 | INIT_WORK(&priv->wep_key_work, cw1200_wep_key_work); | ||
356 | INIT_WORK(&priv->tx_policy_upload_work, tx_policy_upload_work); | ||
357 | spin_lock_init(&priv->event_queue_lock); | ||
358 | INIT_LIST_HEAD(&priv->event_queue); | ||
359 | INIT_WORK(&priv->event_handler, cw1200_event_handler); | ||
360 | INIT_DELAYED_WORK(&priv->bss_loss_work, cw1200_bss_loss_work); | ||
361 | INIT_WORK(&priv->bss_params_work, cw1200_bss_params_work); | ||
362 | spin_lock_init(&priv->bss_loss_lock); | ||
363 | spin_lock_init(&priv->ps_state_lock); | ||
364 | INIT_WORK(&priv->set_cts_work, cw1200_set_cts_work); | ||
365 | INIT_WORK(&priv->set_tim_work, cw1200_set_tim_work); | ||
366 | INIT_WORK(&priv->multicast_start_work, cw1200_multicast_start_work); | ||
367 | INIT_WORK(&priv->multicast_stop_work, cw1200_multicast_stop_work); | ||
368 | INIT_WORK(&priv->link_id_work, cw1200_link_id_work); | ||
369 | INIT_DELAYED_WORK(&priv->link_id_gc_work, cw1200_link_id_gc_work); | ||
370 | INIT_WORK(&priv->linkid_reset_work, cw1200_link_id_reset); | ||
371 | INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work); | ||
372 | INIT_WORK(&priv->set_beacon_wakeup_period_work, | ||
373 | cw1200_set_beacon_wakeup_period_work); | ||
374 | init_timer(&priv->mcast_timeout); | ||
375 | priv->mcast_timeout.data = (unsigned long)priv; | ||
376 | priv->mcast_timeout.function = cw1200_mcast_timeout; | ||
377 | |||
378 | if (cw1200_queue_stats_init(&priv->tx_queue_stats, | ||
379 | CW1200_LINK_ID_MAX, | ||
380 | cw1200_skb_dtor, | ||
381 | priv)) { | ||
382 | ieee80211_free_hw(hw); | ||
383 | return NULL; | ||
384 | } | ||
385 | |||
386 | for (i = 0; i < 4; ++i) { | ||
387 | if (cw1200_queue_init(&priv->tx_queue[i], | ||
388 | &priv->tx_queue_stats, i, 16, | ||
389 | cw1200_ttl[i])) { | ||
390 | for (; i > 0; i--) | ||
391 | cw1200_queue_deinit(&priv->tx_queue[i - 1]); | ||
392 | cw1200_queue_stats_deinit(&priv->tx_queue_stats); | ||
393 | ieee80211_free_hw(hw); | ||
394 | return NULL; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | init_waitqueue_head(&priv->channel_switch_done); | ||
399 | init_waitqueue_head(&priv->wsm_cmd_wq); | ||
400 | init_waitqueue_head(&priv->wsm_startup_done); | ||
401 | init_waitqueue_head(&priv->ps_mode_switch_done); | ||
402 | wsm_buf_init(&priv->wsm_cmd_buf); | ||
403 | spin_lock_init(&priv->wsm_cmd.lock); | ||
404 | priv->wsm_cmd.done = 1; | ||
405 | tx_policy_init(priv); | ||
406 | |||
407 | return hw; | ||
408 | } | ||
409 | |||
410 | static int cw1200_register_common(struct ieee80211_hw *dev) | ||
411 | { | ||
412 | struct cw1200_common *priv = dev->priv; | ||
413 | int err; | ||
414 | |||
415 | #ifdef CONFIG_PM | ||
416 | err = cw1200_pm_init(&priv->pm_state, priv); | ||
417 | if (err) { | ||
418 | pr_err("Cannot init PM. (%d).\n", | ||
419 | err); | ||
420 | return err; | ||
421 | } | ||
422 | #endif | ||
423 | |||
424 | err = ieee80211_register_hw(dev); | ||
425 | if (err) { | ||
426 | pr_err("Cannot register device (%d).\n", | ||
427 | err); | ||
428 | #ifdef CONFIG_PM | ||
429 | cw1200_pm_deinit(&priv->pm_state); | ||
430 | #endif | ||
431 | return err; | ||
432 | } | ||
433 | |||
434 | cw1200_debug_init(priv); | ||
435 | |||
436 | pr_info("Registered as '%s'\n", wiphy_name(dev->wiphy)); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static void cw1200_free_common(struct ieee80211_hw *dev) | ||
441 | { | ||
442 | ieee80211_free_hw(dev); | ||
443 | } | ||
444 | |||
445 | static void cw1200_unregister_common(struct ieee80211_hw *dev) | ||
446 | { | ||
447 | struct cw1200_common *priv = dev->priv; | ||
448 | int i; | ||
449 | |||
450 | ieee80211_unregister_hw(dev); | ||
451 | |||
452 | del_timer_sync(&priv->mcast_timeout); | ||
453 | cw1200_unregister_bh(priv); | ||
454 | |||
455 | cw1200_debug_release(priv); | ||
456 | |||
457 | mutex_destroy(&priv->conf_mutex); | ||
458 | |||
459 | wsm_buf_deinit(&priv->wsm_cmd_buf); | ||
460 | |||
461 | destroy_workqueue(priv->workqueue); | ||
462 | priv->workqueue = NULL; | ||
463 | |||
464 | if (priv->sdd) { | ||
465 | release_firmware(priv->sdd); | ||
466 | priv->sdd = NULL; | ||
467 | } | ||
468 | |||
469 | for (i = 0; i < 4; ++i) | ||
470 | cw1200_queue_deinit(&priv->tx_queue[i]); | ||
471 | |||
472 | cw1200_queue_stats_deinit(&priv->tx_queue_stats); | ||
473 | #ifdef CONFIG_PM | ||
474 | cw1200_pm_deinit(&priv->pm_state); | ||
475 | #endif | ||
476 | } | ||
477 | |||
478 | /* Clock is in KHz */ | ||
479 | u32 cw1200_dpll_from_clk(u16 clk_khz) | ||
480 | { | ||
481 | switch (clk_khz) { | ||
482 | case 0x32C8: /* 13000 KHz */ | ||
483 | return 0x1D89D241; | ||
484 | case 0x3E80: /* 16000 KHz */ | ||
485 | return 0x000001E1; | ||
486 | case 0x41A0: /* 16800 KHz */ | ||
487 | return 0x124931C1; | ||
488 | case 0x4B00: /* 19200 KHz */ | ||
489 | return 0x00000191; | ||
490 | case 0x5DC0: /* 24000 KHz */ | ||
491 | return 0x00000141; | ||
492 | case 0x6590: /* 26000 KHz */ | ||
493 | return 0x0EC4F121; | ||
494 | case 0x8340: /* 33600 KHz */ | ||
495 | return 0x092490E1; | ||
496 | case 0x9600: /* 38400 KHz */ | ||
497 | return 0x100010C1; | ||
498 | case 0x9C40: /* 40000 KHz */ | ||
499 | return 0x000000C1; | ||
500 | case 0xBB80: /* 48000 KHz */ | ||
501 | return 0x000000A1; | ||
502 | case 0xCB20: /* 52000 KHz */ | ||
503 | return 0x07627091; | ||
504 | default: | ||
505 | pr_err("Unknown Refclk freq (0x%04x), using 2600KHz\n", | ||
506 | clk_khz); | ||
507 | return 0x0EC4F121; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | int cw1200_core_probe(const struct hwbus_ops *hwbus_ops, | ||
512 | struct hwbus_priv *hwbus, | ||
513 | struct device *pdev, | ||
514 | struct cw1200_common **core, | ||
515 | int ref_clk, const u8 *macaddr, | ||
516 | const char *sdd_path, bool have_5ghz) | ||
517 | { | ||
518 | int err = -EINVAL; | ||
519 | struct ieee80211_hw *dev; | ||
520 | struct cw1200_common *priv; | ||
521 | struct wsm_operational_mode mode = { | ||
522 | .power_mode = cw1200_power_mode, | ||
523 | .disable_more_flag_usage = true, | ||
524 | }; | ||
525 | |||
526 | dev = cw1200_init_common(macaddr, have_5ghz); | ||
527 | if (!dev) | ||
528 | goto err; | ||
529 | |||
530 | priv = dev->priv; | ||
531 | priv->hw_refclk = ref_clk; | ||
532 | if (cw1200_refclk) | ||
533 | priv->hw_refclk = cw1200_refclk; | ||
534 | |||
535 | priv->sdd_path = (char *)sdd_path; | ||
536 | if (cw1200_sdd_path) | ||
537 | priv->sdd_path = cw1200_sdd_path; | ||
538 | |||
539 | priv->hwbus_ops = hwbus_ops; | ||
540 | priv->hwbus_priv = hwbus; | ||
541 | priv->pdev = pdev; | ||
542 | SET_IEEE80211_DEV(priv->hw, pdev); | ||
543 | |||
544 | /* Pass struct cw1200_common back up */ | ||
545 | *core = priv; | ||
546 | |||
547 | err = cw1200_register_bh(priv); | ||
548 | if (err) | ||
549 | goto err1; | ||
550 | |||
551 | err = cw1200_load_firmware(priv); | ||
552 | if (err) | ||
553 | goto err2; | ||
554 | |||
555 | if (wait_event_interruptible_timeout(priv->wsm_startup_done, | ||
556 | priv->firmware_ready, | ||
557 | 3*HZ) <= 0) { | ||
558 | /* TODO: Need to find how to reset device | ||
559 | in QUEUE mode properly. | ||
560 | */ | ||
561 | pr_err("Timeout waiting on device startup\n"); | ||
562 | err = -ETIMEDOUT; | ||
563 | goto err2; | ||
564 | } | ||
565 | |||
566 | /* Set low-power mode. */ | ||
567 | wsm_set_operational_mode(priv, &mode); | ||
568 | |||
569 | /* Enable multi-TX confirmation */ | ||
570 | wsm_use_multi_tx_conf(priv, true); | ||
571 | |||
572 | err = cw1200_register_common(dev); | ||
573 | if (err) | ||
574 | goto err2; | ||
575 | |||
576 | return err; | ||
577 | |||
578 | err2: | ||
579 | cw1200_unregister_bh(priv); | ||
580 | err1: | ||
581 | cw1200_free_common(dev); | ||
582 | err: | ||
583 | *core = NULL; | ||
584 | return err; | ||
585 | } | ||
586 | EXPORT_SYMBOL_GPL(cw1200_core_probe); | ||
587 | |||
588 | void cw1200_core_release(struct cw1200_common *self) | ||
589 | { | ||
590 | /* Disable device interrupts */ | ||
591 | self->hwbus_ops->lock(self->hwbus_priv); | ||
592 | __cw1200_irq_enable(self, 0); | ||
593 | self->hwbus_ops->unlock(self->hwbus_priv); | ||
594 | |||
595 | /* And then clean up */ | ||
596 | cw1200_unregister_common(self->hw); | ||
597 | cw1200_free_common(self->hw); | ||
598 | return; | ||
599 | } | ||
600 | 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..4cd0352b508d --- /dev/null +++ b/drivers/net/wireless/cw1200/sta.c | |||
@@ -0,0 +1,2404 @@ | |||
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 | /* When acting as p2p client being connected to p2p GO, in order to | ||
487 | * receive frames from a different p2p device, turn off bssid filter. | ||
488 | * | ||
489 | * WARNING: FW dependency! | ||
490 | * This can only be used with FW WSM371 and its successors. | ||
491 | * In that FW version even with bssid filter turned off, | ||
492 | * device will block most of the unwanted frames. | ||
493 | */ | ||
494 | if (is_p2p) | ||
495 | bssid_filtering = false; | ||
496 | |||
497 | ret = wsm_set_rx_filter(priv, &priv->rx_filter); | ||
498 | if (!ret) | ||
499 | ret = wsm_set_beacon_filter_table(priv, &bf_tbl); | ||
500 | if (!ret) | ||
501 | ret = wsm_beacon_filter_control(priv, &bf_ctrl); | ||
502 | if (!ret) | ||
503 | ret = wsm_set_bssid_filtering(priv, bssid_filtering); | ||
504 | if (!ret) | ||
505 | ret = wsm_set_multicast_filter(priv, &priv->multicast_filter); | ||
506 | if (ret) | ||
507 | wiphy_err(priv->hw->wiphy, | ||
508 | "Update filtering failed: %d.\n", ret); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | void cw1200_update_filtering_work(struct work_struct *work) | ||
513 | { | ||
514 | struct cw1200_common *priv = | ||
515 | container_of(work, struct cw1200_common, | ||
516 | update_filtering_work); | ||
517 | |||
518 | cw1200_update_filtering(priv); | ||
519 | } | ||
520 | |||
521 | void cw1200_set_beacon_wakeup_period_work(struct work_struct *work) | ||
522 | { | ||
523 | struct cw1200_common *priv = | ||
524 | container_of(work, struct cw1200_common, | ||
525 | set_beacon_wakeup_period_work); | ||
526 | |||
527 | wsm_set_beacon_wakeup_period(priv, | ||
528 | priv->beacon_int * priv->join_dtim_period > | ||
529 | MAX_BEACON_SKIP_TIME_MS ? 1 : | ||
530 | priv->join_dtim_period, 0); | ||
531 | } | ||
532 | |||
533 | u64 cw1200_prepare_multicast(struct ieee80211_hw *hw, | ||
534 | struct netdev_hw_addr_list *mc_list) | ||
535 | { | ||
536 | static u8 broadcast_ipv6[ETH_ALEN] = { | ||
537 | 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 | ||
538 | }; | ||
539 | static u8 broadcast_ipv4[ETH_ALEN] = { | ||
540 | 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01 | ||
541 | }; | ||
542 | struct cw1200_common *priv = hw->priv; | ||
543 | struct netdev_hw_addr *ha; | ||
544 | int count = 0; | ||
545 | |||
546 | /* Disable multicast filtering */ | ||
547 | priv->has_multicast_subscription = false; | ||
548 | memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter)); | ||
549 | |||
550 | if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES) | ||
551 | return 0; | ||
552 | |||
553 | /* Enable if requested */ | ||
554 | netdev_hw_addr_list_for_each(ha, mc_list) { | ||
555 | pr_debug("[STA] multicast: %pM\n", ha->addr); | ||
556 | memcpy(&priv->multicast_filter.macaddrs[count], | ||
557 | ha->addr, ETH_ALEN); | ||
558 | if (memcmp(ha->addr, broadcast_ipv4, ETH_ALEN) && | ||
559 | memcmp(ha->addr, broadcast_ipv6, ETH_ALEN)) | ||
560 | priv->has_multicast_subscription = true; | ||
561 | count++; | ||
562 | } | ||
563 | |||
564 | if (count) { | ||
565 | priv->multicast_filter.enable = __cpu_to_le32(1); | ||
566 | priv->multicast_filter.num_addrs = __cpu_to_le32(count); | ||
567 | } | ||
568 | |||
569 | return netdev_hw_addr_list_count(mc_list); | ||
570 | } | ||
571 | |||
572 | void cw1200_configure_filter(struct ieee80211_hw *dev, | ||
573 | unsigned int changed_flags, | ||
574 | unsigned int *total_flags, | ||
575 | u64 multicast) | ||
576 | { | ||
577 | struct cw1200_common *priv = dev->priv; | ||
578 | bool listening = !!(*total_flags & | ||
579 | (FIF_PROMISC_IN_BSS | | ||
580 | FIF_OTHER_BSS | | ||
581 | FIF_BCN_PRBRESP_PROMISC | | ||
582 | FIF_PROBE_REQ)); | ||
583 | |||
584 | *total_flags &= FIF_PROMISC_IN_BSS | | ||
585 | FIF_OTHER_BSS | | ||
586 | FIF_FCSFAIL | | ||
587 | FIF_BCN_PRBRESP_PROMISC | | ||
588 | FIF_PROBE_REQ; | ||
589 | |||
590 | down(&priv->scan.lock); | ||
591 | mutex_lock(&priv->conf_mutex); | ||
592 | |||
593 | priv->rx_filter.promiscuous = (*total_flags & FIF_PROMISC_IN_BSS) | ||
594 | ? 1 : 0; | ||
595 | priv->rx_filter.bssid = (*total_flags & (FIF_OTHER_BSS | | ||
596 | FIF_PROBE_REQ)) ? 1 : 0; | ||
597 | priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0; | ||
598 | priv->disable_beacon_filter = !(*total_flags & | ||
599 | (FIF_BCN_PRBRESP_PROMISC | | ||
600 | FIF_PROMISC_IN_BSS | | ||
601 | FIF_PROBE_REQ)); | ||
602 | if (priv->listening != listening) { | ||
603 | priv->listening = listening; | ||
604 | wsm_lock_tx(priv); | ||
605 | cw1200_update_listening(priv, listening); | ||
606 | wsm_unlock_tx(priv); | ||
607 | } | ||
608 | cw1200_update_filtering(priv); | ||
609 | mutex_unlock(&priv->conf_mutex); | ||
610 | up(&priv->scan.lock); | ||
611 | } | ||
612 | |||
613 | int cw1200_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, | ||
614 | u16 queue, const struct ieee80211_tx_queue_params *params) | ||
615 | { | ||
616 | struct cw1200_common *priv = dev->priv; | ||
617 | int ret = 0; | ||
618 | /* To prevent re-applying PM request OID again and again*/ | ||
619 | bool old_uapsd_flags; | ||
620 | |||
621 | mutex_lock(&priv->conf_mutex); | ||
622 | |||
623 | if (queue < dev->queues) { | ||
624 | old_uapsd_flags = priv->uapsd_info.uapsd_flags; | ||
625 | |||
626 | WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0); | ||
627 | ret = wsm_set_tx_queue_params(priv, | ||
628 | &priv->tx_queue_params.params[queue], queue); | ||
629 | if (ret) { | ||
630 | ret = -EINVAL; | ||
631 | goto out; | ||
632 | } | ||
633 | |||
634 | WSM_EDCA_SET(&priv->edca, queue, params->aifs, | ||
635 | params->cw_min, params->cw_max, | ||
636 | params->txop, 0xc8, | ||
637 | params->uapsd); | ||
638 | ret = wsm_set_edca_params(priv, &priv->edca); | ||
639 | if (ret) { | ||
640 | ret = -EINVAL; | ||
641 | goto out; | ||
642 | } | ||
643 | |||
644 | if (priv->mode == NL80211_IFTYPE_STATION) { | ||
645 | ret = cw1200_set_uapsd_param(priv, &priv->edca); | ||
646 | if (!ret && priv->setbssparams_done && | ||
647 | (priv->join_status == CW1200_JOIN_STATUS_STA) && | ||
648 | (old_uapsd_flags != priv->uapsd_info.uapsd_flags)) | ||
649 | ret = cw1200_set_pm(priv, &priv->powersave_mode); | ||
650 | } | ||
651 | } else { | ||
652 | ret = -EINVAL; | ||
653 | } | ||
654 | |||
655 | out: | ||
656 | mutex_unlock(&priv->conf_mutex); | ||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | int cw1200_get_stats(struct ieee80211_hw *dev, | ||
661 | struct ieee80211_low_level_stats *stats) | ||
662 | { | ||
663 | struct cw1200_common *priv = dev->priv; | ||
664 | |||
665 | memcpy(stats, &priv->stats, sizeof(*stats)); | ||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | int cw1200_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) | ||
670 | { | ||
671 | struct wsm_set_pm pm = *arg; | ||
672 | |||
673 | if (priv->uapsd_info.uapsd_flags != 0) | ||
674 | pm.mode &= ~WSM_PSM_FAST_PS_FLAG; | ||
675 | |||
676 | if (memcmp(&pm, &priv->firmware_ps_mode, | ||
677 | sizeof(struct wsm_set_pm))) { | ||
678 | priv->firmware_ps_mode = pm; | ||
679 | return wsm_set_pm(priv, &pm); | ||
680 | } else { | ||
681 | return 0; | ||
682 | } | ||
683 | } | ||
684 | |||
685 | int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | ||
686 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
687 | struct ieee80211_key_conf *key) | ||
688 | { | ||
689 | int ret = -EOPNOTSUPP; | ||
690 | struct cw1200_common *priv = dev->priv; | ||
691 | struct ieee80211_key_seq seq; | ||
692 | |||
693 | mutex_lock(&priv->conf_mutex); | ||
694 | |||
695 | if (cmd == SET_KEY) { | ||
696 | u8 *peer_addr = NULL; | ||
697 | int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? | ||
698 | 1 : 0; | ||
699 | int idx = cw1200_alloc_key(priv); | ||
700 | struct wsm_add_key *wsm_key = &priv->keys[idx]; | ||
701 | |||
702 | if (idx < 0) { | ||
703 | ret = -EINVAL; | ||
704 | goto finally; | ||
705 | } | ||
706 | |||
707 | if (sta) | ||
708 | peer_addr = sta->addr; | ||
709 | |||
710 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; | ||
711 | |||
712 | switch (key->cipher) { | ||
713 | case WLAN_CIPHER_SUITE_WEP40: | ||
714 | case WLAN_CIPHER_SUITE_WEP104: | ||
715 | if (key->keylen > 16) { | ||
716 | cw1200_free_key(priv, idx); | ||
717 | ret = -EINVAL; | ||
718 | goto finally; | ||
719 | } | ||
720 | |||
721 | if (pairwise) { | ||
722 | wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; | ||
723 | memcpy(wsm_key->wep_pairwise.peer, | ||
724 | peer_addr, ETH_ALEN); | ||
725 | memcpy(wsm_key->wep_pairwise.keydata, | ||
726 | &key->key[0], key->keylen); | ||
727 | wsm_key->wep_pairwise.keylen = key->keylen; | ||
728 | } else { | ||
729 | wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; | ||
730 | memcpy(wsm_key->wep_group.keydata, | ||
731 | &key->key[0], key->keylen); | ||
732 | wsm_key->wep_group.keylen = key->keylen; | ||
733 | wsm_key->wep_group.keyid = key->keyidx; | ||
734 | } | ||
735 | break; | ||
736 | case WLAN_CIPHER_SUITE_TKIP: | ||
737 | ieee80211_get_key_rx_seq(key, 0, &seq); | ||
738 | if (pairwise) { | ||
739 | wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; | ||
740 | memcpy(wsm_key->tkip_pairwise.peer, | ||
741 | peer_addr, ETH_ALEN); | ||
742 | memcpy(wsm_key->tkip_pairwise.keydata, | ||
743 | &key->key[0], 16); | ||
744 | memcpy(wsm_key->tkip_pairwise.tx_mic_key, | ||
745 | &key->key[16], 8); | ||
746 | memcpy(wsm_key->tkip_pairwise.rx_mic_key, | ||
747 | &key->key[24], 8); | ||
748 | } else { | ||
749 | size_t mic_offset = | ||
750 | (priv->mode == NL80211_IFTYPE_AP) ? | ||
751 | 16 : 24; | ||
752 | wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; | ||
753 | memcpy(wsm_key->tkip_group.keydata, | ||
754 | &key->key[0], 16); | ||
755 | memcpy(wsm_key->tkip_group.rx_mic_key, | ||
756 | &key->key[mic_offset], 8); | ||
757 | |||
758 | wsm_key->tkip_group.rx_seqnum[0] = seq.tkip.iv16 & 0xff; | ||
759 | wsm_key->tkip_group.rx_seqnum[1] = (seq.tkip.iv16 >> 8) & 0xff; | ||
760 | wsm_key->tkip_group.rx_seqnum[2] = seq.tkip.iv32 & 0xff; | ||
761 | wsm_key->tkip_group.rx_seqnum[3] = (seq.tkip.iv32 >> 8) & 0xff; | ||
762 | wsm_key->tkip_group.rx_seqnum[4] = (seq.tkip.iv32 >> 16) & 0xff; | ||
763 | wsm_key->tkip_group.rx_seqnum[5] = (seq.tkip.iv32 >> 24) & 0xff; | ||
764 | wsm_key->tkip_group.rx_seqnum[6] = 0; | ||
765 | wsm_key->tkip_group.rx_seqnum[7] = 0; | ||
766 | |||
767 | wsm_key->tkip_group.keyid = key->keyidx; | ||
768 | } | ||
769 | break; | ||
770 | case WLAN_CIPHER_SUITE_CCMP: | ||
771 | ieee80211_get_key_rx_seq(key, 0, &seq); | ||
772 | if (pairwise) { | ||
773 | wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; | ||
774 | memcpy(wsm_key->aes_pairwise.peer, | ||
775 | peer_addr, ETH_ALEN); | ||
776 | memcpy(wsm_key->aes_pairwise.keydata, | ||
777 | &key->key[0], 16); | ||
778 | } else { | ||
779 | wsm_key->type = WSM_KEY_TYPE_AES_GROUP; | ||
780 | memcpy(wsm_key->aes_group.keydata, | ||
781 | &key->key[0], 16); | ||
782 | |||
783 | wsm_key->aes_group.rx_seqnum[0] = seq.ccmp.pn[5]; | ||
784 | wsm_key->aes_group.rx_seqnum[1] = seq.ccmp.pn[4]; | ||
785 | wsm_key->aes_group.rx_seqnum[2] = seq.ccmp.pn[3]; | ||
786 | wsm_key->aes_group.rx_seqnum[3] = seq.ccmp.pn[2]; | ||
787 | wsm_key->aes_group.rx_seqnum[4] = seq.ccmp.pn[1]; | ||
788 | wsm_key->aes_group.rx_seqnum[5] = seq.ccmp.pn[0]; | ||
789 | wsm_key->aes_group.rx_seqnum[6] = 0; | ||
790 | wsm_key->aes_group.rx_seqnum[7] = 0; | ||
791 | wsm_key->aes_group.keyid = key->keyidx; | ||
792 | } | ||
793 | break; | ||
794 | case WLAN_CIPHER_SUITE_SMS4: | ||
795 | if (pairwise) { | ||
796 | wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; | ||
797 | memcpy(wsm_key->wapi_pairwise.peer, | ||
798 | peer_addr, ETH_ALEN); | ||
799 | memcpy(wsm_key->wapi_pairwise.keydata, | ||
800 | &key->key[0], 16); | ||
801 | memcpy(wsm_key->wapi_pairwise.mic_key, | ||
802 | &key->key[16], 16); | ||
803 | wsm_key->wapi_pairwise.keyid = key->keyidx; | ||
804 | } else { | ||
805 | wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; | ||
806 | memcpy(wsm_key->wapi_group.keydata, | ||
807 | &key->key[0], 16); | ||
808 | memcpy(wsm_key->wapi_group.mic_key, | ||
809 | &key->key[16], 16); | ||
810 | wsm_key->wapi_group.keyid = key->keyidx; | ||
811 | } | ||
812 | break; | ||
813 | default: | ||
814 | pr_warn("Unhandled key type %d\n", key->cipher); | ||
815 | cw1200_free_key(priv, idx); | ||
816 | ret = -EOPNOTSUPP; | ||
817 | goto finally; | ||
818 | } | ||
819 | ret = wsm_add_key(priv, wsm_key); | ||
820 | if (!ret) | ||
821 | key->hw_key_idx = idx; | ||
822 | else | ||
823 | cw1200_free_key(priv, idx); | ||
824 | } else if (cmd == DISABLE_KEY) { | ||
825 | struct wsm_remove_key wsm_key = { | ||
826 | .index = key->hw_key_idx, | ||
827 | }; | ||
828 | |||
829 | if (wsm_key.index > WSM_KEY_MAX_INDEX) { | ||
830 | ret = -EINVAL; | ||
831 | goto finally; | ||
832 | } | ||
833 | |||
834 | cw1200_free_key(priv, wsm_key.index); | ||
835 | ret = wsm_remove_key(priv, &wsm_key); | ||
836 | } else { | ||
837 | pr_warn("Unhandled key command %d\n", cmd); | ||
838 | } | ||
839 | |||
840 | finally: | ||
841 | mutex_unlock(&priv->conf_mutex); | ||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | void cw1200_wep_key_work(struct work_struct *work) | ||
846 | { | ||
847 | struct cw1200_common *priv = | ||
848 | container_of(work, struct cw1200_common, wep_key_work); | ||
849 | u8 queue_id = cw1200_queue_get_queue_id(priv->pending_frame_id); | ||
850 | struct cw1200_queue *queue = &priv->tx_queue[queue_id]; | ||
851 | __le32 wep_default_key_id = __cpu_to_le32( | ||
852 | priv->wep_default_key_id); | ||
853 | |||
854 | pr_debug("[STA] Setting default WEP key: %d\n", | ||
855 | priv->wep_default_key_id); | ||
856 | wsm_flush_tx(priv); | ||
857 | wsm_write_mib(priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, | ||
858 | &wep_default_key_id, sizeof(wep_default_key_id)); | ||
859 | cw1200_queue_requeue(queue, priv->pending_frame_id); | ||
860 | wsm_unlock_tx(priv); | ||
861 | } | ||
862 | |||
863 | int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) | ||
864 | { | ||
865 | int ret = 0; | ||
866 | __le32 val32; | ||
867 | struct cw1200_common *priv = hw->priv; | ||
868 | |||
869 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
870 | return 0; | ||
871 | |||
872 | if (value != (u32) -1) | ||
873 | val32 = __cpu_to_le32(value); | ||
874 | else | ||
875 | val32 = 0; /* disabled */ | ||
876 | |||
877 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
878 | /* device is down, can _not_ set threshold */ | ||
879 | ret = -ENODEV; | ||
880 | goto out; | ||
881 | } | ||
882 | |||
883 | if (priv->rts_threshold == value) | ||
884 | goto out; | ||
885 | |||
886 | pr_debug("[STA] Setting RTS threshold: %d\n", | ||
887 | priv->rts_threshold); | ||
888 | |||
889 | /* mutex_lock(&priv->conf_mutex); */ | ||
890 | ret = wsm_write_mib(priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD, | ||
891 | &val32, sizeof(val32)); | ||
892 | if (!ret) | ||
893 | priv->rts_threshold = value; | ||
894 | /* mutex_unlock(&priv->conf_mutex); */ | ||
895 | |||
896 | out: | ||
897 | return ret; | ||
898 | } | ||
899 | |||
900 | /* If successful, LOCKS the TX queue! */ | ||
901 | static int __cw1200_flush(struct cw1200_common *priv, bool drop) | ||
902 | { | ||
903 | int i, ret; | ||
904 | |||
905 | for (;;) { | ||
906 | /* TODO: correct flush handling is required when dev_stop. | ||
907 | * Temporary workaround: 2s | ||
908 | */ | ||
909 | if (drop) { | ||
910 | for (i = 0; i < 4; ++i) | ||
911 | cw1200_queue_clear(&priv->tx_queue[i]); | ||
912 | } else { | ||
913 | ret = wait_event_timeout( | ||
914 | priv->tx_queue_stats.wait_link_id_empty, | ||
915 | cw1200_queue_stats_is_empty( | ||
916 | &priv->tx_queue_stats, -1), | ||
917 | 2 * HZ); | ||
918 | } | ||
919 | |||
920 | if (!drop && ret <= 0) { | ||
921 | ret = -ETIMEDOUT; | ||
922 | break; | ||
923 | } else { | ||
924 | ret = 0; | ||
925 | } | ||
926 | |||
927 | wsm_lock_tx(priv); | ||
928 | if (!cw1200_queue_stats_is_empty(&priv->tx_queue_stats, -1)) { | ||
929 | /* Highly unlikely: WSM requeued frames. */ | ||
930 | wsm_unlock_tx(priv); | ||
931 | continue; | ||
932 | } | ||
933 | break; | ||
934 | } | ||
935 | return ret; | ||
936 | } | ||
937 | |||
938 | void cw1200_flush(struct ieee80211_hw *hw, u32 queues, bool drop) | ||
939 | { | ||
940 | struct cw1200_common *priv = hw->priv; | ||
941 | |||
942 | switch (priv->mode) { | ||
943 | case NL80211_IFTYPE_MONITOR: | ||
944 | drop = true; | ||
945 | break; | ||
946 | case NL80211_IFTYPE_AP: | ||
947 | if (!priv->enable_beacon) | ||
948 | drop = true; | ||
949 | break; | ||
950 | } | ||
951 | |||
952 | if (!__cw1200_flush(priv, drop)) | ||
953 | wsm_unlock_tx(priv); | ||
954 | |||
955 | return; | ||
956 | } | ||
957 | |||
958 | /* ******************************************************************** */ | ||
959 | /* WSM callbacks */ | ||
960 | |||
961 | void cw1200_free_event_queue(struct cw1200_common *priv) | ||
962 | { | ||
963 | LIST_HEAD(list); | ||
964 | |||
965 | spin_lock(&priv->event_queue_lock); | ||
966 | list_splice_init(&priv->event_queue, &list); | ||
967 | spin_unlock(&priv->event_queue_lock); | ||
968 | |||
969 | __cw1200_free_event_queue(&list); | ||
970 | } | ||
971 | |||
972 | void cw1200_event_handler(struct work_struct *work) | ||
973 | { | ||
974 | struct cw1200_common *priv = | ||
975 | container_of(work, struct cw1200_common, event_handler); | ||
976 | struct cw1200_wsm_event *event; | ||
977 | LIST_HEAD(list); | ||
978 | |||
979 | spin_lock(&priv->event_queue_lock); | ||
980 | list_splice_init(&priv->event_queue, &list); | ||
981 | spin_unlock(&priv->event_queue_lock); | ||
982 | |||
983 | list_for_each_entry(event, &list, link) { | ||
984 | switch (event->evt.id) { | ||
985 | case WSM_EVENT_ERROR: | ||
986 | pr_err("Unhandled WSM Error from LMAC\n"); | ||
987 | break; | ||
988 | case WSM_EVENT_BSS_LOST: | ||
989 | pr_debug("[CQM] BSS lost.\n"); | ||
990 | cancel_work_sync(&priv->unjoin_work); | ||
991 | if (!down_trylock(&priv->scan.lock)) { | ||
992 | cw1200_cqm_bssloss_sm(priv, 1, 0, 0); | ||
993 | up(&priv->scan.lock); | ||
994 | } else { | ||
995 | /* Scan is in progress. Delay reporting. | ||
996 | * Scan complete will trigger bss_loss_work | ||
997 | */ | ||
998 | priv->delayed_link_loss = 1; | ||
999 | /* Also start a watchdog. */ | ||
1000 | queue_delayed_work(priv->workqueue, | ||
1001 | &priv->bss_loss_work, 5*HZ); | ||
1002 | } | ||
1003 | break; | ||
1004 | case WSM_EVENT_BSS_REGAINED: | ||
1005 | pr_debug("[CQM] BSS regained.\n"); | ||
1006 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1007 | cancel_work_sync(&priv->unjoin_work); | ||
1008 | break; | ||
1009 | case WSM_EVENT_RADAR_DETECTED: | ||
1010 | wiphy_info(priv->hw->wiphy, "radar pulse detected\n"); | ||
1011 | break; | ||
1012 | case WSM_EVENT_RCPI_RSSI: | ||
1013 | { | ||
1014 | /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 | ||
1015 | * RSSI = RCPI / 2 - 110 | ||
1016 | */ | ||
1017 | int rcpi_rssi = (int)(event->evt.data & 0xFF); | ||
1018 | int cqm_evt; | ||
1019 | if (priv->cqm_use_rssi) | ||
1020 | rcpi_rssi = (s8)rcpi_rssi; | ||
1021 | else | ||
1022 | rcpi_rssi = rcpi_rssi / 2 - 110; | ||
1023 | |||
1024 | cqm_evt = (rcpi_rssi <= priv->cqm_rssi_thold) ? | ||
1025 | NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : | ||
1026 | NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; | ||
1027 | pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi); | ||
1028 | ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, | ||
1029 | GFP_KERNEL); | ||
1030 | break; | ||
1031 | } | ||
1032 | case WSM_EVENT_BT_INACTIVE: | ||
1033 | pr_warn("Unhandled BT INACTIVE from LMAC\n"); | ||
1034 | break; | ||
1035 | case WSM_EVENT_BT_ACTIVE: | ||
1036 | pr_warn("Unhandled BT ACTIVE from LMAC\n"); | ||
1037 | break; | ||
1038 | } | ||
1039 | } | ||
1040 | __cw1200_free_event_queue(&list); | ||
1041 | } | ||
1042 | |||
1043 | void cw1200_bss_loss_work(struct work_struct *work) | ||
1044 | { | ||
1045 | struct cw1200_common *priv = | ||
1046 | container_of(work, struct cw1200_common, bss_loss_work.work); | ||
1047 | |||
1048 | pr_debug("[CQM] Reporting connection loss.\n"); | ||
1049 | wsm_lock_tx(priv); | ||
1050 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1051 | wsm_unlock_tx(priv); | ||
1052 | } | ||
1053 | |||
1054 | void cw1200_bss_params_work(struct work_struct *work) | ||
1055 | { | ||
1056 | struct cw1200_common *priv = | ||
1057 | container_of(work, struct cw1200_common, bss_params_work); | ||
1058 | mutex_lock(&priv->conf_mutex); | ||
1059 | |||
1060 | priv->bss_params.reset_beacon_loss = 1; | ||
1061 | wsm_set_bss_params(priv, &priv->bss_params); | ||
1062 | priv->bss_params.reset_beacon_loss = 0; | ||
1063 | |||
1064 | mutex_unlock(&priv->conf_mutex); | ||
1065 | } | ||
1066 | |||
1067 | /* ******************************************************************** */ | ||
1068 | /* Internal API */ | ||
1069 | |||
1070 | /* This function is called to Parse the SDD file | ||
1071 | * to extract listen_interval and PTA related information | ||
1072 | * sdd is a TLV: u8 id, u8 len, u8 data[] | ||
1073 | */ | ||
1074 | static int cw1200_parse_sdd_file(struct cw1200_common *priv) | ||
1075 | { | ||
1076 | const u8 *p = priv->sdd->data; | ||
1077 | int ret = 0; | ||
1078 | |||
1079 | while (p + 2 <= priv->sdd->data + priv->sdd->size) { | ||
1080 | if (p + p[1] + 2 > priv->sdd->data + priv->sdd->size) { | ||
1081 | pr_warn("Malformed sdd structure\n"); | ||
1082 | return -1; | ||
1083 | } | ||
1084 | switch (p[0]) { | ||
1085 | case SDD_PTA_CFG_ELT_ID: { | ||
1086 | u16 v; | ||
1087 | if (p[1] < 4) { | ||
1088 | pr_warn("SDD_PTA_CFG_ELT_ID malformed\n"); | ||
1089 | ret = -1; | ||
1090 | break; | ||
1091 | } | ||
1092 | v = le16_to_cpu(*((u16 *)(p + 2))); | ||
1093 | if (!v) /* non-zero means this is enabled */ | ||
1094 | break; | ||
1095 | |||
1096 | v = le16_to_cpu(*((u16 *)(p + 4))); | ||
1097 | priv->conf_listen_interval = (v >> 7) & 0x1F; | ||
1098 | pr_debug("PTA found; Listen Interval %d\n", | ||
1099 | priv->conf_listen_interval); | ||
1100 | break; | ||
1101 | } | ||
1102 | case SDD_REFERENCE_FREQUENCY_ELT_ID: { | ||
1103 | u16 clk = le16_to_cpu(*((u16 *)(p + 2))); | ||
1104 | if (clk != priv->hw_refclk) | ||
1105 | pr_warn("SDD file doesn't match configured refclk (%d vs %d)\n", | ||
1106 | clk, priv->hw_refclk); | ||
1107 | break; | ||
1108 | } | ||
1109 | default: | ||
1110 | break; | ||
1111 | } | ||
1112 | p += p[1] + 2; | ||
1113 | } | ||
1114 | |||
1115 | if (!priv->bt_present) { | ||
1116 | pr_debug("PTA element NOT found.\n"); | ||
1117 | priv->conf_listen_interval = 0; | ||
1118 | } | ||
1119 | return ret; | ||
1120 | } | ||
1121 | |||
1122 | int cw1200_setup_mac(struct cw1200_common *priv) | ||
1123 | { | ||
1124 | int ret = 0; | ||
1125 | |||
1126 | /* NOTE: There is a bug in FW: it reports signal | ||
1127 | * as RSSI if RSSI subscription is enabled. | ||
1128 | * It's not enough to set WSM_RCPI_RSSI_USE_RSSI. | ||
1129 | * | ||
1130 | * NOTE2: RSSI based reports have been switched to RCPI, since | ||
1131 | * FW has a bug and RSSI reported values are not stable, | ||
1132 | * what can leads to signal level oscilations in user-end applications | ||
1133 | */ | ||
1134 | struct wsm_rcpi_rssi_threshold threshold = { | ||
1135 | .rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE | | ||
1136 | WSM_RCPI_RSSI_DONT_USE_UPPER | | ||
1137 | WSM_RCPI_RSSI_DONT_USE_LOWER, | ||
1138 | .rollingAverageCount = 16, | ||
1139 | }; | ||
1140 | |||
1141 | struct wsm_configuration cfg = { | ||
1142 | .dot11StationId = &priv->mac_addr[0], | ||
1143 | }; | ||
1144 | |||
1145 | /* Remember the decission here to make sure, we will handle | ||
1146 | * the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS | ||
1147 | */ | ||
1148 | if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI) | ||
1149 | priv->cqm_use_rssi = true; | ||
1150 | |||
1151 | if (!priv->sdd) { | ||
1152 | ret = request_firmware(&priv->sdd, priv->sdd_path, priv->pdev); | ||
1153 | if (ret) { | ||
1154 | pr_err("Can't load sdd file %s.\n", priv->sdd_path); | ||
1155 | return ret; | ||
1156 | } | ||
1157 | cw1200_parse_sdd_file(priv); | ||
1158 | } | ||
1159 | |||
1160 | cfg.dpdData = priv->sdd->data; | ||
1161 | cfg.dpdData_size = priv->sdd->size; | ||
1162 | ret = wsm_configuration(priv, &cfg); | ||
1163 | if (ret) | ||
1164 | return ret; | ||
1165 | |||
1166 | /* Configure RSSI/SCPI reporting as RSSI. */ | ||
1167 | wsm_set_rcpi_rssi_threshold(priv, &threshold); | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | static void cw1200_join_complete(struct cw1200_common *priv) | ||
1173 | { | ||
1174 | pr_debug("[STA] Join complete (%d)\n", priv->join_complete_status); | ||
1175 | |||
1176 | priv->join_pending = false; | ||
1177 | if (priv->join_complete_status) { | ||
1178 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1179 | cw1200_update_listening(priv, priv->listening); | ||
1180 | cw1200_do_unjoin(priv); | ||
1181 | ieee80211_connection_loss(priv->vif); | ||
1182 | } else { | ||
1183 | if (priv->mode == NL80211_IFTYPE_ADHOC) | ||
1184 | priv->join_status = CW1200_JOIN_STATUS_IBSS; | ||
1185 | else | ||
1186 | priv->join_status = CW1200_JOIN_STATUS_PRE_STA; | ||
1187 | } | ||
1188 | wsm_unlock_tx(priv); /* Clearing the lock held before do_join() */ | ||
1189 | } | ||
1190 | |||
1191 | void cw1200_join_complete_work(struct work_struct *work) | ||
1192 | { | ||
1193 | struct cw1200_common *priv = | ||
1194 | container_of(work, struct cw1200_common, join_complete_work); | ||
1195 | mutex_lock(&priv->conf_mutex); | ||
1196 | cw1200_join_complete(priv); | ||
1197 | mutex_unlock(&priv->conf_mutex); | ||
1198 | } | ||
1199 | |||
1200 | void cw1200_join_complete_cb(struct cw1200_common *priv, | ||
1201 | struct wsm_join_complete *arg) | ||
1202 | { | ||
1203 | pr_debug("[STA] cw1200_join_complete_cb called, status=%d.\n", | ||
1204 | arg->status); | ||
1205 | |||
1206 | if (cancel_delayed_work(&priv->join_timeout)) { | ||
1207 | priv->join_complete_status = arg->status; | ||
1208 | queue_work(priv->workqueue, &priv->join_complete_work); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | /* MUST be called with tx_lock held! It will be unlocked for us. */ | ||
1213 | static void cw1200_do_join(struct cw1200_common *priv) | ||
1214 | { | ||
1215 | const u8 *bssid; | ||
1216 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
1217 | struct cfg80211_bss *bss = NULL; | ||
1218 | struct wsm_protected_mgmt_policy mgmt_policy; | ||
1219 | struct wsm_join join = { | ||
1220 | .mode = conf->ibss_joined ? | ||
1221 | WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, | ||
1222 | .preamble_type = WSM_JOIN_PREAMBLE_LONG, | ||
1223 | .probe_for_join = 1, | ||
1224 | .atim_window = 0, | ||
1225 | .basic_rate_set = cw1200_rate_mask_to_wsm(priv, | ||
1226 | conf->basic_rates), | ||
1227 | }; | ||
1228 | if (delayed_work_pending(&priv->join_timeout)) { | ||
1229 | pr_warn("[STA] - Join request already pending, skipping..\n"); | ||
1230 | wsm_unlock_tx(priv); | ||
1231 | return; | ||
1232 | } | ||
1233 | |||
1234 | if (priv->join_status) | ||
1235 | cw1200_do_unjoin(priv); | ||
1236 | |||
1237 | bssid = priv->vif->bss_conf.bssid; | ||
1238 | |||
1239 | bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, | ||
1240 | bssid, NULL, 0, 0, 0); | ||
1241 | |||
1242 | if (!bss && !conf->ibss_joined) { | ||
1243 | wsm_unlock_tx(priv); | ||
1244 | return; | ||
1245 | } | ||
1246 | |||
1247 | mutex_lock(&priv->conf_mutex); | ||
1248 | |||
1249 | /* Under the conf lock: check scan status and | ||
1250 | * bail out if it is in progress. | ||
1251 | */ | ||
1252 | if (atomic_read(&priv->scan.in_progress)) { | ||
1253 | wsm_unlock_tx(priv); | ||
1254 | goto done_put; | ||
1255 | } | ||
1256 | |||
1257 | priv->join_pending = true; | ||
1258 | |||
1259 | /* Sanity check basic rates */ | ||
1260 | if (!join.basic_rate_set) | ||
1261 | join.basic_rate_set = 7; | ||
1262 | |||
1263 | /* Sanity check beacon interval */ | ||
1264 | if (!priv->beacon_int) | ||
1265 | priv->beacon_int = 1; | ||
1266 | |||
1267 | join.beacon_interval = priv->beacon_int; | ||
1268 | |||
1269 | /* BT Coex related changes */ | ||
1270 | if (priv->bt_present) { | ||
1271 | if (((priv->conf_listen_interval * 100) % | ||
1272 | priv->beacon_int) == 0) | ||
1273 | priv->listen_interval = | ||
1274 | ((priv->conf_listen_interval * 100) / | ||
1275 | priv->beacon_int); | ||
1276 | else | ||
1277 | priv->listen_interval = | ||
1278 | ((priv->conf_listen_interval * 100) / | ||
1279 | priv->beacon_int + 1); | ||
1280 | } | ||
1281 | |||
1282 | if (priv->hw->conf.ps_dtim_period) | ||
1283 | priv->join_dtim_period = priv->hw->conf.ps_dtim_period; | ||
1284 | join.dtim_period = priv->join_dtim_period; | ||
1285 | |||
1286 | join.channel_number = priv->channel->hw_value; | ||
1287 | join.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? | ||
1288 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; | ||
1289 | |||
1290 | memcpy(join.bssid, bssid, sizeof(join.bssid)); | ||
1291 | |||
1292 | pr_debug("[STA] Join BSSID: %pM DTIM: %d, interval: %d\n", | ||
1293 | join.bssid, | ||
1294 | join.dtim_period, priv->beacon_int); | ||
1295 | |||
1296 | if (!conf->ibss_joined) { | ||
1297 | const u8 *ssidie; | ||
1298 | rcu_read_lock(); | ||
1299 | ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); | ||
1300 | if (ssidie) { | ||
1301 | join.ssid_len = ssidie[1]; | ||
1302 | memcpy(join.ssid, &ssidie[2], join.ssid_len); | ||
1303 | } | ||
1304 | rcu_read_unlock(); | ||
1305 | } | ||
1306 | |||
1307 | if (priv->vif->p2p) { | ||
1308 | join.flags |= WSM_JOIN_FLAGS_P2P_GO; | ||
1309 | join.basic_rate_set = | ||
1310 | cw1200_rate_mask_to_wsm(priv, 0xFF0); | ||
1311 | } | ||
1312 | |||
1313 | /* Enable asynchronous join calls */ | ||
1314 | if (!conf->ibss_joined) { | ||
1315 | join.flags |= WSM_JOIN_FLAGS_FORCE; | ||
1316 | join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND; | ||
1317 | } | ||
1318 | |||
1319 | wsm_flush_tx(priv); | ||
1320 | |||
1321 | /* Stay Awake for Join and Auth Timeouts and a bit more */ | ||
1322 | cw1200_pm_stay_awake(&priv->pm_state, | ||
1323 | CW1200_JOIN_TIMEOUT + CW1200_AUTH_TIMEOUT); | ||
1324 | |||
1325 | cw1200_update_listening(priv, false); | ||
1326 | |||
1327 | /* Turn on Block ACKs */ | ||
1328 | wsm_set_block_ack_policy(priv, priv->ba_tx_tid_mask, | ||
1329 | priv->ba_rx_tid_mask); | ||
1330 | |||
1331 | /* Set up timeout */ | ||
1332 | if (join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND) { | ||
1333 | priv->join_status = CW1200_JOIN_STATUS_JOINING; | ||
1334 | queue_delayed_work(priv->workqueue, | ||
1335 | &priv->join_timeout, | ||
1336 | CW1200_JOIN_TIMEOUT); | ||
1337 | } | ||
1338 | |||
1339 | /* 802.11w protected mgmt frames */ | ||
1340 | mgmt_policy.protectedMgmtEnable = 0; | ||
1341 | mgmt_policy.unprotectedMgmtFramesAllowed = 1; | ||
1342 | mgmt_policy.encryptionForAuthFrame = 1; | ||
1343 | wsm_set_protected_mgmt_policy(priv, &mgmt_policy); | ||
1344 | |||
1345 | /* Perform actual join */ | ||
1346 | if (wsm_join(priv, &join)) { | ||
1347 | pr_err("[STA] cw1200_join_work: wsm_join failed!\n"); | ||
1348 | cancel_delayed_work_sync(&priv->join_timeout); | ||
1349 | cw1200_update_listening(priv, priv->listening); | ||
1350 | /* Tx lock still held, unjoin will clear it. */ | ||
1351 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1352 | wsm_unlock_tx(priv); | ||
1353 | } else { | ||
1354 | if (!(join.flags & WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND)) | ||
1355 | cw1200_join_complete(priv); /* Will clear tx_lock */ | ||
1356 | |||
1357 | /* Upload keys */ | ||
1358 | cw1200_upload_keys(priv); | ||
1359 | |||
1360 | /* Due to beacon filtering it is possible that the | ||
1361 | * AP's beacon is not known for the mac80211 stack. | ||
1362 | * Disable filtering temporary to make sure the stack | ||
1363 | * receives at least one | ||
1364 | */ | ||
1365 | priv->disable_beacon_filter = true; | ||
1366 | } | ||
1367 | cw1200_update_filtering(priv); | ||
1368 | |||
1369 | done_put: | ||
1370 | mutex_unlock(&priv->conf_mutex); | ||
1371 | if (bss) | ||
1372 | cfg80211_put_bss(priv->hw->wiphy, bss); | ||
1373 | } | ||
1374 | |||
1375 | void cw1200_join_timeout(struct work_struct *work) | ||
1376 | { | ||
1377 | struct cw1200_common *priv = | ||
1378 | container_of(work, struct cw1200_common, join_timeout.work); | ||
1379 | pr_debug("[WSM] Join timed out.\n"); | ||
1380 | wsm_lock_tx(priv); | ||
1381 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1382 | wsm_unlock_tx(priv); | ||
1383 | } | ||
1384 | |||
1385 | static void cw1200_do_unjoin(struct cw1200_common *priv) | ||
1386 | { | ||
1387 | struct wsm_reset reset = { | ||
1388 | .reset_statistics = true, | ||
1389 | }; | ||
1390 | |||
1391 | cancel_delayed_work_sync(&priv->join_timeout); | ||
1392 | |||
1393 | mutex_lock(&priv->conf_mutex); | ||
1394 | priv->join_pending = false; | ||
1395 | |||
1396 | if (atomic_read(&priv->scan.in_progress)) { | ||
1397 | if (priv->delayed_unjoin) | ||
1398 | wiphy_dbg(priv->hw->wiphy, "Delayed unjoin is already scheduled.\n"); | ||
1399 | else | ||
1400 | priv->delayed_unjoin = true; | ||
1401 | goto done; | ||
1402 | } | ||
1403 | |||
1404 | priv->delayed_link_loss = false; | ||
1405 | |||
1406 | if (!priv->join_status) | ||
1407 | goto done; | ||
1408 | |||
1409 | if (priv->join_status > CW1200_JOIN_STATUS_IBSS) { | ||
1410 | wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n", | ||
1411 | priv->join_status); | ||
1412 | BUG_ON(1); | ||
1413 | } | ||
1414 | |||
1415 | cancel_work_sync(&priv->update_filtering_work); | ||
1416 | cancel_work_sync(&priv->set_beacon_wakeup_period_work); | ||
1417 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1418 | |||
1419 | /* Unjoin is a reset. */ | ||
1420 | wsm_flush_tx(priv); | ||
1421 | wsm_keep_alive_period(priv, 0); | ||
1422 | wsm_reset(priv, &reset); | ||
1423 | wsm_set_output_power(priv, priv->output_power * 10); | ||
1424 | priv->join_dtim_period = 0; | ||
1425 | cw1200_setup_mac(priv); | ||
1426 | cw1200_free_event_queue(priv); | ||
1427 | cancel_work_sync(&priv->event_handler); | ||
1428 | cw1200_update_listening(priv, priv->listening); | ||
1429 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1430 | |||
1431 | /* Disable Block ACKs */ | ||
1432 | wsm_set_block_ack_policy(priv, 0, 0); | ||
1433 | |||
1434 | priv->disable_beacon_filter = false; | ||
1435 | cw1200_update_filtering(priv); | ||
1436 | memset(&priv->association_mode, 0, | ||
1437 | sizeof(priv->association_mode)); | ||
1438 | memset(&priv->bss_params, 0, sizeof(priv->bss_params)); | ||
1439 | priv->setbssparams_done = false; | ||
1440 | memset(&priv->firmware_ps_mode, 0, | ||
1441 | sizeof(priv->firmware_ps_mode)); | ||
1442 | |||
1443 | pr_debug("[STA] Unjoin completed.\n"); | ||
1444 | |||
1445 | done: | ||
1446 | mutex_unlock(&priv->conf_mutex); | ||
1447 | } | ||
1448 | |||
1449 | void cw1200_unjoin_work(struct work_struct *work) | ||
1450 | { | ||
1451 | struct cw1200_common *priv = | ||
1452 | container_of(work, struct cw1200_common, unjoin_work); | ||
1453 | |||
1454 | cw1200_do_unjoin(priv); | ||
1455 | |||
1456 | /* Tell the stack we're dead */ | ||
1457 | ieee80211_connection_loss(priv->vif); | ||
1458 | |||
1459 | wsm_unlock_tx(priv); | ||
1460 | } | ||
1461 | |||
1462 | int cw1200_enable_listening(struct cw1200_common *priv) | ||
1463 | { | ||
1464 | struct wsm_start start = { | ||
1465 | .mode = WSM_START_MODE_P2P_DEV, | ||
1466 | .band = WSM_PHY_BAND_2_4G, | ||
1467 | .beacon_interval = 100, | ||
1468 | .dtim_period = 1, | ||
1469 | .probe_delay = 0, | ||
1470 | .basic_rate_set = 0x0F, | ||
1471 | }; | ||
1472 | |||
1473 | if (priv->channel) { | ||
1474 | start.band = priv->channel->band == IEEE80211_BAND_5GHZ ? | ||
1475 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; | ||
1476 | start.channel_number = priv->channel->hw_value; | ||
1477 | } else { | ||
1478 | start.band = WSM_PHY_BAND_2_4G; | ||
1479 | start.channel_number = 1; | ||
1480 | } | ||
1481 | |||
1482 | return wsm_start(priv, &start); | ||
1483 | } | ||
1484 | |||
1485 | int cw1200_disable_listening(struct cw1200_common *priv) | ||
1486 | { | ||
1487 | int ret; | ||
1488 | struct wsm_reset reset = { | ||
1489 | .reset_statistics = true, | ||
1490 | }; | ||
1491 | ret = wsm_reset(priv, &reset); | ||
1492 | return ret; | ||
1493 | } | ||
1494 | |||
1495 | void cw1200_update_listening(struct cw1200_common *priv, bool enabled) | ||
1496 | { | ||
1497 | if (enabled) { | ||
1498 | if (priv->join_status == CW1200_JOIN_STATUS_PASSIVE) { | ||
1499 | if (!cw1200_enable_listening(priv)) | ||
1500 | priv->join_status = CW1200_JOIN_STATUS_MONITOR; | ||
1501 | wsm_set_probe_responder(priv, true); | ||
1502 | } | ||
1503 | } else { | ||
1504 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) { | ||
1505 | if (!cw1200_disable_listening(priv)) | ||
1506 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
1507 | wsm_set_probe_responder(priv, false); | ||
1508 | } | ||
1509 | } | ||
1510 | } | ||
1511 | |||
1512 | int cw1200_set_uapsd_param(struct cw1200_common *priv, | ||
1513 | const struct wsm_edca_params *arg) | ||
1514 | { | ||
1515 | int ret; | ||
1516 | u16 uapsd_flags = 0; | ||
1517 | |||
1518 | /* Here's the mapping AC [queue, bit] | ||
1519 | * VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0] | ||
1520 | */ | ||
1521 | |||
1522 | if (arg->uapsd_enable[0]) | ||
1523 | uapsd_flags |= 1 << 3; | ||
1524 | |||
1525 | if (arg->uapsd_enable[1]) | ||
1526 | uapsd_flags |= 1 << 2; | ||
1527 | |||
1528 | if (arg->uapsd_enable[2]) | ||
1529 | uapsd_flags |= 1 << 1; | ||
1530 | |||
1531 | if (arg->uapsd_enable[3]) | ||
1532 | uapsd_flags |= 1; | ||
1533 | |||
1534 | /* Currently pseudo U-APSD operation is not supported, so setting | ||
1535 | * MinAutoTriggerInterval, MaxAutoTriggerInterval and | ||
1536 | * AutoTriggerStep to 0 | ||
1537 | */ | ||
1538 | |||
1539 | priv->uapsd_info.uapsd_flags = cpu_to_le16(uapsd_flags); | ||
1540 | priv->uapsd_info.min_auto_trigger_interval = 0; | ||
1541 | priv->uapsd_info.max_auto_trigger_interval = 0; | ||
1542 | priv->uapsd_info.auto_trigger_step = 0; | ||
1543 | |||
1544 | ret = wsm_set_uapsd_info(priv, &priv->uapsd_info); | ||
1545 | return ret; | ||
1546 | } | ||
1547 | |||
1548 | /* ******************************************************************** */ | ||
1549 | /* AP API */ | ||
1550 | |||
1551 | int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1552 | struct ieee80211_sta *sta) | ||
1553 | { | ||
1554 | struct cw1200_common *priv = hw->priv; | ||
1555 | struct cw1200_sta_priv *sta_priv = | ||
1556 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1557 | struct cw1200_link_entry *entry; | ||
1558 | struct sk_buff *skb; | ||
1559 | |||
1560 | if (priv->mode != NL80211_IFTYPE_AP) | ||
1561 | return 0; | ||
1562 | |||
1563 | sta_priv->link_id = cw1200_find_link_id(priv, sta->addr); | ||
1564 | if (WARN_ON(!sta_priv->link_id)) { | ||
1565 | wiphy_info(priv->hw->wiphy, | ||
1566 | "[AP] No more link IDs available.\n"); | ||
1567 | return -ENOENT; | ||
1568 | } | ||
1569 | |||
1570 | entry = &priv->link_id_db[sta_priv->link_id - 1]; | ||
1571 | spin_lock_bh(&priv->ps_state_lock); | ||
1572 | if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == | ||
1573 | IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
1574 | priv->sta_asleep_mask |= BIT(sta_priv->link_id); | ||
1575 | entry->status = CW1200_LINK_HARD; | ||
1576 | while ((skb = skb_dequeue(&entry->rx_queue))) | ||
1577 | ieee80211_rx_irqsafe(priv->hw, skb); | ||
1578 | spin_unlock_bh(&priv->ps_state_lock); | ||
1579 | return 0; | ||
1580 | } | ||
1581 | |||
1582 | int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||
1583 | struct ieee80211_sta *sta) | ||
1584 | { | ||
1585 | struct cw1200_common *priv = hw->priv; | ||
1586 | struct cw1200_sta_priv *sta_priv = | ||
1587 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1588 | struct cw1200_link_entry *entry; | ||
1589 | |||
1590 | if (priv->mode != NL80211_IFTYPE_AP || !sta_priv->link_id) | ||
1591 | return 0; | ||
1592 | |||
1593 | entry = &priv->link_id_db[sta_priv->link_id - 1]; | ||
1594 | spin_lock_bh(&priv->ps_state_lock); | ||
1595 | entry->status = CW1200_LINK_RESERVE; | ||
1596 | entry->timestamp = jiffies; | ||
1597 | wsm_lock_tx_async(priv); | ||
1598 | if (queue_work(priv->workqueue, &priv->link_id_work) <= 0) | ||
1599 | wsm_unlock_tx(priv); | ||
1600 | spin_unlock_bh(&priv->ps_state_lock); | ||
1601 | flush_workqueue(priv->workqueue); | ||
1602 | return 0; | ||
1603 | } | ||
1604 | |||
1605 | static void __cw1200_sta_notify(struct ieee80211_hw *dev, | ||
1606 | struct ieee80211_vif *vif, | ||
1607 | enum sta_notify_cmd notify_cmd, | ||
1608 | int link_id) | ||
1609 | { | ||
1610 | struct cw1200_common *priv = dev->priv; | ||
1611 | u32 bit, prev; | ||
1612 | |||
1613 | /* Zero link id means "for all link IDs" */ | ||
1614 | if (link_id) | ||
1615 | bit = BIT(link_id); | ||
1616 | else if (WARN_ON_ONCE(notify_cmd != STA_NOTIFY_AWAKE)) | ||
1617 | bit = 0; | ||
1618 | else | ||
1619 | bit = priv->link_id_map; | ||
1620 | prev = priv->sta_asleep_mask & bit; | ||
1621 | |||
1622 | switch (notify_cmd) { | ||
1623 | case STA_NOTIFY_SLEEP: | ||
1624 | if (!prev) { | ||
1625 | if (priv->buffered_multicasts && | ||
1626 | !priv->sta_asleep_mask) | ||
1627 | queue_work(priv->workqueue, | ||
1628 | &priv->multicast_start_work); | ||
1629 | priv->sta_asleep_mask |= bit; | ||
1630 | } | ||
1631 | break; | ||
1632 | case STA_NOTIFY_AWAKE: | ||
1633 | if (prev) { | ||
1634 | priv->sta_asleep_mask &= ~bit; | ||
1635 | priv->pspoll_mask &= ~bit; | ||
1636 | if (priv->tx_multicast && link_id && | ||
1637 | !priv->sta_asleep_mask) | ||
1638 | queue_work(priv->workqueue, | ||
1639 | &priv->multicast_stop_work); | ||
1640 | cw1200_bh_wakeup(priv); | ||
1641 | } | ||
1642 | break; | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | void cw1200_sta_notify(struct ieee80211_hw *dev, | ||
1647 | struct ieee80211_vif *vif, | ||
1648 | enum sta_notify_cmd notify_cmd, | ||
1649 | struct ieee80211_sta *sta) | ||
1650 | { | ||
1651 | struct cw1200_common *priv = dev->priv; | ||
1652 | struct cw1200_sta_priv *sta_priv = | ||
1653 | (struct cw1200_sta_priv *)&sta->drv_priv; | ||
1654 | |||
1655 | spin_lock_bh(&priv->ps_state_lock); | ||
1656 | __cw1200_sta_notify(dev, vif, notify_cmd, sta_priv->link_id); | ||
1657 | spin_unlock_bh(&priv->ps_state_lock); | ||
1658 | } | ||
1659 | |||
1660 | static void cw1200_ps_notify(struct cw1200_common *priv, | ||
1661 | int link_id, bool ps) | ||
1662 | { | ||
1663 | if (link_id > CW1200_MAX_STA_IN_AP_MODE) | ||
1664 | return; | ||
1665 | |||
1666 | pr_debug("%s for LinkId: %d. STAs asleep: %.8X\n", | ||
1667 | ps ? "Stop" : "Start", | ||
1668 | link_id, priv->sta_asleep_mask); | ||
1669 | |||
1670 | __cw1200_sta_notify(priv->hw, priv->vif, | ||
1671 | ps ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, link_id); | ||
1672 | } | ||
1673 | |||
1674 | static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) | ||
1675 | { | ||
1676 | struct sk_buff *skb; | ||
1677 | struct wsm_update_ie update_ie = { | ||
1678 | .what = WSM_UPDATE_IE_BEACON, | ||
1679 | .count = 1, | ||
1680 | }; | ||
1681 | u16 tim_offset, tim_length; | ||
1682 | |||
1683 | pr_debug("[AP] mcast: %s.\n", aid0_bit_set ? "ena" : "dis"); | ||
1684 | |||
1685 | skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, | ||
1686 | &tim_offset, &tim_length); | ||
1687 | if (!skb) { | ||
1688 | if (!__cw1200_flush(priv, true)) | ||
1689 | wsm_unlock_tx(priv); | ||
1690 | return -ENOENT; | ||
1691 | } | ||
1692 | |||
1693 | if (tim_offset && tim_length >= 6) { | ||
1694 | /* Ignore DTIM count from mac80211: | ||
1695 | * firmware handles DTIM internally. | ||
1696 | */ | ||
1697 | skb->data[tim_offset + 2] = 0; | ||
1698 | |||
1699 | /* Set/reset aid0 bit */ | ||
1700 | if (aid0_bit_set) | ||
1701 | skb->data[tim_offset + 4] |= 1; | ||
1702 | else | ||
1703 | skb->data[tim_offset + 4] &= ~1; | ||
1704 | } | ||
1705 | |||
1706 | update_ie.ies = &skb->data[tim_offset]; | ||
1707 | update_ie.length = tim_length; | ||
1708 | wsm_update_ie(priv, &update_ie); | ||
1709 | |||
1710 | dev_kfree_skb(skb); | ||
1711 | |||
1712 | return 0; | ||
1713 | } | ||
1714 | |||
1715 | void cw1200_set_tim_work(struct work_struct *work) | ||
1716 | { | ||
1717 | struct cw1200_common *priv = | ||
1718 | container_of(work, struct cw1200_common, set_tim_work); | ||
1719 | (void)cw1200_set_tim_impl(priv, priv->aid0_bit_set); | ||
1720 | } | ||
1721 | |||
1722 | int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, | ||
1723 | bool set) | ||
1724 | { | ||
1725 | struct cw1200_common *priv = dev->priv; | ||
1726 | queue_work(priv->workqueue, &priv->set_tim_work); | ||
1727 | return 0; | ||
1728 | } | ||
1729 | |||
1730 | void cw1200_set_cts_work(struct work_struct *work) | ||
1731 | { | ||
1732 | struct cw1200_common *priv = | ||
1733 | container_of(work, struct cw1200_common, set_cts_work); | ||
1734 | |||
1735 | u8 erp_ie[3] = {WLAN_EID_ERP_INFO, 0x1, 0}; | ||
1736 | struct wsm_update_ie update_ie = { | ||
1737 | .what = WSM_UPDATE_IE_BEACON, | ||
1738 | .count = 1, | ||
1739 | .ies = erp_ie, | ||
1740 | .length = 3, | ||
1741 | }; | ||
1742 | u32 erp_info; | ||
1743 | __le32 use_cts_prot; | ||
1744 | mutex_lock(&priv->conf_mutex); | ||
1745 | erp_info = priv->erp_info; | ||
1746 | mutex_unlock(&priv->conf_mutex); | ||
1747 | use_cts_prot = | ||
1748 | erp_info & WLAN_ERP_USE_PROTECTION ? | ||
1749 | __cpu_to_le32(1) : 0; | ||
1750 | |||
1751 | erp_ie[ERP_INFO_BYTE_OFFSET] = erp_info; | ||
1752 | |||
1753 | pr_debug("[STA] ERP information 0x%x\n", erp_info); | ||
1754 | |||
1755 | wsm_write_mib(priv, WSM_MIB_ID_NON_ERP_PROTECTION, | ||
1756 | &use_cts_prot, sizeof(use_cts_prot)); | ||
1757 | wsm_update_ie(priv, &update_ie); | ||
1758 | |||
1759 | return; | ||
1760 | } | ||
1761 | |||
1762 | static int cw1200_set_btcoexinfo(struct cw1200_common *priv) | ||
1763 | { | ||
1764 | struct wsm_override_internal_txrate arg; | ||
1765 | int ret = 0; | ||
1766 | |||
1767 | if (priv->mode == NL80211_IFTYPE_STATION) { | ||
1768 | /* Plumb PSPOLL and NULL template */ | ||
1769 | cw1200_upload_pspoll(priv); | ||
1770 | cw1200_upload_null(priv); | ||
1771 | cw1200_upload_qosnull(priv); | ||
1772 | } else { | ||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | memset(&arg, 0, sizeof(struct wsm_override_internal_txrate)); | ||
1777 | |||
1778 | if (!priv->vif->p2p) { | ||
1779 | /* STATION mode */ | ||
1780 | if (priv->bss_params.operational_rate_set & ~0xF) { | ||
1781 | pr_debug("[STA] STA has ERP rates\n"); | ||
1782 | /* G or BG mode */ | ||
1783 | arg.internalTxRate = (__ffs( | ||
1784 | priv->bss_params.operational_rate_set & ~0xF)); | ||
1785 | } else { | ||
1786 | pr_debug("[STA] STA has non ERP rates\n"); | ||
1787 | /* B only mode */ | ||
1788 | arg.internalTxRate = (__ffs(priv->association_mode.basic_rate_set)); | ||
1789 | } | ||
1790 | arg.nonErpInternalTxRate = (__ffs(priv->association_mode.basic_rate_set)); | ||
1791 | } else { | ||
1792 | /* P2P mode */ | ||
1793 | arg.internalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); | ||
1794 | arg.nonErpInternalTxRate = (__ffs(priv->bss_params.operational_rate_set & ~0xF)); | ||
1795 | } | ||
1796 | |||
1797 | pr_debug("[STA] BTCOEX_INFO MODE %d, internalTxRate : %x, nonErpInternalTxRate: %x\n", | ||
1798 | priv->mode, | ||
1799 | arg.internalTxRate, | ||
1800 | arg.nonErpInternalTxRate); | ||
1801 | |||
1802 | ret = wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, | ||
1803 | &arg, sizeof(arg)); | ||
1804 | |||
1805 | return ret; | ||
1806 | } | ||
1807 | |||
1808 | void cw1200_bss_info_changed(struct ieee80211_hw *dev, | ||
1809 | struct ieee80211_vif *vif, | ||
1810 | struct ieee80211_bss_conf *info, | ||
1811 | u32 changed) | ||
1812 | { | ||
1813 | struct cw1200_common *priv = dev->priv; | ||
1814 | bool do_join = false; | ||
1815 | |||
1816 | mutex_lock(&priv->conf_mutex); | ||
1817 | |||
1818 | pr_debug("BSS CHANGED: %08x\n", changed); | ||
1819 | |||
1820 | /* TODO: BSS_CHANGED_QOS */ | ||
1821 | /* TODO: BSS_CHANGED_TXPOWER */ | ||
1822 | |||
1823 | if (changed & BSS_CHANGED_ARP_FILTER) { | ||
1824 | struct wsm_mib_arp_ipv4_filter filter = {0}; | ||
1825 | int i; | ||
1826 | |||
1827 | pr_debug("[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", | ||
1828 | info->arp_addr_cnt); | ||
1829 | |||
1830 | /* Currently only one IP address is supported by firmware. | ||
1831 | * In case of more IPs arp filtering will be disabled. | ||
1832 | */ | ||
1833 | if (info->arp_addr_cnt > 0 && | ||
1834 | info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { | ||
1835 | for (i = 0; i < info->arp_addr_cnt; i++) { | ||
1836 | filter.ipv4addrs[i] = info->arp_addr_list[i]; | ||
1837 | pr_debug("[STA] addr[%d]: 0x%X\n", | ||
1838 | i, filter.ipv4addrs[i]); | ||
1839 | } | ||
1840 | filter.enable = __cpu_to_le32(1); | ||
1841 | } | ||
1842 | |||
1843 | pr_debug("[STA] arp ip filter enable: %d\n", | ||
1844 | __le32_to_cpu(filter.enable)); | ||
1845 | |||
1846 | wsm_set_arp_ipv4_filter(priv, &filter); | ||
1847 | } | ||
1848 | |||
1849 | if (changed & | ||
1850 | (BSS_CHANGED_BEACON | | ||
1851 | BSS_CHANGED_AP_PROBE_RESP | | ||
1852 | BSS_CHANGED_BSSID | | ||
1853 | BSS_CHANGED_SSID | | ||
1854 | BSS_CHANGED_IBSS)) { | ||
1855 | pr_debug("BSS_CHANGED_BEACON\n"); | ||
1856 | priv->beacon_int = info->beacon_int; | ||
1857 | cw1200_update_beaconing(priv); | ||
1858 | cw1200_upload_beacon(priv); | ||
1859 | } | ||
1860 | |||
1861 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | ||
1862 | pr_debug("BSS_CHANGED_BEACON_ENABLED (%d)\n", info->enable_beacon); | ||
1863 | |||
1864 | if (priv->enable_beacon != info->enable_beacon) { | ||
1865 | cw1200_enable_beaconing(priv, info->enable_beacon); | ||
1866 | priv->enable_beacon = info->enable_beacon; | ||
1867 | } | ||
1868 | } | ||
1869 | |||
1870 | if (changed & BSS_CHANGED_BEACON_INT) { | ||
1871 | pr_debug("CHANGED_BEACON_INT\n"); | ||
1872 | if (info->ibss_joined) | ||
1873 | do_join = true; | ||
1874 | else if (priv->join_status == CW1200_JOIN_STATUS_AP) | ||
1875 | cw1200_update_beaconing(priv); | ||
1876 | } | ||
1877 | |||
1878 | /* assoc/disassoc, or maybe AID changed */ | ||
1879 | if (changed & BSS_CHANGED_ASSOC) { | ||
1880 | wsm_lock_tx(priv); | ||
1881 | priv->wep_default_key_id = -1; | ||
1882 | wsm_unlock_tx(priv); | ||
1883 | } | ||
1884 | |||
1885 | if (changed & BSS_CHANGED_BSSID) { | ||
1886 | pr_debug("BSS_CHANGED_BSSID\n"); | ||
1887 | do_join = true; | ||
1888 | } | ||
1889 | |||
1890 | if (changed & | ||
1891 | (BSS_CHANGED_ASSOC | | ||
1892 | BSS_CHANGED_BSSID | | ||
1893 | BSS_CHANGED_IBSS | | ||
1894 | BSS_CHANGED_BASIC_RATES | | ||
1895 | BSS_CHANGED_HT)) { | ||
1896 | pr_debug("BSS_CHANGED_ASSOC\n"); | ||
1897 | if (info->assoc) { | ||
1898 | if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) { | ||
1899 | ieee80211_connection_loss(vif); | ||
1900 | mutex_unlock(&priv->conf_mutex); | ||
1901 | return; | ||
1902 | } else if (priv->join_status == CW1200_JOIN_STATUS_PRE_STA) { | ||
1903 | priv->join_status = CW1200_JOIN_STATUS_STA; | ||
1904 | } | ||
1905 | } else { | ||
1906 | do_join = true; | ||
1907 | } | ||
1908 | |||
1909 | if (info->assoc || info->ibss_joined) { | ||
1910 | struct ieee80211_sta *sta = NULL; | ||
1911 | u32 val = 0; | ||
1912 | |||
1913 | if (info->dtim_period) | ||
1914 | priv->join_dtim_period = info->dtim_period; | ||
1915 | priv->beacon_int = info->beacon_int; | ||
1916 | |||
1917 | rcu_read_lock(); | ||
1918 | |||
1919 | if (info->bssid && !info->ibss_joined) | ||
1920 | sta = ieee80211_find_sta(vif, info->bssid); | ||
1921 | if (sta) { | ||
1922 | priv->ht_info.ht_cap = sta->ht_cap; | ||
1923 | priv->bss_params.operational_rate_set = | ||
1924 | cw1200_rate_mask_to_wsm(priv, | ||
1925 | sta->supp_rates[priv->channel->band]); | ||
1926 | priv->ht_info.channel_type = cfg80211_get_chandef_type(&dev->conf.chandef); | ||
1927 | priv->ht_info.operation_mode = info->ht_operation_mode; | ||
1928 | } else { | ||
1929 | memset(&priv->ht_info, 0, | ||
1930 | sizeof(priv->ht_info)); | ||
1931 | priv->bss_params.operational_rate_set = -1; | ||
1932 | } | ||
1933 | rcu_read_unlock(); | ||
1934 | |||
1935 | /* Non Greenfield stations present */ | ||
1936 | if (priv->ht_info.operation_mode & | ||
1937 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) | ||
1938 | val |= WSM_NON_GREENFIELD_STA_PRESENT; | ||
1939 | |||
1940 | /* Set HT protection method */ | ||
1941 | val |= (priv->ht_info.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION) << 2; | ||
1942 | |||
1943 | /* TODO: | ||
1944 | * STBC_param.dual_cts | ||
1945 | * STBC_param.LSIG_TXOP_FILL | ||
1946 | */ | ||
1947 | |||
1948 | val = cpu_to_le32(val); | ||
1949 | wsm_write_mib(priv, WSM_MIB_ID_SET_HT_PROTECTION, | ||
1950 | &val, sizeof(val)); | ||
1951 | |||
1952 | priv->association_mode.greenfield = | ||
1953 | cw1200_ht_greenfield(&priv->ht_info); | ||
1954 | priv->association_mode.flags = | ||
1955 | WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES | | ||
1956 | WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE | | ||
1957 | WSM_ASSOCIATION_MODE_USE_HT_MODE | | ||
1958 | WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET | | ||
1959 | WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING; | ||
1960 | priv->association_mode.preamble = | ||
1961 | info->use_short_preamble ? | ||
1962 | WSM_JOIN_PREAMBLE_SHORT : | ||
1963 | WSM_JOIN_PREAMBLE_LONG; | ||
1964 | priv->association_mode.basic_rate_set = __cpu_to_le32( | ||
1965 | cw1200_rate_mask_to_wsm(priv, | ||
1966 | info->basic_rates)); | ||
1967 | priv->association_mode.mpdu_start_spacing = | ||
1968 | cw1200_ht_ampdu_density(&priv->ht_info); | ||
1969 | |||
1970 | cw1200_cqm_bssloss_sm(priv, 0, 0, 0); | ||
1971 | cancel_work_sync(&priv->unjoin_work); | ||
1972 | |||
1973 | priv->bss_params.beacon_lost_count = priv->cqm_beacon_loss_count; | ||
1974 | priv->bss_params.aid = info->aid; | ||
1975 | |||
1976 | if (priv->join_dtim_period < 1) | ||
1977 | priv->join_dtim_period = 1; | ||
1978 | |||
1979 | pr_debug("[STA] DTIM %d, interval: %d\n", | ||
1980 | priv->join_dtim_period, priv->beacon_int); | ||
1981 | pr_debug("[STA] Preamble: %d, Greenfield: %d, Aid: %d, Rates: 0x%.8X, Basic: 0x%.8X\n", | ||
1982 | priv->association_mode.preamble, | ||
1983 | priv->association_mode.greenfield, | ||
1984 | priv->bss_params.aid, | ||
1985 | priv->bss_params.operational_rate_set, | ||
1986 | priv->association_mode.basic_rate_set); | ||
1987 | wsm_set_association_mode(priv, &priv->association_mode); | ||
1988 | |||
1989 | if (!info->ibss_joined) { | ||
1990 | wsm_keep_alive_period(priv, 30 /* sec */); | ||
1991 | wsm_set_bss_params(priv, &priv->bss_params); | ||
1992 | priv->setbssparams_done = true; | ||
1993 | cw1200_set_beacon_wakeup_period_work(&priv->set_beacon_wakeup_period_work); | ||
1994 | cw1200_set_pm(priv, &priv->powersave_mode); | ||
1995 | } | ||
1996 | if (priv->vif->p2p) { | ||
1997 | pr_debug("[STA] Setting p2p powersave configuration.\n"); | ||
1998 | wsm_set_p2p_ps_modeinfo(priv, | ||
1999 | &priv->p2p_ps_modeinfo); | ||
2000 | } | ||
2001 | if (priv->bt_present) | ||
2002 | cw1200_set_btcoexinfo(priv); | ||
2003 | } else { | ||
2004 | memset(&priv->association_mode, 0, | ||
2005 | sizeof(priv->association_mode)); | ||
2006 | memset(&priv->bss_params, 0, sizeof(priv->bss_params)); | ||
2007 | } | ||
2008 | } | ||
2009 | |||
2010 | /* ERP Protection */ | ||
2011 | if (changed & (BSS_CHANGED_ASSOC | | ||
2012 | BSS_CHANGED_ERP_CTS_PROT | | ||
2013 | BSS_CHANGED_ERP_PREAMBLE)) { | ||
2014 | u32 prev_erp_info = priv->erp_info; | ||
2015 | if (info->use_cts_prot) | ||
2016 | priv->erp_info |= WLAN_ERP_USE_PROTECTION; | ||
2017 | else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) | ||
2018 | priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; | ||
2019 | |||
2020 | if (info->use_short_preamble) | ||
2021 | priv->erp_info |= WLAN_ERP_BARKER_PREAMBLE; | ||
2022 | else | ||
2023 | priv->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; | ||
2024 | |||
2025 | pr_debug("[STA] ERP Protection: %x\n", priv->erp_info); | ||
2026 | |||
2027 | if (prev_erp_info != priv->erp_info) | ||
2028 | queue_work(priv->workqueue, &priv->set_cts_work); | ||
2029 | } | ||
2030 | |||
2031 | /* ERP Slottime */ | ||
2032 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) { | ||
2033 | __le32 slot_time = info->use_short_slot ? | ||
2034 | __cpu_to_le32(9) : __cpu_to_le32(20); | ||
2035 | pr_debug("[STA] Slot time: %d us.\n", | ||
2036 | __le32_to_cpu(slot_time)); | ||
2037 | wsm_write_mib(priv, WSM_MIB_ID_DOT11_SLOT_TIME, | ||
2038 | &slot_time, sizeof(slot_time)); | ||
2039 | } | ||
2040 | |||
2041 | if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { | ||
2042 | struct wsm_rcpi_rssi_threshold threshold = { | ||
2043 | .rollingAverageCount = 8, | ||
2044 | }; | ||
2045 | pr_debug("[CQM] RSSI threshold subscribe: %d +- %d\n", | ||
2046 | info->cqm_rssi_thold, info->cqm_rssi_hyst); | ||
2047 | priv->cqm_rssi_thold = info->cqm_rssi_thold; | ||
2048 | priv->cqm_rssi_hyst = info->cqm_rssi_hyst; | ||
2049 | |||
2050 | if (info->cqm_rssi_thold || info->cqm_rssi_hyst) { | ||
2051 | /* RSSI subscription enabled */ | ||
2052 | /* TODO: It's not a correct way of setting threshold. | ||
2053 | * Upper and lower must be set equal here and adjusted | ||
2054 | * in callback. However current implementation is much | ||
2055 | * more relaible and stable. | ||
2056 | */ | ||
2057 | |||
2058 | /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 | ||
2059 | * RSSI = RCPI / 2 - 110 | ||
2060 | */ | ||
2061 | if (priv->cqm_use_rssi) { | ||
2062 | threshold.upperThreshold = | ||
2063 | info->cqm_rssi_thold + info->cqm_rssi_hyst; | ||
2064 | threshold.lowerThreshold = | ||
2065 | info->cqm_rssi_thold; | ||
2066 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; | ||
2067 | } else { | ||
2068 | threshold.upperThreshold = (info->cqm_rssi_thold + info->cqm_rssi_hyst + 110) * 2; | ||
2069 | threshold.lowerThreshold = (info->cqm_rssi_thold + 110) * 2; | ||
2070 | } | ||
2071 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE; | ||
2072 | } else { | ||
2073 | /* There is a bug in FW, see sta.c. We have to enable | ||
2074 | * dummy subscription to get correct RSSI values. | ||
2075 | */ | ||
2076 | threshold.rssiRcpiMode |= | ||
2077 | WSM_RCPI_RSSI_THRESHOLD_ENABLE | | ||
2078 | WSM_RCPI_RSSI_DONT_USE_UPPER | | ||
2079 | WSM_RCPI_RSSI_DONT_USE_LOWER; | ||
2080 | if (priv->cqm_use_rssi) | ||
2081 | threshold.rssiRcpiMode |= WSM_RCPI_RSSI_USE_RSSI; | ||
2082 | } | ||
2083 | wsm_set_rcpi_rssi_threshold(priv, &threshold); | ||
2084 | } | ||
2085 | mutex_unlock(&priv->conf_mutex); | ||
2086 | |||
2087 | if (do_join) { | ||
2088 | wsm_lock_tx(priv); | ||
2089 | cw1200_do_join(priv); /* Will unlock it for us */ | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2093 | void cw1200_multicast_start_work(struct work_struct *work) | ||
2094 | { | ||
2095 | struct cw1200_common *priv = | ||
2096 | container_of(work, struct cw1200_common, multicast_start_work); | ||
2097 | long tmo = priv->join_dtim_period * | ||
2098 | (priv->beacon_int + 20) * HZ / 1024; | ||
2099 | |||
2100 | cancel_work_sync(&priv->multicast_stop_work); | ||
2101 | |||
2102 | if (!priv->aid0_bit_set) { | ||
2103 | wsm_lock_tx(priv); | ||
2104 | cw1200_set_tim_impl(priv, true); | ||
2105 | priv->aid0_bit_set = true; | ||
2106 | mod_timer(&priv->mcast_timeout, jiffies + tmo); | ||
2107 | wsm_unlock_tx(priv); | ||
2108 | } | ||
2109 | } | ||
2110 | |||
2111 | void cw1200_multicast_stop_work(struct work_struct *work) | ||
2112 | { | ||
2113 | struct cw1200_common *priv = | ||
2114 | container_of(work, struct cw1200_common, multicast_stop_work); | ||
2115 | |||
2116 | if (priv->aid0_bit_set) { | ||
2117 | del_timer_sync(&priv->mcast_timeout); | ||
2118 | wsm_lock_tx(priv); | ||
2119 | priv->aid0_bit_set = false; | ||
2120 | cw1200_set_tim_impl(priv, false); | ||
2121 | wsm_unlock_tx(priv); | ||
2122 | } | ||
2123 | } | ||
2124 | |||
2125 | void cw1200_mcast_timeout(unsigned long arg) | ||
2126 | { | ||
2127 | struct cw1200_common *priv = | ||
2128 | (struct cw1200_common *)arg; | ||
2129 | |||
2130 | wiphy_warn(priv->hw->wiphy, | ||
2131 | "Multicast delivery timeout.\n"); | ||
2132 | spin_lock_bh(&priv->ps_state_lock); | ||
2133 | priv->tx_multicast = priv->aid0_bit_set && | ||
2134 | priv->buffered_multicasts; | ||
2135 | if (priv->tx_multicast) | ||
2136 | cw1200_bh_wakeup(priv); | ||
2137 | spin_unlock_bh(&priv->ps_state_lock); | ||
2138 | } | ||
2139 | |||
2140 | int cw1200_ampdu_action(struct ieee80211_hw *hw, | ||
2141 | struct ieee80211_vif *vif, | ||
2142 | enum ieee80211_ampdu_mlme_action action, | ||
2143 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, | ||
2144 | u8 buf_size) | ||
2145 | { | ||
2146 | /* Aggregation is implemented fully in firmware, | ||
2147 | * including block ack negotiation. Do not allow | ||
2148 | * mac80211 stack to do anything: it interferes with | ||
2149 | * the firmware. | ||
2150 | */ | ||
2151 | |||
2152 | /* Note that we still need this function stubbed. */ | ||
2153 | return -ENOTSUPP; | ||
2154 | } | ||
2155 | |||
2156 | /* ******************************************************************** */ | ||
2157 | /* WSM callback */ | ||
2158 | void cw1200_suspend_resume(struct cw1200_common *priv, | ||
2159 | struct wsm_suspend_resume *arg) | ||
2160 | { | ||
2161 | pr_debug("[AP] %s: %s\n", | ||
2162 | arg->stop ? "stop" : "start", | ||
2163 | arg->multicast ? "broadcast" : "unicast"); | ||
2164 | |||
2165 | if (arg->multicast) { | ||
2166 | bool cancel_tmo = false; | ||
2167 | spin_lock_bh(&priv->ps_state_lock); | ||
2168 | if (arg->stop) { | ||
2169 | priv->tx_multicast = false; | ||
2170 | } else { | ||
2171 | /* Firmware sends this indication every DTIM if there | ||
2172 | * is a STA in powersave connected. There is no reason | ||
2173 | * to suspend, following wakeup will consume much more | ||
2174 | * power than it could be saved. | ||
2175 | */ | ||
2176 | cw1200_pm_stay_awake(&priv->pm_state, | ||
2177 | priv->join_dtim_period * | ||
2178 | (priv->beacon_int + 20) * HZ / 1024); | ||
2179 | priv->tx_multicast = (priv->aid0_bit_set && | ||
2180 | priv->buffered_multicasts); | ||
2181 | if (priv->tx_multicast) { | ||
2182 | cancel_tmo = true; | ||
2183 | cw1200_bh_wakeup(priv); | ||
2184 | } | ||
2185 | } | ||
2186 | spin_unlock_bh(&priv->ps_state_lock); | ||
2187 | if (cancel_tmo) | ||
2188 | del_timer_sync(&priv->mcast_timeout); | ||
2189 | } else { | ||
2190 | spin_lock_bh(&priv->ps_state_lock); | ||
2191 | cw1200_ps_notify(priv, arg->link_id, arg->stop); | ||
2192 | spin_unlock_bh(&priv->ps_state_lock); | ||
2193 | if (!arg->stop) | ||
2194 | cw1200_bh_wakeup(priv); | ||
2195 | } | ||
2196 | return; | ||
2197 | } | ||
2198 | |||
2199 | /* ******************************************************************** */ | ||
2200 | /* AP privates */ | ||
2201 | |||
2202 | static int cw1200_upload_beacon(struct cw1200_common *priv) | ||
2203 | { | ||
2204 | int ret = 0; | ||
2205 | struct ieee80211_mgmt *mgmt; | ||
2206 | struct wsm_template_frame frame = { | ||
2207 | .frame_type = WSM_FRAME_TYPE_BEACON, | ||
2208 | }; | ||
2209 | |||
2210 | u16 tim_offset; | ||
2211 | u16 tim_len; | ||
2212 | |||
2213 | if (priv->mode == NL80211_IFTYPE_STATION || | ||
2214 | priv->mode == NL80211_IFTYPE_MONITOR || | ||
2215 | priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||
2216 | goto done; | ||
2217 | |||
2218 | if (priv->vif->p2p) | ||
2219 | frame.rate = WSM_TRANSMIT_RATE_6; | ||
2220 | |||
2221 | frame.skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, | ||
2222 | &tim_offset, &tim_len); | ||
2223 | if (!frame.skb) | ||
2224 | return -ENOMEM; | ||
2225 | |||
2226 | ret = wsm_set_template_frame(priv, &frame); | ||
2227 | |||
2228 | if (ret) | ||
2229 | goto done; | ||
2230 | |||
2231 | /* TODO: Distill probe resp; remove TIM | ||
2232 | * and any other beacon-specific IEs | ||
2233 | */ | ||
2234 | mgmt = (void *)frame.skb->data; | ||
2235 | mgmt->frame_control = | ||
2236 | __cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2237 | IEEE80211_STYPE_PROBE_RESP); | ||
2238 | |||
2239 | frame.frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE; | ||
2240 | if (priv->vif->p2p) { | ||
2241 | ret = wsm_set_probe_responder(priv, true); | ||
2242 | } else { | ||
2243 | ret = wsm_set_template_frame(priv, &frame); | ||
2244 | wsm_set_probe_responder(priv, false); | ||
2245 | } | ||
2246 | |||
2247 | done: | ||
2248 | dev_kfree_skb(frame.skb); | ||
2249 | |||
2250 | return ret; | ||
2251 | } | ||
2252 | |||
2253 | static int cw1200_upload_pspoll(struct cw1200_common *priv) | ||
2254 | { | ||
2255 | int ret = 0; | ||
2256 | struct wsm_template_frame frame = { | ||
2257 | .frame_type = WSM_FRAME_TYPE_PS_POLL, | ||
2258 | .rate = 0xFF, | ||
2259 | }; | ||
2260 | |||
2261 | |||
2262 | frame.skb = ieee80211_pspoll_get(priv->hw, priv->vif); | ||
2263 | if (!frame.skb) | ||
2264 | return -ENOMEM; | ||
2265 | |||
2266 | ret = wsm_set_template_frame(priv, &frame); | ||
2267 | |||
2268 | dev_kfree_skb(frame.skb); | ||
2269 | |||
2270 | return ret; | ||
2271 | } | ||
2272 | |||
2273 | static int cw1200_upload_null(struct cw1200_common *priv) | ||
2274 | { | ||
2275 | int ret = 0; | ||
2276 | struct wsm_template_frame frame = { | ||
2277 | .frame_type = WSM_FRAME_TYPE_NULL, | ||
2278 | .rate = 0xFF, | ||
2279 | }; | ||
2280 | |||
2281 | frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif); | ||
2282 | if (!frame.skb) | ||
2283 | return -ENOMEM; | ||
2284 | |||
2285 | ret = wsm_set_template_frame(priv, &frame); | ||
2286 | |||
2287 | dev_kfree_skb(frame.skb); | ||
2288 | |||
2289 | return ret; | ||
2290 | } | ||
2291 | |||
2292 | static int cw1200_upload_qosnull(struct cw1200_common *priv) | ||
2293 | { | ||
2294 | int ret = 0; | ||
2295 | /* TODO: This needs to be implemented | ||
2296 | |||
2297 | struct wsm_template_frame frame = { | ||
2298 | .frame_type = WSM_FRAME_TYPE_QOS_NULL, | ||
2299 | .rate = 0xFF, | ||
2300 | }; | ||
2301 | |||
2302 | frame.skb = ieee80211_qosnullfunc_get(priv->hw, priv->vif); | ||
2303 | if (!frame.skb) | ||
2304 | return -ENOMEM; | ||
2305 | |||
2306 | ret = wsm_set_template_frame(priv, &frame); | ||
2307 | |||
2308 | dev_kfree_skb(frame.skb); | ||
2309 | |||
2310 | */ | ||
2311 | return ret; | ||
2312 | } | ||
2313 | |||
2314 | static int cw1200_enable_beaconing(struct cw1200_common *priv, | ||
2315 | bool enable) | ||
2316 | { | ||
2317 | struct wsm_beacon_transmit transmit = { | ||
2318 | .enable_beaconing = enable, | ||
2319 | }; | ||
2320 | |||
2321 | return wsm_beacon_transmit(priv, &transmit); | ||
2322 | } | ||
2323 | |||
2324 | static int cw1200_start_ap(struct cw1200_common *priv) | ||
2325 | { | ||
2326 | int ret; | ||
2327 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
2328 | struct wsm_start start = { | ||
2329 | .mode = priv->vif->p2p ? | ||
2330 | WSM_START_MODE_P2P_GO : WSM_START_MODE_AP, | ||
2331 | .band = (priv->channel->band == IEEE80211_BAND_5GHZ) ? | ||
2332 | WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, | ||
2333 | .channel_number = priv->channel->hw_value, | ||
2334 | .beacon_interval = conf->beacon_int, | ||
2335 | .dtim_period = conf->dtim_period, | ||
2336 | .preamble = conf->use_short_preamble ? | ||
2337 | WSM_JOIN_PREAMBLE_SHORT : | ||
2338 | WSM_JOIN_PREAMBLE_LONG, | ||
2339 | .probe_delay = 100, | ||
2340 | .basic_rate_set = cw1200_rate_mask_to_wsm(priv, | ||
2341 | conf->basic_rates), | ||
2342 | }; | ||
2343 | struct wsm_operational_mode mode = { | ||
2344 | .power_mode = cw1200_power_mode, | ||
2345 | .disable_more_flag_usage = true, | ||
2346 | }; | ||
2347 | |||
2348 | memset(start.ssid, 0, sizeof(start.ssid)); | ||
2349 | if (!conf->hidden_ssid) { | ||
2350 | start.ssid_len = conf->ssid_len; | ||
2351 | memcpy(start.ssid, conf->ssid, start.ssid_len); | ||
2352 | } | ||
2353 | |||
2354 | priv->beacon_int = conf->beacon_int; | ||
2355 | priv->join_dtim_period = conf->dtim_period; | ||
2356 | |||
2357 | memset(&priv->link_id_db, 0, sizeof(priv->link_id_db)); | ||
2358 | |||
2359 | pr_debug("[AP] ch: %d(%d), bcn: %d(%d), brt: 0x%.8X, ssid: %.*s.\n", | ||
2360 | start.channel_number, start.band, | ||
2361 | start.beacon_interval, start.dtim_period, | ||
2362 | start.basic_rate_set, | ||
2363 | start.ssid_len, start.ssid); | ||
2364 | ret = wsm_start(priv, &start); | ||
2365 | if (!ret) | ||
2366 | ret = cw1200_upload_keys(priv); | ||
2367 | if (!ret && priv->vif->p2p) { | ||
2368 | pr_debug("[AP] Setting p2p powersave configuration.\n"); | ||
2369 | wsm_set_p2p_ps_modeinfo(priv, &priv->p2p_ps_modeinfo); | ||
2370 | } | ||
2371 | if (!ret) { | ||
2372 | wsm_set_block_ack_policy(priv, 0, 0); | ||
2373 | priv->join_status = CW1200_JOIN_STATUS_AP; | ||
2374 | cw1200_update_filtering(priv); | ||
2375 | } | ||
2376 | wsm_set_operational_mode(priv, &mode); | ||
2377 | return ret; | ||
2378 | } | ||
2379 | |||
2380 | static int cw1200_update_beaconing(struct cw1200_common *priv) | ||
2381 | { | ||
2382 | struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; | ||
2383 | struct wsm_reset reset = { | ||
2384 | .link_id = 0, | ||
2385 | .reset_statistics = true, | ||
2386 | }; | ||
2387 | |||
2388 | if (priv->mode == NL80211_IFTYPE_AP) { | ||
2389 | /* TODO: check if changed channel, band */ | ||
2390 | if (priv->join_status != CW1200_JOIN_STATUS_AP || | ||
2391 | priv->beacon_int != conf->beacon_int) { | ||
2392 | pr_debug("ap restarting\n"); | ||
2393 | wsm_lock_tx(priv); | ||
2394 | if (priv->join_status != CW1200_JOIN_STATUS_PASSIVE) | ||
2395 | wsm_reset(priv, &reset); | ||
2396 | priv->join_status = CW1200_JOIN_STATUS_PASSIVE; | ||
2397 | cw1200_start_ap(priv); | ||
2398 | wsm_unlock_tx(priv); | ||
2399 | } else | ||
2400 | pr_debug("ap started join_status: %d\n", | ||
2401 | priv->join_status); | ||
2402 | } | ||
2403 | return 0; | ||
2404 | } | ||
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..44ca10cb0d39 --- /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 | /* Sort rates in descending order. */ | ||
79 | for (i = 1; i < count; ++i) { | ||
80 | if (rates[i].idx < 0) { | ||
81 | count = i; | ||
82 | break; | ||
83 | } | ||
84 | if (rates[i].idx > rates[i - 1].idx) { | ||
85 | struct ieee80211_tx_rate tmp = rates[i - 1]; | ||
86 | rates[i - 1] = rates[i]; | ||
87 | rates[i] = tmp; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /* Eliminate duplicates. */ | ||
92 | total = rates[0].count; | ||
93 | for (i = 0, j = 1; j < count; ++j) { | ||
94 | if (rates[j].idx == rates[i].idx) { | ||
95 | rates[i].count += rates[j].count; | ||
96 | } else if (rates[j].idx > rates[i].idx) { | ||
97 | break; | ||
98 | } else { | ||
99 | ++i; | ||
100 | if (i != j) | ||
101 | rates[i] = rates[j]; | ||
102 | } | ||
103 | total += rates[j].count; | ||
104 | } | ||
105 | count = i + 1; | ||
106 | |||
107 | /* Re-fill policy trying to keep every requested rate and with | ||
108 | * respect to the global max tx retransmission count. | ||
109 | */ | ||
110 | if (limit < count) | ||
111 | limit = count; | ||
112 | if (total > limit) { | ||
113 | for (i = 0; i < count; ++i) { | ||
114 | int left = count - i - 1; | ||
115 | if (rates[i].count > limit - left) | ||
116 | rates[i].count = limit - left; | ||
117 | limit -= rates[i].count; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* HACK!!! Device has problems (at least) switching from | ||
122 | * 54Mbps CTS to 1Mbps. This switch takes enormous amount | ||
123 | * of time (100-200 ms), leading to valuable throughput drop. | ||
124 | * As a workaround, additional g-rates are injected to the | ||
125 | * policy. | ||
126 | */ | ||
127 | if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && | ||
128 | rates[0].idx > 4 && rates[0].count > 2 && | ||
129 | rates[1].idx < 2) { | ||
130 | int mid_rate = (rates[0].idx + 4) >> 1; | ||
131 | |||
132 | /* Decrease number of retries for the initial rate */ | ||
133 | rates[0].count -= 2; | ||
134 | |||
135 | if (mid_rate != 4) { | ||
136 | /* Keep fallback rate at 1Mbps. */ | ||
137 | rates[3] = rates[1]; | ||
138 | |||
139 | /* Inject 1 transmission on lowest g-rate */ | ||
140 | rates[2].idx = 4; | ||
141 | rates[2].count = 1; | ||
142 | rates[2].flags = rates[1].flags; | ||
143 | |||
144 | /* Inject 1 transmission on mid-rate */ | ||
145 | rates[1].idx = mid_rate; | ||
146 | rates[1].count = 1; | ||
147 | |||
148 | /* Fallback to 1 Mbps is a really bad thing, | ||
149 | * so let's try to increase probability of | ||
150 | * successful transmission on the lowest g rate | ||
151 | * even more | ||
152 | */ | ||
153 | if (rates[0].count >= 3) { | ||
154 | --rates[0].count; | ||
155 | ++rates[2].count; | ||
156 | } | ||
157 | |||
158 | /* Adjust amount of rates defined */ | ||
159 | count += 2; | ||
160 | } else { | ||
161 | /* Keep fallback rate at 1Mbps. */ | ||
162 | rates[2] = rates[1]; | ||
163 | |||
164 | /* Inject 2 transmissions on lowest g-rate */ | ||
165 | rates[1].idx = 4; | ||
166 | rates[1].count = 2; | ||
167 | |||
168 | /* Adjust amount of rates defined */ | ||
169 | count += 1; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | policy->defined = cw1200_get_tx_rate(priv, &rates[0])->hw_value + 1; | ||
174 | |||
175 | for (i = 0; i < count; ++i) { | ||
176 | register unsigned rateid, off, shift, retries; | ||
177 | |||
178 | rateid = cw1200_get_tx_rate(priv, &rates[i])->hw_value; | ||
179 | off = rateid >> 3; /* eq. rateid / 8 */ | ||
180 | shift = (rateid & 0x07) << 2; /* eq. (rateid % 8) * 4 */ | ||
181 | |||
182 | retries = rates[i].count; | ||
183 | if (retries > 0x0F) { | ||
184 | rates[i].count = 0x0f; | ||
185 | retries = 0x0F; | ||
186 | } | ||
187 | policy->tbl[off] |= __cpu_to_le32(retries << shift); | ||
188 | policy->retry_count += retries; | ||
189 | } | ||
190 | |||
191 | pr_debug("[TX policy] Policy (%zu): %d:%d, %d:%d, %d:%d, %d:%d\n", | ||
192 | count, | ||
193 | rates[0].idx, rates[0].count, | ||
194 | rates[1].idx, rates[1].count, | ||
195 | rates[2].idx, rates[2].count, | ||
196 | rates[3].idx, rates[3].count); | ||
197 | } | ||
198 | |||
199 | static inline bool tx_policy_is_equal(const struct tx_policy *wanted, | ||
200 | const struct tx_policy *cached) | ||
201 | { | ||
202 | size_t count = wanted->defined >> 1; | ||
203 | if (wanted->defined > cached->defined) | ||
204 | return false; | ||
205 | if (count) { | ||
206 | if (memcmp(wanted->raw, cached->raw, count)) | ||
207 | return false; | ||
208 | } | ||
209 | if (wanted->defined & 1) { | ||
210 | if ((wanted->raw[count] & 0x0F) != (cached->raw[count] & 0x0F)) | ||
211 | return false; | ||
212 | } | ||
213 | return true; | ||
214 | } | ||
215 | |||
216 | static int tx_policy_find(struct tx_policy_cache *cache, | ||
217 | const struct tx_policy *wanted) | ||
218 | { | ||
219 | /* O(n) complexity. Not so good, but there's only 8 entries in | ||
220 | * the cache. | ||
221 | * Also lru helps to reduce search time. | ||
222 | */ | ||
223 | struct tx_policy_cache_entry *it; | ||
224 | /* First search for policy in "used" list */ | ||
225 | list_for_each_entry(it, &cache->used, link) { | ||
226 | if (tx_policy_is_equal(wanted, &it->policy)) | ||
227 | return it - cache->cache; | ||
228 | } | ||
229 | /* Then - in "free list" */ | ||
230 | list_for_each_entry(it, &cache->free, link) { | ||
231 | if (tx_policy_is_equal(wanted, &it->policy)) | ||
232 | return it - cache->cache; | ||
233 | } | ||
234 | return -1; | ||
235 | } | ||
236 | |||
237 | static inline void tx_policy_use(struct tx_policy_cache *cache, | ||
238 | struct tx_policy_cache_entry *entry) | ||
239 | { | ||
240 | ++entry->policy.usage_count; | ||
241 | list_move(&entry->link, &cache->used); | ||
242 | } | ||
243 | |||
244 | static inline int tx_policy_release(struct tx_policy_cache *cache, | ||
245 | struct tx_policy_cache_entry *entry) | ||
246 | { | ||
247 | int ret = --entry->policy.usage_count; | ||
248 | if (!ret) | ||
249 | list_move(&entry->link, &cache->free); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | void tx_policy_clean(struct cw1200_common *priv) | ||
254 | { | ||
255 | int idx, locked; | ||
256 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
257 | struct tx_policy_cache_entry *entry; | ||
258 | |||
259 | cw1200_tx_queues_lock(priv); | ||
260 | spin_lock_bh(&cache->lock); | ||
261 | locked = list_empty(&cache->free); | ||
262 | |||
263 | for (idx = 0; idx < TX_POLICY_CACHE_SIZE; idx++) { | ||
264 | entry = &cache->cache[idx]; | ||
265 | /* Policy usage count should be 0 at this time as all queues | ||
266 | should be empty | ||
267 | */ | ||
268 | if (WARN_ON(entry->policy.usage_count)) { | ||
269 | entry->policy.usage_count = 0; | ||
270 | list_move(&entry->link, &cache->free); | ||
271 | } | ||
272 | memset(&entry->policy, 0, sizeof(entry->policy)); | ||
273 | } | ||
274 | if (locked) | ||
275 | cw1200_tx_queues_unlock(priv); | ||
276 | |||
277 | cw1200_tx_queues_unlock(priv); | ||
278 | spin_unlock_bh(&cache->lock); | ||
279 | } | ||
280 | |||
281 | /* ******************************************************************** */ | ||
282 | /* External TX policy cache API */ | ||
283 | |||
284 | void tx_policy_init(struct cw1200_common *priv) | ||
285 | { | ||
286 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
287 | int i; | ||
288 | |||
289 | memset(cache, 0, sizeof(*cache)); | ||
290 | |||
291 | spin_lock_init(&cache->lock); | ||
292 | INIT_LIST_HEAD(&cache->used); | ||
293 | INIT_LIST_HEAD(&cache->free); | ||
294 | |||
295 | for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) | ||
296 | list_add(&cache->cache[i].link, &cache->free); | ||
297 | } | ||
298 | |||
299 | static int tx_policy_get(struct cw1200_common *priv, | ||
300 | struct ieee80211_tx_rate *rates, | ||
301 | size_t count, bool *renew) | ||
302 | { | ||
303 | int idx; | ||
304 | struct tx_policy_cache *cache = &priv->tx_policy_cache; | ||
305 | struct tx_policy wanted; | ||
306 | |||
307 | tx_policy_build(priv, &wanted, rates, count); | ||
308 | |||
309 | spin_lock_bh(&cache->lock); | ||
310 | if (WARN_ON_ONCE(list_empty(&cache->free))) { | ||
311 | spin_unlock_bh(&cache->lock); | ||
312 | return CW1200_INVALID_RATE_ID; | ||
313 | } | ||
314 | idx = tx_policy_find(cache, &wanted); | ||
315 | if (idx >= 0) { | ||
316 | pr_debug("[TX policy] Used TX policy: %d\n", idx); | ||
317 | *renew = false; | ||
318 | } else { | ||
319 | struct tx_policy_cache_entry *entry; | ||
320 | *renew = true; | ||
321 | /* If policy is not found create a new one | ||
322 | * using the oldest entry in "free" list | ||
323 | */ | ||
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 | */ | ||
618 | mgt_frame->u.assoc_req.listen_interval = | ||
619 | priv->listen_interval; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | if (!priority) { | ||
624 | if (ieee80211_is_action(t->hdr->frame_control)) | ||
625 | priority = WSM_EPTA_PRIORITY_ACTION; | ||
626 | else if (ieee80211_is_mgmt(t->hdr->frame_control)) | ||
627 | priority = WSM_EPTA_PRIORITY_MGT; | ||
628 | else if ((wsm->queue_id == WSM_QUEUE_VOICE)) | ||
629 | priority = WSM_EPTA_PRIORITY_VOICE; | ||
630 | else if ((wsm->queue_id == WSM_QUEUE_VIDEO)) | ||
631 | priority = WSM_EPTA_PRIORITY_VIDEO; | ||
632 | else | ||
633 | priority = WSM_EPTA_PRIORITY_DATA; | ||
634 | } | ||
635 | |||
636 | pr_debug("[TX] EPTA priority %d.\n", priority); | ||
637 | |||
638 | wsm->flags |= priority << 1; | ||
639 | } | ||
640 | |||
641 | static int | ||
642 | cw1200_tx_h_rate_policy(struct cw1200_common *priv, | ||
643 | struct cw1200_txinfo *t, | ||
644 | struct wsm_tx *wsm) | ||
645 | { | ||
646 | bool tx_policy_renew = false; | ||
647 | |||
648 | t->txpriv.rate_id = tx_policy_get(priv, | ||
649 | t->tx_info->control.rates, IEEE80211_TX_MAX_RATES, | ||
650 | &tx_policy_renew); | ||
651 | if (t->txpriv.rate_id == CW1200_INVALID_RATE_ID) | ||
652 | return -EFAULT; | ||
653 | |||
654 | wsm->flags |= t->txpriv.rate_id << 4; | ||
655 | |||
656 | t->rate = cw1200_get_tx_rate(priv, | ||
657 | &t->tx_info->control.rates[0]), | ||
658 | wsm->max_tx_rate = t->rate->hw_value; | ||
659 | if (t->rate->flags & IEEE80211_TX_RC_MCS) { | ||
660 | if (cw1200_ht_greenfield(&priv->ht_info)) | ||
661 | wsm->ht_tx_parameters |= | ||
662 | __cpu_to_le32(WSM_HT_TX_GREENFIELD); | ||
663 | else | ||
664 | wsm->ht_tx_parameters |= | ||
665 | __cpu_to_le32(WSM_HT_TX_MIXED); | ||
666 | } | ||
667 | |||
668 | if (tx_policy_renew) { | ||
669 | pr_debug("[TX] TX policy renew.\n"); | ||
670 | /* It's not so optimal to stop TX queues every now and then. | ||
671 | * Better to reimplement task scheduling with | ||
672 | * a counter. TODO. | ||
673 | */ | ||
674 | wsm_lock_tx_async(priv); | ||
675 | cw1200_tx_queues_lock(priv); | ||
676 | if (queue_work(priv->workqueue, | ||
677 | &priv->tx_policy_upload_work) <= 0) { | ||
678 | cw1200_tx_queues_unlock(priv); | ||
679 | wsm_unlock_tx(priv); | ||
680 | } | ||
681 | } | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static bool | ||
686 | cw1200_tx_h_pm_state(struct cw1200_common *priv, | ||
687 | struct cw1200_txinfo *t) | ||
688 | { | ||
689 | int was_buffered = 1; | ||
690 | |||
691 | if (t->txpriv.link_id == CW1200_LINK_ID_AFTER_DTIM && | ||
692 | !priv->buffered_multicasts) { | ||
693 | priv->buffered_multicasts = true; | ||
694 | if (priv->sta_asleep_mask) | ||
695 | queue_work(priv->workqueue, | ||
696 | &priv->multicast_start_work); | ||
697 | } | ||
698 | |||
699 | if (t->txpriv.raw_link_id && t->txpriv.tid < CW1200_MAX_TID) | ||
700 | was_buffered = priv->link_id_db[t->txpriv.raw_link_id - 1].buffered[t->txpriv.tid]++; | ||
701 | |||
702 | return !was_buffered; | ||
703 | } | ||
704 | |||
705 | /* ******************************************************************** */ | ||
706 | |||
707 | void cw1200_tx(struct ieee80211_hw *dev, | ||
708 | struct ieee80211_tx_control *control, | ||
709 | struct sk_buff *skb) | ||
710 | { | ||
711 | struct cw1200_common *priv = dev->priv; | ||
712 | struct cw1200_txinfo t = { | ||
713 | .skb = skb, | ||
714 | .queue = skb_get_queue_mapping(skb), | ||
715 | .tx_info = IEEE80211_SKB_CB(skb), | ||
716 | .hdr = (struct ieee80211_hdr *)skb->data, | ||
717 | .txpriv.tid = CW1200_MAX_TID, | ||
718 | .txpriv.rate_id = CW1200_INVALID_RATE_ID, | ||
719 | }; | ||
720 | struct ieee80211_sta *sta; | ||
721 | struct wsm_tx *wsm; | ||
722 | bool tid_update = 0; | ||
723 | u8 flags = 0; | ||
724 | int ret; | ||
725 | |||
726 | if (priv->bh_error) | ||
727 | goto drop; | ||
728 | |||
729 | t.hdrlen = ieee80211_hdrlen(t.hdr->frame_control); | ||
730 | t.da = ieee80211_get_DA(t.hdr); | ||
731 | if (control) { | ||
732 | t.sta = control->sta; | ||
733 | t.sta_priv = (struct cw1200_sta_priv *)&t.sta->drv_priv; | ||
734 | } | ||
735 | |||
736 | if (WARN_ON(t.queue >= 4)) | ||
737 | goto drop; | ||
738 | |||
739 | ret = cw1200_tx_h_calc_link_ids(priv, &t); | ||
740 | if (ret) | ||
741 | goto drop; | ||
742 | |||
743 | pr_debug("[TX] TX %d bytes (queue: %d, link_id: %d (%d)).\n", | ||
744 | skb->len, t.queue, t.txpriv.link_id, | ||
745 | t.txpriv.raw_link_id); | ||
746 | |||
747 | cw1200_tx_h_pm(priv, &t); | ||
748 | cw1200_tx_h_calc_tid(priv, &t); | ||
749 | ret = cw1200_tx_h_crypt(priv, &t); | ||
750 | if (ret) | ||
751 | goto drop; | ||
752 | ret = cw1200_tx_h_align(priv, &t, &flags); | ||
753 | if (ret) | ||
754 | goto drop; | ||
755 | ret = cw1200_tx_h_action(priv, &t); | ||
756 | if (ret) | ||
757 | goto drop; | ||
758 | wsm = cw1200_tx_h_wsm(priv, &t); | ||
759 | if (!wsm) { | ||
760 | ret = -ENOMEM; | ||
761 | goto drop; | ||
762 | } | ||
763 | wsm->flags |= flags; | ||
764 | cw1200_tx_h_bt(priv, &t, wsm); | ||
765 | ret = cw1200_tx_h_rate_policy(priv, &t, wsm); | ||
766 | if (ret) | ||
767 | goto drop; | ||
768 | |||
769 | rcu_read_lock(); | ||
770 | sta = rcu_dereference(t.sta); | ||
771 | |||
772 | spin_lock_bh(&priv->ps_state_lock); | ||
773 | { | ||
774 | tid_update = cw1200_tx_h_pm_state(priv, &t); | ||
775 | BUG_ON(cw1200_queue_put(&priv->tx_queue[t.queue], | ||
776 | t.skb, &t.txpriv)); | ||
777 | } | ||
778 | spin_unlock_bh(&priv->ps_state_lock); | ||
779 | |||
780 | if (tid_update && sta) | ||
781 | ieee80211_sta_set_buffered(sta, t.txpriv.tid, true); | ||
782 | |||
783 | rcu_read_unlock(); | ||
784 | |||
785 | cw1200_bh_wakeup(priv); | ||
786 | |||
787 | return; | ||
788 | |||
789 | drop: | ||
790 | cw1200_skb_dtor(priv, skb, &t.txpriv); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | /* ******************************************************************** */ | ||
795 | |||
796 | static int cw1200_handle_action_rx(struct cw1200_common *priv, | ||
797 | struct sk_buff *skb) | ||
798 | { | ||
799 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
800 | |||
801 | /* Filter block ACK negotiation: fully controlled by firmware */ | ||
802 | if (mgmt->u.action.category == WLAN_CATEGORY_BACK) | ||
803 | return 1; | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static int cw1200_handle_pspoll(struct cw1200_common *priv, | ||
809 | struct sk_buff *skb) | ||
810 | { | ||
811 | struct ieee80211_sta *sta; | ||
812 | struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data; | ||
813 | int link_id = 0; | ||
814 | u32 pspoll_mask = 0; | ||
815 | int drop = 1; | ||
816 | int i; | ||
817 | |||
818 | if (priv->join_status != CW1200_JOIN_STATUS_AP) | ||
819 | goto done; | ||
820 | if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) | ||
821 | goto done; | ||
822 | |||
823 | rcu_read_lock(); | ||
824 | sta = ieee80211_find_sta(priv->vif, pspoll->ta); | ||
825 | if (sta) { | ||
826 | struct cw1200_sta_priv *sta_priv; | ||
827 | sta_priv = (struct cw1200_sta_priv *)&sta->drv_priv; | ||
828 | link_id = sta_priv->link_id; | ||
829 | pspoll_mask = BIT(sta_priv->link_id); | ||
830 | } | ||
831 | rcu_read_unlock(); | ||
832 | if (!link_id) | ||
833 | goto done; | ||
834 | |||
835 | priv->pspoll_mask |= pspoll_mask; | ||
836 | drop = 0; | ||
837 | |||
838 | /* Do not report pspols if data for given link id is queued already. */ | ||
839 | for (i = 0; i < 4; ++i) { | ||
840 | if (cw1200_queue_get_num_queued(&priv->tx_queue[i], | ||
841 | pspoll_mask)) { | ||
842 | cw1200_bh_wakeup(priv); | ||
843 | drop = 1; | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | pr_debug("[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); | ||
848 | done: | ||
849 | return drop; | ||
850 | } | ||
851 | |||
852 | /* ******************************************************************** */ | ||
853 | |||
854 | void cw1200_tx_confirm_cb(struct cw1200_common *priv, | ||
855 | int link_id, | ||
856 | struct wsm_tx_confirm *arg) | ||
857 | { | ||
858 | u8 queue_id = cw1200_queue_get_queue_id(arg->packet_id); | ||
859 | struct cw1200_queue *queue = &priv->tx_queue[queue_id]; | ||
860 | struct sk_buff *skb; | ||
861 | const struct cw1200_txpriv *txpriv; | ||
862 | |||
863 | pr_debug("[TX] TX confirm: %d, %d.\n", | ||
864 | arg->status, arg->ack_failures); | ||
865 | |||
866 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
867 | /* STA is stopped. */ | ||
868 | return; | ||
869 | } | ||
870 | |||
871 | if (WARN_ON(queue_id >= 4)) | ||
872 | return; | ||
873 | |||
874 | if (arg->status) | ||
875 | pr_debug("TX failed: %d.\n", arg->status); | ||
876 | |||
877 | if ((arg->status == WSM_REQUEUE) && | ||
878 | (arg->flags & WSM_TX_STATUS_REQUEUE)) { | ||
879 | /* "Requeue" means "implicit suspend" */ | ||
880 | struct wsm_suspend_resume suspend = { | ||
881 | .link_id = link_id, | ||
882 | .stop = 1, | ||
883 | .multicast = !link_id, | ||
884 | }; | ||
885 | cw1200_suspend_resume(priv, &suspend); | ||
886 | wiphy_warn(priv->hw->wiphy, "Requeue for link_id %d (try %d). STAs asleep: 0x%.8X\n", | ||
887 | link_id, | ||
888 | cw1200_queue_get_generation(arg->packet_id) + 1, | ||
889 | priv->sta_asleep_mask); | ||
890 | cw1200_queue_requeue(queue, arg->packet_id); | ||
891 | spin_lock_bh(&priv->ps_state_lock); | ||
892 | if (!link_id) { | ||
893 | priv->buffered_multicasts = true; | ||
894 | if (priv->sta_asleep_mask) { | ||
895 | queue_work(priv->workqueue, | ||
896 | &priv->multicast_start_work); | ||
897 | } | ||
898 | } | ||
899 | spin_unlock_bh(&priv->ps_state_lock); | ||
900 | } else if (!cw1200_queue_get_skb(queue, arg->packet_id, | ||
901 | &skb, &txpriv)) { | ||
902 | struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb); | ||
903 | int tx_count = arg->ack_failures; | ||
904 | u8 ht_flags = 0; | ||
905 | int i; | ||
906 | |||
907 | if (cw1200_ht_greenfield(&priv->ht_info)) | ||
908 | ht_flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
909 | |||
910 | spin_lock(&priv->bss_loss_lock); | ||
911 | if (priv->bss_loss_state && | ||
912 | arg->packet_id == priv->bss_loss_confirm_id) { | ||
913 | if (arg->status) { | ||
914 | /* Recovery failed */ | ||
915 | __cw1200_cqm_bssloss_sm(priv, 0, 0, 1); | ||
916 | } else { | ||
917 | /* Recovery succeeded */ | ||
918 | __cw1200_cqm_bssloss_sm(priv, 0, 1, 0); | ||
919 | } | ||
920 | } | ||
921 | spin_unlock(&priv->bss_loss_lock); | ||
922 | |||
923 | if (!arg->status) { | ||
924 | tx->flags |= IEEE80211_TX_STAT_ACK; | ||
925 | ++tx_count; | ||
926 | cw1200_debug_txed(priv); | ||
927 | if (arg->flags & WSM_TX_STATUS_AGGREGATION) { | ||
928 | /* Do not report aggregation to mac80211: | ||
929 | * it confuses minstrel a lot. | ||
930 | */ | ||
931 | /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ | ||
932 | cw1200_debug_txed_agg(priv); | ||
933 | } | ||
934 | } else { | ||
935 | if (tx_count) | ||
936 | ++tx_count; | ||
937 | } | ||
938 | |||
939 | for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { | ||
940 | if (tx->status.rates[i].count >= tx_count) { | ||
941 | tx->status.rates[i].count = tx_count; | ||
942 | break; | ||
943 | } | ||
944 | tx_count -= tx->status.rates[i].count; | ||
945 | if (tx->status.rates[i].flags & IEEE80211_TX_RC_MCS) | ||
946 | tx->status.rates[i].flags |= ht_flags; | ||
947 | } | ||
948 | |||
949 | for (++i; i < IEEE80211_TX_MAX_RATES; ++i) { | ||
950 | tx->status.rates[i].count = 0; | ||
951 | tx->status.rates[i].idx = -1; | ||
952 | } | ||
953 | |||
954 | /* Pull off any crypto trailers that we added on */ | ||
955 | if (tx->control.hw_key) { | ||
956 | skb_trim(skb, skb->len - tx->control.hw_key->icv_len); | ||
957 | if (tx->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) | ||
958 | skb_trim(skb, skb->len - 8); /* MIC space */ | ||
959 | } | ||
960 | cw1200_queue_remove(queue, arg->packet_id); | ||
961 | } | ||
962 | /* XXX TODO: Only wake if there are pending transmits.. */ | ||
963 | cw1200_bh_wakeup(priv); | ||
964 | } | ||
965 | |||
966 | static void cw1200_notify_buffered_tx(struct cw1200_common *priv, | ||
967 | struct sk_buff *skb, int link_id, int tid) | ||
968 | { | ||
969 | struct ieee80211_sta *sta; | ||
970 | struct ieee80211_hdr *hdr; | ||
971 | u8 *buffered; | ||
972 | u8 still_buffered = 0; | ||
973 | |||
974 | if (link_id && tid < CW1200_MAX_TID) { | ||
975 | buffered = priv->link_id_db | ||
976 | [link_id - 1].buffered; | ||
977 | |||
978 | spin_lock_bh(&priv->ps_state_lock); | ||
979 | if (!WARN_ON(!buffered[tid])) | ||
980 | still_buffered = --buffered[tid]; | ||
981 | spin_unlock_bh(&priv->ps_state_lock); | ||
982 | |||
983 | if (!still_buffered && tid < CW1200_MAX_TID) { | ||
984 | hdr = (struct ieee80211_hdr *)skb->data; | ||
985 | rcu_read_lock(); | ||
986 | sta = ieee80211_find_sta(priv->vif, hdr->addr1); | ||
987 | if (sta) | ||
988 | ieee80211_sta_set_buffered(sta, tid, false); | ||
989 | rcu_read_unlock(); | ||
990 | } | ||
991 | } | ||
992 | } | ||
993 | |||
994 | void cw1200_skb_dtor(struct cw1200_common *priv, | ||
995 | struct sk_buff *skb, | ||
996 | const struct cw1200_txpriv *txpriv) | ||
997 | { | ||
998 | skb_pull(skb, txpriv->offset); | ||
999 | if (txpriv->rate_id != CW1200_INVALID_RATE_ID) { | ||
1000 | cw1200_notify_buffered_tx(priv, skb, | ||
1001 | txpriv->raw_link_id, txpriv->tid); | ||
1002 | tx_policy_put(priv, txpriv->rate_id); | ||
1003 | } | ||
1004 | ieee80211_tx_status(priv->hw, skb); | ||
1005 | } | ||
1006 | |||
1007 | void cw1200_rx_cb(struct cw1200_common *priv, | ||
1008 | struct wsm_rx *arg, | ||
1009 | int link_id, | ||
1010 | struct sk_buff **skb_p) | ||
1011 | { | ||
1012 | struct sk_buff *skb = *skb_p; | ||
1013 | struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); | ||
1014 | struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; | ||
1015 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; | ||
1016 | struct cw1200_link_entry *entry = NULL; | ||
1017 | unsigned long grace_period; | ||
1018 | |||
1019 | bool early_data = false; | ||
1020 | bool p2p = priv->vif && priv->vif->p2p; | ||
1021 | size_t hdrlen; | ||
1022 | hdr->flag = 0; | ||
1023 | |||
1024 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
1025 | /* STA is stopped. */ | ||
1026 | goto drop; | ||
1027 | } | ||
1028 | |||
1029 | if (link_id && link_id <= CW1200_MAX_STA_IN_AP_MODE) { | ||
1030 | entry = &priv->link_id_db[link_id - 1]; | ||
1031 | if (entry->status == CW1200_LINK_SOFT && | ||
1032 | ieee80211_is_data(frame->frame_control)) | ||
1033 | early_data = true; | ||
1034 | entry->timestamp = jiffies; | ||
1035 | } else if (p2p && | ||
1036 | ieee80211_is_action(frame->frame_control) && | ||
1037 | (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { | ||
1038 | pr_debug("[RX] Going to MAP&RESET link ID\n"); | ||
1039 | WARN_ON(work_pending(&priv->linkid_reset_work)); | ||
1040 | memcpy(&priv->action_frame_sa[0], | ||
1041 | ieee80211_get_SA(frame), ETH_ALEN); | ||
1042 | priv->action_linkid = 0; | ||
1043 | schedule_work(&priv->linkid_reset_work); | ||
1044 | } | ||
1045 | |||
1046 | if (link_id && p2p && | ||
1047 | ieee80211_is_action(frame->frame_control) && | ||
1048 | (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { | ||
1049 | /* Link ID already exists for the ACTION frame. | ||
1050 | * Reset and Remap | ||
1051 | */ | ||
1052 | WARN_ON(work_pending(&priv->linkid_reset_work)); | ||
1053 | memcpy(&priv->action_frame_sa[0], | ||
1054 | ieee80211_get_SA(frame), ETH_ALEN); | ||
1055 | priv->action_linkid = link_id; | ||
1056 | schedule_work(&priv->linkid_reset_work); | ||
1057 | } | ||
1058 | if (arg->status) { | ||
1059 | if (arg->status == WSM_STATUS_MICFAILURE) { | ||
1060 | pr_debug("[RX] MIC failure.\n"); | ||
1061 | hdr->flag |= RX_FLAG_MMIC_ERROR; | ||
1062 | } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { | ||
1063 | pr_debug("[RX] No key found.\n"); | ||
1064 | goto drop; | ||
1065 | } else { | ||
1066 | pr_debug("[RX] Receive failure: %d.\n", | ||
1067 | arg->status); | ||
1068 | goto drop; | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | if (skb->len < sizeof(struct ieee80211_pspoll)) { | ||
1073 | wiphy_warn(priv->hw->wiphy, "Mailformed SDU rx'ed. Size is lesser than IEEE header.\n"); | ||
1074 | goto drop; | ||
1075 | } | ||
1076 | |||
1077 | if (ieee80211_is_pspoll(frame->frame_control)) | ||
1078 | if (cw1200_handle_pspoll(priv, skb)) | ||
1079 | goto drop; | ||
1080 | |||
1081 | hdr->band = ((arg->channel_number & 0xff00) || | ||
1082 | (arg->channel_number > 14)) ? | ||
1083 | IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; | ||
1084 | hdr->freq = ieee80211_channel_to_frequency( | ||
1085 | arg->channel_number, | ||
1086 | hdr->band); | ||
1087 | |||
1088 | if (arg->rx_rate >= 14) { | ||
1089 | hdr->flag |= RX_FLAG_HT; | ||
1090 | hdr->rate_idx = arg->rx_rate - 14; | ||
1091 | } else if (arg->rx_rate >= 4) { | ||
1092 | hdr->rate_idx = arg->rx_rate - 2; | ||
1093 | } else { | ||
1094 | hdr->rate_idx = arg->rx_rate; | ||
1095 | } | ||
1096 | |||
1097 | hdr->signal = (s8)arg->rcpi_rssi; | ||
1098 | hdr->antenna = 0; | ||
1099 | |||
1100 | hdrlen = ieee80211_hdrlen(frame->frame_control); | ||
1101 | |||
1102 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { | ||
1103 | size_t iv_len = 0, icv_len = 0; | ||
1104 | |||
1105 | hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; | ||
1106 | |||
1107 | /* Oops... There is no fast way to ask mac80211 about | ||
1108 | * IV/ICV lengths. Even defineas are not exposed. | ||
1109 | */ | ||
1110 | switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { | ||
1111 | case WSM_RX_STATUS_WEP: | ||
1112 | iv_len = 4 /* WEP_IV_LEN */; | ||
1113 | icv_len = 4 /* WEP_ICV_LEN */; | ||
1114 | break; | ||
1115 | case WSM_RX_STATUS_TKIP: | ||
1116 | iv_len = 8 /* TKIP_IV_LEN */; | ||
1117 | icv_len = 4 /* TKIP_ICV_LEN */ | ||
1118 | + 8 /*MICHAEL_MIC_LEN*/; | ||
1119 | hdr->flag |= RX_FLAG_MMIC_STRIPPED; | ||
1120 | break; | ||
1121 | case WSM_RX_STATUS_AES: | ||
1122 | iv_len = 8 /* CCMP_HDR_LEN */; | ||
1123 | icv_len = 8 /* CCMP_MIC_LEN */; | ||
1124 | break; | ||
1125 | case WSM_RX_STATUS_WAPI: | ||
1126 | iv_len = 18 /* WAPI_HDR_LEN */; | ||
1127 | icv_len = 16 /* WAPI_MIC_LEN */; | ||
1128 | break; | ||
1129 | default: | ||
1130 | pr_warn("Unknown encryption type %d\n", | ||
1131 | WSM_RX_STATUS_ENCRYPTION(arg->flags)); | ||
1132 | goto drop; | ||
1133 | } | ||
1134 | |||
1135 | /* Firmware strips ICV in case of MIC failure. */ | ||
1136 | if (arg->status == WSM_STATUS_MICFAILURE) | ||
1137 | icv_len = 0; | ||
1138 | |||
1139 | if (skb->len < hdrlen + iv_len + icv_len) { | ||
1140 | wiphy_warn(priv->hw->wiphy, "Malformed SDU rx'ed. Size is lesser than crypto headers.\n"); | ||
1141 | goto drop; | ||
1142 | } | ||
1143 | |||
1144 | /* Remove IV, ICV and MIC */ | ||
1145 | skb_trim(skb, skb->len - icv_len); | ||
1146 | memmove(skb->data + iv_len, skb->data, hdrlen); | ||
1147 | skb_pull(skb, iv_len); | ||
1148 | } | ||
1149 | |||
1150 | /* Remove TSF from the end of frame */ | ||
1151 | if (arg->flags & WSM_RX_STATUS_TSF_INCLUDED) { | ||
1152 | memcpy(&hdr->mactime, skb->data + skb->len - 8, 8); | ||
1153 | hdr->mactime = le64_to_cpu(hdr->mactime); | ||
1154 | if (skb->len >= 8) | ||
1155 | skb_trim(skb, skb->len - 8); | ||
1156 | } else { | ||
1157 | hdr->mactime = 0; | ||
1158 | } | ||
1159 | |||
1160 | cw1200_debug_rxed(priv); | ||
1161 | if (arg->flags & WSM_RX_STATUS_AGGREGATE) | ||
1162 | cw1200_debug_rxed_agg(priv); | ||
1163 | |||
1164 | if (ieee80211_is_action(frame->frame_control) && | ||
1165 | (arg->flags & WSM_RX_STATUS_ADDRESS1)) { | ||
1166 | if (cw1200_handle_action_rx(priv, skb)) | ||
1167 | return; | ||
1168 | } else if (ieee80211_is_beacon(frame->frame_control) && | ||
1169 | !arg->status && | ||
1170 | !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid, | ||
1171 | ETH_ALEN)) { | ||
1172 | const u8 *tim_ie; | ||
1173 | u8 *ies = ((struct ieee80211_mgmt *) | ||
1174 | (skb->data))->u.beacon.variable; | ||
1175 | size_t ies_len = skb->len - (ies - (u8 *)(skb->data)); | ||
1176 | |||
1177 | tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len); | ||
1178 | if (tim_ie) { | ||
1179 | struct ieee80211_tim_ie *tim = | ||
1180 | (struct ieee80211_tim_ie *)&tim_ie[2]; | ||
1181 | |||
1182 | if (priv->join_dtim_period != tim->dtim_period) { | ||
1183 | priv->join_dtim_period = tim->dtim_period; | ||
1184 | queue_work(priv->workqueue, | ||
1185 | &priv->set_beacon_wakeup_period_work); | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | /* Disable beacon filter once we're associated... */ | ||
1190 | if (priv->disable_beacon_filter && | ||
1191 | (priv->vif->bss_conf.assoc || | ||
1192 | priv->vif->bss_conf.ibss_joined)) { | ||
1193 | priv->disable_beacon_filter = false; | ||
1194 | queue_work(priv->workqueue, | ||
1195 | &priv->update_filtering_work); | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | /* Stay awake after frame is received to give | ||
1200 | * userspace chance to react and acquire appropriate | ||
1201 | * wakelock. | ||
1202 | */ | ||
1203 | if (ieee80211_is_auth(frame->frame_control)) | ||
1204 | grace_period = 5 * HZ; | ||
1205 | else if (ieee80211_is_deauth(frame->frame_control)) | ||
1206 | grace_period = 5 * HZ; | ||
1207 | else | ||
1208 | grace_period = 1 * HZ; | ||
1209 | cw1200_pm_stay_awake(&priv->pm_state, grace_period); | ||
1210 | |||
1211 | 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..d95094fdcc50 --- /dev/null +++ b/drivers/net/wireless/cw1200/wsm.c | |||
@@ -0,0 +1,1823 @@ | |||
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 | |||
25 | #define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ | ||
26 | #define WSM_CMD_START_TIMEOUT (7 * HZ) | ||
27 | #define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */ | ||
28 | #define WSM_CMD_MAX_TIMEOUT (3 * HZ) | ||
29 | |||
30 | #define WSM_SKIP(buf, size) \ | ||
31 | do { \ | ||
32 | if ((buf)->data + size > (buf)->end) \ | ||
33 | goto underflow; \ | ||
34 | (buf)->data += size; \ | ||
35 | } while (0) | ||
36 | |||
37 | #define WSM_GET(buf, ptr, size) \ | ||
38 | do { \ | ||
39 | if ((buf)->data + size > (buf)->end) \ | ||
40 | goto underflow; \ | ||
41 | memcpy(ptr, (buf)->data, size); \ | ||
42 | (buf)->data += size; \ | ||
43 | } while (0) | ||
44 | |||
45 | #define __WSM_GET(buf, type, cvt) \ | ||
46 | ({ \ | ||
47 | type val; \ | ||
48 | if ((buf)->data + sizeof(type) > (buf)->end) \ | ||
49 | goto underflow; \ | ||
50 | val = cvt(*(type *)(buf)->data); \ | ||
51 | (buf)->data += sizeof(type); \ | ||
52 | val; \ | ||
53 | }) | ||
54 | |||
55 | #define WSM_GET8(buf) __WSM_GET(buf, u8, (u8)) | ||
56 | #define WSM_GET16(buf) __WSM_GET(buf, u16, __le16_to_cpu) | ||
57 | #define WSM_GET32(buf) __WSM_GET(buf, u32, __le32_to_cpu) | ||
58 | |||
59 | #define WSM_PUT(buf, ptr, size) \ | ||
60 | do { \ | ||
61 | if ((buf)->data + size > (buf)->end) \ | ||
62 | if (wsm_buf_reserve((buf), size)) \ | ||
63 | goto nomem; \ | ||
64 | memcpy((buf)->data, ptr, size); \ | ||
65 | (buf)->data += size; \ | ||
66 | } while (0) | ||
67 | |||
68 | #define __WSM_PUT(buf, val, type, cvt) \ | ||
69 | do { \ | ||
70 | if ((buf)->data + sizeof(type) > (buf)->end) \ | ||
71 | if (wsm_buf_reserve((buf), sizeof(type))) \ | ||
72 | goto nomem; \ | ||
73 | *(type *)(buf)->data = cvt(val); \ | ||
74 | (buf)->data += sizeof(type); \ | ||
75 | } while (0) | ||
76 | |||
77 | #define WSM_PUT8(buf, val) __WSM_PUT(buf, val, u8, (u8)) | ||
78 | #define WSM_PUT16(buf, val) __WSM_PUT(buf, val, u16, __cpu_to_le16) | ||
79 | #define WSM_PUT32(buf, val) __WSM_PUT(buf, val, u32, __cpu_to_le32) | ||
80 | |||
81 | static void wsm_buf_reset(struct wsm_buf *buf); | ||
82 | static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size); | ||
83 | |||
84 | static int wsm_cmd_send(struct cw1200_common *priv, | ||
85 | struct wsm_buf *buf, | ||
86 | void *arg, u16 cmd, long tmo); | ||
87 | |||
88 | #define wsm_cmd_lock(__priv) mutex_lock(&((__priv)->wsm_cmd_mux)) | ||
89 | #define wsm_cmd_unlock(__priv) mutex_unlock(&((__priv)->wsm_cmd_mux)) | ||
90 | |||
91 | /* ******************************************************************** */ | ||
92 | /* WSM API implementation */ | ||
93 | |||
94 | static int wsm_generic_confirm(struct cw1200_common *priv, | ||
95 | void *arg, | ||
96 | struct wsm_buf *buf) | ||
97 | { | ||
98 | u32 status = WSM_GET32(buf); | ||
99 | if (status != WSM_STATUS_SUCCESS) | ||
100 | return -EINVAL; | ||
101 | return 0; | ||
102 | |||
103 | underflow: | ||
104 | WARN_ON(1); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | int wsm_configuration(struct cw1200_common *priv, struct wsm_configuration *arg) | ||
109 | { | ||
110 | int ret; | ||
111 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
112 | |||
113 | wsm_cmd_lock(priv); | ||
114 | |||
115 | WSM_PUT32(buf, arg->dot11MaxTransmitMsduLifeTime); | ||
116 | WSM_PUT32(buf, arg->dot11MaxReceiveLifeTime); | ||
117 | WSM_PUT32(buf, arg->dot11RtsThreshold); | ||
118 | |||
119 | /* DPD block. */ | ||
120 | WSM_PUT16(buf, arg->dpdData_size + 12); | ||
121 | WSM_PUT16(buf, 1); /* DPD version */ | ||
122 | WSM_PUT(buf, arg->dot11StationId, ETH_ALEN); | ||
123 | WSM_PUT16(buf, 5); /* DPD flags */ | ||
124 | WSM_PUT(buf, arg->dpdData, arg->dpdData_size); | ||
125 | |||
126 | ret = wsm_cmd_send(priv, buf, arg, | ||
127 | WSM_CONFIGURATION_REQ_ID, WSM_CMD_TIMEOUT); | ||
128 | |||
129 | wsm_cmd_unlock(priv); | ||
130 | return ret; | ||
131 | |||
132 | nomem: | ||
133 | wsm_cmd_unlock(priv); | ||
134 | return -ENOMEM; | ||
135 | } | ||
136 | |||
137 | static int wsm_configuration_confirm(struct cw1200_common *priv, | ||
138 | struct wsm_configuration *arg, | ||
139 | struct wsm_buf *buf) | ||
140 | { | ||
141 | int i; | ||
142 | int status; | ||
143 | |||
144 | status = WSM_GET32(buf); | ||
145 | if (WARN_ON(status != WSM_STATUS_SUCCESS)) | ||
146 | return -EINVAL; | ||
147 | |||
148 | WSM_GET(buf, arg->dot11StationId, ETH_ALEN); | ||
149 | arg->dot11FrequencyBandsSupported = WSM_GET8(buf); | ||
150 | WSM_SKIP(buf, 1); | ||
151 | arg->supportedRateMask = WSM_GET32(buf); | ||
152 | for (i = 0; i < 2; ++i) { | ||
153 | arg->txPowerRange[i].min_power_level = WSM_GET32(buf); | ||
154 | arg->txPowerRange[i].max_power_level = WSM_GET32(buf); | ||
155 | arg->txPowerRange[i].stepping = WSM_GET32(buf); | ||
156 | } | ||
157 | return 0; | ||
158 | |||
159 | underflow: | ||
160 | WARN_ON(1); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | /* ******************************************************************** */ | ||
165 | |||
166 | int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg) | ||
167 | { | ||
168 | int ret; | ||
169 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
170 | u16 cmd = WSM_RESET_REQ_ID | WSM_TX_LINK_ID(arg->link_id); | ||
171 | |||
172 | wsm_cmd_lock(priv); | ||
173 | |||
174 | WSM_PUT32(buf, arg->reset_statistics ? 0 : 1); | ||
175 | ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_RESET_TIMEOUT); | ||
176 | wsm_cmd_unlock(priv); | ||
177 | return ret; | ||
178 | |||
179 | nomem: | ||
180 | wsm_cmd_unlock(priv); | ||
181 | return -ENOMEM; | ||
182 | } | ||
183 | |||
184 | /* ******************************************************************** */ | ||
185 | |||
186 | struct wsm_mib { | ||
187 | u16 mib_id; | ||
188 | void *buf; | ||
189 | size_t buf_size; | ||
190 | }; | ||
191 | |||
192 | int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, | ||
193 | size_t buf_size) | ||
194 | { | ||
195 | int ret; | ||
196 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
197 | struct wsm_mib mib_buf = { | ||
198 | .mib_id = mib_id, | ||
199 | .buf = _buf, | ||
200 | .buf_size = buf_size, | ||
201 | }; | ||
202 | wsm_cmd_lock(priv); | ||
203 | |||
204 | WSM_PUT16(buf, mib_id); | ||
205 | WSM_PUT16(buf, 0); | ||
206 | |||
207 | ret = wsm_cmd_send(priv, buf, &mib_buf, | ||
208 | WSM_READ_MIB_REQ_ID, WSM_CMD_TIMEOUT); | ||
209 | wsm_cmd_unlock(priv); | ||
210 | return ret; | ||
211 | |||
212 | nomem: | ||
213 | wsm_cmd_unlock(priv); | ||
214 | return -ENOMEM; | ||
215 | } | ||
216 | |||
217 | static int wsm_read_mib_confirm(struct cw1200_common *priv, | ||
218 | struct wsm_mib *arg, | ||
219 | struct wsm_buf *buf) | ||
220 | { | ||
221 | u16 size; | ||
222 | if (WARN_ON(WSM_GET32(buf) != WSM_STATUS_SUCCESS)) | ||
223 | return -EINVAL; | ||
224 | |||
225 | if (WARN_ON(WSM_GET16(buf) != arg->mib_id)) | ||
226 | return -EINVAL; | ||
227 | |||
228 | size = WSM_GET16(buf); | ||
229 | if (size > arg->buf_size) | ||
230 | size = arg->buf_size; | ||
231 | |||
232 | WSM_GET(buf, arg->buf, size); | ||
233 | arg->buf_size = size; | ||
234 | return 0; | ||
235 | |||
236 | underflow: | ||
237 | WARN_ON(1); | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | /* ******************************************************************** */ | ||
242 | |||
243 | int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *_buf, | ||
244 | size_t buf_size) | ||
245 | { | ||
246 | int ret; | ||
247 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
248 | struct wsm_mib mib_buf = { | ||
249 | .mib_id = mib_id, | ||
250 | .buf = _buf, | ||
251 | .buf_size = buf_size, | ||
252 | }; | ||
253 | |||
254 | wsm_cmd_lock(priv); | ||
255 | |||
256 | WSM_PUT16(buf, mib_id); | ||
257 | WSM_PUT16(buf, buf_size); | ||
258 | WSM_PUT(buf, _buf, buf_size); | ||
259 | |||
260 | ret = wsm_cmd_send(priv, buf, &mib_buf, | ||
261 | WSM_WRITE_MIB_REQ_ID, WSM_CMD_TIMEOUT); | ||
262 | wsm_cmd_unlock(priv); | ||
263 | return ret; | ||
264 | |||
265 | nomem: | ||
266 | wsm_cmd_unlock(priv); | ||
267 | return -ENOMEM; | ||
268 | } | ||
269 | |||
270 | static int wsm_write_mib_confirm(struct cw1200_common *priv, | ||
271 | struct wsm_mib *arg, | ||
272 | struct wsm_buf *buf) | ||
273 | { | ||
274 | int ret; | ||
275 | |||
276 | ret = wsm_generic_confirm(priv, arg, buf); | ||
277 | if (ret) | ||
278 | return ret; | ||
279 | |||
280 | if (arg->mib_id == WSM_MIB_ID_OPERATIONAL_POWER_MODE) { | ||
281 | /* OperationalMode: update PM status. */ | ||
282 | const char *p = arg->buf; | ||
283 | cw1200_enable_powersave(priv, (p[0] & 0x0F) ? true : false); | ||
284 | } | ||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* ******************************************************************** */ | ||
289 | |||
290 | int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg) | ||
291 | { | ||
292 | int i; | ||
293 | int ret; | ||
294 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
295 | |||
296 | if (arg->num_channels > 48) | ||
297 | return -EINVAL; | ||
298 | |||
299 | if (arg->num_ssids > 2) | ||
300 | return -EINVAL; | ||
301 | |||
302 | if (arg->band > 1) | ||
303 | return -EINVAL; | ||
304 | |||
305 | wsm_cmd_lock(priv); | ||
306 | |||
307 | WSM_PUT8(buf, arg->band); | ||
308 | WSM_PUT8(buf, arg->type); | ||
309 | WSM_PUT8(buf, arg->flags); | ||
310 | WSM_PUT8(buf, arg->max_tx_rate); | ||
311 | WSM_PUT32(buf, arg->auto_scan_interval); | ||
312 | WSM_PUT8(buf, arg->num_probes); | ||
313 | WSM_PUT8(buf, arg->num_channels); | ||
314 | WSM_PUT8(buf, arg->num_ssids); | ||
315 | WSM_PUT8(buf, arg->probe_delay); | ||
316 | |||
317 | for (i = 0; i < arg->num_channels; ++i) { | ||
318 | WSM_PUT16(buf, arg->ch[i].number); | ||
319 | WSM_PUT16(buf, 0); | ||
320 | WSM_PUT32(buf, arg->ch[i].min_chan_time); | ||
321 | WSM_PUT32(buf, arg->ch[i].max_chan_time); | ||
322 | WSM_PUT32(buf, 0); | ||
323 | } | ||
324 | |||
325 | for (i = 0; i < arg->num_ssids; ++i) { | ||
326 | WSM_PUT32(buf, arg->ssids[i].length); | ||
327 | WSM_PUT(buf, &arg->ssids[i].ssid[0], | ||
328 | sizeof(arg->ssids[i].ssid)); | ||
329 | } | ||
330 | |||
331 | ret = wsm_cmd_send(priv, buf, NULL, | ||
332 | WSM_START_SCAN_REQ_ID, WSM_CMD_TIMEOUT); | ||
333 | wsm_cmd_unlock(priv); | ||
334 | return ret; | ||
335 | |||
336 | nomem: | ||
337 | wsm_cmd_unlock(priv); | ||
338 | return -ENOMEM; | ||
339 | } | ||
340 | |||
341 | /* ******************************************************************** */ | ||
342 | |||
343 | int wsm_stop_scan(struct cw1200_common *priv) | ||
344 | { | ||
345 | int ret; | ||
346 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
347 | wsm_cmd_lock(priv); | ||
348 | ret = wsm_cmd_send(priv, buf, NULL, | ||
349 | WSM_STOP_SCAN_REQ_ID, WSM_CMD_TIMEOUT); | ||
350 | wsm_cmd_unlock(priv); | ||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | |||
355 | static int wsm_tx_confirm(struct cw1200_common *priv, | ||
356 | struct wsm_buf *buf, | ||
357 | int link_id) | ||
358 | { | ||
359 | struct wsm_tx_confirm tx_confirm; | ||
360 | |||
361 | tx_confirm.packet_id = WSM_GET32(buf); | ||
362 | tx_confirm.status = WSM_GET32(buf); | ||
363 | tx_confirm.tx_rate = WSM_GET8(buf); | ||
364 | tx_confirm.ack_failures = WSM_GET8(buf); | ||
365 | tx_confirm.flags = WSM_GET16(buf); | ||
366 | tx_confirm.media_delay = WSM_GET32(buf); | ||
367 | tx_confirm.tx_queue_delay = WSM_GET32(buf); | ||
368 | |||
369 | cw1200_tx_confirm_cb(priv, link_id, &tx_confirm); | ||
370 | return 0; | ||
371 | |||
372 | underflow: | ||
373 | WARN_ON(1); | ||
374 | return -EINVAL; | ||
375 | } | ||
376 | |||
377 | static int wsm_multi_tx_confirm(struct cw1200_common *priv, | ||
378 | struct wsm_buf *buf, int link_id) | ||
379 | { | ||
380 | int ret; | ||
381 | int count; | ||
382 | int i; | ||
383 | |||
384 | count = WSM_GET32(buf); | ||
385 | if (WARN_ON(count <= 0)) | ||
386 | return -EINVAL; | ||
387 | |||
388 | if (count > 1) { | ||
389 | /* We already released one buffer, now for the rest */ | ||
390 | ret = wsm_release_tx_buffer(priv, count - 1); | ||
391 | if (ret < 0) | ||
392 | return ret; | ||
393 | else if (ret > 0) | ||
394 | cw1200_bh_wakeup(priv); | ||
395 | } | ||
396 | |||
397 | cw1200_debug_txed_multi(priv, count); | ||
398 | for (i = 0; i < count; ++i) { | ||
399 | ret = wsm_tx_confirm(priv, buf, link_id); | ||
400 | if (ret) | ||
401 | return ret; | ||
402 | } | ||
403 | return ret; | ||
404 | |||
405 | underflow: | ||
406 | WARN_ON(1); | ||
407 | return -EINVAL; | ||
408 | } | ||
409 | |||
410 | /* ******************************************************************** */ | ||
411 | |||
412 | static int wsm_join_confirm(struct cw1200_common *priv, | ||
413 | struct wsm_join_cnf *arg, | ||
414 | struct wsm_buf *buf) | ||
415 | { | ||
416 | arg->status = WSM_GET32(buf); | ||
417 | if (WARN_ON(arg->status) != WSM_STATUS_SUCCESS) | ||
418 | return -EINVAL; | ||
419 | |||
420 | arg->min_power_level = WSM_GET32(buf); | ||
421 | arg->max_power_level = WSM_GET32(buf); | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | underflow: | ||
426 | WARN_ON(1); | ||
427 | return -EINVAL; | ||
428 | } | ||
429 | |||
430 | int wsm_join(struct cw1200_common *priv, struct wsm_join *arg) | ||
431 | { | ||
432 | int ret; | ||
433 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
434 | struct wsm_join_cnf resp; | ||
435 | wsm_cmd_lock(priv); | ||
436 | |||
437 | WSM_PUT8(buf, arg->mode); | ||
438 | WSM_PUT8(buf, arg->band); | ||
439 | WSM_PUT16(buf, arg->channel_number); | ||
440 | WSM_PUT(buf, &arg->bssid[0], sizeof(arg->bssid)); | ||
441 | WSM_PUT16(buf, arg->atim_window); | ||
442 | WSM_PUT8(buf, arg->preamble_type); | ||
443 | WSM_PUT8(buf, arg->probe_for_join); | ||
444 | WSM_PUT8(buf, arg->dtim_period); | ||
445 | WSM_PUT8(buf, arg->flags); | ||
446 | WSM_PUT32(buf, arg->ssid_len); | ||
447 | WSM_PUT(buf, &arg->ssid[0], sizeof(arg->ssid)); | ||
448 | WSM_PUT32(buf, arg->beacon_interval); | ||
449 | WSM_PUT32(buf, arg->basic_rate_set); | ||
450 | |||
451 | priv->tx_burst_idx = -1; | ||
452 | ret = wsm_cmd_send(priv, buf, &resp, | ||
453 | WSM_JOIN_REQ_ID, WSM_CMD_TIMEOUT); | ||
454 | /* TODO: Update state based on resp.min|max_power_level */ | ||
455 | |||
456 | priv->join_complete_status = resp.status; | ||
457 | |||
458 | wsm_cmd_unlock(priv); | ||
459 | return ret; | ||
460 | |||
461 | nomem: | ||
462 | wsm_cmd_unlock(priv); | ||
463 | return -ENOMEM; | ||
464 | } | ||
465 | |||
466 | /* ******************************************************************** */ | ||
467 | |||
468 | int wsm_set_bss_params(struct cw1200_common *priv, | ||
469 | const struct wsm_set_bss_params *arg) | ||
470 | { | ||
471 | int ret; | ||
472 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
473 | |||
474 | wsm_cmd_lock(priv); | ||
475 | |||
476 | WSM_PUT8(buf, (arg->reset_beacon_loss ? 0x1 : 0)); | ||
477 | WSM_PUT8(buf, arg->beacon_lost_count); | ||
478 | WSM_PUT16(buf, arg->aid); | ||
479 | WSM_PUT32(buf, arg->operational_rate_set); | ||
480 | |||
481 | ret = wsm_cmd_send(priv, buf, NULL, | ||
482 | WSM_SET_BSS_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); | ||
483 | |||
484 | wsm_cmd_unlock(priv); | ||
485 | return ret; | ||
486 | |||
487 | nomem: | ||
488 | wsm_cmd_unlock(priv); | ||
489 | return -ENOMEM; | ||
490 | } | ||
491 | |||
492 | /* ******************************************************************** */ | ||
493 | |||
494 | int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg) | ||
495 | { | ||
496 | int ret; | ||
497 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
498 | |||
499 | wsm_cmd_lock(priv); | ||
500 | |||
501 | WSM_PUT(buf, arg, sizeof(*arg)); | ||
502 | |||
503 | ret = wsm_cmd_send(priv, buf, NULL, | ||
504 | WSM_ADD_KEY_REQ_ID, WSM_CMD_TIMEOUT); | ||
505 | |||
506 | wsm_cmd_unlock(priv); | ||
507 | return ret; | ||
508 | |||
509 | nomem: | ||
510 | wsm_cmd_unlock(priv); | ||
511 | return -ENOMEM; | ||
512 | } | ||
513 | |||
514 | /* ******************************************************************** */ | ||
515 | |||
516 | int wsm_remove_key(struct cw1200_common *priv, const struct wsm_remove_key *arg) | ||
517 | { | ||
518 | int ret; | ||
519 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
520 | |||
521 | wsm_cmd_lock(priv); | ||
522 | |||
523 | WSM_PUT8(buf, arg->index); | ||
524 | WSM_PUT8(buf, 0); | ||
525 | WSM_PUT16(buf, 0); | ||
526 | |||
527 | ret = wsm_cmd_send(priv, buf, NULL, | ||
528 | WSM_REMOVE_KEY_REQ_ID, WSM_CMD_TIMEOUT); | ||
529 | |||
530 | wsm_cmd_unlock(priv); | ||
531 | return ret; | ||
532 | |||
533 | nomem: | ||
534 | wsm_cmd_unlock(priv); | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | |||
538 | /* ******************************************************************** */ | ||
539 | |||
540 | int wsm_set_tx_queue_params(struct cw1200_common *priv, | ||
541 | const struct wsm_set_tx_queue_params *arg, u8 id) | ||
542 | { | ||
543 | int ret; | ||
544 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
545 | u8 queue_id_to_wmm_aci[] = {3, 2, 0, 1}; | ||
546 | |||
547 | wsm_cmd_lock(priv); | ||
548 | |||
549 | WSM_PUT8(buf, queue_id_to_wmm_aci[id]); | ||
550 | WSM_PUT8(buf, 0); | ||
551 | WSM_PUT8(buf, arg->ackPolicy); | ||
552 | WSM_PUT8(buf, 0); | ||
553 | WSM_PUT32(buf, arg->maxTransmitLifetime); | ||
554 | WSM_PUT16(buf, arg->allowedMediumTime); | ||
555 | WSM_PUT16(buf, 0); | ||
556 | |||
557 | ret = wsm_cmd_send(priv, buf, NULL, 0x0012, WSM_CMD_TIMEOUT); | ||
558 | |||
559 | wsm_cmd_unlock(priv); | ||
560 | return ret; | ||
561 | |||
562 | nomem: | ||
563 | wsm_cmd_unlock(priv); | ||
564 | return -ENOMEM; | ||
565 | } | ||
566 | |||
567 | /* ******************************************************************** */ | ||
568 | |||
569 | int wsm_set_edca_params(struct cw1200_common *priv, | ||
570 | const struct wsm_edca_params *arg) | ||
571 | { | ||
572 | int ret; | ||
573 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
574 | |||
575 | wsm_cmd_lock(priv); | ||
576 | |||
577 | /* Implemented according to specification. */ | ||
578 | |||
579 | WSM_PUT16(buf, arg->params[3].cwmin); | ||
580 | WSM_PUT16(buf, arg->params[2].cwmin); | ||
581 | WSM_PUT16(buf, arg->params[1].cwmin); | ||
582 | WSM_PUT16(buf, arg->params[0].cwmin); | ||
583 | |||
584 | WSM_PUT16(buf, arg->params[3].cwmax); | ||
585 | WSM_PUT16(buf, arg->params[2].cwmax); | ||
586 | WSM_PUT16(buf, arg->params[1].cwmax); | ||
587 | WSM_PUT16(buf, arg->params[0].cwmax); | ||
588 | |||
589 | WSM_PUT8(buf, arg->params[3].aifns); | ||
590 | WSM_PUT8(buf, arg->params[2].aifns); | ||
591 | WSM_PUT8(buf, arg->params[1].aifns); | ||
592 | WSM_PUT8(buf, arg->params[0].aifns); | ||
593 | |||
594 | WSM_PUT16(buf, arg->params[3].txop_limit); | ||
595 | WSM_PUT16(buf, arg->params[2].txop_limit); | ||
596 | WSM_PUT16(buf, arg->params[1].txop_limit); | ||
597 | WSM_PUT16(buf, arg->params[0].txop_limit); | ||
598 | |||
599 | WSM_PUT32(buf, arg->params[3].max_rx_lifetime); | ||
600 | WSM_PUT32(buf, arg->params[2].max_rx_lifetime); | ||
601 | WSM_PUT32(buf, arg->params[1].max_rx_lifetime); | ||
602 | WSM_PUT32(buf, arg->params[0].max_rx_lifetime); | ||
603 | |||
604 | ret = wsm_cmd_send(priv, buf, NULL, | ||
605 | WSM_EDCA_PARAMS_REQ_ID, WSM_CMD_TIMEOUT); | ||
606 | wsm_cmd_unlock(priv); | ||
607 | return ret; | ||
608 | |||
609 | nomem: | ||
610 | wsm_cmd_unlock(priv); | ||
611 | return -ENOMEM; | ||
612 | } | ||
613 | |||
614 | /* ******************************************************************** */ | ||
615 | |||
616 | int wsm_switch_channel(struct cw1200_common *priv, | ||
617 | const struct wsm_switch_channel *arg) | ||
618 | { | ||
619 | int ret; | ||
620 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
621 | |||
622 | wsm_cmd_lock(priv); | ||
623 | |||
624 | WSM_PUT8(buf, arg->mode); | ||
625 | WSM_PUT8(buf, arg->switch_count); | ||
626 | WSM_PUT16(buf, arg->channel_number); | ||
627 | |||
628 | priv->channel_switch_in_progress = 1; | ||
629 | |||
630 | ret = wsm_cmd_send(priv, buf, NULL, | ||
631 | WSM_SWITCH_CHANNEL_REQ_ID, WSM_CMD_TIMEOUT); | ||
632 | if (ret) | ||
633 | priv->channel_switch_in_progress = 0; | ||
634 | |||
635 | wsm_cmd_unlock(priv); | ||
636 | return ret; | ||
637 | |||
638 | nomem: | ||
639 | wsm_cmd_unlock(priv); | ||
640 | return -ENOMEM; | ||
641 | } | ||
642 | |||
643 | /* ******************************************************************** */ | ||
644 | |||
645 | int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg) | ||
646 | { | ||
647 | int ret; | ||
648 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
649 | priv->ps_mode_switch_in_progress = 1; | ||
650 | |||
651 | wsm_cmd_lock(priv); | ||
652 | |||
653 | WSM_PUT8(buf, arg->mode); | ||
654 | WSM_PUT8(buf, arg->fast_psm_idle_period); | ||
655 | WSM_PUT8(buf, arg->ap_psm_change_period); | ||
656 | WSM_PUT8(buf, arg->min_auto_pspoll_period); | ||
657 | |||
658 | ret = wsm_cmd_send(priv, buf, NULL, | ||
659 | WSM_SET_PM_REQ_ID, WSM_CMD_TIMEOUT); | ||
660 | |||
661 | wsm_cmd_unlock(priv); | ||
662 | return ret; | ||
663 | |||
664 | nomem: | ||
665 | wsm_cmd_unlock(priv); | ||
666 | return -ENOMEM; | ||
667 | } | ||
668 | |||
669 | /* ******************************************************************** */ | ||
670 | |||
671 | int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg) | ||
672 | { | ||
673 | int ret; | ||
674 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
675 | |||
676 | wsm_cmd_lock(priv); | ||
677 | |||
678 | WSM_PUT8(buf, arg->mode); | ||
679 | WSM_PUT8(buf, arg->band); | ||
680 | WSM_PUT16(buf, arg->channel_number); | ||
681 | WSM_PUT32(buf, arg->ct_window); | ||
682 | WSM_PUT32(buf, arg->beacon_interval); | ||
683 | WSM_PUT8(buf, arg->dtim_period); | ||
684 | WSM_PUT8(buf, arg->preamble); | ||
685 | WSM_PUT8(buf, arg->probe_delay); | ||
686 | WSM_PUT8(buf, arg->ssid_len); | ||
687 | WSM_PUT(buf, arg->ssid, sizeof(arg->ssid)); | ||
688 | WSM_PUT32(buf, arg->basic_rate_set); | ||
689 | |||
690 | priv->tx_burst_idx = -1; | ||
691 | ret = wsm_cmd_send(priv, buf, NULL, | ||
692 | WSM_START_REQ_ID, WSM_CMD_START_TIMEOUT); | ||
693 | |||
694 | wsm_cmd_unlock(priv); | ||
695 | return ret; | ||
696 | |||
697 | nomem: | ||
698 | wsm_cmd_unlock(priv); | ||
699 | return -ENOMEM; | ||
700 | } | ||
701 | |||
702 | /* ******************************************************************** */ | ||
703 | |||
704 | int wsm_beacon_transmit(struct cw1200_common *priv, | ||
705 | const struct wsm_beacon_transmit *arg) | ||
706 | { | ||
707 | int ret; | ||
708 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
709 | |||
710 | wsm_cmd_lock(priv); | ||
711 | |||
712 | WSM_PUT32(buf, arg->enable_beaconing ? 1 : 0); | ||
713 | |||
714 | ret = wsm_cmd_send(priv, buf, NULL, | ||
715 | WSM_BEACON_TRANSMIT_REQ_ID, WSM_CMD_TIMEOUT); | ||
716 | |||
717 | wsm_cmd_unlock(priv); | ||
718 | return ret; | ||
719 | |||
720 | nomem: | ||
721 | wsm_cmd_unlock(priv); | ||
722 | return -ENOMEM; | ||
723 | } | ||
724 | |||
725 | /* ******************************************************************** */ | ||
726 | |||
727 | int wsm_start_find(struct cw1200_common *priv) | ||
728 | { | ||
729 | int ret; | ||
730 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
731 | |||
732 | wsm_cmd_lock(priv); | ||
733 | ret = wsm_cmd_send(priv, buf, NULL, 0x0019, WSM_CMD_TIMEOUT); | ||
734 | wsm_cmd_unlock(priv); | ||
735 | return ret; | ||
736 | } | ||
737 | |||
738 | /* ******************************************************************** */ | ||
739 | |||
740 | int wsm_stop_find(struct cw1200_common *priv) | ||
741 | { | ||
742 | int ret; | ||
743 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
744 | |||
745 | wsm_cmd_lock(priv); | ||
746 | ret = wsm_cmd_send(priv, buf, NULL, 0x001A, WSM_CMD_TIMEOUT); | ||
747 | wsm_cmd_unlock(priv); | ||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | /* ******************************************************************** */ | ||
752 | |||
753 | int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg) | ||
754 | { | ||
755 | int ret; | ||
756 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
757 | u16 cmd = 0x001C | WSM_TX_LINK_ID(arg->link_id); | ||
758 | |||
759 | wsm_cmd_lock(priv); | ||
760 | |||
761 | WSM_PUT(buf, &arg->mac_addr[0], sizeof(arg->mac_addr)); | ||
762 | WSM_PUT16(buf, 0); | ||
763 | |||
764 | ret = wsm_cmd_send(priv, buf, NULL, cmd, WSM_CMD_TIMEOUT); | ||
765 | |||
766 | wsm_cmd_unlock(priv); | ||
767 | return ret; | ||
768 | |||
769 | nomem: | ||
770 | wsm_cmd_unlock(priv); | ||
771 | return -ENOMEM; | ||
772 | } | ||
773 | |||
774 | /* ******************************************************************** */ | ||
775 | |||
776 | int wsm_update_ie(struct cw1200_common *priv, | ||
777 | const struct wsm_update_ie *arg) | ||
778 | { | ||
779 | int ret; | ||
780 | struct wsm_buf *buf = &priv->wsm_cmd_buf; | ||
781 | |||
782 | wsm_cmd_lock(priv); | ||
783 | |||
784 | WSM_PUT16(buf, arg->what); | ||
785 | WSM_PUT16(buf, arg->count); | ||
786 | WSM_PUT(buf, arg->ies, arg->length); | ||
787 | |||
788 | ret = wsm_cmd_send(priv, buf, NULL, 0x001B, WSM_CMD_TIMEOUT); | ||
789 | |||
790 | wsm_cmd_unlock(priv); | ||
791 | return ret; | ||
792 | |||
793 | nomem: | ||
794 | wsm_cmd_unlock(priv); | ||
795 | return -ENOMEM; | ||
796 | } | ||
797 | |||
798 | /* ******************************************************************** */ | ||
799 | int wsm_set_probe_responder(struct cw1200_common *priv, bool enable) | ||
800 | { | ||
801 | priv->rx_filter.probeResponder = enable; | ||
802 | return wsm_set_rx_filter(priv, &priv->rx_filter); | ||
803 | } | ||
804 | |||
805 | /* ******************************************************************** */ | ||
806 | /* WSM indication events implementation */ | ||
807 | const char * const cw1200_fw_types[] = { | ||
808 | "ETF", | ||
809 | "WFM", | ||
810 | "WSM", | ||
811 | "HI test", | ||
812 | "Platform test" | ||
813 | }; | ||
814 | |||
815 | static int wsm_startup_indication(struct cw1200_common *priv, | ||
816 | struct wsm_buf *buf) | ||
817 | { | ||
818 | priv->wsm_caps.input_buffers = WSM_GET16(buf); | ||
819 | priv->wsm_caps.input_buffer_size = WSM_GET16(buf); | ||
820 | priv->wsm_caps.hw_id = WSM_GET16(buf); | ||
821 | priv->wsm_caps.hw_subid = WSM_GET16(buf); | ||
822 | priv->wsm_caps.status = WSM_GET16(buf); | ||
823 | priv->wsm_caps.fw_cap = WSM_GET16(buf); | ||
824 | priv->wsm_caps.fw_type = WSM_GET16(buf); | ||
825 | priv->wsm_caps.fw_api = WSM_GET16(buf); | ||
826 | priv->wsm_caps.fw_build = WSM_GET16(buf); | ||
827 | priv->wsm_caps.fw_ver = WSM_GET16(buf); | ||
828 | WSM_GET(buf, priv->wsm_caps.fw_label, sizeof(priv->wsm_caps.fw_label)); | ||
829 | priv->wsm_caps.fw_label[sizeof(priv->wsm_caps.fw_label) - 1] = 0; /* Do not trust FW too much... */ | ||
830 | |||
831 | if (WARN_ON(priv->wsm_caps.status)) | ||
832 | return -EINVAL; | ||
833 | |||
834 | if (WARN_ON(priv->wsm_caps.fw_type > 4)) | ||
835 | return -EINVAL; | ||
836 | |||
837 | pr_info("CW1200 WSM init done.\n" | ||
838 | " Input buffers: %d x %d bytes\n" | ||
839 | " Hardware: %d.%d\n" | ||
840 | " %s firmware [%s], ver: %d, build: %d," | ||
841 | " api: %d, cap: 0x%.4X\n", | ||
842 | priv->wsm_caps.input_buffers, | ||
843 | priv->wsm_caps.input_buffer_size, | ||
844 | priv->wsm_caps.hw_id, priv->wsm_caps.hw_subid, | ||
845 | cw1200_fw_types[priv->wsm_caps.fw_type], | ||
846 | priv->wsm_caps.fw_label, priv->wsm_caps.fw_ver, | ||
847 | priv->wsm_caps.fw_build, | ||
848 | priv->wsm_caps.fw_api, priv->wsm_caps.fw_cap); | ||
849 | |||
850 | /* Disable unsupported frequency bands */ | ||
851 | if (!(priv->wsm_caps.fw_cap & 0x1)) | ||
852 | priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; | ||
853 | if (!(priv->wsm_caps.fw_cap & 0x2)) | ||
854 | priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; | ||
855 | |||
856 | priv->firmware_ready = 1; | ||
857 | wake_up(&priv->wsm_startup_done); | ||
858 | return 0; | ||
859 | |||
860 | underflow: | ||
861 | WARN_ON(1); | ||
862 | return -EINVAL; | ||
863 | } | ||
864 | |||
865 | static int wsm_receive_indication(struct cw1200_common *priv, | ||
866 | int link_id, | ||
867 | struct wsm_buf *buf, | ||
868 | struct sk_buff **skb_p) | ||
869 | { | ||
870 | struct wsm_rx rx; | ||
871 | struct ieee80211_hdr *hdr; | ||
872 | size_t hdr_len; | ||
873 | __le16 fctl; | ||
874 | |||
875 | rx.status = WSM_GET32(buf); | ||
876 | rx.channel_number = WSM_GET16(buf); | ||
877 | rx.rx_rate = WSM_GET8(buf); | ||
878 | rx.rcpi_rssi = WSM_GET8(buf); | ||
879 | rx.flags = WSM_GET32(buf); | ||
880 | |||
881 | /* FW Workaround: Drop probe resp or | ||
882 | beacon when RSSI is 0 | ||
883 | */ | ||
884 | hdr = (struct ieee80211_hdr *)(*skb_p)->data; | ||
885 | |||
886 | if (!rx.rcpi_rssi && | ||
887 | (ieee80211_is_probe_resp(hdr->frame_control) || | ||
888 | ieee80211_is_beacon(hdr->frame_control))) | ||
889 | return 0; | ||
890 | |||
891 | /* If no RSSI subscription has been made, | ||
892 | * convert RCPI to RSSI here | ||
893 | */ | ||
894 | if (!priv->cqm_use_rssi) | ||
895 | rx.rcpi_rssi = rx.rcpi_rssi / 2 - 110; | ||
896 | |||
897 | fctl = *(__le16 *)buf->data; | ||
898 | hdr_len = buf->data - buf->begin; | ||
899 | skb_pull(*skb_p, hdr_len); | ||
900 | if (!rx.status && ieee80211_is_deauth(fctl)) { | ||
901 | if (priv->join_status == CW1200_JOIN_STATUS_STA) { | ||
902 | /* Shedule unjoin work */ | ||
903 | pr_debug("[WSM] Issue unjoin command (RX).\n"); | ||
904 | wsm_lock_tx_async(priv); | ||
905 | if (queue_work(priv->workqueue, | ||
906 | &priv->unjoin_work) <= 0) | ||
907 | wsm_unlock_tx(priv); | ||
908 | } | ||
909 | } | ||
910 | cw1200_rx_cb(priv, &rx, link_id, skb_p); | ||
911 | if (*skb_p) | ||
912 | skb_push(*skb_p, hdr_len); | ||
913 | |||
914 | return 0; | ||
915 | |||
916 | underflow: | ||
917 | return -EINVAL; | ||
918 | } | ||
919 | |||
920 | static int wsm_event_indication(struct cw1200_common *priv, struct wsm_buf *buf) | ||
921 | { | ||
922 | int first; | ||
923 | struct cw1200_wsm_event *event; | ||
924 | |||
925 | if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) { | ||
926 | /* STA is stopped. */ | ||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | event = kzalloc(sizeof(struct cw1200_wsm_event), GFP_KERNEL); | ||
931 | if (!event) | ||
932 | return -ENOMEM; | ||
933 | |||
934 | event->evt.id = __le32_to_cpu(WSM_GET32(buf)); | ||
935 | event->evt.data = __le32_to_cpu(WSM_GET32(buf)); | ||
936 | |||
937 | pr_debug("[WSM] Event: %d(%d)\n", | ||
938 | event->evt.id, event->evt.data); | ||
939 | |||
940 | spin_lock(&priv->event_queue_lock); | ||
941 | first = list_empty(&priv->event_queue); | ||
942 | list_add_tail(&event->link, &priv->event_queue); | ||
943 | spin_unlock(&priv->event_queue_lock); | ||
944 | |||
945 | if (first) | ||
946 | queue_work(priv->workqueue, &priv->event_handler); | ||
947 | |||
948 | return 0; | ||
949 | |||
950 | underflow: | ||
951 | kfree(event); | ||
952 | return -EINVAL; | ||
953 | } | ||
954 | |||
955 | static int wsm_channel_switch_indication(struct cw1200_common *priv, | ||
956 | struct wsm_buf *buf) | ||
957 | { | ||
958 | WARN_ON(WSM_GET32(buf)); | ||
959 | |||
960 | priv->channel_switch_in_progress = 0; | ||
961 | wake_up(&priv->channel_switch_done); | ||
962 | |||
963 | wsm_unlock_tx(priv); | ||
964 | |||
965 | return 0; | ||
966 | |||
967 | underflow: | ||
968 | return -EINVAL; | ||
969 | } | ||
970 | |||
971 | static int wsm_set_pm_indication(struct cw1200_common *priv, | ||
972 | struct wsm_buf *buf) | ||
973 | { | ||
974 | /* TODO: Check buf (struct wsm_set_pm_complete) for validity */ | ||
975 | if (priv->ps_mode_switch_in_progress) { | ||
976 | priv->ps_mode_switch_in_progress = 0; | ||
977 | wake_up(&priv->ps_mode_switch_done); | ||
978 | } | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int wsm_scan_started(struct cw1200_common *priv, void *arg, | ||
983 | struct wsm_buf *buf) | ||
984 | { | ||
985 | u32 status = WSM_GET32(buf); | ||
986 | if (status != WSM_STATUS_SUCCESS) { | ||
987 | cw1200_scan_failed_cb(priv); | ||
988 | return -EINVAL; | ||
989 | } | ||
990 | return 0; | ||
991 | |||
992 | underflow: | ||
993 | WARN_ON(1); | ||
994 | return -EINVAL; | ||
995 | } | ||
996 | |||
997 | static int wsm_scan_complete_indication(struct cw1200_common *priv, | ||
998 | struct wsm_buf *buf) | ||
999 | { | ||
1000 | struct wsm_scan_complete arg; | ||
1001 | arg.status = WSM_GET32(buf); | ||
1002 | arg.psm = WSM_GET8(buf); | ||
1003 | arg.num_channels = WSM_GET8(buf); | ||
1004 | cw1200_scan_complete_cb(priv, &arg); | ||
1005 | |||
1006 | return 0; | ||
1007 | |||
1008 | underflow: | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | static int wsm_join_complete_indication(struct cw1200_common *priv, | ||
1013 | struct wsm_buf *buf) | ||
1014 | { | ||
1015 | struct wsm_join_complete arg; | ||
1016 | arg.status = WSM_GET32(buf); | ||
1017 | pr_debug("[WSM] Join complete indication, status: %d\n", arg.status); | ||
1018 | cw1200_join_complete_cb(priv, &arg); | ||
1019 | |||
1020 | return 0; | ||
1021 | |||
1022 | underflow: | ||
1023 | return -EINVAL; | ||
1024 | } | ||
1025 | |||
1026 | static int wsm_find_complete_indication(struct cw1200_common *priv, | ||
1027 | struct wsm_buf *buf) | ||
1028 | { | ||
1029 | pr_warn("Implement find_complete_indication\n"); | ||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int wsm_ba_timeout_indication(struct cw1200_common *priv, | ||
1034 | struct wsm_buf *buf) | ||
1035 | { | ||
1036 | u32 dummy; | ||
1037 | u8 tid; | ||
1038 | u8 dummy2; | ||
1039 | u8 addr[ETH_ALEN]; | ||
1040 | |||
1041 | dummy = WSM_GET32(buf); | ||
1042 | tid = WSM_GET8(buf); | ||
1043 | dummy2 = WSM_GET8(buf); | ||
1044 | WSM_GET(buf, addr, ETH_ALEN); | ||
1045 | |||
1046 | pr_info("BlockACK timeout, tid %d, addr %pM\n", | ||
1047 | tid, addr); | ||
1048 | |||
1049 | return 0; | ||
1050 | |||
1051 | underflow: | ||
1052 | return -EINVAL; | ||
1053 | } | ||
1054 | |||
1055 | static int wsm_suspend_resume_indication(struct cw1200_common *priv, | ||
1056 | int link_id, struct wsm_buf *buf) | ||
1057 | { | ||
1058 | u32 flags; | ||
1059 | struct wsm_suspend_resume arg; | ||
1060 | |||
1061 | flags = WSM_GET32(buf); | ||
1062 | arg.link_id = link_id; | ||
1063 | arg.stop = !(flags & 1); | ||
1064 | arg.multicast = !!(flags & 8); | ||
1065 | arg.queue = (flags >> 1) & 3; | ||
1066 | |||
1067 | cw1200_suspend_resume(priv, &arg); | ||
1068 | |||
1069 | return 0; | ||
1070 | |||
1071 | underflow: | ||
1072 | return -EINVAL; | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | /* ******************************************************************** */ | ||
1077 | /* WSM TX */ | ||
1078 | |||
1079 | static int wsm_cmd_send(struct cw1200_common *priv, | ||
1080 | struct wsm_buf *buf, | ||
1081 | void *arg, u16 cmd, long tmo) | ||
1082 | { | ||
1083 | size_t buf_len = buf->data - buf->begin; | ||
1084 | int ret; | ||
1085 | |||
1086 | /* Don't bother if we're dead. */ | ||
1087 | if (priv->bh_error) { | ||
1088 | ret = 0; | ||
1089 | goto done; | ||
1090 | } | ||
1091 | |||
1092 | /* Block until the cmd buffer is completed. Tortuous. */ | ||
1093 | spin_lock(&priv->wsm_cmd.lock); | ||
1094 | while (!priv->wsm_cmd.done) { | ||
1095 | spin_unlock(&priv->wsm_cmd.lock); | ||
1096 | spin_lock(&priv->wsm_cmd.lock); | ||
1097 | } | ||
1098 | priv->wsm_cmd.done = 0; | ||
1099 | spin_unlock(&priv->wsm_cmd.lock); | ||
1100 | |||
1101 | if (cmd == WSM_WRITE_MIB_REQ_ID || | ||
1102 | cmd == WSM_READ_MIB_REQ_ID) | ||
1103 | pr_debug("[WSM] >>> 0x%.4X [MIB: 0x%.4X] (%zu)\n", | ||
1104 | cmd, __le16_to_cpu(((__le16 *)buf->begin)[2]), | ||
1105 | buf_len); | ||
1106 | else | ||
1107 | pr_debug("[WSM] >>> 0x%.4X (%zu)\n", cmd, buf_len); | ||
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 | buf_len += 4; | ||
1114 | |||
1115 | /* Fill HI message header */ | ||
1116 | /* BH will add sequence number */ | ||
1117 | ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); | ||
1118 | ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd); | ||
1119 | |||
1120 | spin_lock(&priv->wsm_cmd.lock); | ||
1121 | BUG_ON(priv->wsm_cmd.ptr); | ||
1122 | priv->wsm_cmd.ptr = buf->begin; | ||
1123 | priv->wsm_cmd.len = buf_len; | ||
1124 | priv->wsm_cmd.arg = arg; | ||
1125 | priv->wsm_cmd.cmd = cmd; | ||
1126 | spin_unlock(&priv->wsm_cmd.lock); | ||
1127 | |||
1128 | cw1200_bh_wakeup(priv); | ||
1129 | |||
1130 | /* Wait for command completion */ | ||
1131 | ret = wait_event_timeout(priv->wsm_cmd_wq, | ||
1132 | priv->wsm_cmd.done, tmo); | ||
1133 | |||
1134 | if (!ret && !priv->wsm_cmd.done) { | ||
1135 | spin_lock(&priv->wsm_cmd.lock); | ||
1136 | priv->wsm_cmd.done = 1; | ||
1137 | priv->wsm_cmd.ptr = NULL; | ||
1138 | spin_unlock(&priv->wsm_cmd.lock); | ||
1139 | if (priv->bh_error) { | ||
1140 | /* Return ok to help system cleanup */ | ||
1141 | ret = 0; | ||
1142 | } else { | ||
1143 | pr_err("CMD req (0x%04x) stuck in firmware, killing BH\n", priv->wsm_cmd.cmd); | ||
1144 | print_hex_dump_bytes("REQDUMP: ", DUMP_PREFIX_NONE, | ||
1145 | buf->begin, buf_len); | ||
1146 | pr_err("Outstanding outgoing frames: %d\n", priv->hw_bufs_used); | ||
1147 | |||
1148 | /* Kill BH thread to report the error to the top layer. */ | ||
1149 | atomic_add(1, &priv->bh_term); | ||
1150 | wake_up(&priv->bh_wq); | ||
1151 | ret = -ETIMEDOUT; | ||
1152 | } | ||
1153 | } else { | ||
1154 | spin_lock(&priv->wsm_cmd.lock); | ||
1155 | BUG_ON(!priv->wsm_cmd.done); | ||
1156 | ret = priv->wsm_cmd.ret; | ||
1157 | spin_unlock(&priv->wsm_cmd.lock); | ||
1158 | } | ||
1159 | done: | ||
1160 | wsm_buf_reset(buf); | ||
1161 | return ret; | ||
1162 | } | ||
1163 | |||
1164 | /* ******************************************************************** */ | ||
1165 | /* WSM TX port control */ | ||
1166 | |||
1167 | void wsm_lock_tx(struct cw1200_common *priv) | ||
1168 | { | ||
1169 | wsm_cmd_lock(priv); | ||
1170 | if (atomic_add_return(1, &priv->tx_lock) == 1) { | ||
1171 | if (wsm_flush_tx(priv)) | ||
1172 | pr_debug("[WSM] TX is locked.\n"); | ||
1173 | } | ||
1174 | wsm_cmd_unlock(priv); | ||
1175 | } | ||
1176 | |||
1177 | void wsm_lock_tx_async(struct cw1200_common *priv) | ||
1178 | { | ||
1179 | if (atomic_add_return(1, &priv->tx_lock) == 1) | ||
1180 | pr_debug("[WSM] TX is locked (async).\n"); | ||
1181 | } | ||
1182 | |||
1183 | bool wsm_flush_tx(struct cw1200_common *priv) | ||
1184 | { | ||
1185 | unsigned long timestamp = jiffies; | ||
1186 | bool pending = false; | ||
1187 | long timeout; | ||
1188 | int i; | ||
1189 | |||
1190 | /* Flush must be called with TX lock held. */ | ||
1191 | BUG_ON(!atomic_read(&priv->tx_lock)); | ||
1192 | |||
1193 | /* First check if we really need to do something. | ||
1194 | * It is safe to use unprotected access, as hw_bufs_used | ||
1195 | * can only decrements. | ||
1196 | */ | ||
1197 | if (!priv->hw_bufs_used) | ||
1198 | return true; | ||
1199 | |||
1200 | if (priv->bh_error) { | ||
1201 | /* In case of failure do not wait for magic. */ | ||
1202 | pr_err("[WSM] Fatal error occured, will not flush TX.\n"); | ||
1203 | return false; | ||
1204 | } else { | ||
1205 | /* Get a timestamp of "oldest" frame */ | ||
1206 | for (i = 0; i < 4; ++i) | ||
1207 | pending |= cw1200_queue_get_xmit_timestamp( | ||
1208 | &priv->tx_queue[i], | ||
1209 | ×tamp, 0xffffffff); | ||
1210 | /* If there's nothing pending, we're good */ | ||
1211 | if (!pending) | ||
1212 | return true; | ||
1213 | |||
1214 | timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies; | ||
1215 | if (timeout < 0 || wait_event_timeout(priv->bh_evt_wq, | ||
1216 | !priv->hw_bufs_used, | ||
1217 | timeout) <= 0) { | ||
1218 | /* Hmmm... Not good. Frame had stuck in firmware. */ | ||
1219 | priv->bh_error = 1; | ||
1220 | wiphy_err(priv->hw->wiphy, "[WSM] TX Frames (%d) stuck in firmware, killing BH\n", priv->hw_bufs_used); | ||
1221 | wake_up(&priv->bh_wq); | ||
1222 | return false; | ||
1223 | } | ||
1224 | |||
1225 | /* Ok, everything is flushed. */ | ||
1226 | return true; | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | void wsm_unlock_tx(struct cw1200_common *priv) | ||
1231 | { | ||
1232 | int tx_lock; | ||
1233 | tx_lock = atomic_sub_return(1, &priv->tx_lock); | ||
1234 | BUG_ON(tx_lock < 0); | ||
1235 | |||
1236 | if (tx_lock == 0) { | ||
1237 | if (!priv->bh_error) | ||
1238 | cw1200_bh_wakeup(priv); | ||
1239 | pr_debug("[WSM] TX is unlocked.\n"); | ||
1240 | } | ||
1241 | } | ||
1242 | |||
1243 | /* ******************************************************************** */ | ||
1244 | /* WSM RX */ | ||
1245 | |||
1246 | int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len) | ||
1247 | { | ||
1248 | struct wsm_buf buf; | ||
1249 | u32 reason; | ||
1250 | u32 reg[18]; | ||
1251 | char fname[48]; | ||
1252 | unsigned int i; | ||
1253 | |||
1254 | static const char * const reason_str[] = { | ||
1255 | "undefined instruction", | ||
1256 | "prefetch abort", | ||
1257 | "data abort", | ||
1258 | "unknown error", | ||
1259 | }; | ||
1260 | |||
1261 | buf.begin = buf.data = data; | ||
1262 | buf.end = &buf.begin[len]; | ||
1263 | |||
1264 | reason = WSM_GET32(&buf); | ||
1265 | for (i = 0; i < ARRAY_SIZE(reg); ++i) | ||
1266 | reg[i] = WSM_GET32(&buf); | ||
1267 | WSM_GET(&buf, fname, sizeof(fname)); | ||
1268 | |||
1269 | if (reason < 4) | ||
1270 | wiphy_err(priv->hw->wiphy, | ||
1271 | "Firmware exception: %s.\n", | ||
1272 | reason_str[reason]); | ||
1273 | else | ||
1274 | wiphy_err(priv->hw->wiphy, | ||
1275 | "Firmware assert at %.*s, line %d\n", | ||
1276 | (int) sizeof(fname), fname, reg[1]); | ||
1277 | |||
1278 | for (i = 0; i < 12; i += 4) | ||
1279 | wiphy_err(priv->hw->wiphy, | ||
1280 | "R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X,\n", | ||
1281 | i + 0, reg[i + 0], i + 1, reg[i + 1], | ||
1282 | i + 2, reg[i + 2], i + 3, reg[i + 3]); | ||
1283 | wiphy_err(priv->hw->wiphy, | ||
1284 | "R12: 0x%.8X, SP: 0x%.8X, LR: 0x%.8X, PC: 0x%.8X,\n", | ||
1285 | reg[i + 0], reg[i + 1], reg[i + 2], reg[i + 3]); | ||
1286 | i += 4; | ||
1287 | wiphy_err(priv->hw->wiphy, | ||
1288 | "CPSR: 0x%.8X, SPSR: 0x%.8X\n", | ||
1289 | reg[i + 0], reg[i + 1]); | ||
1290 | |||
1291 | print_hex_dump_bytes("R1: ", DUMP_PREFIX_NONE, | ||
1292 | fname, sizeof(fname)); | ||
1293 | return 0; | ||
1294 | |||
1295 | underflow: | ||
1296 | wiphy_err(priv->hw->wiphy, "Firmware exception.\n"); | ||
1297 | print_hex_dump_bytes("Exception: ", DUMP_PREFIX_NONE, | ||
1298 | data, len); | ||
1299 | return -EINVAL; | ||
1300 | } | ||
1301 | |||
1302 | int wsm_handle_rx(struct cw1200_common *priv, u16 id, | ||
1303 | struct wsm_hdr *wsm, struct sk_buff **skb_p) | ||
1304 | { | ||
1305 | int ret = 0; | ||
1306 | struct wsm_buf wsm_buf; | ||
1307 | int link_id = (id >> 6) & 0x0F; | ||
1308 | |||
1309 | /* Strip link id. */ | ||
1310 | id &= ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); | ||
1311 | |||
1312 | wsm_buf.begin = (u8 *)&wsm[0]; | ||
1313 | wsm_buf.data = (u8 *)&wsm[1]; | ||
1314 | wsm_buf.end = &wsm_buf.begin[__le32_to_cpu(wsm->len)]; | ||
1315 | |||
1316 | pr_debug("[WSM] <<< 0x%.4X (%td)\n", id, | ||
1317 | wsm_buf.end - wsm_buf.begin); | ||
1318 | |||
1319 | if (id == WSM_TX_CONFIRM_IND_ID) { | ||
1320 | ret = wsm_tx_confirm(priv, &wsm_buf, link_id); | ||
1321 | } else if (id == WSM_MULTI_TX_CONFIRM_ID) { | ||
1322 | ret = wsm_multi_tx_confirm(priv, &wsm_buf, link_id); | ||
1323 | } else if (id & 0x0400) { | ||
1324 | void *wsm_arg; | ||
1325 | u16 wsm_cmd; | ||
1326 | |||
1327 | /* Do not trust FW too much. Protection against repeated | ||
1328 | * response and race condition removal (see above). | ||
1329 | */ | ||
1330 | spin_lock(&priv->wsm_cmd.lock); | ||
1331 | wsm_arg = priv->wsm_cmd.arg; | ||
1332 | wsm_cmd = priv->wsm_cmd.cmd & | ||
1333 | ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); | ||
1334 | priv->wsm_cmd.cmd = 0xFFFF; | ||
1335 | spin_unlock(&priv->wsm_cmd.lock); | ||
1336 | |||
1337 | if (WARN_ON((id & ~0x0400) != wsm_cmd)) { | ||
1338 | /* Note that any non-zero is a fatal retcode. */ | ||
1339 | ret = -EINVAL; | ||
1340 | goto out; | ||
1341 | } | ||
1342 | |||
1343 | /* Note that wsm_arg can be NULL in case of timeout in | ||
1344 | * wsm_cmd_send(). | ||
1345 | */ | ||
1346 | |||
1347 | switch (id) { | ||
1348 | case WSM_READ_MIB_RESP_ID: | ||
1349 | if (wsm_arg) | ||
1350 | ret = wsm_read_mib_confirm(priv, wsm_arg, | ||
1351 | &wsm_buf); | ||
1352 | break; | ||
1353 | case WSM_WRITE_MIB_RESP_ID: | ||
1354 | if (wsm_arg) | ||
1355 | ret = wsm_write_mib_confirm(priv, wsm_arg, | ||
1356 | &wsm_buf); | ||
1357 | break; | ||
1358 | case WSM_START_SCAN_RESP_ID: | ||
1359 | if (wsm_arg) | ||
1360 | ret = wsm_scan_started(priv, wsm_arg, &wsm_buf); | ||
1361 | break; | ||
1362 | case WSM_CONFIGURATION_RESP_ID: | ||
1363 | if (wsm_arg) | ||
1364 | ret = wsm_configuration_confirm(priv, wsm_arg, | ||
1365 | &wsm_buf); | ||
1366 | break; | ||
1367 | case WSM_JOIN_RESP_ID: | ||
1368 | if (wsm_arg) | ||
1369 | ret = wsm_join_confirm(priv, wsm_arg, &wsm_buf); | ||
1370 | break; | ||
1371 | case WSM_STOP_SCAN_RESP_ID: | ||
1372 | case WSM_RESET_RESP_ID: | ||
1373 | case WSM_ADD_KEY_RESP_ID: | ||
1374 | case WSM_REMOVE_KEY_RESP_ID: | ||
1375 | case WSM_SET_PM_RESP_ID: | ||
1376 | case WSM_SET_BSS_PARAMS_RESP_ID: | ||
1377 | case 0x0412: /* set_tx_queue_params */ | ||
1378 | case WSM_EDCA_PARAMS_RESP_ID: | ||
1379 | case WSM_SWITCH_CHANNEL_RESP_ID: | ||
1380 | case WSM_START_RESP_ID: | ||
1381 | case WSM_BEACON_TRANSMIT_RESP_ID: | ||
1382 | case 0x0419: /* start_find */ | ||
1383 | case 0x041A: /* stop_find */ | ||
1384 | case 0x041B: /* update_ie */ | ||
1385 | case 0x041C: /* map_link */ | ||
1386 | WARN_ON(wsm_arg != NULL); | ||
1387 | ret = wsm_generic_confirm(priv, wsm_arg, &wsm_buf); | ||
1388 | if (ret) { | ||
1389 | wiphy_warn(priv->hw->wiphy, | ||
1390 | "wsm_generic_confirm failed for request 0x%04x.\n", | ||
1391 | id & ~0x0400); | ||
1392 | |||
1393 | /* often 0x407 and 0x410 occur, this means we're dead.. */ | ||
1394 | if (priv->join_status >= CW1200_JOIN_STATUS_JOINING) { | ||
1395 | wsm_lock_tx(priv); | ||
1396 | if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) | ||
1397 | wsm_unlock_tx(priv); | ||
1398 | } | ||
1399 | } | ||
1400 | break; | ||
1401 | default: | ||
1402 | wiphy_warn(priv->hw->wiphy, | ||
1403 | "Unrecognized confirmation 0x%04x\n", | ||
1404 | id & ~0x0400); | ||
1405 | } | ||
1406 | |||
1407 | spin_lock(&priv->wsm_cmd.lock); | ||
1408 | priv->wsm_cmd.ret = ret; | ||
1409 | priv->wsm_cmd.done = 1; | ||
1410 | spin_unlock(&priv->wsm_cmd.lock); | ||
1411 | |||
1412 | ret = 0; /* Error response from device should ne stop BH. */ | ||
1413 | |||
1414 | wake_up(&priv->wsm_cmd_wq); | ||
1415 | } else if (id & 0x0800) { | ||
1416 | switch (id) { | ||
1417 | case WSM_STARTUP_IND_ID: | ||
1418 | ret = wsm_startup_indication(priv, &wsm_buf); | ||
1419 | break; | ||
1420 | case WSM_RECEIVE_IND_ID: | ||
1421 | ret = wsm_receive_indication(priv, link_id, | ||
1422 | &wsm_buf, skb_p); | ||
1423 | break; | ||
1424 | case 0x0805: | ||
1425 | ret = wsm_event_indication(priv, &wsm_buf); | ||
1426 | break; | ||
1427 | case WSM_SCAN_COMPLETE_IND_ID: | ||
1428 | ret = wsm_scan_complete_indication(priv, &wsm_buf); | ||
1429 | break; | ||
1430 | case 0x0808: | ||
1431 | ret = wsm_ba_timeout_indication(priv, &wsm_buf); | ||
1432 | break; | ||
1433 | case 0x0809: | ||
1434 | ret = wsm_set_pm_indication(priv, &wsm_buf); | ||
1435 | break; | ||
1436 | case 0x080A: | ||
1437 | ret = wsm_channel_switch_indication(priv, &wsm_buf); | ||
1438 | break; | ||
1439 | case 0x080B: | ||
1440 | ret = wsm_find_complete_indication(priv, &wsm_buf); | ||
1441 | break; | ||
1442 | case 0x080C: | ||
1443 | ret = wsm_suspend_resume_indication(priv, | ||
1444 | link_id, &wsm_buf); | ||
1445 | break; | ||
1446 | case 0x080F: | ||
1447 | ret = wsm_join_complete_indication(priv, &wsm_buf); | ||
1448 | break; | ||
1449 | default: | ||
1450 | pr_warn("Unrecognised WSM ID %04x\n", id); | ||
1451 | } | ||
1452 | } else { | ||
1453 | WARN_ON(1); | ||
1454 | ret = -EINVAL; | ||
1455 | } | ||
1456 | out: | ||
1457 | return ret; | ||
1458 | } | ||
1459 | |||
1460 | static bool wsm_handle_tx_data(struct cw1200_common *priv, | ||
1461 | struct wsm_tx *wsm, | ||
1462 | const struct ieee80211_tx_info *tx_info, | ||
1463 | const struct cw1200_txpriv *txpriv, | ||
1464 | struct cw1200_queue *queue) | ||
1465 | { | ||
1466 | bool handled = false; | ||
1467 | const struct ieee80211_hdr *frame = | ||
1468 | (struct ieee80211_hdr *)&((u8 *)wsm)[txpriv->offset]; | ||
1469 | __le16 fctl = frame->frame_control; | ||
1470 | enum { | ||
1471 | do_probe, | ||
1472 | do_drop, | ||
1473 | do_wep, | ||
1474 | do_tx, | ||
1475 | } action = do_tx; | ||
1476 | |||
1477 | switch (priv->mode) { | ||
1478 | case NL80211_IFTYPE_STATION: | ||
1479 | if (priv->join_status == CW1200_JOIN_STATUS_MONITOR) | ||
1480 | action = do_tx; | ||
1481 | else if (priv->join_status < CW1200_JOIN_STATUS_PRE_STA) | ||
1482 | action = do_drop; | ||
1483 | break; | ||
1484 | case NL80211_IFTYPE_AP: | ||
1485 | if (!priv->join_status) { | ||
1486 | action = do_drop; | ||
1487 | } else if (!(BIT(txpriv->raw_link_id) & | ||
1488 | (BIT(0) | priv->link_id_map))) { | ||
1489 | wiphy_warn(priv->hw->wiphy, | ||
1490 | "A frame with expired link id is dropped.\n"); | ||
1491 | action = do_drop; | ||
1492 | } | ||
1493 | if (cw1200_queue_get_generation(wsm->packet_id) > | ||
1494 | CW1200_MAX_REQUEUE_ATTEMPTS) { | ||
1495 | /* HACK!!! WSM324 firmware has tendency to requeue | ||
1496 | * multicast frames in a loop, causing performance | ||
1497 | * drop and high power consumption of the driver. | ||
1498 | * In this situation it is better just to drop | ||
1499 | * the problematic frame. | ||
1500 | */ | ||
1501 | wiphy_warn(priv->hw->wiphy, | ||
1502 | "Too many attempts to requeue a frame; dropped.\n"); | ||
1503 | action = do_drop; | ||
1504 | } | ||
1505 | break; | ||
1506 | case NL80211_IFTYPE_ADHOC: | ||
1507 | if (priv->join_status != CW1200_JOIN_STATUS_IBSS) | ||
1508 | action = do_drop; | ||
1509 | break; | ||
1510 | case NL80211_IFTYPE_MESH_POINT: | ||
1511 | action = do_tx; /* TODO: Test me! */ | ||
1512 | break; | ||
1513 | case NL80211_IFTYPE_MONITOR: | ||
1514 | default: | ||
1515 | action = do_drop; | ||
1516 | break; | ||
1517 | } | ||
1518 | |||
1519 | if (action == do_tx) { | ||
1520 | if (ieee80211_is_nullfunc(fctl)) { | ||
1521 | spin_lock(&priv->bss_loss_lock); | ||
1522 | if (priv->bss_loss_state) { | ||
1523 | priv->bss_loss_confirm_id = wsm->packet_id; | ||
1524 | wsm->queue_id = WSM_QUEUE_VOICE; | ||
1525 | } | ||
1526 | spin_unlock(&priv->bss_loss_lock); | ||
1527 | } else if (ieee80211_is_probe_req(fctl)) { | ||
1528 | action = do_probe; | ||
1529 | } else if (ieee80211_is_deauth(fctl) && | ||
1530 | priv->mode != NL80211_IFTYPE_AP) { | ||
1531 | pr_debug("[WSM] Issue unjoin command due to tx deauth.\n"); | ||
1532 | wsm_lock_tx_async(priv); | ||
1533 | if (queue_work(priv->workqueue, | ||
1534 | &priv->unjoin_work) <= 0) | ||
1535 | wsm_unlock_tx(priv); | ||
1536 | } else if (ieee80211_has_protected(fctl) && | ||
1537 | tx_info->control.hw_key && | ||
1538 | tx_info->control.hw_key->keyidx != priv->wep_default_key_id && | ||
1539 | (tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
1540 | tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) { | ||
1541 | action = do_wep; | ||
1542 | } | ||
1543 | } | ||
1544 | |||
1545 | switch (action) { | ||
1546 | case do_probe: | ||
1547 | /* An interesting FW "feature". Device filters probe responses. | ||
1548 | * The easiest way to get it back is to convert | ||
1549 | * probe request into WSM start_scan command. | ||
1550 | */ | ||
1551 | pr_debug("[WSM] Convert probe request to scan.\n"); | ||
1552 | wsm_lock_tx_async(priv); | ||
1553 | priv->pending_frame_id = __le32_to_cpu(wsm->packet_id); | ||
1554 | if (queue_delayed_work(priv->workqueue, | ||
1555 | &priv->scan.probe_work, 0) <= 0) | ||
1556 | wsm_unlock_tx(priv); | ||
1557 | handled = true; | ||
1558 | break; | ||
1559 | case do_drop: | ||
1560 | pr_debug("[WSM] Drop frame (0x%.4X).\n", fctl); | ||
1561 | BUG_ON(cw1200_queue_remove(queue, | ||
1562 | __le32_to_cpu(wsm->packet_id))); | ||
1563 | handled = true; | ||
1564 | break; | ||
1565 | case do_wep: | ||
1566 | pr_debug("[WSM] Issue set_default_wep_key.\n"); | ||
1567 | wsm_lock_tx_async(priv); | ||
1568 | priv->wep_default_key_id = tx_info->control.hw_key->keyidx; | ||
1569 | priv->pending_frame_id = __le32_to_cpu(wsm->packet_id); | ||
1570 | if (queue_work(priv->workqueue, &priv->wep_key_work) <= 0) | ||
1571 | wsm_unlock_tx(priv); | ||
1572 | handled = true; | ||
1573 | break; | ||
1574 | case do_tx: | ||
1575 | pr_debug("[WSM] Transmit frame.\n"); | ||
1576 | break; | ||
1577 | default: | ||
1578 | /* Do nothing */ | ||
1579 | break; | ||
1580 | } | ||
1581 | return handled; | ||
1582 | } | ||
1583 | |||
1584 | static int cw1200_get_prio_queue(struct cw1200_common *priv, | ||
1585 | u32 link_id_map, int *total) | ||
1586 | { | ||
1587 | static const int urgent = BIT(CW1200_LINK_ID_AFTER_DTIM) | | ||
1588 | BIT(CW1200_LINK_ID_UAPSD); | ||
1589 | struct wsm_edca_queue_params *edca; | ||
1590 | unsigned score, best = -1; | ||
1591 | int winner = -1; | ||
1592 | int queued; | ||
1593 | int i; | ||
1594 | |||
1595 | /* search for a winner using edca params */ | ||
1596 | for (i = 0; i < 4; ++i) { | ||
1597 | queued = cw1200_queue_get_num_queued(&priv->tx_queue[i], | ||
1598 | link_id_map); | ||
1599 | if (!queued) | ||
1600 | continue; | ||
1601 | *total += queued; | ||
1602 | edca = &priv->edca.params[i]; | ||
1603 | score = ((edca->aifns + edca->cwmin) << 16) + | ||
1604 | ((edca->cwmax - edca->cwmin) * | ||
1605 | (get_random_int() & 0xFFFF)); | ||
1606 | if (score < best && (winner < 0 || i != 3)) { | ||
1607 | best = score; | ||
1608 | winner = i; | ||
1609 | } | ||
1610 | } | ||
1611 | |||
1612 | /* override winner if bursting */ | ||
1613 | if (winner >= 0 && priv->tx_burst_idx >= 0 && | ||
1614 | winner != priv->tx_burst_idx && | ||
1615 | !cw1200_queue_get_num_queued( | ||
1616 | &priv->tx_queue[winner], | ||
1617 | link_id_map & urgent) && | ||
1618 | cw1200_queue_get_num_queued( | ||
1619 | &priv->tx_queue[priv->tx_burst_idx], | ||
1620 | link_id_map)) | ||
1621 | winner = priv->tx_burst_idx; | ||
1622 | |||
1623 | return winner; | ||
1624 | } | ||
1625 | |||
1626 | static int wsm_get_tx_queue_and_mask(struct cw1200_common *priv, | ||
1627 | struct cw1200_queue **queue_p, | ||
1628 | u32 *tx_allowed_mask_p, | ||
1629 | bool *more) | ||
1630 | { | ||
1631 | int idx; | ||
1632 | u32 tx_allowed_mask; | ||
1633 | int total = 0; | ||
1634 | |||
1635 | /* Search for a queue with multicast frames buffered */ | ||
1636 | if (priv->tx_multicast) { | ||
1637 | tx_allowed_mask = BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1638 | idx = cw1200_get_prio_queue(priv, | ||
1639 | tx_allowed_mask, &total); | ||
1640 | if (idx >= 0) { | ||
1641 | *more = total > 1; | ||
1642 | goto found; | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | /* Search for unicast traffic */ | ||
1647 | tx_allowed_mask = ~priv->sta_asleep_mask; | ||
1648 | tx_allowed_mask |= BIT(CW1200_LINK_ID_UAPSD); | ||
1649 | if (priv->sta_asleep_mask) { | ||
1650 | tx_allowed_mask |= priv->pspoll_mask; | ||
1651 | tx_allowed_mask &= ~BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1652 | } else { | ||
1653 | tx_allowed_mask |= BIT(CW1200_LINK_ID_AFTER_DTIM); | ||
1654 | } | ||
1655 | idx = cw1200_get_prio_queue(priv, | ||
1656 | tx_allowed_mask, &total); | ||
1657 | if (idx < 0) | ||
1658 | return -ENOENT; | ||
1659 | |||
1660 | found: | ||
1661 | *queue_p = &priv->tx_queue[idx]; | ||
1662 | *tx_allowed_mask_p = tx_allowed_mask; | ||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | int wsm_get_tx(struct cw1200_common *priv, u8 **data, | ||
1667 | size_t *tx_len, int *burst) | ||
1668 | { | ||
1669 | struct wsm_tx *wsm = NULL; | ||
1670 | struct ieee80211_tx_info *tx_info; | ||
1671 | struct cw1200_queue *queue = NULL; | ||
1672 | int queue_num; | ||
1673 | u32 tx_allowed_mask = 0; | ||
1674 | const struct cw1200_txpriv *txpriv = NULL; | ||
1675 | int count = 0; | ||
1676 | |||
1677 | /* More is used only for broadcasts. */ | ||
1678 | bool more = false; | ||
1679 | |||
1680 | if (priv->wsm_cmd.ptr) { /* CMD request */ | ||
1681 | ++count; | ||
1682 | spin_lock(&priv->wsm_cmd.lock); | ||
1683 | BUG_ON(!priv->wsm_cmd.ptr); | ||
1684 | *data = priv->wsm_cmd.ptr; | ||
1685 | *tx_len = priv->wsm_cmd.len; | ||
1686 | *burst = 1; | ||
1687 | spin_unlock(&priv->wsm_cmd.lock); | ||
1688 | } else { | ||
1689 | for (;;) { | ||
1690 | int ret; | ||
1691 | |||
1692 | if (atomic_add_return(0, &priv->tx_lock)) | ||
1693 | break; | ||
1694 | |||
1695 | spin_lock_bh(&priv->ps_state_lock); | ||
1696 | |||
1697 | ret = wsm_get_tx_queue_and_mask(priv, &queue, | ||
1698 | &tx_allowed_mask, &more); | ||
1699 | queue_num = queue - priv->tx_queue; | ||
1700 | |||
1701 | if (priv->buffered_multicasts && | ||
1702 | (ret || !more) && | ||
1703 | (priv->tx_multicast || !priv->sta_asleep_mask)) { | ||
1704 | priv->buffered_multicasts = false; | ||
1705 | if (priv->tx_multicast) { | ||
1706 | priv->tx_multicast = false; | ||
1707 | queue_work(priv->workqueue, | ||
1708 | &priv->multicast_stop_work); | ||
1709 | } | ||
1710 | } | ||
1711 | |||
1712 | spin_unlock_bh(&priv->ps_state_lock); | ||
1713 | |||
1714 | if (ret) | ||
1715 | break; | ||
1716 | |||
1717 | if (cw1200_queue_get(queue, | ||
1718 | tx_allowed_mask, | ||
1719 | &wsm, &tx_info, &txpriv)) | ||
1720 | continue; | ||
1721 | |||
1722 | if (wsm_handle_tx_data(priv, wsm, | ||
1723 | tx_info, txpriv, queue)) | ||
1724 | continue; /* Handled by WSM */ | ||
1725 | |||
1726 | wsm->hdr.id &= __cpu_to_le16( | ||
1727 | ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX)); | ||
1728 | wsm->hdr.id |= cpu_to_le16( | ||
1729 | WSM_TX_LINK_ID(txpriv->raw_link_id)); | ||
1730 | priv->pspoll_mask &= ~BIT(txpriv->raw_link_id); | ||
1731 | |||
1732 | *data = (u8 *)wsm; | ||
1733 | *tx_len = __le16_to_cpu(wsm->hdr.len); | ||
1734 | |||
1735 | /* allow bursting if txop is set */ | ||
1736 | if (priv->edca.params[queue_num].txop_limit) | ||
1737 | *burst = min(*burst, | ||
1738 | (int)cw1200_queue_get_num_queued(queue, tx_allowed_mask) + 1); | ||
1739 | else | ||
1740 | *burst = 1; | ||
1741 | |||
1742 | /* store index of bursting queue */ | ||
1743 | if (*burst > 1) | ||
1744 | priv->tx_burst_idx = queue_num; | ||
1745 | else | ||
1746 | priv->tx_burst_idx = -1; | ||
1747 | |||
1748 | if (more) { | ||
1749 | struct ieee80211_hdr *hdr = | ||
1750 | (struct ieee80211_hdr *) | ||
1751 | &((u8 *)wsm)[txpriv->offset]; | ||
1752 | /* more buffered multicast/broadcast frames | ||
1753 | * ==> set MoreData flag in IEEE 802.11 header | ||
1754 | * to inform PS STAs | ||
1755 | */ | ||
1756 | hdr->frame_control |= | ||
1757 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | ||
1758 | } | ||
1759 | |||
1760 | pr_debug("[WSM] >>> 0x%.4X (%zu) %p %c\n", | ||
1761 | 0x0004, *tx_len, *data, | ||
1762 | wsm->more ? 'M' : ' '); | ||
1763 | ++count; | ||
1764 | break; | ||
1765 | } | ||
1766 | } | ||
1767 | |||
1768 | return count; | ||
1769 | } | ||
1770 | |||
1771 | void wsm_txed(struct cw1200_common *priv, u8 *data) | ||
1772 | { | ||
1773 | if (data == priv->wsm_cmd.ptr) { | ||
1774 | spin_lock(&priv->wsm_cmd.lock); | ||
1775 | priv->wsm_cmd.ptr = NULL; | ||
1776 | spin_unlock(&priv->wsm_cmd.lock); | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | /* ******************************************************************** */ | ||
1781 | /* WSM buffer */ | ||
1782 | |||
1783 | void wsm_buf_init(struct wsm_buf *buf) | ||
1784 | { | ||
1785 | BUG_ON(buf->begin); | ||
1786 | buf->begin = kmalloc(FWLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA); | ||
1787 | buf->end = buf->begin ? &buf->begin[FWLOAD_BLOCK_SIZE] : buf->begin; | ||
1788 | wsm_buf_reset(buf); | ||
1789 | } | ||
1790 | |||
1791 | void wsm_buf_deinit(struct wsm_buf *buf) | ||
1792 | { | ||
1793 | kfree(buf->begin); | ||
1794 | buf->begin = buf->data = buf->end = NULL; | ||
1795 | } | ||
1796 | |||
1797 | static void wsm_buf_reset(struct wsm_buf *buf) | ||
1798 | { | ||
1799 | if (buf->begin) { | ||
1800 | buf->data = &buf->begin[4]; | ||
1801 | *(u32 *)buf->begin = 0; | ||
1802 | } else { | ||
1803 | buf->data = buf->begin; | ||
1804 | } | ||
1805 | } | ||
1806 | |||
1807 | static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) | ||
1808 | { | ||
1809 | size_t pos = buf->data - buf->begin; | ||
1810 | size_t size = pos + extra_size; | ||
1811 | |||
1812 | size = round_up(size, FWLOAD_BLOCK_SIZE); | ||
1813 | |||
1814 | buf->begin = krealloc(buf->begin, size, GFP_KERNEL | GFP_DMA); | ||
1815 | if (buf->begin) { | ||
1816 | buf->data = &buf->begin[pos]; | ||
1817 | buf->end = &buf->begin[size]; | ||
1818 | return 0; | ||
1819 | } else { | ||
1820 | buf->end = buf->data = buf->begin; | ||
1821 | return -ENOMEM; | ||
1822 | } | ||
1823 | } | ||
diff --git a/drivers/net/wireless/cw1200/wsm.h b/drivers/net/wireless/cw1200/wsm.h new file mode 100644 index 000000000000..2816171f7a1d --- /dev/null +++ b/drivers/net/wireless/cw1200/wsm.h | |||
@@ -0,0 +1,1873 @@ | |||
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 | */ | ||
319 | #define WSM_JOIN_FLAGS_FORCE BIT(2) | ||
320 | /* Give probe request/response higher | ||
321 | * priority over the BT traffic | ||
322 | */ | ||
323 | #define WSM_JOIN_FLAGS_PRIO BIT(3) | ||
324 | /* Issue immediate join confirmation and use | ||
325 | * join complete to notify about completion | ||
326 | */ | ||
327 | #define WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND BIT(5) | ||
328 | |||
329 | /* Key types */ | ||
330 | #define WSM_KEY_TYPE_WEP_DEFAULT (0) | ||
331 | #define WSM_KEY_TYPE_WEP_PAIRWISE (1) | ||
332 | #define WSM_KEY_TYPE_TKIP_GROUP (2) | ||
333 | #define WSM_KEY_TYPE_TKIP_PAIRWISE (3) | ||
334 | #define WSM_KEY_TYPE_AES_GROUP (4) | ||
335 | #define WSM_KEY_TYPE_AES_PAIRWISE (5) | ||
336 | #define WSM_KEY_TYPE_WAPI_GROUP (6) | ||
337 | #define WSM_KEY_TYPE_WAPI_PAIRWISE (7) | ||
338 | |||
339 | /* Key indexes */ | ||
340 | #define WSM_KEY_MAX_INDEX (10) | ||
341 | |||
342 | /* ACK policy */ | ||
343 | #define WSM_ACK_POLICY_NORMAL (0) | ||
344 | #define WSM_ACK_POLICY_NO_ACK (1) | ||
345 | |||
346 | /* Start modes */ | ||
347 | #define WSM_START_MODE_AP (0) /* Mini AP */ | ||
348 | #define WSM_START_MODE_P2P_GO (1) /* P2P GO */ | ||
349 | #define WSM_START_MODE_P2P_DEV (2) /* P2P device */ | ||
350 | |||
351 | /* SetAssociationMode MIB flags */ | ||
352 | #define WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE (BIT(0)) | ||
353 | #define WSM_ASSOCIATION_MODE_USE_HT_MODE (BIT(1)) | ||
354 | #define WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET (BIT(2)) | ||
355 | #define WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING (BIT(3)) | ||
356 | #define WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES (BIT(4)) | ||
357 | |||
358 | /* RcpiRssiThreshold MIB flags */ | ||
359 | #define WSM_RCPI_RSSI_THRESHOLD_ENABLE (BIT(0)) | ||
360 | #define WSM_RCPI_RSSI_USE_RSSI (BIT(1)) | ||
361 | #define WSM_RCPI_RSSI_DONT_USE_UPPER (BIT(2)) | ||
362 | #define WSM_RCPI_RSSI_DONT_USE_LOWER (BIT(3)) | ||
363 | |||
364 | /* Update-ie constants */ | ||
365 | #define WSM_UPDATE_IE_BEACON (BIT(0)) | ||
366 | #define WSM_UPDATE_IE_PROBE_RESP (BIT(1)) | ||
367 | #define WSM_UPDATE_IE_PROBE_REQ (BIT(2)) | ||
368 | |||
369 | /* WSM events */ | ||
370 | /* Error */ | ||
371 | #define WSM_EVENT_ERROR (0) | ||
372 | |||
373 | /* BSS lost */ | ||
374 | #define WSM_EVENT_BSS_LOST (1) | ||
375 | |||
376 | /* BSS regained */ | ||
377 | #define WSM_EVENT_BSS_REGAINED (2) | ||
378 | |||
379 | /* Radar detected */ | ||
380 | #define WSM_EVENT_RADAR_DETECTED (3) | ||
381 | |||
382 | /* RCPI or RSSI threshold triggered */ | ||
383 | #define WSM_EVENT_RCPI_RSSI (4) | ||
384 | |||
385 | /* BT inactive */ | ||
386 | #define WSM_EVENT_BT_INACTIVE (5) | ||
387 | |||
388 | /* BT active */ | ||
389 | #define WSM_EVENT_BT_ACTIVE (6) | ||
390 | |||
391 | /* MIB IDs */ | ||
392 | /* 4.1 dot11StationId */ | ||
393 | #define WSM_MIB_ID_DOT11_STATION_ID 0x0000 | ||
394 | |||
395 | /* 4.2 dot11MaxtransmitMsduLifeTime */ | ||
396 | #define WSM_MIB_ID_DOT11_MAX_TRANSMIT_LIFTIME 0x0001 | ||
397 | |||
398 | /* 4.3 dot11MaxReceiveLifeTime */ | ||
399 | #define WSM_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME 0x0002 | ||
400 | |||
401 | /* 4.4 dot11SlotTime */ | ||
402 | #define WSM_MIB_ID_DOT11_SLOT_TIME 0x0003 | ||
403 | |||
404 | /* 4.5 dot11GroupAddressesTable */ | ||
405 | #define WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE 0x0004 | ||
406 | #define WSM_MAX_GRP_ADDRTABLE_ENTRIES 8 | ||
407 | |||
408 | /* 4.6 dot11WepDefaultKeyId */ | ||
409 | #define WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID 0x0005 | ||
410 | |||
411 | /* 4.7 dot11CurrentTxPowerLevel */ | ||
412 | #define WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL 0x0006 | ||
413 | |||
414 | /* 4.8 dot11RTSThreshold */ | ||
415 | #define WSM_MIB_ID_DOT11_RTS_THRESHOLD 0x0007 | ||
416 | |||
417 | /* 4.9 NonErpProtection */ | ||
418 | #define WSM_MIB_ID_NON_ERP_PROTECTION 0x1000 | ||
419 | |||
420 | /* 4.10 ArpIpAddressesTable */ | ||
421 | #define WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE 0x1001 | ||
422 | #define WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES 1 | ||
423 | |||
424 | /* 4.11 TemplateFrame */ | ||
425 | #define WSM_MIB_ID_TEMPLATE_FRAME 0x1002 | ||
426 | |||
427 | /* 4.12 RxFilter */ | ||
428 | #define WSM_MIB_ID_RX_FILTER 0x1003 | ||
429 | |||
430 | /* 4.13 BeaconFilterTable */ | ||
431 | #define WSM_MIB_ID_BEACON_FILTER_TABLE 0x1004 | ||
432 | |||
433 | /* 4.14 BeaconFilterEnable */ | ||
434 | #define WSM_MIB_ID_BEACON_FILTER_ENABLE 0x1005 | ||
435 | |||
436 | /* 4.15 OperationalPowerMode */ | ||
437 | #define WSM_MIB_ID_OPERATIONAL_POWER_MODE 0x1006 | ||
438 | |||
439 | /* 4.16 BeaconWakeUpPeriod */ | ||
440 | #define WSM_MIB_ID_BEACON_WAKEUP_PERIOD 0x1007 | ||
441 | |||
442 | /* 4.17 RcpiRssiThreshold */ | ||
443 | #define WSM_MIB_ID_RCPI_RSSI_THRESHOLD 0x1009 | ||
444 | |||
445 | /* 4.18 StatisticsTable */ | ||
446 | #define WSM_MIB_ID_STATISTICS_TABLE 0x100A | ||
447 | |||
448 | /* 4.19 IbssPsConfig */ | ||
449 | #define WSM_MIB_ID_IBSS_PS_CONFIG 0x100B | ||
450 | |||
451 | /* 4.20 CountersTable */ | ||
452 | #define WSM_MIB_ID_COUNTERS_TABLE 0x100C | ||
453 | |||
454 | /* 4.21 BlockAckPolicy */ | ||
455 | #define WSM_MIB_ID_BLOCK_ACK_POLICY 0x100E | ||
456 | |||
457 | /* 4.22 OverrideInternalTxRate */ | ||
458 | #define WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE 0x100F | ||
459 | |||
460 | /* 4.23 SetAssociationMode */ | ||
461 | #define WSM_MIB_ID_SET_ASSOCIATION_MODE 0x1010 | ||
462 | |||
463 | /* 4.24 UpdateEptaConfigData */ | ||
464 | #define WSM_MIB_ID_UPDATE_EPTA_CONFIG_DATA 0x1011 | ||
465 | |||
466 | /* 4.25 SelectCcaMethod */ | ||
467 | #define WSM_MIB_ID_SELECT_CCA_METHOD 0x1012 | ||
468 | |||
469 | /* 4.26 SetUpasdInformation */ | ||
470 | #define WSM_MIB_ID_SET_UAPSD_INFORMATION 0x1013 | ||
471 | |||
472 | /* 4.27 SetAutoCalibrationMode WBF00004073 */ | ||
473 | #define WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE 0x1015 | ||
474 | |||
475 | /* 4.28 SetTxRateRetryPolicy */ | ||
476 | #define WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY 0x1016 | ||
477 | |||
478 | /* 4.29 SetHostMessageTypeFilter */ | ||
479 | #define WSM_MIB_ID_SET_HOST_MSG_TYPE_FILTER 0x1017 | ||
480 | |||
481 | /* 4.30 P2PFindInfo */ | ||
482 | #define WSM_MIB_ID_P2P_FIND_INFO 0x1018 | ||
483 | |||
484 | /* 4.31 P2PPsModeInfo */ | ||
485 | #define WSM_MIB_ID_P2P_PS_MODE_INFO 0x1019 | ||
486 | |||
487 | /* 4.32 SetEtherTypeDataFrameFilter */ | ||
488 | #define WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER 0x101A | ||
489 | |||
490 | /* 4.33 SetUDPPortDataFrameFilter */ | ||
491 | #define WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER 0x101B | ||
492 | |||
493 | /* 4.34 SetMagicDataFrameFilter */ | ||
494 | #define WSM_MIB_ID_SET_MAGIC_DATAFRAME_FILTER 0x101C | ||
495 | |||
496 | /* 4.35 P2PDeviceInfo */ | ||
497 | #define WSM_MIB_ID_P2P_DEVICE_INFO 0x101D | ||
498 | |||
499 | /* 4.36 SetWCDMABand */ | ||
500 | #define WSM_MIB_ID_SET_WCDMA_BAND 0x101E | ||
501 | |||
502 | /* 4.37 GroupTxSequenceCounter */ | ||
503 | #define WSM_MIB_ID_GRP_SEQ_COUNTER 0x101F | ||
504 | |||
505 | /* 4.38 ProtectedMgmtPolicy */ | ||
506 | #define WSM_MIB_ID_PROTECTED_MGMT_POLICY 0x1020 | ||
507 | |||
508 | /* 4.39 SetHtProtection */ | ||
509 | #define WSM_MIB_ID_SET_HT_PROTECTION 0x1021 | ||
510 | |||
511 | /* 4.40 GPIO Command */ | ||
512 | #define WSM_MIB_ID_GPIO_COMMAND 0x1022 | ||
513 | |||
514 | /* 4.41 TSF Counter Value */ | ||
515 | #define WSM_MIB_ID_TSF_COUNTER 0x1023 | ||
516 | |||
517 | /* Test Purposes Only */ | ||
518 | #define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D | ||
519 | |||
520 | /* 4.42 UseMultiTxConfMessage */ | ||
521 | #define WSM_MIB_USE_MULTI_TX_CONF 0x1024 | ||
522 | |||
523 | /* 4.43 Keep-alive period */ | ||
524 | #define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025 | ||
525 | |||
526 | /* 4.44 Disable BSSID filter */ | ||
527 | #define WSM_MIB_ID_DISABLE_BSSID_FILTER 0x1026 | ||
528 | |||
529 | /* Frame template types */ | ||
530 | #define WSM_FRAME_TYPE_PROBE_REQUEST (0) | ||
531 | #define WSM_FRAME_TYPE_BEACON (1) | ||
532 | #define WSM_FRAME_TYPE_NULL (2) | ||
533 | #define WSM_FRAME_TYPE_QOS_NULL (3) | ||
534 | #define WSM_FRAME_TYPE_PS_POLL (4) | ||
535 | #define WSM_FRAME_TYPE_PROBE_RESPONSE (5) | ||
536 | |||
537 | #define WSM_FRAME_GREENFIELD (0x80) /* See 4.11 */ | ||
538 | |||
539 | /* Status */ | ||
540 | /* The WSM firmware has completed a request */ | ||
541 | /* successfully. */ | ||
542 | #define WSM_STATUS_SUCCESS (0) | ||
543 | |||
544 | /* This is a generic failure code if other error codes do */ | ||
545 | /* not apply. */ | ||
546 | #define WSM_STATUS_FAILURE (1) | ||
547 | |||
548 | /* A request contains one or more invalid parameters. */ | ||
549 | #define WSM_INVALID_PARAMETER (2) | ||
550 | |||
551 | /* The request cannot perform because the device is in */ | ||
552 | /* an inappropriate mode. */ | ||
553 | #define WSM_ACCESS_DENIED (3) | ||
554 | |||
555 | /* The frame received includes a decryption error. */ | ||
556 | #define WSM_STATUS_DECRYPTFAILURE (4) | ||
557 | |||
558 | /* A MIC failure is detected in the received packets. */ | ||
559 | #define WSM_STATUS_MICFAILURE (5) | ||
560 | |||
561 | /* The transmit request failed due to retry limit being */ | ||
562 | /* exceeded. */ | ||
563 | #define WSM_STATUS_RETRY_EXCEEDED (6) | ||
564 | |||
565 | /* The transmit request failed due to MSDU life time */ | ||
566 | /* being exceeded. */ | ||
567 | #define WSM_STATUS_TX_LIFETIME_EXCEEDED (7) | ||
568 | |||
569 | /* The link to the AP is lost. */ | ||
570 | #define WSM_STATUS_LINK_LOST (8) | ||
571 | |||
572 | /* No key was found for the encrypted frame */ | ||
573 | #define WSM_STATUS_NO_KEY_FOUND (9) | ||
574 | |||
575 | /* Jammer was detected when transmitting this frame */ | ||
576 | #define WSM_STATUS_JAMMER_DETECTED (10) | ||
577 | |||
578 | /* The message should be requeued later. */ | ||
579 | /* This is applicable only to Transmit */ | ||
580 | #define WSM_REQUEUE (11) | ||
581 | |||
582 | /* Advanced filtering options */ | ||
583 | #define WSM_MAX_FILTER_ELEMENTS (4) | ||
584 | |||
585 | #define WSM_FILTER_ACTION_IGNORE (0) | ||
586 | #define WSM_FILTER_ACTION_FILTER_IN (1) | ||
587 | #define WSM_FILTER_ACTION_FILTER_OUT (2) | ||
588 | |||
589 | #define WSM_FILTER_PORT_TYPE_DST (0) | ||
590 | #define WSM_FILTER_PORT_TYPE_SRC (1) | ||
591 | |||
592 | /* Actual header of WSM messages */ | ||
593 | struct wsm_hdr { | ||
594 | __le16 len; | ||
595 | __le16 id; | ||
596 | }; | ||
597 | |||
598 | #define WSM_TX_SEQ_MAX (7) | ||
599 | #define WSM_TX_SEQ(seq) \ | ||
600 | ((seq & WSM_TX_SEQ_MAX) << 13) | ||
601 | #define WSM_TX_LINK_ID_MAX (0x0F) | ||
602 | #define WSM_TX_LINK_ID(link_id) \ | ||
603 | ((link_id & WSM_TX_LINK_ID_MAX) << 6) | ||
604 | |||
605 | #define MAX_BEACON_SKIP_TIME_MS 1000 | ||
606 | |||
607 | #define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 3 / 2) | ||
608 | |||
609 | /* ******************************************************************** */ | ||
610 | /* WSM capability */ | ||
611 | |||
612 | #define WSM_STARTUP_IND_ID 0x0801 | ||
613 | |||
614 | struct wsm_startup_ind { | ||
615 | u16 input_buffers; | ||
616 | u16 input_buffer_size; | ||
617 | u16 status; | ||
618 | u16 hw_id; | ||
619 | u16 hw_subid; | ||
620 | u16 fw_cap; | ||
621 | u16 fw_type; | ||
622 | u16 fw_api; | ||
623 | u16 fw_build; | ||
624 | u16 fw_ver; | ||
625 | char fw_label[128]; | ||
626 | u32 config[4]; | ||
627 | }; | ||
628 | |||
629 | /* ******************************************************************** */ | ||
630 | /* WSM commands */ | ||
631 | |||
632 | /* 3.1 */ | ||
633 | #define WSM_CONFIGURATION_REQ_ID 0x0009 | ||
634 | #define WSM_CONFIGURATION_RESP_ID 0x0409 | ||
635 | |||
636 | struct wsm_tx_power_range { | ||
637 | int min_power_level; | ||
638 | int max_power_level; | ||
639 | u32 stepping; | ||
640 | }; | ||
641 | |||
642 | struct wsm_configuration { | ||
643 | /* [in] */ u32 dot11MaxTransmitMsduLifeTime; | ||
644 | /* [in] */ u32 dot11MaxReceiveLifeTime; | ||
645 | /* [in] */ u32 dot11RtsThreshold; | ||
646 | /* [in, out] */ u8 *dot11StationId; | ||
647 | /* [in] */ const void *dpdData; | ||
648 | /* [in] */ size_t dpdData_size; | ||
649 | /* [out] */ u8 dot11FrequencyBandsSupported; | ||
650 | /* [out] */ u32 supportedRateMask; | ||
651 | /* [out] */ struct wsm_tx_power_range txPowerRange[2]; | ||
652 | }; | ||
653 | |||
654 | int wsm_configuration(struct cw1200_common *priv, | ||
655 | struct wsm_configuration *arg); | ||
656 | |||
657 | /* 3.3 */ | ||
658 | #define WSM_RESET_REQ_ID 0x000A | ||
659 | #define WSM_RESET_RESP_ID 0x040A | ||
660 | struct wsm_reset { | ||
661 | /* [in] */ int link_id; | ||
662 | /* [in] */ bool reset_statistics; | ||
663 | }; | ||
664 | |||
665 | int wsm_reset(struct cw1200_common *priv, const struct wsm_reset *arg); | ||
666 | |||
667 | /* 3.5 */ | ||
668 | #define WSM_READ_MIB_REQ_ID 0x0005 | ||
669 | #define WSM_READ_MIB_RESP_ID 0x0405 | ||
670 | int wsm_read_mib(struct cw1200_common *priv, u16 mib_id, void *buf, | ||
671 | size_t buf_size); | ||
672 | |||
673 | /* 3.7 */ | ||
674 | #define WSM_WRITE_MIB_REQ_ID 0x0006 | ||
675 | #define WSM_WRITE_MIB_RESP_ID 0x0406 | ||
676 | int wsm_write_mib(struct cw1200_common *priv, u16 mib_id, void *buf, | ||
677 | size_t buf_size); | ||
678 | |||
679 | /* 3.9 */ | ||
680 | #define WSM_START_SCAN_REQ_ID 0x0007 | ||
681 | #define WSM_START_SCAN_RESP_ID 0x0407 | ||
682 | |||
683 | struct wsm_ssid { | ||
684 | u8 ssid[32]; | ||
685 | u32 length; | ||
686 | }; | ||
687 | |||
688 | struct wsm_scan_ch { | ||
689 | u16 number; | ||
690 | u32 min_chan_time; | ||
691 | u32 max_chan_time; | ||
692 | u32 tx_power_level; | ||
693 | }; | ||
694 | |||
695 | struct wsm_scan { | ||
696 | /* WSM_PHY_BAND_... */ | ||
697 | u8 band; | ||
698 | |||
699 | /* WSM_SCAN_TYPE_... */ | ||
700 | u8 type; | ||
701 | |||
702 | /* WSM_SCAN_FLAG_... */ | ||
703 | u8 flags; | ||
704 | |||
705 | /* WSM_TRANSMIT_RATE_... */ | ||
706 | u8 max_tx_rate; | ||
707 | |||
708 | /* Interval period in TUs that the device shall the re- */ | ||
709 | /* execute the requested scan. Max value supported by the device */ | ||
710 | /* is 256s. */ | ||
711 | u32 auto_scan_interval; | ||
712 | |||
713 | /* Number of probe requests (per SSID) sent to one (1) */ | ||
714 | /* channel. Zero (0) means that none is send, which */ | ||
715 | /* means that a passive scan is to be done. Value */ | ||
716 | /* greater than zero (0) means that an active scan is to */ | ||
717 | /* be done. */ | ||
718 | u32 num_probes; | ||
719 | |||
720 | /* Number of channels to be scanned. */ | ||
721 | /* Maximum value is WSM_SCAN_MAX_NUM_OF_CHANNELS. */ | ||
722 | u8 num_channels; | ||
723 | |||
724 | /* Number of SSID provided in the scan command (this */ | ||
725 | /* is zero (0) in broadcast scan) */ | ||
726 | /* The maximum number of SSIDs is WSM_SCAN_MAX_NUM_OF_SSIDS. */ | ||
727 | u8 num_ssids; | ||
728 | |||
729 | /* The delay time (in microseconds) period */ | ||
730 | /* before sending a probe-request. */ | ||
731 | u8 probe_delay; | ||
732 | |||
733 | /* SSIDs to be scanned [numOfSSIDs]; */ | ||
734 | struct wsm_ssid *ssids; | ||
735 | |||
736 | /* Channels to be scanned [numOfChannels]; */ | ||
737 | struct wsm_scan_ch *ch; | ||
738 | }; | ||
739 | |||
740 | int wsm_scan(struct cw1200_common *priv, const struct wsm_scan *arg); | ||
741 | |||
742 | /* 3.11 */ | ||
743 | #define WSM_STOP_SCAN_REQ_ID 0x0008 | ||
744 | #define WSM_STOP_SCAN_RESP_ID 0x0408 | ||
745 | int wsm_stop_scan(struct cw1200_common *priv); | ||
746 | |||
747 | /* 3.13 */ | ||
748 | #define WSM_SCAN_COMPLETE_IND_ID 0x0806 | ||
749 | struct wsm_scan_complete { | ||
750 | /* WSM_STATUS_... */ | ||
751 | u32 status; | ||
752 | |||
753 | /* WSM_PSM_... */ | ||
754 | u8 psm; | ||
755 | |||
756 | /* Number of channels that the scan operation completed. */ | ||
757 | u8 num_channels; | ||
758 | }; | ||
759 | |||
760 | /* 3.14 */ | ||
761 | #define WSM_TX_CONFIRM_IND_ID 0x0404 | ||
762 | #define WSM_MULTI_TX_CONFIRM_ID 0x041E | ||
763 | |||
764 | struct wsm_tx_confirm { | ||
765 | /* Packet identifier used in wsm_tx. */ | ||
766 | u32 packet_id; | ||
767 | |||
768 | /* WSM_STATUS_... */ | ||
769 | u32 status; | ||
770 | |||
771 | /* WSM_TRANSMIT_RATE_... */ | ||
772 | u8 tx_rate; | ||
773 | |||
774 | /* The number of times the frame was transmitted */ | ||
775 | /* without receiving an acknowledgement. */ | ||
776 | u8 ack_failures; | ||
777 | |||
778 | /* WSM_TX_STATUS_... */ | ||
779 | u16 flags; | ||
780 | |||
781 | /* The total time in microseconds that the frame spent in */ | ||
782 | /* the WLAN device before transmission as completed. */ | ||
783 | u32 media_delay; | ||
784 | |||
785 | /* The total time in microseconds that the frame spent in */ | ||
786 | /* the WLAN device before transmission was started. */ | ||
787 | u32 tx_queue_delay; | ||
788 | }; | ||
789 | |||
790 | /* 3.15 */ | ||
791 | typedef void (*wsm_tx_confirm_cb) (struct cw1200_common *priv, | ||
792 | struct wsm_tx_confirm *arg); | ||
793 | |||
794 | /* Note that ideology of wsm_tx struct is different against the rest of | ||
795 | * WSM API. wsm_hdr is /not/ a caller-adapted struct to be used as an input | ||
796 | * argument for WSM call, but a prepared bytestream to be sent to firmware. | ||
797 | * It is filled partly in cw1200_tx, partly in low-level WSM code. | ||
798 | * Please pay attention once again: ideology is different. | ||
799 | * | ||
800 | * Legend: | ||
801 | * - [in]: cw1200_tx must fill this field. | ||
802 | * - [wsm]: the field is filled by low-level WSM. | ||
803 | */ | ||
804 | struct wsm_tx { | ||
805 | /* common WSM header */ | ||
806 | struct wsm_hdr hdr; | ||
807 | |||
808 | /* Packet identifier that meant to be used in completion. */ | ||
809 | __le32 packet_id; | ||
810 | |||
811 | /* WSM_TRANSMIT_RATE_... */ | ||
812 | u8 max_tx_rate; | ||
813 | |||
814 | /* WSM_QUEUE_... */ | ||
815 | u8 queue_id; | ||
816 | |||
817 | /* True: another packet is pending on the host for transmission. */ | ||
818 | u8 more; | ||
819 | |||
820 | /* Bit 0 = 0 - Start expiry time from first Tx attempt (default) */ | ||
821 | /* Bit 0 = 1 - Start expiry time from receipt of Tx Request */ | ||
822 | /* Bits 3:1 - PTA Priority */ | ||
823 | /* Bits 6:4 - Tx Rate Retry Policy */ | ||
824 | /* Bit 7 - Reserved */ | ||
825 | u8 flags; | ||
826 | |||
827 | /* Should be 0. */ | ||
828 | __le32 reserved; | ||
829 | |||
830 | /* The elapsed time in TUs, after the initial transmission */ | ||
831 | /* of an MSDU, after which further attempts to transmit */ | ||
832 | /* the MSDU shall be terminated. Overrides the global */ | ||
833 | /* dot11MaxTransmitMsduLifeTime setting [optional] */ | ||
834 | /* Device will set the default value if this is 0. */ | ||
835 | __le32 expire_time; | ||
836 | |||
837 | /* WSM_HT_TX_... */ | ||
838 | __le32 ht_tx_parameters; | ||
839 | }; | ||
840 | |||
841 | /* = sizeof(generic hi hdr) + sizeof(wsm hdr) + sizeof(alignment) */ | ||
842 | #define WSM_TX_EXTRA_HEADROOM (28) | ||
843 | |||
844 | /* 3.16 */ | ||
845 | #define WSM_RECEIVE_IND_ID 0x0804 | ||
846 | |||
847 | struct wsm_rx { | ||
848 | /* WSM_STATUS_... */ | ||
849 | __le32 status; | ||
850 | |||
851 | /* Specifies the channel of the received packet. */ | ||
852 | __le16 channel_number; | ||
853 | |||
854 | /* WSM_TRANSMIT_RATE_... */ | ||
855 | u8 rx_rate; | ||
856 | |||
857 | /* This value is expressed in signed Q8.0 format for */ | ||
858 | /* RSSI and unsigned Q7.1 format for RCPI. */ | ||
859 | u8 rcpi_rssi; | ||
860 | |||
861 | /* WSM_RX_STATUS_... */ | ||
862 | __le32 flags; | ||
863 | |||
864 | /* Payload */ | ||
865 | u8 data[0]; | ||
866 | } __packed; | ||
867 | |||
868 | /* = sizeof(generic hi hdr) + sizeof(wsm hdr) */ | ||
869 | #define WSM_RX_EXTRA_HEADROOM (16) | ||
870 | |||
871 | typedef void (*wsm_rx_cb) (struct cw1200_common *priv, struct wsm_rx *arg, | ||
872 | struct sk_buff **skb_p); | ||
873 | |||
874 | /* 3.17 */ | ||
875 | struct wsm_event { | ||
876 | /* WSM_STATUS_... */ | ||
877 | /* [out] */ u32 id; | ||
878 | |||
879 | /* Indication parameters. */ | ||
880 | /* For error indication, this shall be a 32-bit WSM status. */ | ||
881 | /* For RCPI or RSSI indication, this should be an 8-bit */ | ||
882 | /* RCPI or RSSI value. */ | ||
883 | /* [out] */ u32 data; | ||
884 | }; | ||
885 | |||
886 | struct cw1200_wsm_event { | ||
887 | struct list_head link; | ||
888 | struct wsm_event evt; | ||
889 | }; | ||
890 | |||
891 | /* 3.18 - 3.22 */ | ||
892 | /* Measurement. Skipped for now. Irrelevent. */ | ||
893 | |||
894 | typedef void (*wsm_event_cb) (struct cw1200_common *priv, | ||
895 | struct wsm_event *arg); | ||
896 | |||
897 | /* 3.23 */ | ||
898 | #define WSM_JOIN_REQ_ID 0x000B | ||
899 | #define WSM_JOIN_RESP_ID 0x040B | ||
900 | |||
901 | struct wsm_join { | ||
902 | /* WSM_JOIN_MODE_... */ | ||
903 | u8 mode; | ||
904 | |||
905 | /* WSM_PHY_BAND_... */ | ||
906 | u8 band; | ||
907 | |||
908 | /* Specifies the channel number to join. The channel */ | ||
909 | /* number will be mapped to an actual frequency */ | ||
910 | /* according to the band */ | ||
911 | u16 channel_number; | ||
912 | |||
913 | /* Specifies the BSSID of the BSS or IBSS to be joined */ | ||
914 | /* or the IBSS to be started. */ | ||
915 | u8 bssid[6]; | ||
916 | |||
917 | /* ATIM window of IBSS */ | ||
918 | /* When ATIM window is zero the initiated IBSS does */ | ||
919 | /* not support power saving. */ | ||
920 | u16 atim_window; | ||
921 | |||
922 | /* WSM_JOIN_PREAMBLE_... */ | ||
923 | u8 preamble_type; | ||
924 | |||
925 | /* Specifies if a probe request should be send with the */ | ||
926 | /* specified SSID when joining to the network. */ | ||
927 | u8 probe_for_join; | ||
928 | |||
929 | /* DTIM Period (In multiples of beacon interval) */ | ||
930 | u8 dtim_period; | ||
931 | |||
932 | /* WSM_JOIN_FLAGS_... */ | ||
933 | u8 flags; | ||
934 | |||
935 | /* Length of the SSID */ | ||
936 | u32 ssid_len; | ||
937 | |||
938 | /* Specifies the SSID of the IBSS to join or start */ | ||
939 | u8 ssid[32]; | ||
940 | |||
941 | /* Specifies the time between TBTTs in TUs */ | ||
942 | u32 beacon_interval; | ||
943 | |||
944 | /* A bit mask that defines the BSS basic rate set. */ | ||
945 | u32 basic_rate_set; | ||
946 | }; | ||
947 | |||
948 | struct wsm_join_cnf { | ||
949 | u32 status; | ||
950 | |||
951 | /* Minimum transmission power level in units of 0.1dBm */ | ||
952 | u32 min_power_level; | ||
953 | |||
954 | /* Maximum transmission power level in units of 0.1dBm */ | ||
955 | u32 max_power_level; | ||
956 | }; | ||
957 | |||
958 | int wsm_join(struct cw1200_common *priv, struct wsm_join *arg); | ||
959 | |||
960 | /* 3.24 */ | ||
961 | struct wsm_join_complete { | ||
962 | /* WSM_STATUS_... */ | ||
963 | u32 status; | ||
964 | }; | ||
965 | |||
966 | /* 3.25 */ | ||
967 | #define WSM_SET_PM_REQ_ID 0x0010 | ||
968 | #define WSM_SET_PM_RESP_ID 0x0410 | ||
969 | struct wsm_set_pm { | ||
970 | /* WSM_PSM_... */ | ||
971 | u8 mode; | ||
972 | |||
973 | /* in unit of 500us; 0 to use default */ | ||
974 | u8 fast_psm_idle_period; | ||
975 | |||
976 | /* in unit of 500us; 0 to use default */ | ||
977 | u8 ap_psm_change_period; | ||
978 | |||
979 | /* in unit of 500us; 0 to disable auto-pspoll */ | ||
980 | u8 min_auto_pspoll_period; | ||
981 | }; | ||
982 | |||
983 | int wsm_set_pm(struct cw1200_common *priv, const struct wsm_set_pm *arg); | ||
984 | |||
985 | /* 3.27 */ | ||
986 | struct wsm_set_pm_complete { | ||
987 | u8 psm; /* WSM_PSM_... */ | ||
988 | }; | ||
989 | |||
990 | /* 3.28 */ | ||
991 | #define WSM_SET_BSS_PARAMS_REQ_ID 0x0011 | ||
992 | #define WSM_SET_BSS_PARAMS_RESP_ID 0x0411 | ||
993 | struct wsm_set_bss_params { | ||
994 | /* This resets the beacon loss counters only */ | ||
995 | u8 reset_beacon_loss; | ||
996 | |||
997 | /* The number of lost consecutive beacons after which */ | ||
998 | /* the WLAN device should indicate the BSS-Lost event */ | ||
999 | /* to the WLAN host driver. */ | ||
1000 | u8 beacon_lost_count; | ||
1001 | |||
1002 | /* The AID received during the association process. */ | ||
1003 | u16 aid; | ||
1004 | |||
1005 | /* The operational rate set mask */ | ||
1006 | u32 operational_rate_set; | ||
1007 | }; | ||
1008 | |||
1009 | int wsm_set_bss_params(struct cw1200_common *priv, | ||
1010 | const struct wsm_set_bss_params *arg); | ||
1011 | |||
1012 | /* 3.30 */ | ||
1013 | #define WSM_ADD_KEY_REQ_ID 0x000C | ||
1014 | #define WSM_ADD_KEY_RESP_ID 0x040C | ||
1015 | struct wsm_add_key { | ||
1016 | u8 type; /* WSM_KEY_TYPE_... */ | ||
1017 | u8 index; /* Key entry index: 0 -- WSM_KEY_MAX_INDEX */ | ||
1018 | u16 reserved; | ||
1019 | union { | ||
1020 | struct { | ||
1021 | u8 peer[6]; /* MAC address of the peer station */ | ||
1022 | u8 reserved; | ||
1023 | u8 keylen; /* Key length in bytes */ | ||
1024 | u8 keydata[16]; /* Key data */ | ||
1025 | } __packed wep_pairwise; | ||
1026 | struct { | ||
1027 | u8 keyid; /* Unique per key identifier (0..3) */ | ||
1028 | u8 keylen; /* Key length in bytes */ | ||
1029 | u16 reserved; | ||
1030 | u8 keydata[16]; /* Key data */ | ||
1031 | } __packed wep_group; | ||
1032 | struct { | ||
1033 | u8 peer[6]; /* MAC address of the 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 peer station */ | ||
1048 | u16 reserved; | ||
1049 | u8 keydata[16]; /* AES key data */ | ||
1050 | } __packed aes_pairwise; | ||
1051 | struct { | ||
1052 | u8 keydata[16]; /* AES key data */ | ||
1053 | u8 keyid; /* Key ID */ | ||
1054 | u8 reserved[3]; | ||
1055 | u8 rx_seqnum[8]; /* Receive Sequence Counter */ | ||
1056 | } __packed aes_group; | ||
1057 | struct { | ||
1058 | u8 peer[6]; /* MAC address of the peer station */ | ||
1059 | u8 keyid; /* Key ID */ | ||
1060 | u8 reserved; | ||
1061 | u8 keydata[16]; /* WAPI key data */ | ||
1062 | u8 mic_key[16]; /* MIC key data */ | ||
1063 | } __packed wapi_pairwise; | ||
1064 | struct { | ||
1065 | u8 keydata[16]; /* WAPI key data */ | ||
1066 | u8 mic_key[16]; /* MIC key data */ | ||
1067 | u8 keyid; /* Key ID */ | ||
1068 | u8 reserved[3]; | ||
1069 | } __packed wapi_group; | ||
1070 | } __packed; | ||
1071 | } __packed; | ||
1072 | |||
1073 | int wsm_add_key(struct cw1200_common *priv, const struct wsm_add_key *arg); | ||
1074 | |||
1075 | /* 3.32 */ | ||
1076 | #define WSM_REMOVE_KEY_REQ_ID 0x000D | ||
1077 | #define WSM_REMOVE_KEY_RESP_ID 0x040D | ||
1078 | struct wsm_remove_key { | ||
1079 | u8 index; /* Key entry index : 0-10 */ | ||
1080 | }; | ||
1081 | |||
1082 | int wsm_remove_key(struct cw1200_common *priv, | ||
1083 | const struct wsm_remove_key *arg); | ||
1084 | |||
1085 | /* 3.34 */ | ||
1086 | struct wsm_set_tx_queue_params { | ||
1087 | /* WSM_ACK_POLICY_... */ | ||
1088 | u8 ackPolicy; | ||
1089 | |||
1090 | /* Medium Time of TSPEC (in 32us units) allowed per */ | ||
1091 | /* One Second Averaging Period for this queue. */ | ||
1092 | u16 allowedMediumTime; | ||
1093 | |||
1094 | /* dot11MaxTransmitMsduLifetime to be used for the */ | ||
1095 | /* specified queue. */ | ||
1096 | u32 maxTransmitLifetime; | ||
1097 | }; | ||
1098 | |||
1099 | struct wsm_tx_queue_params { | ||
1100 | /* NOTE: index is a linux queue id. */ | ||
1101 | struct wsm_set_tx_queue_params params[4]; | ||
1102 | }; | ||
1103 | |||
1104 | |||
1105 | #define WSM_TX_QUEUE_SET(queue_params, queue, ack_policy, allowed_time,\ | ||
1106 | max_life_time) \ | ||
1107 | do { \ | ||
1108 | struct wsm_set_tx_queue_params *p = &(queue_params)->params[queue]; \ | ||
1109 | p->ackPolicy = (ack_policy); \ | ||
1110 | p->allowedMediumTime = (allowed_time); \ | ||
1111 | p->maxTransmitLifetime = (max_life_time); \ | ||
1112 | } while (0) | ||
1113 | |||
1114 | int wsm_set_tx_queue_params(struct cw1200_common *priv, | ||
1115 | const struct wsm_set_tx_queue_params *arg, u8 id); | ||
1116 | |||
1117 | /* 3.36 */ | ||
1118 | #define WSM_EDCA_PARAMS_REQ_ID 0x0013 | ||
1119 | #define WSM_EDCA_PARAMS_RESP_ID 0x0413 | ||
1120 | struct wsm_edca_queue_params { | ||
1121 | /* CWmin (in slots) for the access class. */ | ||
1122 | __le16 cwmin; | ||
1123 | |||
1124 | /* CWmax (in slots) for the access class. */ | ||
1125 | __le16 cwmax; | ||
1126 | |||
1127 | /* AIFS (in slots) for the access class. */ | ||
1128 | __le16 aifns; | ||
1129 | |||
1130 | /* TX OP Limit (in microseconds) for the access class. */ | ||
1131 | __le16 txop_limit; | ||
1132 | |||
1133 | /* dot11MaxReceiveLifetime to be used for the specified */ | ||
1134 | /* the access class. Overrides the global */ | ||
1135 | /* dot11MaxReceiveLifetime value */ | ||
1136 | __le32 max_rx_lifetime; | ||
1137 | } __packed; | ||
1138 | |||
1139 | struct wsm_edca_params { | ||
1140 | /* NOTE: index is a linux queue id. */ | ||
1141 | struct wsm_edca_queue_params params[4]; | ||
1142 | bool uapsd_enable[4]; | ||
1143 | }; | ||
1144 | |||
1145 | #define TXOP_UNIT 32 | ||
1146 | #define WSM_EDCA_SET(__edca, __queue, __aifs, __cw_min, __cw_max, __txop, __lifetime,\ | ||
1147 | __uapsd) \ | ||
1148 | do { \ | ||
1149 | struct wsm_edca_queue_params *p = &(__edca)->params[__queue]; \ | ||
1150 | p->cwmin = (__cw_min); \ | ||
1151 | p->cwmax = (__cw_max); \ | ||
1152 | p->aifns = (__aifs); \ | ||
1153 | p->txop_limit = ((__txop) * TXOP_UNIT); \ | ||
1154 | p->max_rx_lifetime = (__lifetime); \ | ||
1155 | (__edca)->uapsd_enable[__queue] = (__uapsd); \ | ||
1156 | } while (0) | ||
1157 | |||
1158 | int wsm_set_edca_params(struct cw1200_common *priv, | ||
1159 | const struct wsm_edca_params *arg); | ||
1160 | |||
1161 | int wsm_set_uapsd_param(struct cw1200_common *priv, | ||
1162 | const struct wsm_edca_params *arg); | ||
1163 | |||
1164 | /* 3.38 */ | ||
1165 | /* Set-System info. Skipped for now. Irrelevent. */ | ||
1166 | |||
1167 | /* 3.40 */ | ||
1168 | #define WSM_SWITCH_CHANNEL_REQ_ID 0x0016 | ||
1169 | #define WSM_SWITCH_CHANNEL_RESP_ID 0x0416 | ||
1170 | |||
1171 | struct wsm_switch_channel { | ||
1172 | /* 1 - means the STA shall not transmit any further */ | ||
1173 | /* frames until the channel switch has completed */ | ||
1174 | u8 mode; | ||
1175 | |||
1176 | /* Number of TBTTs until channel switch occurs. */ | ||
1177 | /* 0 - indicates switch shall occur at any time */ | ||
1178 | /* 1 - occurs immediately before the next TBTT */ | ||
1179 | u8 switch_count; | ||
1180 | |||
1181 | /* The new channel number to switch to. */ | ||
1182 | /* Note this is defined as per section 2.7. */ | ||
1183 | u16 channel_number; | ||
1184 | }; | ||
1185 | |||
1186 | int wsm_switch_channel(struct cw1200_common *priv, | ||
1187 | const struct wsm_switch_channel *arg); | ||
1188 | |||
1189 | typedef void (*wsm_channel_switch_cb) (struct cw1200_common *priv); | ||
1190 | |||
1191 | #define WSM_START_REQ_ID 0x0017 | ||
1192 | #define WSM_START_RESP_ID 0x0417 | ||
1193 | |||
1194 | struct wsm_start { | ||
1195 | /* WSM_START_MODE_... */ | ||
1196 | /* [in] */ u8 mode; | ||
1197 | |||
1198 | /* WSM_PHY_BAND_... */ | ||
1199 | /* [in] */ u8 band; | ||
1200 | |||
1201 | /* Channel number */ | ||
1202 | /* [in] */ u16 channel_number; | ||
1203 | |||
1204 | /* Client Traffic window in units of TU */ | ||
1205 | /* Valid only when mode == ..._P2P */ | ||
1206 | /* [in] */ u32 ct_window; | ||
1207 | |||
1208 | /* Interval between two consecutive */ | ||
1209 | /* beacon transmissions in TU. */ | ||
1210 | /* [in] */ u32 beacon_interval; | ||
1211 | |||
1212 | /* DTIM period in terms of beacon intervals */ | ||
1213 | /* [in] */ u8 dtim_period; | ||
1214 | |||
1215 | /* WSM_JOIN_PREAMBLE_... */ | ||
1216 | /* [in] */ u8 preamble; | ||
1217 | |||
1218 | /* The delay time (in microseconds) period */ | ||
1219 | /* before sending a probe-request. */ | ||
1220 | /* [in] */ u8 probe_delay; | ||
1221 | |||
1222 | /* Length of the SSID */ | ||
1223 | /* [in] */ u8 ssid_len; | ||
1224 | |||
1225 | /* SSID of the BSS or P2P_GO to be started now. */ | ||
1226 | /* [in] */ u8 ssid[32]; | ||
1227 | |||
1228 | /* The basic supported rates for the MiniAP. */ | ||
1229 | /* [in] */ u32 basic_rate_set; | ||
1230 | }; | ||
1231 | |||
1232 | int wsm_start(struct cw1200_common *priv, const struct wsm_start *arg); | ||
1233 | |||
1234 | #define WSM_BEACON_TRANSMIT_REQ_ID 0x0018 | ||
1235 | #define WSM_BEACON_TRANSMIT_RESP_ID 0x0418 | ||
1236 | |||
1237 | struct wsm_beacon_transmit { | ||
1238 | /* 1: enable; 0: disable */ | ||
1239 | /* [in] */ u8 enable_beaconing; | ||
1240 | }; | ||
1241 | |||
1242 | int wsm_beacon_transmit(struct cw1200_common *priv, | ||
1243 | const struct wsm_beacon_transmit *arg); | ||
1244 | |||
1245 | int wsm_start_find(struct cw1200_common *priv); | ||
1246 | |||
1247 | int wsm_stop_find(struct cw1200_common *priv); | ||
1248 | |||
1249 | typedef void (*wsm_find_complete_cb) (struct cw1200_common *priv, u32 status); | ||
1250 | |||
1251 | struct wsm_suspend_resume { | ||
1252 | /* See 3.52 */ | ||
1253 | /* Link ID */ | ||
1254 | /* [out] */ int link_id; | ||
1255 | /* Stop sending further Tx requests down to device for this link */ | ||
1256 | /* [out] */ bool stop; | ||
1257 | /* Transmit multicast Frames */ | ||
1258 | /* [out] */ bool multicast; | ||
1259 | /* The AC on which Tx to be suspended /resumed. */ | ||
1260 | /* This is applicable only for U-APSD */ | ||
1261 | /* WSM_QUEUE_... */ | ||
1262 | /* [out] */ int queue; | ||
1263 | }; | ||
1264 | |||
1265 | typedef void (*wsm_suspend_resume_cb) (struct cw1200_common *priv, | ||
1266 | struct wsm_suspend_resume *arg); | ||
1267 | |||
1268 | /* 3.54 Update-IE request. */ | ||
1269 | struct wsm_update_ie { | ||
1270 | /* WSM_UPDATE_IE_... */ | ||
1271 | /* [in] */ u16 what; | ||
1272 | /* [in] */ u16 count; | ||
1273 | /* [in] */ u8 *ies; | ||
1274 | /* [in] */ size_t length; | ||
1275 | }; | ||
1276 | |||
1277 | int wsm_update_ie(struct cw1200_common *priv, | ||
1278 | const struct wsm_update_ie *arg); | ||
1279 | |||
1280 | /* 3.56 */ | ||
1281 | struct wsm_map_link { | ||
1282 | /* MAC address of the remote device */ | ||
1283 | /* [in] */ u8 mac_addr[6]; | ||
1284 | /* [in] */ u8 link_id; | ||
1285 | }; | ||
1286 | |||
1287 | int wsm_map_link(struct cw1200_common *priv, const struct wsm_map_link *arg); | ||
1288 | |||
1289 | /* ******************************************************************** */ | ||
1290 | /* MIB shortcats */ | ||
1291 | |||
1292 | static inline int wsm_set_output_power(struct cw1200_common *priv, | ||
1293 | int power_level) | ||
1294 | { | ||
1295 | __le32 val = __cpu_to_le32(power_level); | ||
1296 | return wsm_write_mib(priv, WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL, | ||
1297 | &val, sizeof(val)); | ||
1298 | } | ||
1299 | |||
1300 | static inline int wsm_set_beacon_wakeup_period(struct cw1200_common *priv, | ||
1301 | unsigned dtim_interval, | ||
1302 | unsigned listen_interval) | ||
1303 | { | ||
1304 | struct { | ||
1305 | u8 numBeaconPeriods; | ||
1306 | u8 reserved; | ||
1307 | __le16 listenInterval; | ||
1308 | } val = { | ||
1309 | dtim_interval, 0, __cpu_to_le16(listen_interval) | ||
1310 | }; | ||
1311 | |||
1312 | if (dtim_interval > 0xFF || listen_interval > 0xFFFF) | ||
1313 | return -EINVAL; | ||
1314 | else | ||
1315 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_WAKEUP_PERIOD, | ||
1316 | &val, sizeof(val)); | ||
1317 | } | ||
1318 | |||
1319 | struct wsm_rcpi_rssi_threshold { | ||
1320 | u8 rssiRcpiMode; /* WSM_RCPI_RSSI_... */ | ||
1321 | u8 lowerThreshold; | ||
1322 | u8 upperThreshold; | ||
1323 | u8 rollingAverageCount; | ||
1324 | }; | ||
1325 | |||
1326 | static inline int wsm_set_rcpi_rssi_threshold(struct cw1200_common *priv, | ||
1327 | struct wsm_rcpi_rssi_threshold *arg) | ||
1328 | { | ||
1329 | return wsm_write_mib(priv, WSM_MIB_ID_RCPI_RSSI_THRESHOLD, arg, | ||
1330 | sizeof(*arg)); | ||
1331 | } | ||
1332 | |||
1333 | struct wsm_mib_counters_table { | ||
1334 | __le32 plcp_errors; | ||
1335 | __le32 fcs_errors; | ||
1336 | __le32 tx_packets; | ||
1337 | __le32 rx_packets; | ||
1338 | __le32 rx_packet_errors; | ||
1339 | __le32 rx_decryption_failures; | ||
1340 | __le32 rx_mic_failures; | ||
1341 | __le32 rx_no_key_failures; | ||
1342 | __le32 tx_multicast_frames; | ||
1343 | __le32 tx_frames_success; | ||
1344 | __le32 tx_frame_failures; | ||
1345 | __le32 tx_frames_retried; | ||
1346 | __le32 tx_frames_multi_retried; | ||
1347 | __le32 rx_frame_duplicates; | ||
1348 | __le32 rts_success; | ||
1349 | __le32 rts_failures; | ||
1350 | __le32 ack_failures; | ||
1351 | __le32 rx_multicast_frames; | ||
1352 | __le32 rx_frames_success; | ||
1353 | __le32 rx_cmac_icv_errors; | ||
1354 | __le32 rx_cmac_replays; | ||
1355 | __le32 rx_mgmt_ccmp_replays; | ||
1356 | } __packed; | ||
1357 | |||
1358 | static inline int wsm_get_counters_table(struct cw1200_common *priv, | ||
1359 | struct wsm_mib_counters_table *arg) | ||
1360 | { | ||
1361 | return wsm_read_mib(priv, WSM_MIB_ID_COUNTERS_TABLE, | ||
1362 | arg, sizeof(*arg)); | ||
1363 | } | ||
1364 | |||
1365 | static inline int wsm_get_station_id(struct cw1200_common *priv, u8 *mac) | ||
1366 | { | ||
1367 | return wsm_read_mib(priv, WSM_MIB_ID_DOT11_STATION_ID, mac, ETH_ALEN); | ||
1368 | } | ||
1369 | |||
1370 | struct wsm_rx_filter { | ||
1371 | bool promiscuous; | ||
1372 | bool bssid; | ||
1373 | bool fcs; | ||
1374 | bool probeResponder; | ||
1375 | }; | ||
1376 | |||
1377 | static inline int wsm_set_rx_filter(struct cw1200_common *priv, | ||
1378 | const struct wsm_rx_filter *arg) | ||
1379 | { | ||
1380 | __le32 val = 0; | ||
1381 | if (arg->promiscuous) | ||
1382 | val |= __cpu_to_le32(BIT(0)); | ||
1383 | if (arg->bssid) | ||
1384 | val |= __cpu_to_le32(BIT(1)); | ||
1385 | if (arg->fcs) | ||
1386 | val |= __cpu_to_le32(BIT(2)); | ||
1387 | if (arg->probeResponder) | ||
1388 | val |= __cpu_to_le32(BIT(3)); | ||
1389 | return wsm_write_mib(priv, WSM_MIB_ID_RX_FILTER, &val, sizeof(val)); | ||
1390 | } | ||
1391 | |||
1392 | int wsm_set_probe_responder(struct cw1200_common *priv, bool enable); | ||
1393 | |||
1394 | #define WSM_BEACON_FILTER_IE_HAS_CHANGED BIT(0) | ||
1395 | #define WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT BIT(1) | ||
1396 | #define WSM_BEACON_FILTER_IE_HAS_APPEARED BIT(2) | ||
1397 | |||
1398 | struct wsm_beacon_filter_table_entry { | ||
1399 | u8 ie_id; | ||
1400 | u8 flags; | ||
1401 | u8 oui[3]; | ||
1402 | u8 match_data[3]; | ||
1403 | } __packed; | ||
1404 | |||
1405 | struct wsm_mib_beacon_filter_table { | ||
1406 | __le32 num; | ||
1407 | struct wsm_beacon_filter_table_entry entry[10]; | ||
1408 | } __packed; | ||
1409 | |||
1410 | static inline int wsm_set_beacon_filter_table(struct cw1200_common *priv, | ||
1411 | struct wsm_mib_beacon_filter_table *ft) | ||
1412 | { | ||
1413 | size_t size = __le32_to_cpu(ft->num) * | ||
1414 | sizeof(struct wsm_beacon_filter_table_entry) + | ||
1415 | sizeof(__le32); | ||
1416 | |||
1417 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size); | ||
1418 | } | ||
1419 | |||
1420 | #define WSM_BEACON_FILTER_ENABLE BIT(0) /* Enable/disable beacon filtering */ | ||
1421 | #define WSM_BEACON_FILTER_AUTO_ERP BIT(1) /* If 1 FW will handle ERP IE changes internally */ | ||
1422 | |||
1423 | struct wsm_beacon_filter_control { | ||
1424 | int enabled; | ||
1425 | int bcn_count; | ||
1426 | }; | ||
1427 | |||
1428 | static inline int wsm_beacon_filter_control(struct cw1200_common *priv, | ||
1429 | struct wsm_beacon_filter_control *arg) | ||
1430 | { | ||
1431 | struct { | ||
1432 | __le32 enabled; | ||
1433 | __le32 bcn_count; | ||
1434 | } val; | ||
1435 | val.enabled = __cpu_to_le32(arg->enabled); | ||
1436 | val.bcn_count = __cpu_to_le32(arg->bcn_count); | ||
1437 | return wsm_write_mib(priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val, | ||
1438 | sizeof(val)); | ||
1439 | } | ||
1440 | |||
1441 | enum wsm_power_mode { | ||
1442 | wsm_power_mode_active = 0, | ||
1443 | wsm_power_mode_doze = 1, | ||
1444 | wsm_power_mode_quiescent = 2, | ||
1445 | }; | ||
1446 | |||
1447 | struct wsm_operational_mode { | ||
1448 | enum wsm_power_mode power_mode; | ||
1449 | int disable_more_flag_usage; | ||
1450 | int perform_ant_diversity; | ||
1451 | }; | ||
1452 | |||
1453 | static inline int wsm_set_operational_mode(struct cw1200_common *priv, | ||
1454 | const struct wsm_operational_mode *arg) | ||
1455 | { | ||
1456 | u8 val = arg->power_mode; | ||
1457 | if (arg->disable_more_flag_usage) | ||
1458 | val |= BIT(4); | ||
1459 | if (arg->perform_ant_diversity) | ||
1460 | val |= BIT(5); | ||
1461 | return wsm_write_mib(priv, WSM_MIB_ID_OPERATIONAL_POWER_MODE, &val, | ||
1462 | sizeof(val)); | ||
1463 | } | ||
1464 | |||
1465 | struct wsm_template_frame { | ||
1466 | u8 frame_type; | ||
1467 | u8 rate; | ||
1468 | struct sk_buff *skb; | ||
1469 | }; | ||
1470 | |||
1471 | static inline int wsm_set_template_frame(struct cw1200_common *priv, | ||
1472 | struct wsm_template_frame *arg) | ||
1473 | { | ||
1474 | int ret; | ||
1475 | u8 *p = skb_push(arg->skb, 4); | ||
1476 | p[0] = arg->frame_type; | ||
1477 | p[1] = arg->rate; | ||
1478 | ((u16 *)p)[1] = __cpu_to_le16(arg->skb->len - 4); | ||
1479 | ret = wsm_write_mib(priv, WSM_MIB_ID_TEMPLATE_FRAME, p, arg->skb->len); | ||
1480 | skb_pull(arg->skb, 4); | ||
1481 | return ret; | ||
1482 | } | ||
1483 | |||
1484 | |||
1485 | struct wsm_protected_mgmt_policy { | ||
1486 | bool protectedMgmtEnable; | ||
1487 | bool unprotectedMgmtFramesAllowed; | ||
1488 | bool encryptionForAuthFrame; | ||
1489 | }; | ||
1490 | |||
1491 | static inline int wsm_set_protected_mgmt_policy(struct cw1200_common *priv, | ||
1492 | struct wsm_protected_mgmt_policy *arg) | ||
1493 | { | ||
1494 | __le32 val = 0; | ||
1495 | int ret; | ||
1496 | if (arg->protectedMgmtEnable) | ||
1497 | val |= __cpu_to_le32(BIT(0)); | ||
1498 | if (arg->unprotectedMgmtFramesAllowed) | ||
1499 | val |= __cpu_to_le32(BIT(1)); | ||
1500 | if (arg->encryptionForAuthFrame) | ||
1501 | val |= __cpu_to_le32(BIT(2)); | ||
1502 | ret = wsm_write_mib(priv, WSM_MIB_ID_PROTECTED_MGMT_POLICY, | ||
1503 | &val, sizeof(val)); | ||
1504 | return ret; | ||
1505 | } | ||
1506 | |||
1507 | struct wsm_mib_block_ack_policy { | ||
1508 | u8 tx_tid; | ||
1509 | u8 reserved1; | ||
1510 | u8 rx_tid; | ||
1511 | u8 reserved2; | ||
1512 | } __packed; | ||
1513 | |||
1514 | static inline int wsm_set_block_ack_policy(struct cw1200_common *priv, | ||
1515 | u8 tx_tid_policy, | ||
1516 | u8 rx_tid_policy) | ||
1517 | { | ||
1518 | struct wsm_mib_block_ack_policy val = { | ||
1519 | .tx_tid = tx_tid_policy, | ||
1520 | .rx_tid = rx_tid_policy, | ||
1521 | }; | ||
1522 | return wsm_write_mib(priv, WSM_MIB_ID_BLOCK_ACK_POLICY, &val, | ||
1523 | sizeof(val)); | ||
1524 | } | ||
1525 | |||
1526 | struct wsm_mib_association_mode { | ||
1527 | u8 flags; /* WSM_ASSOCIATION_MODE_... */ | ||
1528 | u8 preamble; /* WSM_JOIN_PREAMBLE_... */ | ||
1529 | u8 greenfield; /* 1 for greenfield */ | ||
1530 | u8 mpdu_start_spacing; | ||
1531 | __le32 basic_rate_set; | ||
1532 | } __packed; | ||
1533 | |||
1534 | static inline int wsm_set_association_mode(struct cw1200_common *priv, | ||
1535 | struct wsm_mib_association_mode *arg) | ||
1536 | { | ||
1537 | return wsm_write_mib(priv, WSM_MIB_ID_SET_ASSOCIATION_MODE, arg, | ||
1538 | sizeof(*arg)); | ||
1539 | } | ||
1540 | |||
1541 | #define WSM_TX_RATE_POLICY_FLAG_TERMINATE_WHEN_FINISHED BIT(2) | ||
1542 | #define WSM_TX_RATE_POLICY_FLAG_COUNT_INITIAL_TRANSMIT BIT(3) | ||
1543 | struct wsm_tx_rate_retry_policy { | ||
1544 | u8 index; | ||
1545 | u8 short_retries; | ||
1546 | u8 long_retries; | ||
1547 | /* BIT(2) - Terminate retries when Tx rate retry policy | ||
1548 | * finishes. | ||
1549 | * BIT(3) - Count initial frame transmission as part of | ||
1550 | * rate retry counting but not as a retry | ||
1551 | * attempt | ||
1552 | */ | ||
1553 | u8 flags; | ||
1554 | u8 rate_recoveries; | ||
1555 | u8 reserved[3]; | ||
1556 | __le32 rate_count_indices[3]; | ||
1557 | } __packed; | ||
1558 | |||
1559 | struct wsm_set_tx_rate_retry_policy { | ||
1560 | u8 num; | ||
1561 | u8 reserved[3]; | ||
1562 | struct wsm_tx_rate_retry_policy tbl[8]; | ||
1563 | } __packed; | ||
1564 | |||
1565 | static inline int wsm_set_tx_rate_retry_policy(struct cw1200_common *priv, | ||
1566 | struct wsm_set_tx_rate_retry_policy *arg) | ||
1567 | { | ||
1568 | size_t size = 4 + arg->num * sizeof(struct wsm_tx_rate_retry_policy); | ||
1569 | return wsm_write_mib(priv, WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, | ||
1570 | size); | ||
1571 | } | ||
1572 | |||
1573 | /* 4.32 SetEtherTypeDataFrameFilter */ | ||
1574 | struct wsm_ether_type_filter_hdr { | ||
1575 | u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ | ||
1576 | u8 reserved[3]; | ||
1577 | } __packed; | ||
1578 | |||
1579 | struct wsm_ether_type_filter { | ||
1580 | u8 action; /* WSM_FILTER_ACTION_XXX */ | ||
1581 | u8 reserved; | ||
1582 | __le16 type; /* Type of ethernet frame */ | ||
1583 | } __packed; | ||
1584 | |||
1585 | static inline int wsm_set_ether_type_filter(struct cw1200_common *priv, | ||
1586 | struct wsm_ether_type_filter_hdr *arg) | ||
1587 | { | ||
1588 | size_t size = sizeof(struct wsm_ether_type_filter_hdr) + | ||
1589 | arg->num * sizeof(struct wsm_ether_type_filter); | ||
1590 | return wsm_write_mib(priv, WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER, | ||
1591 | arg, size); | ||
1592 | } | ||
1593 | |||
1594 | /* 4.33 SetUDPPortDataFrameFilter */ | ||
1595 | struct wsm_udp_port_filter_hdr { | ||
1596 | u8 num; /* Up to WSM_MAX_FILTER_ELEMENTS */ | ||
1597 | u8 reserved[3]; | ||
1598 | } __packed; | ||
1599 | |||
1600 | struct wsm_udp_port_filter { | ||
1601 | u8 action; /* WSM_FILTER_ACTION_XXX */ | ||
1602 | u8 type; /* WSM_FILTER_PORT_TYPE_XXX */ | ||
1603 | __le16 port; /* Port number */ | ||
1604 | } __packed; | ||
1605 | |||
1606 | static inline int wsm_set_udp_port_filter(struct cw1200_common *priv, | ||
1607 | struct wsm_udp_port_filter_hdr *arg) | ||
1608 | { | ||
1609 | size_t size = sizeof(struct wsm_udp_port_filter_hdr) + | ||
1610 | arg->num * sizeof(struct wsm_udp_port_filter); | ||
1611 | return wsm_write_mib(priv, WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER, | ||
1612 | arg, size); | ||
1613 | } | ||
1614 | |||
1615 | /* Undocumented MIBs: */ | ||
1616 | /* 4.35 P2PDeviceInfo */ | ||
1617 | #define D11_MAX_SSID_LEN (32) | ||
1618 | |||
1619 | struct wsm_p2p_device_type { | ||
1620 | __le16 category_id; | ||
1621 | u8 oui[4]; | ||
1622 | __le16 subcategory_id; | ||
1623 | } __packed; | ||
1624 | |||
1625 | struct wsm_p2p_device_info { | ||
1626 | struct wsm_p2p_device_type primaryDevice; | ||
1627 | u8 reserved1[3]; | ||
1628 | u8 devname_size; | ||
1629 | u8 local_devname[D11_MAX_SSID_LEN]; | ||
1630 | u8 reserved2[3]; | ||
1631 | u8 num_secdev_supported; | ||
1632 | struct wsm_p2p_device_type secdevs[0]; | ||
1633 | } __packed; | ||
1634 | |||
1635 | /* 4.36 SetWCDMABand - WO */ | ||
1636 | struct wsm_cdma_band { | ||
1637 | u8 wcdma_band; | ||
1638 | u8 reserved[3]; | ||
1639 | } __packed; | ||
1640 | |||
1641 | /* 4.37 GroupTxSequenceCounter - RO */ | ||
1642 | struct wsm_group_tx_seq { | ||
1643 | __le32 bits_47_16; | ||
1644 | __le16 bits_15_00; | ||
1645 | __le16 reserved; | ||
1646 | } __packed; | ||
1647 | |||
1648 | /* 4.39 SetHtProtection - WO */ | ||
1649 | #define WSM_DUAL_CTS_PROT_ENB (1 << 0) | ||
1650 | #define WSM_NON_GREENFIELD_STA_PRESENT (1 << 1) | ||
1651 | #define WSM_HT_PROT_MODE__NO_PROT (0 << 2) | ||
1652 | #define WSM_HT_PROT_MODE__NON_MEMBER (1 << 2) | ||
1653 | #define WSM_HT_PROT_MODE__20_MHZ (2 << 2) | ||
1654 | #define WSM_HT_PROT_MODE__NON_HT_MIXED (3 << 2) | ||
1655 | #define WSM_LSIG_TXOP_PROT_FULL (1 << 4) | ||
1656 | #define WSM_LARGE_L_LENGTH_PROT (1 << 5) | ||
1657 | |||
1658 | struct wsm_ht_protection { | ||
1659 | __le32 flags; | ||
1660 | } __packed; | ||
1661 | |||
1662 | /* 4.40 GPIO Command - R/W */ | ||
1663 | #define WSM_GPIO_COMMAND_SETUP 0 | ||
1664 | #define WSM_GPIO_COMMAND_READ 1 | ||
1665 | #define WSM_GPIO_COMMAND_WRITE 2 | ||
1666 | #define WSM_GPIO_COMMAND_RESET 3 | ||
1667 | #define WSM_GPIO_ALL_PINS 0xFF | ||
1668 | |||
1669 | struct wsm_gpio_command { | ||
1670 | u8 command; | ||
1671 | u8 pin; | ||
1672 | __le16 config; | ||
1673 | } __packed; | ||
1674 | |||
1675 | /* 4.41 TSFCounter - RO */ | ||
1676 | struct wsm_tsf_counter { | ||
1677 | __le64 tsf_counter; | ||
1678 | } __packed; | ||
1679 | |||
1680 | /* 4.43 Keep alive period */ | ||
1681 | struct wsm_keep_alive_period { | ||
1682 | __le16 period; | ||
1683 | u8 reserved[2]; | ||
1684 | } __packed; | ||
1685 | |||
1686 | static inline int wsm_keep_alive_period(struct cw1200_common *priv, | ||
1687 | int period) | ||
1688 | { | ||
1689 | struct wsm_keep_alive_period arg = { | ||
1690 | .period = __cpu_to_le16(period), | ||
1691 | }; | ||
1692 | return wsm_write_mib(priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, | ||
1693 | &arg, sizeof(arg)); | ||
1694 | }; | ||
1695 | |||
1696 | /* BSSID filtering */ | ||
1697 | struct wsm_set_bssid_filtering { | ||
1698 | u8 filter; | ||
1699 | u8 reserved[3]; | ||
1700 | } __packed; | ||
1701 | |||
1702 | static inline int wsm_set_bssid_filtering(struct cw1200_common *priv, | ||
1703 | bool enabled) | ||
1704 | { | ||
1705 | struct wsm_set_bssid_filtering arg = { | ||
1706 | .filter = !enabled, | ||
1707 | }; | ||
1708 | return wsm_write_mib(priv, WSM_MIB_ID_DISABLE_BSSID_FILTER, | ||
1709 | &arg, sizeof(arg)); | ||
1710 | } | ||
1711 | |||
1712 | /* Multicast filtering - 4.5 */ | ||
1713 | struct wsm_mib_multicast_filter { | ||
1714 | __le32 enable; | ||
1715 | __le32 num_addrs; | ||
1716 | u8 macaddrs[WSM_MAX_GRP_ADDRTABLE_ENTRIES][ETH_ALEN]; | ||
1717 | } __packed; | ||
1718 | |||
1719 | static inline int wsm_set_multicast_filter(struct cw1200_common *priv, | ||
1720 | struct wsm_mib_multicast_filter *fp) | ||
1721 | { | ||
1722 | return wsm_write_mib(priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, | ||
1723 | fp, sizeof(*fp)); | ||
1724 | } | ||
1725 | |||
1726 | /* ARP IPv4 filtering - 4.10 */ | ||
1727 | struct wsm_mib_arp_ipv4_filter { | ||
1728 | __le32 enable; | ||
1729 | __be32 ipv4addrs[WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES]; | ||
1730 | } __packed; | ||
1731 | |||
1732 | static inline int wsm_set_arp_ipv4_filter(struct cw1200_common *priv, | ||
1733 | struct wsm_mib_arp_ipv4_filter *fp) | ||
1734 | { | ||
1735 | return wsm_write_mib(priv, WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE, | ||
1736 | fp, sizeof(*fp)); | ||
1737 | } | ||
1738 | |||
1739 | /* P2P Power Save Mode Info - 4.31 */ | ||
1740 | struct wsm_p2p_ps_modeinfo { | ||
1741 | u8 opp_ps_ct_window; | ||
1742 | u8 count; | ||
1743 | u8 reserved; | ||
1744 | u8 dtim_count; | ||
1745 | __le32 duration; | ||
1746 | __le32 interval; | ||
1747 | __le32 start_time; | ||
1748 | } __packed; | ||
1749 | |||
1750 | static inline int wsm_set_p2p_ps_modeinfo(struct cw1200_common *priv, | ||
1751 | struct wsm_p2p_ps_modeinfo *mi) | ||
1752 | { | ||
1753 | return wsm_write_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, | ||
1754 | mi, sizeof(*mi)); | ||
1755 | } | ||
1756 | |||
1757 | static inline int wsm_get_p2p_ps_modeinfo(struct cw1200_common *priv, | ||
1758 | struct wsm_p2p_ps_modeinfo *mi) | ||
1759 | { | ||
1760 | return wsm_read_mib(priv, WSM_MIB_ID_P2P_PS_MODE_INFO, | ||
1761 | mi, sizeof(*mi)); | ||
1762 | } | ||
1763 | |||
1764 | /* UseMultiTxConfMessage */ | ||
1765 | |||
1766 | static inline int wsm_use_multi_tx_conf(struct cw1200_common *priv, | ||
1767 | bool enabled) | ||
1768 | { | ||
1769 | __le32 arg = enabled ? __cpu_to_le32(1) : 0; | ||
1770 | |||
1771 | return wsm_write_mib(priv, WSM_MIB_USE_MULTI_TX_CONF, | ||
1772 | &arg, sizeof(arg)); | ||
1773 | } | ||
1774 | |||
1775 | |||
1776 | /* 4.26 SetUpasdInformation */ | ||
1777 | struct wsm_uapsd_info { | ||
1778 | __le16 uapsd_flags; | ||
1779 | __le16 min_auto_trigger_interval; | ||
1780 | __le16 max_auto_trigger_interval; | ||
1781 | __le16 auto_trigger_step; | ||
1782 | }; | ||
1783 | |||
1784 | static inline int wsm_set_uapsd_info(struct cw1200_common *priv, | ||
1785 | struct wsm_uapsd_info *arg) | ||
1786 | { | ||
1787 | return wsm_write_mib(priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, | ||
1788 | arg, sizeof(*arg)); | ||
1789 | } | ||
1790 | |||
1791 | /* 4.22 OverrideInternalTxRate */ | ||
1792 | struct wsm_override_internal_txrate { | ||
1793 | u8 internalTxRate; | ||
1794 | u8 nonErpInternalTxRate; | ||
1795 | u8 reserved[2]; | ||
1796 | } __packed; | ||
1797 | |||
1798 | static inline int wsm_set_override_internal_txrate(struct cw1200_common *priv, | ||
1799 | struct wsm_override_internal_txrate *arg) | ||
1800 | { | ||
1801 | return wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, | ||
1802 | arg, sizeof(*arg)); | ||
1803 | } | ||
1804 | |||
1805 | /* ******************************************************************** */ | ||
1806 | /* WSM TX port control */ | ||
1807 | |||
1808 | void wsm_lock_tx(struct cw1200_common *priv); | ||
1809 | void wsm_lock_tx_async(struct cw1200_common *priv); | ||
1810 | bool wsm_flush_tx(struct cw1200_common *priv); | ||
1811 | void wsm_unlock_tx(struct cw1200_common *priv); | ||
1812 | |||
1813 | /* ******************************************************************** */ | ||
1814 | /* WSM / BH API */ | ||
1815 | |||
1816 | int wsm_handle_exception(struct cw1200_common *priv, u8 *data, size_t len); | ||
1817 | int wsm_handle_rx(struct cw1200_common *priv, u16 id, struct wsm_hdr *wsm, | ||
1818 | struct sk_buff **skb_p); | ||
1819 | |||
1820 | /* ******************************************************************** */ | ||
1821 | /* wsm_buf API */ | ||
1822 | |||
1823 | struct wsm_buf { | ||
1824 | u8 *begin; | ||
1825 | u8 *data; | ||
1826 | u8 *end; | ||
1827 | }; | ||
1828 | |||
1829 | void wsm_buf_init(struct wsm_buf *buf); | ||
1830 | void wsm_buf_deinit(struct wsm_buf *buf); | ||
1831 | |||
1832 | /* ******************************************************************** */ | ||
1833 | /* wsm_cmd API */ | ||
1834 | |||
1835 | struct wsm_cmd { | ||
1836 | spinlock_t lock; /* Protect structure from multiple access */ | ||
1837 | int done; | ||
1838 | u8 *ptr; | ||
1839 | size_t len; | ||
1840 | void *arg; | ||
1841 | int ret; | ||
1842 | u16 cmd; | ||
1843 | }; | ||
1844 | |||
1845 | /* ******************************************************************** */ | ||
1846 | /* WSM TX buffer access */ | ||
1847 | |||
1848 | int wsm_get_tx(struct cw1200_common *priv, u8 **data, | ||
1849 | size_t *tx_len, int *burst); | ||
1850 | void wsm_txed(struct cw1200_common *priv, u8 *data); | ||
1851 | |||
1852 | /* ******************************************************************** */ | ||
1853 | /* Queue mapping: WSM <---> linux */ | ||
1854 | /* Linux: VO VI BE BK */ | ||
1855 | /* WSM: BE BK VI VO */ | ||
1856 | |||
1857 | static inline u8 wsm_queue_id_to_linux(u8 queue_id) | ||
1858 | { | ||
1859 | static const u8 queue_mapping[] = { | ||
1860 | 2, 3, 1, 0 | ||
1861 | }; | ||
1862 | return queue_mapping[queue_id]; | ||
1863 | } | ||
1864 | |||
1865 | static inline u8 wsm_queue_id_to_wsm(u8 queue_id) | ||
1866 | { | ||
1867 | static const u8 queue_mapping[] = { | ||
1868 | 3, 2, 0, 1 | ||
1869 | }; | ||
1870 | return queue_mapping[queue_id]; | ||
1871 | } | ||
1872 | |||
1873 | #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/iwlegacy/commands.h b/drivers/net/wireless/iwlegacy/commands.h index 3b6c99400892..048421511988 100644 --- a/drivers/net/wireless/iwlegacy/commands.h +++ b/drivers/net/wireless/iwlegacy/commands.h | |||
@@ -1348,14 +1348,6 @@ struct il_rx_mpdu_res_start { | |||
1348 | #define TX_CMD_SEC_KEY128 0x08 | 1348 | #define TX_CMD_SEC_KEY128 0x08 |
1349 | 1349 | ||
1350 | /* | 1350 | /* |
1351 | * security overhead sizes | ||
1352 | */ | ||
1353 | #define WEP_IV_LEN 4 | ||
1354 | #define WEP_ICV_LEN 4 | ||
1355 | #define CCMP_MIC_LEN 8 | ||
1356 | #define TKIP_ICV_LEN 4 | ||
1357 | |||
1358 | /* | ||
1359 | * C_TX = 0x1c (command) | 1351 | * C_TX = 0x1c (command) |
1360 | */ | 1352 | */ |
1361 | 1353 | ||
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 95ca026ecc9d..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; |
@@ -1225,14 +1221,6 @@ struct iwl_rx_mpdu_res_start { | |||
1225 | #define TX_CMD_SEC_KEY128 0x08 | 1221 | #define TX_CMD_SEC_KEY128 0x08 |
1226 | 1222 | ||
1227 | /* | 1223 | /* |
1228 | * security overhead sizes | ||
1229 | */ | ||
1230 | #define WEP_IV_LEN 4 | ||
1231 | #define WEP_ICV_LEN 4 | ||
1232 | #define CCMP_MIC_LEN 8 | ||
1233 | #define TKIP_ICV_LEN 4 | ||
1234 | |||
1235 | /* | ||
1236 | * REPLY_TX = 0x1c (command) | 1224 | * REPLY_TX = 0x1c (command) |
1237 | */ | 1225 | */ |
1238 | 1226 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 71ea77576d22..f1b8df16dbba 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 cab23af0be9e..c0039a992909 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -426,7 +426,11 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | |||
426 | if (ret) | 426 | if (ret) |
427 | goto error; | 427 | goto error; |
428 | 428 | ||
429 | iwl_trans_d3_suspend(priv->trans); | 429 | /* let the ucode operate on its own */ |
430 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, | ||
431 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
432 | |||
433 | iwl_trans_d3_suspend(priv->trans, false); | ||
430 | 434 | ||
431 | goto out; | 435 | goto out; |
432 | 436 | ||
@@ -500,7 +504,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
500 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ | 504 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ |
501 | vif = ctx->vif; | 505 | vif = ctx->vif; |
502 | 506 | ||
503 | ret = iwl_trans_d3_resume(priv->trans, &d3_status); | 507 | ret = iwl_trans_d3_resume(priv->trans, &d3_status, false); |
504 | if (ret) | 508 | if (ret) |
505 | goto out_unlock; | 509 | goto out_unlock; |
506 | 510 | ||
@@ -509,6 +513,10 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
509 | goto out_unlock; | 513 | goto out_unlock; |
510 | } | 514 | } |
511 | 515 | ||
516 | /* uCode is no longer operating by itself */ | ||
517 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, | ||
518 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | ||
519 | |||
512 | base = priv->device_pointers.error_event_table; | 520 | base = priv->device_pointers.error_event_table; |
513 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { | 521 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { |
514 | IWL_WARN(priv, "Invalid error table during resume!\n"); | 522 | IWL_WARN(priv, "Invalid error table during resume!\n"); |
@@ -1276,8 +1284,8 @@ static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, | |||
1276 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 1284 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
1277 | mutex_lock(&priv->mutex); | 1285 | mutex_lock(&priv->mutex); |
1278 | 1286 | ||
1279 | if (priv->cfg->bt_params && | 1287 | if (priv->lib->bt_params && |
1280 | priv->cfg->bt_params->advanced_bt_coexist) { | 1288 | priv->lib->bt_params->advanced_bt_coexist) { |
1281 | if (rssi_event == RSSI_EVENT_LOW) | 1289 | if (rssi_event == RSSI_EVENT_LOW) |
1282 | priv->bt_enable_pspoll = true; | 1290 | priv->bt_enable_pspoll = true; |
1283 | else if (rssi_event == RSSI_EVENT_HIGH) | 1291 | else if (rssi_event == RSSI_EVENT_HIGH) |
@@ -1387,7 +1395,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, | |||
1387 | return err; | 1395 | return err; |
1388 | } | 1396 | } |
1389 | 1397 | ||
1390 | if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && | 1398 | if (priv->lib->bt_params && priv->lib->bt_params->advanced_bt_coexist && |
1391 | vif->type == NL80211_IFTYPE_ADHOC) { | 1399 | vif->type == NL80211_IFTYPE_ADHOC) { |
1392 | /* | 1400 | /* |
1393 | * pretend to have high BT traffic as long as we | 1401 | * 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/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..be4b2ac3dbbf 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 |
@@ -427,8 +428,9 @@ struct iwl_trans_ops { | |||
427 | void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); | 428 | void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); |
428 | void (*stop_device)(struct iwl_trans *trans); | 429 | void (*stop_device)(struct iwl_trans *trans); |
429 | 430 | ||
430 | void (*d3_suspend)(struct iwl_trans *trans); | 431 | void (*d3_suspend)(struct iwl_trans *trans, bool test); |
431 | int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status); | 432 | int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, |
433 | bool test); | ||
432 | 434 | ||
433 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); | 435 | int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); |
434 | 436 | ||
@@ -455,7 +457,7 @@ struct iwl_trans_ops { | |||
455 | int (*read_mem)(struct iwl_trans *trans, u32 addr, | 457 | int (*read_mem)(struct iwl_trans *trans, u32 addr, |
456 | void *buf, int dwords); | 458 | void *buf, int dwords); |
457 | int (*write_mem)(struct iwl_trans *trans, u32 addr, | 459 | int (*write_mem)(struct iwl_trans *trans, u32 addr, |
458 | void *buf, int dwords); | 460 | const void *buf, int dwords); |
459 | void (*configure)(struct iwl_trans *trans, | 461 | void (*configure)(struct iwl_trans *trans, |
460 | const struct iwl_trans_config *trans_cfg); | 462 | const struct iwl_trans_config *trans_cfg); |
461 | void (*set_pmi)(struct iwl_trans *trans, bool state); | 463 | void (*set_pmi)(struct iwl_trans *trans, bool state); |
@@ -587,17 +589,18 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans) | |||
587 | trans->state = IWL_TRANS_NO_FW; | 589 | trans->state = IWL_TRANS_NO_FW; |
588 | } | 590 | } |
589 | 591 | ||
590 | static inline void iwl_trans_d3_suspend(struct iwl_trans *trans) | 592 | static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) |
591 | { | 593 | { |
592 | might_sleep(); | 594 | might_sleep(); |
593 | trans->ops->d3_suspend(trans); | 595 | trans->ops->d3_suspend(trans, test); |
594 | } | 596 | } |
595 | 597 | ||
596 | static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | 598 | static inline int iwl_trans_d3_resume(struct iwl_trans *trans, |
597 | enum iwl_d3_status *status) | 599 | enum iwl_d3_status *status, |
600 | bool test) | ||
598 | { | 601 | { |
599 | might_sleep(); | 602 | might_sleep(); |
600 | return trans->ops->d3_resume(trans, status); | 603 | return trans->ops->d3_resume(trans, status, test); |
601 | } | 604 | } |
602 | 605 | ||
603 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 606 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
@@ -761,7 +764,7 @@ static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr) | |||
761 | } | 764 | } |
762 | 765 | ||
763 | static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, | 766 | static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, |
764 | void *buf, int dwords) | 767 | const void *buf, int dwords) |
765 | { | 768 | { |
766 | return trans->ops->write_mem(trans, addr, buf, dwords); | 769 | return trans->ops->write_mem(trans, addr, buf, dwords); |
767 | } | 770 | } |
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..9a4d94a1f90d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c | |||
@@ -174,7 +174,7 @@ static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = { | |||
174 | static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = { | 174 | static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = { |
175 | cpu_to_le32(0xaaaaaaaa), | 175 | cpu_to_le32(0xaaaaaaaa), |
176 | cpu_to_le32(0xaaaaaaaa), | 176 | cpu_to_le32(0xaaaaaaaa), |
177 | cpu_to_le32(0xaeaaaaaa), | 177 | cpu_to_le32(0xaaaaaaaa), |
178 | cpu_to_le32(0xaaaaaaaa), | 178 | cpu_to_le32(0xaaaaaaaa), |
179 | cpu_to_le32(0xcc00ff28), | 179 | cpu_to_le32(0xcc00ff28), |
180 | cpu_to_le32(0x0000aaaa), | 180 | cpu_to_le32(0x0000aaaa), |
@@ -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..7a2ef3f013fd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | #include <linux/etherdevice.h> | 64 | #include <linux/etherdevice.h> |
65 | #include <linux/ip.h> | 65 | #include <linux/ip.h> |
66 | #include <linux/fs.h> | ||
66 | #include <net/cfg80211.h> | 67 | #include <net/cfg80211.h> |
67 | #include <net/ipv6.h> | 68 | #include <net/ipv6.h> |
68 | #include <net/tcp.h> | 69 | #include <net/tcp.h> |
@@ -756,7 +757,9 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
756 | return 0; | 757 | return 0; |
757 | } | 758 | } |
758 | 759 | ||
759 | int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | 760 | static int __iwl_mvm_suspend(struct ieee80211_hw *hw, |
761 | struct cfg80211_wowlan *wowlan, | ||
762 | bool test) | ||
760 | { | 763 | { |
761 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 764 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
762 | struct iwl_d3_iter_data suspend_iter_data = { | 765 | struct iwl_d3_iter_data suspend_iter_data = { |
@@ -769,7 +772,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
769 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | 772 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; |
770 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; | 773 | struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; |
771 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; | 774 | struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; |
772 | struct iwl_d3_manager_config d3_cfg_cmd = { | 775 | struct iwl_d3_manager_config d3_cfg_cmd_data = { |
773 | /* | 776 | /* |
774 | * Program the minimum sleep time to 10 seconds, as many | 777 | * Program the minimum sleep time to 10 seconds, as many |
775 | * platforms have issues processing a wakeup signal while | 778 | * platforms have issues processing a wakeup signal while |
@@ -777,17 +780,30 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
777 | */ | 780 | */ |
778 | .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), | 781 | .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), |
779 | }; | 782 | }; |
783 | struct iwl_host_cmd d3_cfg_cmd = { | ||
784 | .id = D3_CONFIG_CMD, | ||
785 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
786 | .data[0] = &d3_cfg_cmd_data, | ||
787 | .len[0] = sizeof(d3_cfg_cmd_data), | ||
788 | }; | ||
780 | struct wowlan_key_data key_data = { | 789 | struct wowlan_key_data key_data = { |
781 | .use_rsc_tsc = false, | 790 | .use_rsc_tsc = false, |
782 | .tkip = &tkip_cmd, | 791 | .tkip = &tkip_cmd, |
783 | .use_tkip = false, | 792 | .use_tkip = false, |
784 | }; | 793 | }; |
785 | int ret, i; | 794 | int ret, i; |
795 | int len __maybe_unused; | ||
786 | u16 seq; | 796 | u16 seq; |
787 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; | 797 | u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT; |
788 | 798 | ||
789 | if (WARN_ON(!wowlan)) | 799 | if (!wowlan) { |
800 | /* | ||
801 | * mac80211 shouldn't get here, but for D3 test | ||
802 | * it doesn't warrant a warning | ||
803 | */ | ||
804 | WARN_ON(!test); | ||
790 | return -EINVAL; | 805 | return -EINVAL; |
806 | } | ||
791 | 807 | ||
792 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); | 808 | key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL); |
793 | if (!key_data.rsc_tsc) | 809 | if (!key_data.rsc_tsc) |
@@ -1007,15 +1023,31 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1007 | if (ret) | 1023 | if (ret) |
1008 | goto out; | 1024 | goto out; |
1009 | 1025 | ||
1026 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
1027 | if (ret) | ||
1028 | goto out; | ||
1029 | |||
1010 | /* must be last -- this switches firmware state */ | 1030 | /* must be last -- this switches firmware state */ |
1011 | ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC, | 1031 | ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); |
1012 | sizeof(d3_cfg_cmd), &d3_cfg_cmd); | ||
1013 | if (ret) | 1032 | if (ret) |
1014 | goto out; | 1033 | goto out; |
1034 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1035 | len = le32_to_cpu(d3_cfg_cmd.resp_pkt->len_n_flags) & | ||
1036 | FH_RSCSR_FRAME_SIZE_MSK; | ||
1037 | if (len >= sizeof(u32) * 2) { | ||
1038 | mvm->d3_test_pme_ptr = | ||
1039 | le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); | ||
1040 | } else if (test) { | ||
1041 | /* in test mode we require the pointer */ | ||
1042 | ret = -EIO; | ||
1043 | goto out; | ||
1044 | } | ||
1045 | #endif | ||
1046 | iwl_free_resp(&d3_cfg_cmd); | ||
1015 | 1047 | ||
1016 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1048 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
1017 | 1049 | ||
1018 | iwl_trans_d3_suspend(mvm->trans); | 1050 | iwl_trans_d3_suspend(mvm->trans, test); |
1019 | out: | 1051 | out: |
1020 | mvm->aux_sta.sta_id = old_aux_sta_id; | 1052 | mvm->aux_sta.sta_id = old_aux_sta_id; |
1021 | mvm_ap_sta->sta_id = old_ap_sta_id; | 1053 | mvm_ap_sta->sta_id = old_ap_sta_id; |
@@ -1030,6 +1062,11 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1030 | return ret; | 1062 | return ret; |
1031 | } | 1063 | } |
1032 | 1064 | ||
1065 | int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | ||
1066 | { | ||
1067 | return __iwl_mvm_suspend(hw, wowlan, false); | ||
1068 | } | ||
1069 | |||
1033 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | 1070 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, |
1034 | struct ieee80211_vif *vif) | 1071 | struct ieee80211_vif *vif) |
1035 | { | 1072 | { |
@@ -1214,9 +1251,28 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | |||
1214 | iwl_free_resp(&cmd); | 1251 | iwl_free_resp(&cmd); |
1215 | } | 1252 | } |
1216 | 1253 | ||
1217 | int iwl_mvm_resume(struct ieee80211_hw *hw) | 1254 | static void iwl_mvm_read_d3_sram(struct iwl_mvm *mvm) |
1255 | { | ||
1256 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1257 | const struct fw_img *img = &mvm->fw->img[IWL_UCODE_WOWLAN]; | ||
1258 | u32 len = img->sec[IWL_UCODE_SECTION_DATA].len; | ||
1259 | u32 offs = img->sec[IWL_UCODE_SECTION_DATA].offset; | ||
1260 | |||
1261 | if (!mvm->store_d3_resume_sram) | ||
1262 | return; | ||
1263 | |||
1264 | if (!mvm->d3_resume_sram) { | ||
1265 | mvm->d3_resume_sram = kzalloc(len, GFP_KERNEL); | ||
1266 | if (!mvm->d3_resume_sram) | ||
1267 | return; | ||
1268 | } | ||
1269 | |||
1270 | iwl_trans_read_mem_bytes(mvm->trans, offs, mvm->d3_resume_sram, len); | ||
1271 | #endif | ||
1272 | } | ||
1273 | |||
1274 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | ||
1218 | { | 1275 | { |
1219 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1220 | struct iwl_d3_iter_data resume_iter_data = { | 1276 | struct iwl_d3_iter_data resume_iter_data = { |
1221 | .mvm = mvm, | 1277 | .mvm = mvm, |
1222 | }; | 1278 | }; |
@@ -1236,7 +1292,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
1236 | 1292 | ||
1237 | vif = resume_iter_data.vif; | 1293 | vif = resume_iter_data.vif; |
1238 | 1294 | ||
1239 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status); | 1295 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); |
1240 | if (ret) | 1296 | if (ret) |
1241 | goto out_unlock; | 1297 | goto out_unlock; |
1242 | 1298 | ||
@@ -1245,12 +1301,15 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
1245 | goto out_unlock; | 1301 | goto out_unlock; |
1246 | } | 1302 | } |
1247 | 1303 | ||
1304 | /* query SRAM first in case we want event logging */ | ||
1305 | iwl_mvm_read_d3_sram(mvm); | ||
1306 | |||
1248 | iwl_mvm_query_wakeup_reasons(mvm, vif); | 1307 | iwl_mvm_query_wakeup_reasons(mvm, vif); |
1249 | 1308 | ||
1250 | out_unlock: | 1309 | out_unlock: |
1251 | mutex_unlock(&mvm->mutex); | 1310 | mutex_unlock(&mvm->mutex); |
1252 | 1311 | ||
1253 | if (vif) | 1312 | if (!test && vif) |
1254 | ieee80211_resume_disconnect(vif); | 1313 | ieee80211_resume_disconnect(vif); |
1255 | 1314 | ||
1256 | /* return 1 to reconfigure the device */ | 1315 | /* return 1 to reconfigure the device */ |
@@ -1258,9 +1317,106 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
1258 | return 1; | 1317 | return 1; |
1259 | } | 1318 | } |
1260 | 1319 | ||
1320 | int iwl_mvm_resume(struct ieee80211_hw *hw) | ||
1321 | { | ||
1322 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
1323 | |||
1324 | return __iwl_mvm_resume(mvm, false); | ||
1325 | } | ||
1326 | |||
1261 | void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) | 1327 | void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) |
1262 | { | 1328 | { |
1263 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1329 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1264 | 1330 | ||
1265 | device_set_wakeup_enable(mvm->trans->dev, enabled); | 1331 | device_set_wakeup_enable(mvm->trans->dev, enabled); |
1266 | } | 1332 | } |
1333 | |||
1334 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
1335 | static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) | ||
1336 | { | ||
1337 | struct iwl_mvm *mvm = inode->i_private; | ||
1338 | int err; | ||
1339 | |||
1340 | if (mvm->d3_test_active) | ||
1341 | return -EBUSY; | ||
1342 | |||
1343 | file->private_data = inode->i_private; | ||
1344 | |||
1345 | ieee80211_stop_queues(mvm->hw); | ||
1346 | synchronize_net(); | ||
1347 | |||
1348 | /* start pseudo D3 */ | ||
1349 | rtnl_lock(); | ||
1350 | err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); | ||
1351 | rtnl_unlock(); | ||
1352 | if (err > 0) | ||
1353 | err = -EINVAL; | ||
1354 | if (err) { | ||
1355 | ieee80211_wake_queues(mvm->hw); | ||
1356 | return err; | ||
1357 | } | ||
1358 | mvm->d3_test_active = true; | ||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, | ||
1363 | size_t count, loff_t *ppos) | ||
1364 | { | ||
1365 | struct iwl_mvm *mvm = file->private_data; | ||
1366 | u32 pme_asserted; | ||
1367 | |||
1368 | while (true) { | ||
1369 | pme_asserted = iwl_trans_read_mem32(mvm->trans, | ||
1370 | mvm->d3_test_pme_ptr); | ||
1371 | if (pme_asserted) | ||
1372 | break; | ||
1373 | if (msleep_interruptible(100)) | ||
1374 | break; | ||
1375 | } | ||
1376 | |||
1377 | return 0; | ||
1378 | } | ||
1379 | |||
1380 | static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, | ||
1381 | struct ieee80211_vif *vif) | ||
1382 | { | ||
1383 | if (vif->type == NL80211_IFTYPE_STATION) | ||
1384 | ieee80211_connection_loss(vif); | ||
1385 | } | ||
1386 | |||
1387 | static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) | ||
1388 | { | ||
1389 | struct iwl_mvm *mvm = inode->i_private; | ||
1390 | int remaining_time = 10; | ||
1391 | |||
1392 | mvm->d3_test_active = false; | ||
1393 | __iwl_mvm_resume(mvm, true); | ||
1394 | iwl_abort_notification_waits(&mvm->notif_wait); | ||
1395 | ieee80211_restart_hw(mvm->hw); | ||
1396 | |||
1397 | /* wait for restart and disconnect all interfaces */ | ||
1398 | while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && | ||
1399 | remaining_time > 0) { | ||
1400 | remaining_time--; | ||
1401 | msleep(1000); | ||
1402 | } | ||
1403 | |||
1404 | if (remaining_time == 0) | ||
1405 | IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n"); | ||
1406 | |||
1407 | ieee80211_iterate_active_interfaces_atomic( | ||
1408 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
1409 | iwl_mvm_d3_test_disconn_work_iter, NULL); | ||
1410 | |||
1411 | ieee80211_wake_queues(mvm->hw); | ||
1412 | |||
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | const struct file_operations iwl_dbgfs_d3_test_ops = { | ||
1417 | .llseek = no_llseek, | ||
1418 | .open = iwl_mvm_d3_test_open, | ||
1419 | .read = iwl_mvm_d3_test_read, | ||
1420 | .release = iwl_mvm_d3_test_release, | ||
1421 | }; | ||
1422 | #endif | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 2053dccefcd6..b7643c16201f 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,10 @@ 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 | MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); | ||
942 | #endif | ||
545 | 943 | ||
546 | /* | 944 | /* |
547 | * Create a symlink with mac80211. It will be removed when mac80211 | 945 | * Create a symlink with mac80211. It will be removed when mac80211 |
@@ -577,9 +975,19 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
577 | return; | 975 | return; |
578 | } | 976 | } |
579 | 977 | ||
978 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && | ||
979 | vif->type == NL80211_IFTYPE_STATION && !vif->p2p) | ||
980 | MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | | ||
981 | S_IRUSR); | ||
982 | |||
580 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, | 983 | MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, |
581 | S_IRUSR); | 984 | S_IRUSR); |
582 | 985 | ||
986 | if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && | ||
987 | mvmvif == mvm->bf_allowed_vif) | ||
988 | MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, | ||
989 | S_IRUSR | S_IWUSR); | ||
990 | |||
583 | /* | 991 | /* |
584 | * Create symlink for convenience pointing to interface specific | 992 | * Create symlink for convenience pointing to interface specific |
585 | * debugfs entries for the driver. For example, under | 993 | * 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-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index d68640ea41d4..98b1feb43d38 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h | |||
@@ -71,7 +71,13 @@ | |||
71 | #define MAC_INDEX_MIN_DRIVER 0 | 71 | #define MAC_INDEX_MIN_DRIVER 0 |
72 | #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX | 72 | #define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX |
73 | 73 | ||
74 | #define AC_NUM 4 /* Number of access categories */ | 74 | enum iwl_ac { |
75 | AC_BK, | ||
76 | AC_BE, | ||
77 | AC_VI, | ||
78 | AC_VO, | ||
79 | AC_NUM, | ||
80 | }; | ||
75 | 81 | ||
76 | /** | 82 | /** |
77 | * enum iwl_mac_protection_flags - MAC context flags | 83 | * enum iwl_mac_protection_flags - MAC context flags |
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 c6384555aab4..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,6 +175,8 @@ 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 | ||
@@ -938,6 +945,24 @@ struct iwl_card_state_notif { | |||
938 | } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ | 945 | } __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ |
939 | 946 | ||
940 | /** | 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 | /** | ||
941 | * struct iwl_set_calib_default_cmd - set default value for calibration. | 966 | * struct iwl_set_calib_default_cmd - set default value for calibration. |
942 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) | 967 | * ( SET_CALIB_DEFAULT_CMD = 0x8e ) |
943 | * @calib_index: the calibration to set value for | 968 | * @calib_index: the calibration to set value for |
@@ -975,4 +1000,212 @@ struct iwl_mcast_filter_cmd { | |||
975 | u8 addr_list[0]; | 1000 | u8 addr_list[0]; |
976 | } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ | 1001 | } __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ |
977 | 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 | |||
978 | #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 b2cc3d98e0f7..46c7c0507c25 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: |
@@ -362,7 +365,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
362 | break; | 365 | break; |
363 | case NL80211_IFTYPE_AP: | 366 | case NL80211_IFTYPE_AP: |
364 | iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, | 367 | iwl_trans_ac_txq_enable(mvm->trans, vif->cab_queue, |
365 | IWL_MVM_TX_FIFO_VO); | 368 | IWL_MVM_TX_FIFO_MCAST); |
366 | /* fall through */ | 369 | /* fall through */ |
367 | default: | 370 | default: |
368 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) | 371 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
@@ -550,6 +553,10 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, | |||
550 | cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); | 553 | cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); |
551 | } | 554 | } |
552 | 555 | ||
556 | /* in AP mode, the MCAST FIFO takes the EDCA params from VO */ | ||
557 | if (vif->type == NL80211_IFTYPE_AP) | ||
558 | cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST); | ||
559 | |||
553 | if (vif->bss_conf.qos) | 560 | if (vif->bss_conf.qos) |
554 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); | 561 | cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); |
555 | 562 | ||
@@ -1047,3 +1054,28 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1047 | rate); | 1054 | rate); |
1048 | return 0; | 1055 | return 0; |
1049 | } | 1056 | } |
1057 | |||
1058 | static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, | ||
1059 | struct ieee80211_vif *vif) | ||
1060 | { | ||
1061 | u16 *id = _data; | ||
1062 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1063 | |||
1064 | if (mvmvif->id == *id) | ||
1065 | ieee80211_beacon_loss(vif); | ||
1066 | } | ||
1067 | |||
1068 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | ||
1069 | struct iwl_rx_cmd_buffer *rxb, | ||
1070 | struct iwl_device_cmd *cmd) | ||
1071 | { | ||
1072 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1073 | struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data; | ||
1074 | u16 id = (u16)le32_to_cpu(missed_beacons->mac_id); | ||
1075 | |||
1076 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | ||
1077 | IEEE80211_IFACE_ITER_NORMAL, | ||
1078 | iwl_mvm_beacon_loss_iterator, | ||
1079 | &id); | ||
1080 | return 0; | ||
1081 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index a5eb8c82f16a..2ed296caeb28 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 | 580 | ||
542 | mvmvif->phy_ctxt = &mvm->phy_ctxt_roc; | 581 | mvmvif->phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); |
543 | 582 | if (!mvmvif->phy_ctxt) { | |
544 | /* | 583 | ret = -ENOSPC; |
545 | * The channel used here isn't relevant as it's | ||
546 | * going to be overwritten as part of the ROC flow. | ||
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,27 +603,17 @@ 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); |
579 | out_release: | 611 | out_release: |
580 | /* | ||
581 | * TODO: remove this temporary code. | ||
582 | * Currently MVM FW supports power management only on single MAC. | ||
583 | * Check if only one additional interface remains after releasing | ||
584 | * current one. Update power mode on the remaining interface. | ||
585 | */ | ||
586 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) | 612 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) |
587 | mvm->vif_count--; | 613 | mvm->vif_count--; |
588 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | 614 | ieee80211_iterate_active_interfaces( |
589 | mvm->vif_count); | 615 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, |
590 | if (mvm->vif_count == 1) { | 616 | iwl_mvm_power_update_iterator, mvm); |
591 | ieee80211_iterate_active_interfaces( | ||
592 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
593 | iwl_mvm_power_update_iterator, mvm); | ||
594 | } | ||
595 | iwl_mvm_mac_ctxt_release(mvm, vif); | 617 | iwl_mvm_mac_ctxt_release(mvm, vif); |
596 | out_unlock: | 618 | out_unlock: |
597 | mutex_unlock(&mvm->mutex); | 619 | mutex_unlock(&mvm->mutex); |
@@ -646,6 +668,11 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
646 | 668 | ||
647 | mutex_lock(&mvm->mutex); | 669 | mutex_lock(&mvm->mutex); |
648 | 670 | ||
671 | if (mvm->bf_allowed_vif == mvmvif) { | ||
672 | mvm->bf_allowed_vif = NULL; | ||
673 | vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; | ||
674 | } | ||
675 | |||
649 | iwl_mvm_vif_dbgfs_clean(mvm, vif); | 676 | iwl_mvm_vif_dbgfs_clean(mvm, vif); |
650 | 677 | ||
651 | /* | 678 | /* |
@@ -661,7 +688,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, | |||
661 | mvm->p2p_device_vif = NULL; | 688 | mvm->p2p_device_vif = NULL; |
662 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); | 689 | iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta); |
663 | iwl_mvm_binding_remove_vif(mvm, vif); | 690 | iwl_mvm_binding_remove_vif(mvm, vif); |
664 | iwl_mvm_phy_ctxt_remove(mvm, mvmvif->phy_ctxt); | 691 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); |
665 | mvmvif->phy_ctxt = NULL; | 692 | mvmvif->phy_ctxt = NULL; |
666 | } | 693 | } |
667 | 694 | ||
@@ -748,6 +775,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
748 | if (ret) | 775 | if (ret) |
749 | IWL_ERR(mvm, "failed to update quotas\n"); | 776 | IWL_ERR(mvm, "failed to update quotas\n"); |
750 | } | 777 | } |
778 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
779 | if (ret) | ||
780 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
751 | } else if (changes & BSS_CHANGED_DTIM_PERIOD) { | 781 | } else if (changes & BSS_CHANGED_DTIM_PERIOD) { |
752 | /* | 782 | /* |
753 | * We received a beacon _after_ association so | 783 | * We received a beacon _after_ association so |
@@ -756,19 +786,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
756 | iwl_mvm_remove_time_event(mvm, mvmvif, | 786 | iwl_mvm_remove_time_event(mvm, mvmvif, |
757 | &mvmvif->time_event_data); | 787 | &mvmvif->time_event_data); |
758 | } else if (changes & BSS_CHANGED_PS) { | 788 | } else if (changes & BSS_CHANGED_PS) { |
759 | /* | 789 | ret = iwl_mvm_power_update_mode(mvm, vif); |
760 | * TODO: remove this temporary code. | 790 | if (ret) |
761 | * Currently MVM FW supports power management only on single | 791 | IWL_ERR(mvm, "failed to update power mode\n"); |
762 | * MAC. Avoid power mode update if more than one interface | ||
763 | * is active. | ||
764 | */ | ||
765 | IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n", | ||
766 | mvm->vif_count); | ||
767 | if (mvm->vif_count == 1) { | ||
768 | ret = iwl_mvm_power_update_mode(mvm, vif); | ||
769 | if (ret) | ||
770 | IWL_ERR(mvm, "failed to update power mode\n"); | ||
771 | } | ||
772 | } | 792 | } |
773 | } | 793 | } |
774 | 794 | ||
@@ -999,9 +1019,13 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
999 | mvmvif->phy_ctxt->channel->band); | 1019 | mvmvif->phy_ctxt->channel->band); |
1000 | } else if (old_state == IEEE80211_STA_ASSOC && | 1020 | } else if (old_state == IEEE80211_STA_ASSOC && |
1001 | new_state == IEEE80211_STA_AUTHORIZED) { | 1021 | new_state == IEEE80211_STA_AUTHORIZED) { |
1022 | /* enable beacon filtering */ | ||
1023 | WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif)); | ||
1002 | ret = 0; | 1024 | ret = 0; |
1003 | } else if (old_state == IEEE80211_STA_AUTHORIZED && | 1025 | } else if (old_state == IEEE80211_STA_AUTHORIZED && |
1004 | new_state == IEEE80211_STA_ASSOC) { | 1026 | new_state == IEEE80211_STA_ASSOC) { |
1027 | /* disable beacon filtering */ | ||
1028 | WARN_ON(iwl_mvm_disable_beacon_filter(mvm, vif)); | ||
1005 | ret = 0; | 1029 | ret = 0; |
1006 | } else if (old_state == IEEE80211_STA_ASSOC && | 1030 | } else if (old_state == IEEE80211_STA_ASSOC && |
1007 | new_state == IEEE80211_STA_AUTH) { | 1031 | new_state == IEEE80211_STA_AUTH) { |
@@ -1167,29 +1191,107 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
1167 | enum ieee80211_roc_type type) | 1191 | enum ieee80211_roc_type type) |
1168 | { | 1192 | { |
1169 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1193 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1194 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1170 | struct cfg80211_chan_def chandef; | 1195 | struct cfg80211_chan_def chandef; |
1171 | int ret; | 1196 | struct iwl_mvm_phy_ctxt *phy_ctxt; |
1197 | int ret, i; | ||
1198 | |||
1199 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | ||
1200 | duration, type); | ||
1172 | 1201 | ||
1173 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { | 1202 | if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { |
1174 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); | 1203 | IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); |
1175 | return -EINVAL; | 1204 | return -EINVAL; |
1176 | } | 1205 | } |
1177 | 1206 | ||
1178 | IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, | ||
1179 | duration, type); | ||
1180 | |||
1181 | mutex_lock(&mvm->mutex); | 1207 | mutex_lock(&mvm->mutex); |
1182 | 1208 | ||
1209 | for (i = 0; i < NUM_PHY_CTX; i++) { | ||
1210 | phy_ctxt = &mvm->phy_ctxts[i]; | ||
1211 | if (phy_ctxt->ref == 0 || mvmvif->phy_ctxt == phy_ctxt) | ||
1212 | continue; | ||
1213 | |||
1214 | if (phy_ctxt->ref && channel == phy_ctxt->channel) { | ||
1215 | /* | ||
1216 | * Unbind the P2P_DEVICE from the current PHY context, | ||
1217 | * and if the PHY context is not used remove it. | ||
1218 | */ | ||
1219 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | ||
1220 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | ||
1221 | goto out_unlock; | ||
1222 | |||
1223 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | ||
1224 | |||
1225 | /* Bind the P2P_DEVICE to the current PHY Context */ | ||
1226 | mvmvif->phy_ctxt = phy_ctxt; | ||
1227 | |||
1228 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
1229 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | ||
1230 | goto out_unlock; | ||
1231 | |||
1232 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | ||
1233 | goto schedule_time_event; | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | /* Need to update the PHY context only if the ROC channel changed */ | ||
1238 | if (channel == mvmvif->phy_ctxt->channel) | ||
1239 | goto schedule_time_event; | ||
1240 | |||
1183 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); | 1241 | cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); |
1184 | ret = iwl_mvm_phy_ctxt_changed(mvm, &mvm->phy_ctxt_roc, | ||
1185 | &chandef, 1, 1); | ||
1186 | 1242 | ||
1243 | /* | ||
1244 | * Change the PHY context configuration as it is currently referenced | ||
1245 | * only by the P2P Device MAC | ||
1246 | */ | ||
1247 | if (mvmvif->phy_ctxt->ref == 1) { | ||
1248 | ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, | ||
1249 | &chandef, 1, 1); | ||
1250 | if (ret) | ||
1251 | goto out_unlock; | ||
1252 | } else { | ||
1253 | /* | ||
1254 | * The PHY context is shared with other MACs. Need to remove the | ||
1255 | * P2P Device from the binding, allocate an new PHY context and | ||
1256 | * create a new binding | ||
1257 | */ | ||
1258 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | ||
1259 | if (!phy_ctxt) { | ||
1260 | ret = -ENOSPC; | ||
1261 | goto out_unlock; | ||
1262 | } | ||
1263 | |||
1264 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chandef, | ||
1265 | 1, 1); | ||
1266 | if (ret) { | ||
1267 | IWL_ERR(mvm, "Failed to change PHY context\n"); | ||
1268 | goto out_unlock; | ||
1269 | } | ||
1270 | |||
1271 | /* Unbind the P2P_DEVICE from the current PHY context */ | ||
1272 | ret = iwl_mvm_binding_remove_vif(mvm, vif); | ||
1273 | if (WARN(ret, "Failed unbinding P2P_DEVICE\n")) | ||
1274 | goto out_unlock; | ||
1275 | |||
1276 | iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); | ||
1277 | |||
1278 | /* Bind the P2P_DEVICE to the new allocated PHY context */ | ||
1279 | mvmvif->phy_ctxt = phy_ctxt; | ||
1280 | |||
1281 | ret = iwl_mvm_binding_add_vif(mvm, vif); | ||
1282 | if (WARN(ret, "Failed binding P2P_DEVICE\n")) | ||
1283 | goto out_unlock; | ||
1284 | |||
1285 | iwl_mvm_phy_ctxt_ref(mvm, mvmvif->phy_ctxt); | ||
1286 | } | ||
1287 | |||
1288 | schedule_time_event: | ||
1187 | /* Schedule the time events */ | 1289 | /* Schedule the time events */ |
1188 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); | 1290 | ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type); |
1189 | 1291 | ||
1292 | out_unlock: | ||
1190 | mutex_unlock(&mvm->mutex); | 1293 | mutex_unlock(&mvm->mutex); |
1191 | IWL_DEBUG_MAC80211(mvm, "leave\n"); | 1294 | IWL_DEBUG_MAC80211(mvm, "leave\n"); |
1192 | |||
1193 | return ret; | 1295 | return ret; |
1194 | } | 1296 | } |
1195 | 1297 | ||
@@ -1211,15 +1313,30 @@ static int iwl_mvm_add_chanctx(struct ieee80211_hw *hw, | |||
1211 | struct ieee80211_chanctx_conf *ctx) | 1313 | struct ieee80211_chanctx_conf *ctx) |
1212 | { | 1314 | { |
1213 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1315 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1214 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1316 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1317 | struct iwl_mvm_phy_ctxt *phy_ctxt; | ||
1215 | int ret; | 1318 | int ret; |
1216 | 1319 | ||
1320 | IWL_DEBUG_MAC80211(mvm, "Add channel context\n"); | ||
1321 | |||
1217 | mutex_lock(&mvm->mutex); | 1322 | mutex_lock(&mvm->mutex); |
1323 | phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); | ||
1324 | if (!phy_ctxt) { | ||
1325 | ret = -ENOSPC; | ||
1326 | goto out; | ||
1327 | } | ||
1218 | 1328 | ||
1219 | IWL_DEBUG_MAC80211(mvm, "Add PHY context\n"); | 1329 | ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, |
1220 | ret = iwl_mvm_phy_ctxt_add(mvm, phy_ctxt, &ctx->def, | 1330 | ctx->rx_chains_static, |
1221 | ctx->rx_chains_static, | 1331 | ctx->rx_chains_dynamic); |
1222 | ctx->rx_chains_dynamic); | 1332 | if (ret) { |
1333 | IWL_ERR(mvm, "Failed to add PHY context\n"); | ||
1334 | goto out; | ||
1335 | } | ||
1336 | |||
1337 | iwl_mvm_phy_ctxt_ref(mvm, phy_ctxt); | ||
1338 | *phy_ctxt_id = phy_ctxt->id; | ||
1339 | out: | ||
1223 | mutex_unlock(&mvm->mutex); | 1340 | mutex_unlock(&mvm->mutex); |
1224 | return ret; | 1341 | return ret; |
1225 | } | 1342 | } |
@@ -1228,10 +1345,11 @@ static void iwl_mvm_remove_chanctx(struct ieee80211_hw *hw, | |||
1228 | struct ieee80211_chanctx_conf *ctx) | 1345 | struct ieee80211_chanctx_conf *ctx) |
1229 | { | 1346 | { |
1230 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1347 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1231 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1348 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1349 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1232 | 1350 | ||
1233 | mutex_lock(&mvm->mutex); | 1351 | mutex_lock(&mvm->mutex); |
1234 | iwl_mvm_phy_ctxt_remove(mvm, phy_ctxt); | 1352 | iwl_mvm_phy_ctxt_unref(mvm, phy_ctxt); |
1235 | mutex_unlock(&mvm->mutex); | 1353 | mutex_unlock(&mvm->mutex); |
1236 | } | 1354 | } |
1237 | 1355 | ||
@@ -1240,7 +1358,16 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, | |||
1240 | u32 changed) | 1358 | u32 changed) |
1241 | { | 1359 | { |
1242 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1360 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1243 | struct iwl_mvm_phy_ctxt *phy_ctxt = (void *)ctx->drv_priv; | 1361 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1362 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1363 | |||
1364 | if (WARN_ONCE((phy_ctxt->ref > 1) && | ||
1365 | (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | | ||
1366 | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | | ||
1367 | IEEE80211_CHANCTX_CHANGE_RADAR)), | ||
1368 | "Cannot change PHY. Ref=%d, changed=0x%X\n", | ||
1369 | phy_ctxt->ref, changed)) | ||
1370 | return; | ||
1244 | 1371 | ||
1245 | mutex_lock(&mvm->mutex); | 1372 | mutex_lock(&mvm->mutex); |
1246 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, | 1373 | iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx->def, |
@@ -1254,13 +1381,14 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
1254 | struct ieee80211_chanctx_conf *ctx) | 1381 | struct ieee80211_chanctx_conf *ctx) |
1255 | { | 1382 | { |
1256 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 1383 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
1257 | struct iwl_mvm_phy_ctxt *phyctx = (void *)ctx->drv_priv; | 1384 | u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; |
1385 | struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; | ||
1258 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 1386 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
1259 | int ret; | 1387 | int ret; |
1260 | 1388 | ||
1261 | mutex_lock(&mvm->mutex); | 1389 | mutex_lock(&mvm->mutex); |
1262 | 1390 | ||
1263 | mvmvif->phy_ctxt = phyctx; | 1391 | mvmvif->phy_ctxt = phy_ctxt; |
1264 | 1392 | ||
1265 | switch (vif->type) { | 1393 | switch (vif->type) { |
1266 | case NL80211_IFTYPE_AP: | 1394 | case NL80211_IFTYPE_AP: |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 9f46b23801bc..4e10aae71038 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -88,6 +88,7 @@ enum iwl_mvm_tx_fifo { | |||
88 | IWL_MVM_TX_FIFO_BE, | 88 | IWL_MVM_TX_FIFO_BE, |
89 | IWL_MVM_TX_FIFO_VI, | 89 | IWL_MVM_TX_FIFO_VI, |
90 | IWL_MVM_TX_FIFO_VO, | 90 | IWL_MVM_TX_FIFO_VO, |
91 | IWL_MVM_TX_FIFO_MCAST = 5, | ||
91 | }; | 92 | }; |
92 | 93 | ||
93 | extern struct ieee80211_ops iwl_mvm_hw_ops; | 94 | extern struct ieee80211_ops iwl_mvm_hw_ops; |
@@ -109,6 +110,7 @@ extern struct iwl_mvm_mod_params iwlmvm_mod_params; | |||
109 | struct iwl_mvm_phy_ctxt { | 110 | struct iwl_mvm_phy_ctxt { |
110 | u16 id; | 111 | u16 id; |
111 | u16 color; | 112 | u16 color; |
113 | u32 ref; | ||
112 | 114 | ||
113 | /* | 115 | /* |
114 | * TODO: This should probably be removed. Currently here only for rate | 116 | * TODO: This should probably be removed. Currently here only for rate |
@@ -149,6 +151,60 @@ enum iwl_power_scheme { | |||
149 | 151 | ||
150 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 | 152 | #define IWL_CONN_MAX_LISTEN_INTERVAL 70 |
151 | 153 | ||
154 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
155 | enum iwl_dbgfs_pm_mask { | ||
156 | MVM_DEBUGFS_PM_KEEP_ALIVE = BIT(0), | ||
157 | MVM_DEBUGFS_PM_SKIP_OVER_DTIM = BIT(1), | ||
158 | MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS = BIT(2), | ||
159 | MVM_DEBUGFS_PM_RX_DATA_TIMEOUT = BIT(3), | ||
160 | MVM_DEBUGFS_PM_TX_DATA_TIMEOUT = BIT(4), | ||
161 | MVM_DEBUGFS_PM_DISABLE_POWER_OFF = BIT(5), | ||
162 | }; | ||
163 | |||
164 | struct iwl_dbgfs_pm { | ||
165 | u8 keep_alive_seconds; | ||
166 | u32 rx_data_timeout; | ||
167 | u32 tx_data_timeout; | ||
168 | bool skip_over_dtim; | ||
169 | u8 skip_dtim_periods; | ||
170 | bool disable_power_off; | ||
171 | int mask; | ||
172 | }; | ||
173 | |||
174 | /* beacon filtering */ | ||
175 | |||
176 | enum iwl_dbgfs_bf_mask { | ||
177 | MVM_DEBUGFS_BF_ENERGY_DELTA = BIT(0), | ||
178 | MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA = BIT(1), | ||
179 | MVM_DEBUGFS_BF_ROAMING_STATE = BIT(2), | ||
180 | MVM_DEBUGFS_BF_TEMPERATURE_DELTA = BIT(3), | ||
181 | MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER = BIT(4), | ||
182 | MVM_DEBUGFS_BF_DEBUG_FLAG = BIT(5), | ||
183 | MVM_DEBUGFS_BF_ESCAPE_TIMER = BIT(6), | ||
184 | MVM_DEBUGFS_BA_ESCAPE_TIMER = BIT(7), | ||
185 | MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT = BIT(8), | ||
186 | }; | ||
187 | |||
188 | struct iwl_dbgfs_bf { | ||
189 | u8 bf_energy_delta; | ||
190 | u8 bf_roaming_energy_delta; | ||
191 | u8 bf_roaming_state; | ||
192 | u8 bf_temperature_delta; | ||
193 | u8 bf_enable_beacon_filter; | ||
194 | u8 bf_debug_flag; | ||
195 | u32 bf_escape_timer; | ||
196 | u32 ba_escape_timer; | ||
197 | u8 ba_enable_beacon_abort; | ||
198 | int mask; | ||
199 | }; | ||
200 | #endif | ||
201 | |||
202 | enum iwl_mvm_smps_type_request { | ||
203 | IWL_MVM_SMPS_REQ_BT_COEX, | ||
204 | IWL_MVM_SMPS_REQ_TT, | ||
205 | NUM_IWL_MVM_SMPS_REQ, | ||
206 | }; | ||
207 | |||
152 | /** | 208 | /** |
153 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context | 209 | * struct iwl_mvm_vif - data per Virtual Interface, it is a MAC context |
154 | * @id: between 0 and 3 | 210 | * @id: between 0 and 3 |
@@ -163,6 +219,8 @@ enum iwl_power_scheme { | |||
163 | * @bcast_sta: station used for broadcast packets. Used by the following | 219 | * @bcast_sta: station used for broadcast packets. Used by the following |
164 | * vifs: P2P_DEVICE, GO and AP. | 220 | * vifs: P2P_DEVICE, GO and AP. |
165 | * @beacon_skb: the skb used to hold the AP/GO beacon template | 221 | * @beacon_skb: the skb used to hold the AP/GO beacon template |
222 | * @smps_requests: the requests of of differents parts of the driver, regard | ||
223 | the desired smps mode. | ||
166 | */ | 224 | */ |
167 | struct iwl_mvm_vif { | 225 | struct iwl_mvm_vif { |
168 | u16 id; | 226 | u16 id; |
@@ -172,6 +230,8 @@ struct iwl_mvm_vif { | |||
172 | bool uploaded; | 230 | bool uploaded; |
173 | bool ap_active; | 231 | bool ap_active; |
174 | bool monitor_active; | 232 | bool monitor_active; |
233 | /* indicate whether beacon filtering is enabled */ | ||
234 | bool bf_enabled; | ||
175 | 235 | ||
176 | u32 ap_beacon_time; | 236 | u32 ap_beacon_time; |
177 | 237 | ||
@@ -214,7 +274,11 @@ struct iwl_mvm_vif { | |||
214 | struct dentry *dbgfs_dir; | 274 | struct dentry *dbgfs_dir; |
215 | struct dentry *dbgfs_slink; | 275 | struct dentry *dbgfs_slink; |
216 | void *dbgfs_data; | 276 | void *dbgfs_data; |
277 | struct iwl_dbgfs_pm dbgfs_pm; | ||
278 | struct iwl_dbgfs_bf dbgfs_bf; | ||
217 | #endif | 279 | #endif |
280 | |||
281 | enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; | ||
218 | }; | 282 | }; |
219 | 283 | ||
220 | static inline struct iwl_mvm_vif * | 284 | static inline struct iwl_mvm_vif * |
@@ -223,12 +287,6 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif) | |||
223 | return (void *)vif->drv_priv; | 287 | return (void *)vif->drv_priv; |
224 | } | 288 | } |
225 | 289 | ||
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 { | 290 | enum iwl_scan_status { |
233 | IWL_MVM_SCAN_NONE, | 291 | IWL_MVM_SCAN_NONE, |
234 | IWL_MVM_SCAN_OS, | 292 | IWL_MVM_SCAN_OS, |
@@ -246,6 +304,63 @@ struct iwl_nvm_section { | |||
246 | const u8 *data; | 304 | const u8 *data; |
247 | }; | 305 | }; |
248 | 306 | ||
307 | /* | ||
308 | * Tx-backoff threshold | ||
309 | * @temperature: The threshold in Celsius | ||
310 | * @backoff: The tx-backoff in uSec | ||
311 | */ | ||
312 | struct iwl_tt_tx_backoff { | ||
313 | s32 temperature; | ||
314 | u32 backoff; | ||
315 | }; | ||
316 | |||
317 | #define TT_TX_BACKOFF_SIZE 6 | ||
318 | |||
319 | /** | ||
320 | * struct iwl_tt_params - thermal throttling parameters | ||
321 | * @ct_kill_entry: CT Kill entry threshold | ||
322 | * @ct_kill_exit: CT Kill exit threshold | ||
323 | * @ct_kill_duration: The time intervals (in uSec) in which the driver needs | ||
324 | * to checks whether to exit CT Kill. | ||
325 | * @dynamic_smps_entry: Dynamic SMPS entry threshold | ||
326 | * @dynamic_smps_exit: Dynamic SMPS exit threshold | ||
327 | * @tx_protection_entry: TX protection entry threshold | ||
328 | * @tx_protection_exit: TX protection exit threshold | ||
329 | * @tx_backoff: Array of thresholds for tx-backoff , in ascending order. | ||
330 | * @support_ct_kill: Support CT Kill? | ||
331 | * @support_dynamic_smps: Support dynamic SMPS? | ||
332 | * @support_tx_protection: Support tx protection? | ||
333 | * @support_tx_backoff: Support tx-backoff? | ||
334 | */ | ||
335 | struct iwl_tt_params { | ||
336 | s32 ct_kill_entry; | ||
337 | s32 ct_kill_exit; | ||
338 | u32 ct_kill_duration; | ||
339 | s32 dynamic_smps_entry; | ||
340 | s32 dynamic_smps_exit; | ||
341 | s32 tx_protection_entry; | ||
342 | s32 tx_protection_exit; | ||
343 | struct iwl_tt_tx_backoff tx_backoff[TT_TX_BACKOFF_SIZE]; | ||
344 | bool support_ct_kill; | ||
345 | bool support_dynamic_smps; | ||
346 | bool support_tx_protection; | ||
347 | bool support_tx_backoff; | ||
348 | }; | ||
349 | |||
350 | /** | ||
351 | * struct iwl_mvm_tt_mgnt - Thermal Throttling Management structure | ||
352 | * @ct_kill_exit: worker to exit thermal kill | ||
353 | * @dynamic_smps: Is thermal throttling enabled dynamic_smps? | ||
354 | * @tx_backoff: The current thremal throttling tx backoff in uSec. | ||
355 | * @params: Parameters to configure the thermal throttling algorithm. | ||
356 | */ | ||
357 | struct iwl_mvm_tt_mgmt { | ||
358 | struct delayed_work ct_kill_exit; | ||
359 | bool dynamic_smps; | ||
360 | u32 tx_backoff; | ||
361 | const struct iwl_tt_params *params; | ||
362 | }; | ||
363 | |||
249 | struct iwl_mvm { | 364 | struct iwl_mvm { |
250 | /* for logger access */ | 365 | /* for logger access */ |
251 | struct device *dev; | 366 | struct device *dev; |
@@ -266,6 +381,12 @@ struct iwl_mvm { | |||
266 | 381 | ||
267 | unsigned long status; | 382 | unsigned long status; |
268 | 383 | ||
384 | /* | ||
385 | * for beacon filtering - | ||
386 | * currently only one interface can be supported | ||
387 | */ | ||
388 | struct iwl_mvm_vif *bf_allowed_vif; | ||
389 | |||
269 | enum iwl_ucode_type cur_ucode; | 390 | enum iwl_ucode_type cur_ucode; |
270 | bool ucode_loaded; | 391 | bool ucode_loaded; |
271 | bool init_ucode_run; | 392 | bool init_ucode_run; |
@@ -313,7 +434,7 @@ struct iwl_mvm { | |||
313 | bool prevent_power_down_d3; | 434 | bool prevent_power_down_d3; |
314 | #endif | 435 | #endif |
315 | 436 | ||
316 | struct iwl_mvm_phy_ctxt phy_ctxt_roc; | 437 | struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX]; |
317 | 438 | ||
318 | struct list_head time_event_list; | 439 | struct list_head time_event_list; |
319 | spinlock_t time_event_lock; | 440 | spinlock_t time_event_lock; |
@@ -338,11 +459,21 @@ struct iwl_mvm { | |||
338 | 459 | ||
339 | #ifdef CONFIG_PM_SLEEP | 460 | #ifdef CONFIG_PM_SLEEP |
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 d3_test_active; | ||
464 | bool store_d3_resume_sram; | ||
465 | void *d3_resume_sram; | ||
466 | u32 d3_test_pme_ptr; | ||
467 | #endif | ||
341 | #endif | 468 | #endif |
342 | 469 | ||
343 | /* BT-Coex */ | 470 | /* BT-Coex */ |
344 | u8 bt_kill_msk; | 471 | u8 bt_kill_msk; |
345 | struct iwl_bt_coex_profile_notif last_bt_notif; | 472 | struct iwl_bt_coex_profile_notif last_bt_notif; |
473 | |||
474 | /* Thermal Throttling and CTkill */ | ||
475 | struct iwl_mvm_tt_mgmt thermal_throttle; | ||
476 | s32 temperature; /* Celsius */ | ||
346 | }; | 477 | }; |
347 | 478 | ||
348 | /* Extract MVM priv from op_mode and _hw */ | 479 | /* Extract MVM priv from op_mode and _hw */ |
@@ -352,6 +483,19 @@ struct iwl_mvm { | |||
352 | #define IWL_MAC80211_GET_MVM(_hw) \ | 483 | #define IWL_MAC80211_GET_MVM(_hw) \ |
353 | IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) | 484 | IWL_OP_MODE_GET_MVM((struct iwl_op_mode *)((_hw)->priv)) |
354 | 485 | ||
486 | enum iwl_mvm_status { | ||
487 | IWL_MVM_STATUS_HW_RFKILL, | ||
488 | IWL_MVM_STATUS_HW_CTKILL, | ||
489 | IWL_MVM_STATUS_ROC_RUNNING, | ||
490 | IWL_MVM_STATUS_IN_HW_RESTART, | ||
491 | }; | ||
492 | |||
493 | static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | ||
494 | { | ||
495 | return test_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status) || | ||
496 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
497 | } | ||
498 | |||
355 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; | 499 | extern const u8 iwl_mvm_ac_to_tx_fifo[]; |
356 | 500 | ||
357 | struct iwl_rate_info { | 501 | struct iwl_rate_info { |
@@ -443,8 +587,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, | 587 | int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, |
444 | struct cfg80211_chan_def *chandef, | 588 | struct cfg80211_chan_def *chandef, |
445 | u8 chains_static, u8 chains_dynamic); | 589 | u8 chains_static, u8 chains_dynamic); |
446 | void iwl_mvm_phy_ctxt_remove(struct iwl_mvm *mvm, | 590 | void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, |
447 | struct iwl_mvm_phy_ctxt *ctxt); | 591 | struct iwl_mvm_phy_ctxt *ctxt); |
592 | void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, | ||
593 | struct iwl_mvm_phy_ctxt *ctxt); | ||
448 | 594 | ||
449 | /* MAC (virtual interface) programming */ | 595 | /* MAC (virtual interface) programming */ |
450 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 596 | int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -459,6 +605,9 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, | |||
459 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | 605 | int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, |
460 | struct iwl_rx_cmd_buffer *rxb, | 606 | struct iwl_rx_cmd_buffer *rxb, |
461 | struct iwl_device_cmd *cmd); | 607 | struct iwl_device_cmd *cmd); |
608 | int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, | ||
609 | struct iwl_rx_cmd_buffer *rxb, | ||
610 | struct iwl_device_cmd *cmd); | ||
462 | 611 | ||
463 | /* Bindings */ | 612 | /* Bindings */ |
464 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 613 | int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
@@ -523,6 +672,7 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
523 | struct inet6_dev *idev); | 672 | struct inet6_dev *idev); |
524 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, | 673 | void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, |
525 | struct ieee80211_vif *vif, int idx); | 674 | struct ieee80211_vif *vif, int idx); |
675 | extern const struct file_operations iwl_dbgfs_d3_test_ops; | ||
526 | 676 | ||
527 | /* BT Coex */ | 677 | /* BT Coex */ |
528 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); | 678 | int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm); |
@@ -534,4 +684,36 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
534 | enum ieee80211_rssi_event rssi_event); | 684 | enum ieee80211_rssi_event rssi_event); |
535 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | 685 | void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); |
536 | 686 | ||
687 | /* beacon filtering */ | ||
688 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
689 | void | ||
690 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
691 | struct iwl_beacon_filter_cmd *cmd); | ||
692 | int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm); | ||
693 | #else | ||
694 | static inline void | ||
695 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
696 | struct iwl_beacon_filter_cmd *cmd) | ||
697 | {} | ||
698 | static inline int iwl_mvm_dbgfs_set_fw_dbg_log(struct iwl_mvm *mvm) | ||
699 | { | ||
700 | return 0; | ||
701 | } | ||
702 | #endif | ||
703 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | ||
704 | struct ieee80211_vif *vif); | ||
705 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | ||
706 | struct ieee80211_vif *vif); | ||
707 | |||
708 | /* SMPS */ | ||
709 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
710 | enum iwl_mvm_smps_type_request req_type, | ||
711 | enum ieee80211_smps_mode smps_request); | ||
712 | |||
713 | /* Thermal management and CT-kill */ | ||
714 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm); | ||
715 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm); | ||
716 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm); | ||
717 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); | ||
718 | |||
537 | #endif /* __IWL_MVM_H__ */ | 719 | #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 b29c31a41594..af79a14063a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -215,17 +215,22 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
215 | RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), | 215 | RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), |
216 | RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), | 216 | RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), |
217 | RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), | 217 | RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), |
218 | |||
219 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | ||
220 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | ||
221 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), | ||
222 | |||
218 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), | 223 | RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false), |
219 | 224 | ||
220 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), | 225 | RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), |
221 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), | 226 | RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), |
222 | 227 | ||
223 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | ||
224 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | ||
225 | |||
226 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 228 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
227 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 229 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
228 | 230 | ||
231 | RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif, | ||
232 | false), | ||
233 | |||
229 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), | 234 | RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, false), |
230 | }; | 235 | }; |
231 | #undef RX_HANDLER | 236 | #undef RX_HANDLER |
@@ -288,11 +293,14 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
288 | CMD(NET_DETECT_HOTSPOTS_CMD), | 293 | CMD(NET_DETECT_HOTSPOTS_CMD), |
289 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), | 294 | CMD(NET_DETECT_HOTSPOTS_QUERY_CMD), |
290 | CMD(CARD_STATE_NOTIFICATION), | 295 | CMD(CARD_STATE_NOTIFICATION), |
296 | CMD(MISSED_BEACONS_NOTIFICATION), | ||
291 | CMD(BT_COEX_PRIO_TABLE), | 297 | CMD(BT_COEX_PRIO_TABLE), |
292 | CMD(BT_COEX_PROT_ENV), | 298 | CMD(BT_COEX_PROT_ENV), |
293 | CMD(BT_PROFILE_NOTIFICATION), | 299 | CMD(BT_PROFILE_NOTIFICATION), |
294 | CMD(BT_CONFIG), | 300 | CMD(BT_CONFIG), |
295 | CMD(MCAST_FILTER_CMD), | 301 | CMD(MCAST_FILTER_CMD), |
302 | CMD(REPLY_BEACON_FILTERING_CMD), | ||
303 | CMD(REPLY_THERMAL_MNG_BACKOFF), | ||
296 | }; | 304 | }; |
297 | #undef CMD | 305 | #undef CMD |
298 | 306 | ||
@@ -393,10 +401,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
393 | if (err) | 401 | if (err) |
394 | goto out_free; | 402 | goto out_free; |
395 | 403 | ||
404 | iwl_mvm_tt_initialize(mvm); | ||
405 | |||
396 | mutex_lock(&mvm->mutex); | 406 | mutex_lock(&mvm->mutex); |
397 | err = iwl_run_init_mvm_ucode(mvm, true); | 407 | err = iwl_run_init_mvm_ucode(mvm, true); |
398 | mutex_unlock(&mvm->mutex); | 408 | mutex_unlock(&mvm->mutex); |
399 | if (err && !iwlmvm_mod_params.init_dbg) { | 409 | /* returns 0 if successful, 1 if success but in rfkill */ |
410 | if (err < 0 && !iwlmvm_mod_params.init_dbg) { | ||
400 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); | 411 | IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); |
401 | goto out_free; | 412 | goto out_free; |
402 | } | 413 | } |
@@ -439,10 +450,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) | |||
439 | 450 | ||
440 | iwl_mvm_leds_exit(mvm); | 451 | iwl_mvm_leds_exit(mvm); |
441 | 452 | ||
453 | iwl_mvm_tt_exit(mvm); | ||
454 | |||
442 | ieee80211_unregister_hw(mvm->hw); | 455 | ieee80211_unregister_hw(mvm->hw); |
443 | 456 | ||
444 | kfree(mvm->scan_cmd); | 457 | kfree(mvm->scan_cmd); |
445 | 458 | ||
459 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS) | ||
460 | kfree(mvm->d3_resume_sram); | ||
461 | #endif | ||
462 | |||
446 | iwl_trans_stop_hw(mvm->trans, true); | 463 | iwl_trans_stop_hw(mvm->trans, true); |
447 | 464 | ||
448 | iwl_phy_db_free(mvm->phy_db); | 465 | iwl_phy_db_free(mvm->phy_db); |
@@ -589,6 +606,16 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue) | |||
589 | ieee80211_wake_queue(mvm->hw, mq); | 606 | ieee80211_wake_queue(mvm->hw, mq); |
590 | } | 607 | } |
591 | 608 | ||
609 | void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) | ||
610 | { | ||
611 | if (state) | ||
612 | set_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
613 | else | ||
614 | clear_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | ||
615 | |||
616 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); | ||
617 | } | ||
618 | |||
592 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | 619 | static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) |
593 | { | 620 | { |
594 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 621 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
@@ -598,7 +625,7 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) | |||
598 | else | 625 | else |
599 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); | 626 | clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); |
600 | 627 | ||
601 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, state); | 628 | wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); |
602 | } | 629 | } |
603 | 630 | ||
604 | static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) | 631 | 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..a8652ddd6bed 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,28 @@ 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(!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && | ||
208 | ctxt->ref); | ||
231 | lockdep_assert_held(&mvm->mutex); | 209 | lockdep_assert_held(&mvm->mutex); |
232 | ctxt->color++; | ||
233 | 210 | ||
234 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | 211 | ctxt->channel = chandef->chan; |
235 | ieee80211_iter_chan_contexts_atomic( | 212 | ret = iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, |
236 | mvm->hw, iwl_mvm_phy_ctx_used_iter, &data); | 213 | chains_static, chains_dynamic, |
214 | FW_CTXT_ACTION_ADD, 0); | ||
237 | 215 | ||
238 | ctxt->id = find_first_zero_bit(data.used, NUM_PHY_CTX); | 216 | return ret; |
239 | if (WARN_ONCE(ctxt->id == NUM_PHY_CTX, | 217 | } |
240 | "Failed to init PHY context - no free ID!\n")) | ||
241 | return -EIO; | ||
242 | } | ||
243 | 218 | ||
244 | ctxt->channel = chandef->chan; | 219 | /* |
245 | return iwl_mvm_phy_ctxt_apply(mvm, ctxt, chandef, | 220 | * Update the number of references to the given PHY context. This is valid only |
246 | chains_static, chains_dynamic, | 221 | * in case the PHY context was already created, i.e., its reference count > 0. |
247 | FW_CTXT_ACTION_ADD, 0); | 222 | */ |
223 | void iwl_mvm_phy_ctxt_ref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) | ||
224 | { | ||
225 | lockdep_assert_held(&mvm->mutex); | ||
226 | ctxt->ref++; | ||
248 | } | 227 | } |
249 | 228 | ||
250 | /* | 229 | /* |
@@ -264,23 +243,12 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, | |||
264 | FW_CTXT_ACTION_MODIFY, 0); | 243 | FW_CTXT_ACTION_MODIFY, 0); |
265 | } | 244 | } |
266 | 245 | ||
267 | /* | 246 | 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 | { | 247 | { |
274 | struct iwl_phy_context_cmd cmd; | ||
275 | int ret; | ||
276 | |||
277 | lockdep_assert_held(&mvm->mutex); | 248 | lockdep_assert_held(&mvm->mutex); |
278 | 249 | ||
279 | iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, FW_CTXT_ACTION_REMOVE, 0); | 250 | if (WARN_ON_ONCE(!ctxt)) |
280 | ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, CMD_SYNC, | 251 | return; |
281 | sizeof(struct iwl_phy_context_cmd), | 252 | |
282 | &cmd); | 253 | ctxt->ref--; |
283 | if (ret) | ||
284 | IWL_ERR(mvm, "Failed to send PHY remove: ctxt id=%d\n", | ||
285 | ctxt->id); | ||
286 | } | 254 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index ed77e437aac4..3760a33ca3a4 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 |
@@ -115,7 +168,14 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
115 | return; | 168 | return; |
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); |
171 | if (!vif->bss_conf.assoc) | ||
172 | cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK); | ||
118 | 173 | ||
174 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
175 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
176 | mvmvif->dbgfs_pm.disable_power_off) | ||
177 | cmd->flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
178 | #endif | ||
119 | if (!vif->bss_conf.ps) | 179 | if (!vif->bss_conf.ps) |
120 | return; | 180 | return; |
121 | 181 | ||
@@ -135,8 +195,11 @@ void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
135 | 195 | ||
136 | /* Check skip over DTIM conditions */ | 196 | /* Check skip over DTIM conditions */ |
137 | if (!radar_detect && (dtimper <= 10) && | 197 | if (!radar_detect && (dtimper <= 10) && |
138 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) | 198 | (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || |
199 | mvm->cur_ucode == IWL_UCODE_WOWLAN)) { | ||
139 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | 200 | cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); |
201 | cmd->skip_dtim_periods = cpu_to_le32(3); | ||
202 | } | ||
140 | 203 | ||
141 | /* Check that keep alive period is at least 3 * DTIM */ | 204 | /* Check that keep alive period is at least 3 * DTIM */ |
142 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; | 205 | dtimper_msec = dtimper * vif->bss_conf.beacon_int; |
@@ -145,27 +208,76 @@ 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); | 208 | keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC); |
146 | cmd->keep_alive_seconds = keep_alive; | 209 | cmd->keep_alive_seconds = keep_alive; |
147 | 210 | ||
148 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 211 | if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { |
149 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | 212 | cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); |
213 | cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC); | ||
214 | } else { | ||
215 | cmd->rx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
216 | cmd->tx_data_timeout = cpu_to_le32(10 * USEC_PER_MSEC); | ||
217 | } | ||
218 | |||
219 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
220 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_KEEP_ALIVE) | ||
221 | cmd->keep_alive_seconds = mvmvif->dbgfs_pm.keep_alive_seconds; | ||
222 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_OVER_DTIM) { | ||
223 | if (mvmvif->dbgfs_pm.skip_over_dtim) | ||
224 | cmd->flags |= | ||
225 | cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
226 | else | ||
227 | cmd->flags &= | ||
228 | cpu_to_le16(~POWER_FLAGS_SKIP_OVER_DTIM_MSK); | ||
229 | } | ||
230 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_RX_DATA_TIMEOUT) | ||
231 | cmd->rx_data_timeout = | ||
232 | cpu_to_le32(mvmvif->dbgfs_pm.rx_data_timeout); | ||
233 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_TX_DATA_TIMEOUT) | ||
234 | cmd->tx_data_timeout = | ||
235 | cpu_to_le32(mvmvif->dbgfs_pm.tx_data_timeout); | ||
236 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_SKIP_DTIM_PERIODS) | ||
237 | cmd->skip_dtim_periods = | ||
238 | cpu_to_le32(mvmvif->dbgfs_pm.skip_dtim_periods); | ||
239 | #endif /* CONFIG_IWLWIFI_DEBUGFS */ | ||
150 | } | 240 | } |
151 | 241 | ||
152 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 242 | int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
153 | { | 243 | { |
244 | int ret; | ||
245 | bool ba_enable; | ||
154 | struct iwl_powertable_cmd cmd = {}; | 246 | struct iwl_powertable_cmd cmd = {}; |
155 | 247 | ||
156 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 248 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
157 | return 0; | 249 | return 0; |
158 | 250 | ||
251 | /* | ||
252 | * TODO: The following vif_count verification is temporary condition. | ||
253 | * Avoid power mode update if more than one interface is currently | ||
254 | * active. Remove this condition when FW will support power management | ||
255 | * on multiple MACs. | ||
256 | */ | ||
257 | IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", | ||
258 | mvm->vif_count); | ||
259 | if (mvm->vif_count > 1) | ||
260 | return 0; | ||
261 | |||
159 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); | 262 | iwl_mvm_power_build_cmd(mvm, vif, &cmd); |
160 | iwl_mvm_power_log(mvm, &cmd); | 263 | iwl_mvm_power_log(mvm, &cmd); |
161 | 264 | ||
162 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 265 | ret = iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, |
163 | sizeof(cmd), &cmd); | 266 | sizeof(cmd), &cmd); |
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | ba_enable = !!(cmd.flags & | ||
271 | cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); | ||
272 | |||
273 | return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); | ||
164 | } | 274 | } |
165 | 275 | ||
166 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | 276 | int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) |
167 | { | 277 | { |
168 | struct iwl_powertable_cmd cmd = {}; | 278 | struct iwl_powertable_cmd cmd = {}; |
279 | struct iwl_mvm_vif *mvmvif __maybe_unused = | ||
280 | iwl_mvm_vif_from_mac80211(vif); | ||
169 | 281 | ||
170 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | 282 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) |
171 | return 0; | 283 | return 0; |
@@ -173,8 +285,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) | 285 | if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) |
174 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); | 286 | cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); |
175 | 287 | ||
288 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
289 | if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && | ||
290 | mvmvif->dbgfs_pm.disable_power_off) | ||
291 | cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); | ||
292 | #endif | ||
176 | iwl_mvm_power_log(mvm, &cmd); | 293 | iwl_mvm_power_log(mvm, &cmd); |
177 | 294 | ||
178 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, | 295 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
179 | sizeof(cmd), &cmd); | 296 | sizeof(cmd), &cmd); |
180 | } | 297 | } |
298 | |||
299 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
300 | void | ||
301 | iwl_mvm_beacon_filter_debugfs_parameters(struct ieee80211_vif *vif, | ||
302 | struct iwl_beacon_filter_cmd *cmd) | ||
303 | { | ||
304 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
305 | struct iwl_dbgfs_bf *dbgfs_bf = &mvmvif->dbgfs_bf; | ||
306 | |||
307 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ENERGY_DELTA) | ||
308 | cmd->bf_energy_delta = dbgfs_bf->bf_energy_delta; | ||
309 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_ENERGY_DELTA) | ||
310 | cmd->bf_roaming_energy_delta = | ||
311 | dbgfs_bf->bf_roaming_energy_delta; | ||
312 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ROAMING_STATE) | ||
313 | cmd->bf_roaming_state = dbgfs_bf->bf_roaming_state; | ||
314 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_TEMPERATURE_DELTA) | ||
315 | cmd->bf_temperature_delta = dbgfs_bf->bf_temperature_delta; | ||
316 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_DEBUG_FLAG) | ||
317 | cmd->bf_debug_flag = dbgfs_bf->bf_debug_flag; | ||
318 | if (dbgfs_bf->mask & MVM_DEBUGFS_BF_ESCAPE_TIMER) | ||
319 | cmd->bf_escape_timer = cpu_to_le32(dbgfs_bf->bf_escape_timer); | ||
320 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ESCAPE_TIMER) | ||
321 | cmd->ba_escape_timer = cpu_to_le32(dbgfs_bf->ba_escape_timer); | ||
322 | if (dbgfs_bf->mask & MVM_DEBUGFS_BA_ENABLE_BEACON_ABORT) | ||
323 | cmd->ba_enable_beacon_abort = dbgfs_bf->ba_enable_beacon_abort; | ||
324 | } | ||
325 | #endif | ||
326 | |||
327 | int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, | ||
328 | struct ieee80211_vif *vif) | ||
329 | { | ||
330 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
331 | struct iwl_beacon_filter_cmd cmd = { | ||
332 | IWL_BF_CMD_CONFIG_DEFAULTS, | ||
333 | .bf_enable_beacon_filter = 1, | ||
334 | }; | ||
335 | int ret; | ||
336 | |||
337 | if (mvmvif != mvm->bf_allowed_vif || | ||
338 | vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
339 | return 0; | ||
340 | |||
341 | iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); | ||
342 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | ||
343 | |||
344 | if (!ret) | ||
345 | mvmvif->bf_enabled = true; | ||
346 | |||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, | ||
351 | struct ieee80211_vif *vif) | ||
352 | { | ||
353 | struct iwl_beacon_filter_cmd cmd = {}; | ||
354 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
355 | int ret; | ||
356 | |||
357 | if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) | ||
358 | return 0; | ||
359 | |||
360 | ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd); | ||
361 | |||
362 | if (!ret) | ||
363 | mvmvif->bf_enabled = false; | ||
364 | |||
365 | return ret; | ||
366 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index a1e3e923ea3e..29d49cf0fdb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -169,27 +169,34 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
169 | num_active_bindings++; | 169 | num_active_bindings++; |
170 | } | 170 | } |
171 | 171 | ||
172 | if (!num_active_bindings) | 172 | quota = 0; |
173 | goto send_cmd; | 173 | quota_rem = 0; |
174 | 174 | if (num_active_bindings) { | |
175 | quota = IWL_MVM_MAX_QUOTA / num_active_bindings; | 175 | quota = IWL_MVM_MAX_QUOTA / num_active_bindings; |
176 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; | 176 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; |
177 | } | ||
177 | 178 | ||
178 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 179 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
179 | if (data.n_interfaces[i] <= 0) | 180 | if (data.colors[i] < 0) |
180 | continue; | 181 | continue; |
181 | 182 | ||
182 | cmd.quotas[idx].id_and_color = | 183 | cmd.quotas[idx].id_and_color = |
183 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 184 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); |
184 | cmd.quotas[idx].quota = cpu_to_le32(quota); | 185 | |
185 | cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); | 186 | if (data.n_interfaces[i] <= 0) { |
187 | cmd.quotas[idx].quota = cpu_to_le32(0); | ||
188 | cmd.quotas[idx].max_duration = cpu_to_le32(0); | ||
189 | } else { | ||
190 | cmd.quotas[idx].quota = cpu_to_le32(quota); | ||
191 | cmd.quotas[idx].max_duration = | ||
192 | cpu_to_le32(IWL_MVM_MAX_QUOTA); | ||
193 | } | ||
186 | idx++; | 194 | idx++; |
187 | } | 195 | } |
188 | 196 | ||
189 | /* Give the remainder of the session to the first binding */ | 197 | /* Give the remainder of the session to the first binding */ |
190 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); | 198 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); |
191 | 199 | ||
192 | send_cmd: | ||
193 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | 200 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, |
194 | sizeof(cmd), &cmd); | 201 | sizeof(cmd), &cmd); |
195 | if (ret) | 202 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 55334d542e26..d6beec765d65 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -401,6 +401,17 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, | |||
401 | 401 | ||
402 | load = rs_tl_get_load(lq_data, tid); | 402 | load = rs_tl_get_load(lq_data, tid); |
403 | 403 | ||
404 | /* | ||
405 | * Don't create TX aggregation sessions when in high | ||
406 | * BT traffic, as they would just be disrupted by BT. | ||
407 | */ | ||
408 | if (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) { | ||
409 | IWL_DEBUG_COEX(mvm, "BT traffic (%d), no aggregation allowed\n", | ||
410 | BT_MBOX_MSG(&mvm->last_bt_notif, | ||
411 | 3, TRAFFIC_LOAD)); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
404 | if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { | 415 | if ((iwlwifi_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { |
405 | IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", | 416 | IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", |
406 | sta->addr, tid); | 417 | sta->addr, tid); |
@@ -1519,6 +1530,29 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1519 | u8 update_search_tbl_counter = 0; | 1530 | u8 update_search_tbl_counter = 0; |
1520 | int ret; | 1531 | int ret; |
1521 | 1532 | ||
1533 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
1534 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1535 | /* nothing */ | ||
1536 | break; | ||
1537 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1538 | /* avoid antenna B unless MIMO */ | ||
1539 | if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) | ||
1540 | tbl->action = IWL_SISO_SWITCH_MIMO2_AB; | ||
1541 | break; | ||
1542 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1543 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1544 | /* avoid antenna B and MIMO */ | ||
1545 | valid_tx_ant = | ||
1546 | first_antenna(iwl_fw_valid_tx_ant(mvm->fw)); | ||
1547 | if (tbl->action != IWL_SISO_SWITCH_ANTENNA1) | ||
1548 | tbl->action = IWL_SISO_SWITCH_ANTENNA1; | ||
1549 | break; | ||
1550 | default: | ||
1551 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1552 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1553 | break; | ||
1554 | } | ||
1555 | |||
1522 | start_action = tbl->action; | 1556 | start_action = tbl->action; |
1523 | while (1) { | 1557 | while (1) { |
1524 | lq_sta->action_counter++; | 1558 | lq_sta->action_counter++; |
@@ -1532,7 +1566,9 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm, | |||
1532 | tx_chains_num <= 2)) | 1566 | tx_chains_num <= 2)) |
1533 | break; | 1567 | break; |
1534 | 1568 | ||
1535 | if (window->success_ratio >= IWL_RS_GOOD_RATIO) | 1569 | if (window->success_ratio >= IWL_RS_GOOD_RATIO && |
1570 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, | ||
1571 | TRAFFIC_LOAD) == 0) | ||
1536 | break; | 1572 | break; |
1537 | 1573 | ||
1538 | memcpy(search_tbl, tbl, sz); | 1574 | memcpy(search_tbl, tbl, sz); |
@@ -1654,6 +1690,28 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm, | |||
1654 | u8 update_search_tbl_counter = 0; | 1690 | u8 update_search_tbl_counter = 0; |
1655 | int ret; | 1691 | int ret; |
1656 | 1692 | ||
1693 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
1694 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1695 | /* nothing */ | ||
1696 | break; | ||
1697 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1698 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1699 | /* avoid antenna B and MIMO */ | ||
1700 | if (tbl->action != IWL_MIMO2_SWITCH_SISO_A) | ||
1701 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | ||
1702 | break; | ||
1703 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1704 | /* avoid antenna B unless MIMO */ | ||
1705 | if (tbl->action == IWL_MIMO2_SWITCH_SISO_B || | ||
1706 | tbl->action == IWL_MIMO2_SWITCH_SISO_C) | ||
1707 | tbl->action = IWL_MIMO2_SWITCH_SISO_A; | ||
1708 | break; | ||
1709 | default: | ||
1710 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1711 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1712 | break; | ||
1713 | } | ||
1714 | |||
1657 | start_action = tbl->action; | 1715 | start_action = tbl->action; |
1658 | while (1) { | 1716 | while (1) { |
1659 | lq_sta->action_counter++; | 1717 | lq_sta->action_counter++; |
@@ -1791,6 +1849,28 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm, | |||
1791 | int ret; | 1849 | int ret; |
1792 | u8 update_search_tbl_counter = 0; | 1850 | u8 update_search_tbl_counter = 0; |
1793 | 1851 | ||
1852 | switch (BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
1853 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1854 | /* nothing */ | ||
1855 | break; | ||
1856 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1857 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1858 | /* avoid antenna B and MIMO */ | ||
1859 | if (tbl->action != IWL_MIMO3_SWITCH_SISO_A) | ||
1860 | tbl->action = IWL_MIMO3_SWITCH_SISO_A; | ||
1861 | break; | ||
1862 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1863 | /* avoid antenna B unless MIMO */ | ||
1864 | if (tbl->action == IWL_MIMO3_SWITCH_SISO_B || | ||
1865 | tbl->action == IWL_MIMO3_SWITCH_SISO_C) | ||
1866 | tbl->action = IWL_MIMO3_SWITCH_SISO_A; | ||
1867 | break; | ||
1868 | default: | ||
1869 | IWL_ERR(mvm, "Invalid BT load %d", | ||
1870 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)); | ||
1871 | break; | ||
1872 | } | ||
1873 | |||
1794 | start_action = tbl->action; | 1874 | start_action = tbl->action; |
1795 | while (1) { | 1875 | while (1) { |
1796 | lq_sta->action_counter++; | 1876 | lq_sta->action_counter++; |
@@ -2302,6 +2382,32 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, | |||
2302 | (current_tpt > (100 * tbl->expected_tpt[low])))) | 2382 | (current_tpt > (100 * tbl->expected_tpt[low])))) |
2303 | scale_action = 0; | 2383 | scale_action = 0; |
2304 | 2384 | ||
2385 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | ||
2386 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && | ||
2387 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { | ||
2388 | if (lq_sta->last_bt_traffic > | ||
2389 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
2390 | /* | ||
2391 | * don't set scale_action, don't want to scale up if | ||
2392 | * the rate scale doesn't otherwise think that is a | ||
2393 | * good idea. | ||
2394 | */ | ||
2395 | } else if (lq_sta->last_bt_traffic <= | ||
2396 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD)) { | ||
2397 | scale_action = -1; | ||
2398 | } | ||
2399 | } | ||
2400 | lq_sta->last_bt_traffic = | ||
2401 | BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD); | ||
2402 | |||
2403 | if ((BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= | ||
2404 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH) && | ||
2405 | (is_mimo2(tbl->lq_type) || is_mimo3(tbl->lq_type))) { | ||
2406 | /* search for a new modulation */ | ||
2407 | rs_stay_in_table(lq_sta, true); | ||
2408 | goto lq_update; | ||
2409 | } | ||
2410 | |||
2305 | switch (scale_action) { | 2411 | switch (scale_action) { |
2306 | case -1: | 2412 | case -1: |
2307 | /* Decrease starting rate, update uCode's rate table */ | 2413 | /* Decrease starting rate, update uCode's rate table */ |
@@ -2782,6 +2888,13 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm, | |||
2782 | 2888 | ||
2783 | lq_cmd->agg_time_limit = | 2889 | lq_cmd->agg_time_limit = |
2784 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | 2890 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); |
2891 | |||
2892 | /* | ||
2893 | * overwrite if needed, pass aggregation time limit | ||
2894 | * to uCode in uSec - This is racy - but heh, at least it helps... | ||
2895 | */ | ||
2896 | if (mvm && BT_MBOX_MSG(&mvm->last_bt_notif, 3, TRAFFIC_LOAD) >= 2) | ||
2897 | lq_cmd->agg_time_limit = cpu_to_le16(1200); | ||
2785 | } | 2898 | } |
2786 | 2899 | ||
2787 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 2900 | static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
@@ -3080,3 +3193,29 @@ void iwl_mvm_rate_control_unregister(void) | |||
3080 | { | 3193 | { |
3081 | ieee80211_rate_control_unregister(&rs_mvm_ops); | 3194 | ieee80211_rate_control_unregister(&rs_mvm_ops); |
3082 | } | 3195 | } |
3196 | |||
3197 | /** | ||
3198 | * iwl_mvm_tx_protection - Gets LQ command, change it to enable/disable | ||
3199 | * Tx protection, according to this rquest and previous requests, | ||
3200 | * and send the LQ command. | ||
3201 | * @lq: The LQ command | ||
3202 | * @mvmsta: The station | ||
3203 | * @enable: Enable Tx protection? | ||
3204 | */ | ||
3205 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
3206 | struct iwl_mvm_sta *mvmsta, bool enable) | ||
3207 | { | ||
3208 | lockdep_assert_held(&mvm->mutex); | ||
3209 | |||
3210 | if (enable) { | ||
3211 | if (mvmsta->tx_protection == 0) | ||
3212 | lq->flags |= LQ_FLAG_SET_STA_TLC_RTS_MSK; | ||
3213 | mvmsta->tx_protection++; | ||
3214 | } else { | ||
3215 | mvmsta->tx_protection--; | ||
3216 | if (mvmsta->tx_protection == 0) | ||
3217 | lq->flags &= ~LQ_FLAG_SET_STA_TLC_RTS_MSK; | ||
3218 | } | ||
3219 | |||
3220 | return iwl_mvm_send_lq_cmd(mvm, lq, CMD_ASYNC, false); | ||
3221 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 219c6857cc0f..cff4f6da7733 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h | |||
@@ -358,6 +358,18 @@ struct iwl_lq_sta { | |||
358 | u8 last_bt_traffic; | 358 | u8 last_bt_traffic; |
359 | }; | 359 | }; |
360 | 360 | ||
361 | enum iwl_bt_coex_profile_traffic_load { | ||
362 | IWL_BT_COEX_TRAFFIC_LOAD_NONE = 0, | ||
363 | IWL_BT_COEX_TRAFFIC_LOAD_LOW = 1, | ||
364 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH = 2, | ||
365 | IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS = 3, | ||
366 | /* | ||
367 | * There are no more even though below is a u8, the | ||
368 | * indication from the BT device only has two bits. | ||
369 | */ | ||
370 | }; | ||
371 | |||
372 | |||
361 | static inline u8 num_of_ant(u8 mask) | 373 | static inline u8 num_of_ant(u8 mask) |
362 | { | 374 | { |
363 | return !!((mask) & ANT_A) + | 375 | return !!((mask) & ANT_A) + |
@@ -390,4 +402,9 @@ extern int iwl_mvm_rate_control_register(void); | |||
390 | */ | 402 | */ |
391 | extern void iwl_mvm_rate_control_unregister(void); | 403 | extern void iwl_mvm_rate_control_unregister(void); |
392 | 404 | ||
405 | struct iwl_mvm_sta; | ||
406 | |||
407 | int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | ||
408 | struct iwl_mvm_sta *mvmsta, bool enable); | ||
409 | |||
393 | #endif /* __rs__ */ | 410 | #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/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 2476e43799d5..2157b0f8ced5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -298,12 +298,6 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm, | |||
298 | else | 298 | else |
299 | cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); | 299 | cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); |
300 | 300 | ||
301 | /* | ||
302 | * TODO: This is a WA due to a bug in the FW AUX framework that does not | ||
303 | * properly handle time events that fail to be scheduled | ||
304 | */ | ||
305 | cmd->type = cpu_to_le32(SCAN_TYPE_FORCED); | ||
306 | |||
307 | cmd->repeats = cpu_to_le32(1); | 301 | cmd->repeats = cpu_to_le32(1); |
308 | 302 | ||
309 | /* | 303 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 5c664ed54400..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,6 +218,8 @@ 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->pending_frames[sta_id], 0); | 225 | atomic_set(&mvm->pending_frames[sta_id], 0); |
@@ -798,21 +801,23 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
798 | min(mvmsta->max_agg_bufsize, buf_size); | 801 | min(mvmsta->max_agg_bufsize, buf_size); |
799 | 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; |
800 | 803 | ||
804 | IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", | ||
805 | sta->addr, tid); | ||
806 | |||
801 | if (mvm->cfg->ht_params->use_rts_for_aggregation) { | 807 | if (mvm->cfg->ht_params->use_rts_for_aggregation) { |
802 | /* | 808 | /* |
803 | * switch to RTS/CTS if it is the prefer protection | 809 | * switch to RTS/CTS if it is the prefer protection |
804 | * method for HT traffic | 810 | * method for HT traffic |
811 | * this function also sends the LQ command | ||
805 | */ | 812 | */ |
806 | 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); | ||
807 | /* | 815 | /* |
808 | * 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 |
809 | * AGG session (agg_tids_count in DVM) | 817 | * AGG session (agg_tids_count in DVM) |
810 | */ | 818 | */ |
811 | } | 819 | } |
812 | 820 | ||
813 | IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n", | ||
814 | sta->addr, tid); | ||
815 | |||
816 | 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); |
817 | } | 822 | } |
818 | 823 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index a4ddce77aaae..3efa0a0cc987 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -275,6 +275,8 @@ struct iwl_mvm_tid_data { | |||
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 | * @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? | ||
278 | * | 280 | * |
279 | * 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) |
280 | * 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 |
@@ -296,6 +298,10 @@ struct iwl_mvm_sta { | |||
296 | #ifdef CONFIG_PM_SLEEP | 298 | #ifdef CONFIG_PM_SLEEP |
297 | u16 last_seq_ctl; | 299 | u16 last_seq_ctl; |
298 | #endif | 300 | #endif |
301 | |||
302 | /* Temporary, until the new TLC will control the Tx protection */ | ||
303 | s8 tx_protection; | ||
304 | bool tt_tx_protection; | ||
299 | }; | 305 | }; |
300 | 306 | ||
301 | /** | 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..a7e3b8ddf22b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c | |||
@@ -0,0 +1,512 @@ | |||
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 | if (vif->type != NL80211_IFTYPE_STATION) | ||
375 | return; | ||
376 | |||
377 | iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_TT, smps_mode); | ||
378 | } | ||
379 | |||
380 | static void iwl_mvm_tt_tx_protection(struct iwl_mvm *mvm, bool enable) | ||
381 | { | ||
382 | struct ieee80211_sta *sta; | ||
383 | struct iwl_mvm_sta *mvmsta; | ||
384 | int i, err; | ||
385 | |||
386 | for (i = 0; i < IWL_MVM_STATION_COUNT; i++) { | ||
387 | sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], | ||
388 | lockdep_is_held(&mvm->mutex)); | ||
389 | if (IS_ERR_OR_NULL(sta)) | ||
390 | continue; | ||
391 | mvmsta = (void *)sta->drv_priv; | ||
392 | if (enable == mvmsta->tt_tx_protection) | ||
393 | continue; | ||
394 | err = iwl_mvm_tx_protection(mvm, &mvmsta->lq_sta.lq, | ||
395 | mvmsta, enable); | ||
396 | if (err) { | ||
397 | IWL_ERR(mvm, "Failed to %s Tx protection\n", | ||
398 | enable ? "enable" : "disable"); | ||
399 | } else { | ||
400 | IWL_DEBUG_TEMP(mvm, "%s Tx protection\n", | ||
401 | enable ? "Enable" : "Disable"); | ||
402 | mvmsta->tt_tx_protection = enable; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | static void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff) | ||
408 | { | ||
409 | struct iwl_host_cmd cmd = { | ||
410 | .id = REPLY_THERMAL_MNG_BACKOFF, | ||
411 | .len = { sizeof(u32), }, | ||
412 | .data = { &backoff, }, | ||
413 | .flags = CMD_SYNC, | ||
414 | }; | ||
415 | |||
416 | if (iwl_mvm_send_cmd(mvm, &cmd) == 0) { | ||
417 | IWL_DEBUG_TEMP(mvm, "Set Thermal Tx backoff to: %u\n", | ||
418 | backoff); | ||
419 | mvm->thermal_throttle.tx_backoff = backoff; | ||
420 | } else { | ||
421 | IWL_ERR(mvm, "Failed to change Thermal Tx backoff\n"); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | void iwl_mvm_tt_handler(struct iwl_mvm *mvm) | ||
426 | { | ||
427 | const struct iwl_tt_params *params = mvm->thermal_throttle.params; | ||
428 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
429 | s32 temperature = mvm->temperature; | ||
430 | int i; | ||
431 | u32 tx_backoff; | ||
432 | |||
433 | IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", mvm->temperature); | ||
434 | |||
435 | if (params->support_ct_kill && temperature >= params->ct_kill_entry) { | ||
436 | iwl_mvm_enter_ctkill(mvm); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | if (params->support_dynamic_smps) { | ||
441 | if (!tt->dynamic_smps && | ||
442 | temperature >= params->dynamic_smps_entry) { | ||
443 | IWL_DEBUG_TEMP(mvm, "Enable dynamic SMPS\n"); | ||
444 | tt->dynamic_smps = true; | ||
445 | ieee80211_iterate_active_interfaces_atomic( | ||
446 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
447 | iwl_mvm_tt_smps_iterator, mvm); | ||
448 | } else if (tt->dynamic_smps && | ||
449 | temperature <= params->dynamic_smps_exit) { | ||
450 | IWL_DEBUG_TEMP(mvm, "Disable dynamic SMPS\n"); | ||
451 | tt->dynamic_smps = false; | ||
452 | ieee80211_iterate_active_interfaces_atomic( | ||
453 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
454 | iwl_mvm_tt_smps_iterator, mvm); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | if (params->support_tx_protection) { | ||
459 | if (temperature >= params->tx_protection_entry) | ||
460 | iwl_mvm_tt_tx_protection(mvm, true); | ||
461 | else if (temperature <= params->tx_protection_exit) | ||
462 | iwl_mvm_tt_tx_protection(mvm, false); | ||
463 | } | ||
464 | |||
465 | if (params->support_tx_backoff) { | ||
466 | tx_backoff = 0; | ||
467 | for (i = 0; i < TT_TX_BACKOFF_SIZE; i++) { | ||
468 | if (temperature < params->tx_backoff[i].temperature) | ||
469 | break; | ||
470 | tx_backoff = params->tx_backoff[i].backoff; | ||
471 | } | ||
472 | if (tt->tx_backoff != tx_backoff) | ||
473 | iwl_mvm_tt_tx_backoff(mvm, tx_backoff); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | static const struct iwl_tt_params iwl7000_tt_params = { | ||
478 | .ct_kill_entry = 118, | ||
479 | .ct_kill_exit = 96, | ||
480 | .ct_kill_duration = 5, | ||
481 | .dynamic_smps_entry = 114, | ||
482 | .dynamic_smps_exit = 110, | ||
483 | .tx_protection_entry = 114, | ||
484 | .tx_protection_exit = 108, | ||
485 | .tx_backoff = { | ||
486 | {.temperature = 112, .backoff = 200}, | ||
487 | {.temperature = 113, .backoff = 600}, | ||
488 | {.temperature = 114, .backoff = 1200}, | ||
489 | {.temperature = 115, .backoff = 2000}, | ||
490 | {.temperature = 116, .backoff = 4000}, | ||
491 | {.temperature = 117, .backoff = 10000}, | ||
492 | }, | ||
493 | .support_ct_kill = true, | ||
494 | .support_dynamic_smps = true, | ||
495 | .support_tx_protection = true, | ||
496 | .support_tx_backoff = true, | ||
497 | }; | ||
498 | |||
499 | void iwl_mvm_tt_initialize(struct iwl_mvm *mvm) | ||
500 | { | ||
501 | struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; | ||
502 | |||
503 | IWL_DEBUG_TEMP(mvm, "Initialize Thermal Throttling\n"); | ||
504 | tt->params = &iwl7000_tt_params; | ||
505 | INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill); | ||
506 | } | ||
507 | |||
508 | void iwl_mvm_tt_exit(struct iwl_mvm *mvm) | ||
509 | { | ||
510 | cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit); | ||
511 | IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n"); | ||
512 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index f212f16502ff..a830eb6cc411 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -175,7 +175,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, | |||
175 | * table is controlled by LINK_QUALITY commands | 175 | * table is controlled by LINK_QUALITY commands |
176 | */ | 176 | */ |
177 | 177 | ||
178 | if (ieee80211_is_data(fc)) { | 178 | if (ieee80211_is_data(fc) && sta) { |
179 | tx_cmd->initial_rate_index = 0; | 179 | tx_cmd->initial_rate_index = 0; |
180 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); | 180 | tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); |
181 | return; | 181 | return; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 687b34e387ac..1e1332839e4a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c | |||
@@ -76,6 +76,11 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) | |||
76 | { | 76 | { |
77 | int ret; | 77 | int ret; |
78 | 78 | ||
79 | #if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) | ||
80 | if (WARN_ON(mvm->d3_test_active)) | ||
81 | return -EIO; | ||
82 | #endif | ||
83 | |||
79 | /* | 84 | /* |
80 | * Synchronous commands from this op-mode must hold | 85 | * Synchronous commands from this op-mode must hold |
81 | * the mutex, this ensures we don't try to send two | 86 | * the mutex, this ensures we don't try to send two |
@@ -125,6 +130,11 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, | |||
125 | 130 | ||
126 | lockdep_assert_held(&mvm->mutex); | 131 | lockdep_assert_held(&mvm->mutex); |
127 | 132 | ||
133 | #if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) | ||
134 | if (WARN_ON(mvm->d3_test_active)) | ||
135 | return -EIO; | ||
136 | #endif | ||
137 | |||
128 | /* | 138 | /* |
129 | * Only synchronous commands can wait for status, | 139 | * Only synchronous commands can wait for status, |
130 | * we use WANT_SKB so the caller can't. | 140 | * we use WANT_SKB so the caller can't. |
@@ -471,3 +481,34 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, | |||
471 | 481 | ||
472 | return iwl_mvm_send_cmd(mvm, &cmd); | 482 | return iwl_mvm_send_cmd(mvm, &cmd); |
473 | } | 483 | } |
484 | |||
485 | /** | ||
486 | * iwl_mvm_update_smps - Get a requst to change the SMPS mode | ||
487 | * @req_type: The part of the driver who call for a change. | ||
488 | * @smps_requests: The request to change the SMPS mode. | ||
489 | * | ||
490 | * Get a requst to change the SMPS mode, | ||
491 | * and change it according to all other requests in the driver. | ||
492 | */ | ||
493 | void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
494 | enum iwl_mvm_smps_type_request req_type, | ||
495 | enum ieee80211_smps_mode smps_request) | ||
496 | { | ||
497 | struct iwl_mvm_vif *mvmvif; | ||
498 | enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; | ||
499 | int i; | ||
500 | |||
501 | lockdep_assert_held(&mvm->mutex); | ||
502 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
503 | mvmvif->smps_requests[req_type] = smps_request; | ||
504 | for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { | ||
505 | if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC) { | ||
506 | smps_mode = IEEE80211_SMPS_STATIC; | ||
507 | break; | ||
508 | } | ||
509 | if (mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) | ||
510 | smps_mode = IEEE80211_SMPS_DYNAMIC; | ||
511 | } | ||
512 | |||
513 | ieee80211_request_smps(vif, smps_mode); | ||
514 | } | ||
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..197dbe0a868c 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 | ||
@@ -571,13 +578,17 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) | |||
571 | clear_bit(STATUS_RFKILL, &trans_pcie->status); | 578 | clear_bit(STATUS_RFKILL, &trans_pcie->status); |
572 | } | 579 | } |
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, bool test) |
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); |
584 | |||
585 | /* | ||
586 | * in testing mode, the host stays awake and the | ||
587 | * hardware won't be reset (not even partially) | ||
588 | */ | ||
589 | if (test) | ||
590 | return; | ||
591 | |||
581 | iwl_pcie_disable_ict(trans); | 592 | iwl_pcie_disable_ict(trans); |
582 | 593 | ||
583 | iwl_clear_bit(trans, CSR_GP_CNTRL, | 594 | iwl_clear_bit(trans, CSR_GP_CNTRL, |
@@ -596,11 +607,18 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans) | |||
596 | } | 607 | } |
597 | 608 | ||
598 | static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | 609 | static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, |
599 | enum iwl_d3_status *status) | 610 | enum iwl_d3_status *status, |
611 | bool test) | ||
600 | { | 612 | { |
601 | u32 val; | 613 | u32 val; |
602 | int ret; | 614 | int ret; |
603 | 615 | ||
616 | if (test) { | ||
617 | iwl_enable_interrupts(trans); | ||
618 | *status = IWL_D3_STATUS_ALIVE; | ||
619 | return 0; | ||
620 | } | ||
621 | |||
604 | iwl_pcie_set_pwr(trans, false); | 622 | iwl_pcie_set_pwr(trans, false); |
605 | 623 | ||
606 | val = iwl_read32(trans, CSR_RESET); | 624 | val = iwl_read32(trans, CSR_RESET); |
@@ -636,9 +654,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, | |||
636 | return ret; | 654 | return ret; |
637 | } | 655 | } |
638 | 656 | ||
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; | 657 | *status = IWL_D3_STATUS_ALIVE; |
643 | return 0; | 658 | return 0; |
644 | } | 659 | } |
@@ -917,11 +932,11 @@ static int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, | |||
917 | } | 932 | } |
918 | 933 | ||
919 | static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, | 934 | static int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, |
920 | void *buf, int dwords) | 935 | const void *buf, int dwords) |
921 | { | 936 | { |
922 | unsigned long flags; | 937 | unsigned long flags; |
923 | int offs, ret = 0; | 938 | int offs, ret = 0; |
924 | u32 *vals = buf; | 939 | const u32 *vals = buf; |
925 | 940 | ||
926 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { | 941 | if (iwl_trans_grab_nic_access(trans, false, &flags)) { |
927 | iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); | 942 | 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 c5e30294c5ac..f65da1984d91 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -224,13 +224,13 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, | |||
224 | 224 | ||
225 | switch (sec_ctl & TX_CMD_SEC_MSK) { | 225 | switch (sec_ctl & TX_CMD_SEC_MSK) { |
226 | case TX_CMD_SEC_CCM: | 226 | case TX_CMD_SEC_CCM: |
227 | len += CCMP_MIC_LEN; | 227 | len += IEEE80211_CCMP_MIC_LEN; |
228 | break; | 228 | break; |
229 | case TX_CMD_SEC_TKIP: | 229 | case TX_CMD_SEC_TKIP: |
230 | len += TKIP_ICV_LEN; | 230 | len += IEEE80211_TKIP_ICV_LEN; |
231 | break; | 231 | break; |
232 | case TX_CMD_SEC_WEP: | 232 | case TX_CMD_SEC_WEP: |
233 | len += WEP_IV_LEN + WEP_ICV_LEN; | 233 | len += IEEE80211_WEP_IV_LEN + IEEE80211_WEP_ICV_LEN; |
234 | break; | 234 | break; |
235 | } | 235 | } |
236 | 236 | ||
@@ -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,11 +1522,13 @@ 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 | } |
1524 | 1529 | ||
1525 | if (test_bit(STATUS_RFKILL, &trans_pcie->status)) { | 1530 | if (!(cmd->flags & CMD_SEND_IN_RFKILL) && |
1531 | test_bit(STATUS_RFKILL, &trans_pcie->status)) { | ||
1526 | IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); | 1532 | IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n"); |
1527 | ret = -ERFKILL; | 1533 | ret = -ERFKILL; |
1528 | goto cancel; | 1534 | goto cancel; |
@@ -1564,7 +1570,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)) | 1570 | if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) |
1565 | return -EIO; | 1571 | return -EIO; |
1566 | 1572 | ||
1567 | if (test_bit(STATUS_RFKILL, &trans_pcie->status)) { | 1573 | if (!(cmd->flags & CMD_SEND_IN_RFKILL) && |
1574 | test_bit(STATUS_RFKILL, &trans_pcie->status)) { | ||
1568 | IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", | 1575 | IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n", |
1569 | cmd->id); | 1576 | cmd->id); |
1570 | return -ERFKILL; | 1577 | 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 e42b266a023a..00a82817eb6b 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/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2c12311467a9..5efbbbdca701 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -1170,12 +1170,6 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, | |||
1170 | 1170 | ||
1171 | rt2x00queue_reset(queue); | 1171 | rt2x00queue_reset(queue); |
1172 | 1172 | ||
1173 | queue->limit = qdesc->entry_num; | ||
1174 | queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10); | ||
1175 | queue->data_size = qdesc->data_size; | ||
1176 | queue->desc_size = qdesc->desc_size; | ||
1177 | queue->winfo_size = qdesc->winfo_size; | ||
1178 | |||
1179 | /* | 1173 | /* |
1180 | * Allocate all queue entries. | 1174 | * Allocate all queue entries. |
1181 | */ | 1175 | */ |
@@ -1284,9 +1278,38 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) | |||
1284 | } | 1278 | } |
1285 | } | 1279 | } |
1286 | 1280 | ||
1281 | static const struct data_queue_desc * | ||
1282 | rt2x00queue_get_qdesc_by_qid(struct rt2x00_dev *rt2x00dev, | ||
1283 | enum data_queue_qid qid) | ||
1284 | { | ||
1285 | switch (qid) { | ||
1286 | case QID_RX: | ||
1287 | return rt2x00dev->ops->rx; | ||
1288 | |||
1289 | case QID_AC_BE: | ||
1290 | case QID_AC_BK: | ||
1291 | case QID_AC_VO: | ||
1292 | case QID_AC_VI: | ||
1293 | return rt2x00dev->ops->tx; | ||
1294 | |||
1295 | case QID_BEACON: | ||
1296 | return rt2x00dev->ops->bcn; | ||
1297 | |||
1298 | case QID_ATIM: | ||
1299 | return rt2x00dev->ops->atim; | ||
1300 | |||
1301 | default: | ||
1302 | break; | ||
1303 | } | ||
1304 | |||
1305 | return NULL; | ||
1306 | } | ||
1307 | |||
1287 | static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, | 1308 | static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, |
1288 | struct data_queue *queue, enum data_queue_qid qid) | 1309 | struct data_queue *queue, enum data_queue_qid qid) |
1289 | { | 1310 | { |
1311 | const struct data_queue_desc *qdesc; | ||
1312 | |||
1290 | mutex_init(&queue->status_lock); | 1313 | mutex_init(&queue->status_lock); |
1291 | spin_lock_init(&queue->tx_lock); | 1314 | spin_lock_init(&queue->tx_lock); |
1292 | spin_lock_init(&queue->index_lock); | 1315 | spin_lock_init(&queue->index_lock); |
@@ -1297,6 +1320,15 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, | |||
1297 | queue->aifs = 2; | 1320 | queue->aifs = 2; |
1298 | queue->cw_min = 5; | 1321 | queue->cw_min = 5; |
1299 | queue->cw_max = 10; | 1322 | queue->cw_max = 10; |
1323 | |||
1324 | qdesc = rt2x00queue_get_qdesc_by_qid(rt2x00dev, qid); | ||
1325 | BUG_ON(!qdesc); | ||
1326 | |||
1327 | queue->limit = qdesc->entry_num; | ||
1328 | queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10); | ||
1329 | queue->data_size = qdesc->data_size; | ||
1330 | queue->desc_size = qdesc->desc_size; | ||
1331 | queue->winfo_size = qdesc->winfo_size; | ||
1300 | } | 1332 | } |
1301 | 1333 | ||
1302 | int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) | 1334 | int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev) |
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/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c index 19a765532603..47875ba09ff8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c | |||
@@ -842,7 +842,7 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter( | |||
842 | long val_y, ele_c = 0; | 842 | long val_y, ele_c = 0; |
843 | u8 ofdm_index[2]; | 843 | u8 ofdm_index[2]; |
844 | s8 cck_index = 0; | 844 | s8 cck_index = 0; |
845 | u8 ofdm_index_old[2]; | 845 | u8 ofdm_index_old[2] = {0, 0}; |
846 | s8 cck_index_old = 0; | 846 | s8 cck_index_old = 0; |
847 | u8 index; | 847 | u8 index; |
848 | int i; | 848 | int i; |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 06b0ed0154a4..d826e5a84af0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1829,6 +1829,15 @@ enum ieee80211_key_len { | |||
1829 | WLAN_KEY_LEN_AES_CMAC = 16, | 1829 | WLAN_KEY_LEN_AES_CMAC = 16, |
1830 | }; | 1830 | }; |
1831 | 1831 | ||
1832 | #define IEEE80211_WEP_IV_LEN 4 | ||
1833 | #define IEEE80211_WEP_ICV_LEN 4 | ||
1834 | #define IEEE80211_CCMP_HDR_LEN 8 | ||
1835 | #define IEEE80211_CCMP_MIC_LEN 8 | ||
1836 | #define IEEE80211_CCMP_PN_LEN 6 | ||
1837 | #define IEEE80211_TKIP_IV_LEN 8 | ||
1838 | #define IEEE80211_TKIP_ICV_LEN 4 | ||
1839 | #define IEEE80211_CMAC_PN_LEN 6 | ||
1840 | |||
1832 | /* Public action codes */ | 1841 | /* Public action codes */ |
1833 | enum ieee80211_pub_actioncode { | 1842 | enum ieee80211_pub_actioncode { |
1834 | WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, | 1843 | WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, |
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 |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 26b5b692c22b..6dd19593e333 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -753,6 +753,8 @@ int cfg80211_check_station_change(struct wiphy *wiphy, | |||
753 | * @STATION_INFO_LOCAL_PM: @local_pm filled | 753 | * @STATION_INFO_LOCAL_PM: @local_pm filled |
754 | * @STATION_INFO_PEER_PM: @peer_pm filled | 754 | * @STATION_INFO_PEER_PM: @peer_pm filled |
755 | * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled | 755 | * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled |
756 | * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled | ||
757 | * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled | ||
756 | */ | 758 | */ |
757 | enum station_info_flags { | 759 | enum station_info_flags { |
758 | STATION_INFO_INACTIVE_TIME = 1<<0, | 760 | STATION_INFO_INACTIVE_TIME = 1<<0, |
@@ -781,6 +783,8 @@ enum station_info_flags { | |||
781 | STATION_INFO_NONPEER_PM = 1<<23, | 783 | STATION_INFO_NONPEER_PM = 1<<23, |
782 | STATION_INFO_RX_BYTES64 = 1<<24, | 784 | STATION_INFO_RX_BYTES64 = 1<<24, |
783 | STATION_INFO_TX_BYTES64 = 1<<25, | 785 | STATION_INFO_TX_BYTES64 = 1<<25, |
786 | STATION_INFO_CHAIN_SIGNAL = 1<<26, | ||
787 | STATION_INFO_CHAIN_SIGNAL_AVG = 1<<27, | ||
784 | }; | 788 | }; |
785 | 789 | ||
786 | /** | 790 | /** |
@@ -857,6 +861,8 @@ struct sta_bss_parameters { | |||
857 | u16 beacon_interval; | 861 | u16 beacon_interval; |
858 | }; | 862 | }; |
859 | 863 | ||
864 | #define IEEE80211_MAX_CHAINS 4 | ||
865 | |||
860 | /** | 866 | /** |
861 | * struct station_info - station information | 867 | * struct station_info - station information |
862 | * | 868 | * |
@@ -874,6 +880,9 @@ struct sta_bss_parameters { | |||
874 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. | 880 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. |
875 | * @signal_avg: Average signal strength, type depends on the wiphy's signal_type. | 881 | * @signal_avg: Average signal strength, type depends on the wiphy's signal_type. |
876 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. | 882 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. |
883 | * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg | ||
884 | * @chain_signal: per-chain signal strength of last received packet in dBm | ||
885 | * @chain_signal_avg: per-chain signal strength average in dBm | ||
877 | * @txrate: current unicast bitrate from this station | 886 | * @txrate: current unicast bitrate from this station |
878 | * @rxrate: current unicast bitrate to this station | 887 | * @rxrate: current unicast bitrate to this station |
879 | * @rx_packets: packets received from this station | 888 | * @rx_packets: packets received from this station |
@@ -909,6 +918,11 @@ struct station_info { | |||
909 | u8 plink_state; | 918 | u8 plink_state; |
910 | s8 signal; | 919 | s8 signal; |
911 | s8 signal_avg; | 920 | s8 signal_avg; |
921 | |||
922 | u8 chains; | ||
923 | s8 chain_signal[IEEE80211_MAX_CHAINS]; | ||
924 | s8 chain_signal_avg[IEEE80211_MAX_CHAINS]; | ||
925 | |||
912 | struct rate_info txrate; | 926 | struct rate_info txrate; |
913 | struct rate_info rxrate; | 927 | struct rate_info rxrate; |
914 | u32 rx_packets; | 928 | u32 rx_packets; |
@@ -947,6 +961,7 @@ struct station_info { | |||
947 | * @MONITOR_FLAG_CONTROL: pass control frames | 961 | * @MONITOR_FLAG_CONTROL: pass control frames |
948 | * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering | 962 | * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering |
949 | * @MONITOR_FLAG_COOK_FRAMES: report frames after processing | 963 | * @MONITOR_FLAG_COOK_FRAMES: report frames after processing |
964 | * @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address | ||
950 | */ | 965 | */ |
951 | enum monitor_flags { | 966 | enum monitor_flags { |
952 | MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, | 967 | MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, |
@@ -954,6 +969,7 @@ enum monitor_flags { | |||
954 | MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, | 969 | MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, |
955 | MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, | 970 | MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, |
956 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, | 971 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, |
972 | MONITOR_FLAG_ACTIVE = 1<<NL80211_MNTR_FLAG_ACTIVE, | ||
957 | }; | 973 | }; |
958 | 974 | ||
959 | /** | 975 | /** |
@@ -1147,6 +1163,7 @@ struct mesh_config { | |||
1147 | * @sync_method: which synchronization method to use | 1163 | * @sync_method: which synchronization method to use |
1148 | * @path_sel_proto: which path selection protocol to use | 1164 | * @path_sel_proto: which path selection protocol to use |
1149 | * @path_metric: which metric to use | 1165 | * @path_metric: which metric to use |
1166 | * @auth_id: which authentication method this mesh is using | ||
1150 | * @ie: vendor information elements (optional) | 1167 | * @ie: vendor information elements (optional) |
1151 | * @ie_len: length of vendor information elements | 1168 | * @ie_len: length of vendor information elements |
1152 | * @is_authenticated: this mesh requires authentication | 1169 | * @is_authenticated: this mesh requires authentication |
@@ -1165,6 +1182,7 @@ struct mesh_setup { | |||
1165 | u8 sync_method; | 1182 | u8 sync_method; |
1166 | u8 path_sel_proto; | 1183 | u8 path_sel_proto; |
1167 | u8 path_metric; | 1184 | u8 path_metric; |
1185 | u8 auth_id; | ||
1168 | const u8 *ie; | 1186 | const u8 *ie; |
1169 | u8 ie_len; | 1187 | u8 ie_len; |
1170 | bool is_authenticated; | 1188 | bool is_authenticated; |
@@ -1241,6 +1259,7 @@ struct cfg80211_ssid { | |||
1241 | * @scan_start: time (in jiffies) when the scan started | 1259 | * @scan_start: time (in jiffies) when the scan started |
1242 | * @wdev: the wireless device to scan for | 1260 | * @wdev: the wireless device to scan for |
1243 | * @aborted: (internal) scan request was notified as aborted | 1261 | * @aborted: (internal) scan request was notified as aborted |
1262 | * @notified: (internal) scan request was notified as done or aborted | ||
1244 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band | 1263 | * @no_cck: used to send probe requests at non CCK rate in 2GHz band |
1245 | */ | 1264 | */ |
1246 | struct cfg80211_scan_request { | 1265 | struct cfg80211_scan_request { |
@@ -1258,7 +1277,7 @@ struct cfg80211_scan_request { | |||
1258 | /* internal */ | 1277 | /* internal */ |
1259 | struct wiphy *wiphy; | 1278 | struct wiphy *wiphy; |
1260 | unsigned long scan_start; | 1279 | unsigned long scan_start; |
1261 | bool aborted; | 1280 | bool aborted, notified; |
1262 | bool no_cck; | 1281 | bool no_cck; |
1263 | 1282 | ||
1264 | /* keep last */ | 1283 | /* keep last */ |
@@ -1850,7 +1869,9 @@ struct cfg80211_update_ft_ies_params { | |||
1850 | * @get_mpath: get a mesh path for the given parameters | 1869 | * @get_mpath: get a mesh path for the given parameters |
1851 | * @dump_mpath: dump mesh path callback -- resume dump at index @idx | 1870 | * @dump_mpath: dump mesh path callback -- resume dump at index @idx |
1852 | * @join_mesh: join the mesh network with the specified parameters | 1871 | * @join_mesh: join the mesh network with the specified parameters |
1872 | * (invoked with the wireless_dev mutex held) | ||
1853 | * @leave_mesh: leave the current mesh network | 1873 | * @leave_mesh: leave the current mesh network |
1874 | * (invoked with the wireless_dev mutex held) | ||
1854 | * | 1875 | * |
1855 | * @get_mesh_config: Get the current mesh configuration | 1876 | * @get_mesh_config: Get the current mesh configuration |
1856 | * | 1877 | * |
@@ -1877,20 +1898,28 @@ struct cfg80211_update_ft_ies_params { | |||
1877 | * the scan/scan_done bracket too. | 1898 | * the scan/scan_done bracket too. |
1878 | * | 1899 | * |
1879 | * @auth: Request to authenticate with the specified peer | 1900 | * @auth: Request to authenticate with the specified peer |
1901 | * (invoked with the wireless_dev mutex held) | ||
1880 | * @assoc: Request to (re)associate with the specified peer | 1902 | * @assoc: Request to (re)associate with the specified peer |
1903 | * (invoked with the wireless_dev mutex held) | ||
1881 | * @deauth: Request to deauthenticate from the specified peer | 1904 | * @deauth: Request to deauthenticate from the specified peer |
1905 | * (invoked with the wireless_dev mutex held) | ||
1882 | * @disassoc: Request to disassociate from the specified peer | 1906 | * @disassoc: Request to disassociate from the specified peer |
1907 | * (invoked with the wireless_dev mutex held) | ||
1883 | * | 1908 | * |
1884 | * @connect: Connect to the ESS with the specified parameters. When connected, | 1909 | * @connect: Connect to the ESS with the specified parameters. When connected, |
1885 | * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. | 1910 | * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. |
1886 | * If the connection fails for some reason, call cfg80211_connect_result() | 1911 | * If the connection fails for some reason, call cfg80211_connect_result() |
1887 | * with the status from the AP. | 1912 | * with the status from the AP. |
1913 | * (invoked with the wireless_dev mutex held) | ||
1888 | * @disconnect: Disconnect from the BSS/ESS. | 1914 | * @disconnect: Disconnect from the BSS/ESS. |
1915 | * (invoked with the wireless_dev mutex held) | ||
1889 | * | 1916 | * |
1890 | * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call | 1917 | * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call |
1891 | * cfg80211_ibss_joined(), also call that function when changing BSSID due | 1918 | * cfg80211_ibss_joined(), also call that function when changing BSSID due |
1892 | * to a merge. | 1919 | * to a merge. |
1920 | * (invoked with the wireless_dev mutex held) | ||
1893 | * @leave_ibss: Leave the IBSS. | 1921 | * @leave_ibss: Leave the IBSS. |
1922 | * (invoked with the wireless_dev mutex held) | ||
1894 | * | 1923 | * |
1895 | * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or | 1924 | * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or |
1896 | * MESH mode) | 1925 | * MESH mode) |
@@ -2556,6 +2585,9 @@ struct wiphy_wowlan_support { | |||
2556 | * may request, if implemented. | 2585 | * may request, if implemented. |
2557 | * | 2586 | * |
2558 | * @wowlan: WoWLAN support information | 2587 | * @wowlan: WoWLAN support information |
2588 | * @wowlan_config: current WoWLAN configuration; this should usually not be | ||
2589 | * used since access to it is necessarily racy, use the parameter passed | ||
2590 | * to the suspend() operation instead. | ||
2559 | * | 2591 | * |
2560 | * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. | 2592 | * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features. |
2561 | * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden. | 2593 | * @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden. |
@@ -2623,6 +2655,7 @@ struct wiphy { | |||
2623 | 2655 | ||
2624 | #ifdef CONFIG_PM | 2656 | #ifdef CONFIG_PM |
2625 | struct wiphy_wowlan_support wowlan; | 2657 | struct wiphy_wowlan_support wowlan; |
2658 | struct cfg80211_wowlan *wowlan_config; | ||
2626 | #endif | 2659 | #endif |
2627 | 2660 | ||
2628 | u16 max_remain_on_channel_duration; | 2661 | u16 max_remain_on_channel_duration; |
@@ -2834,8 +2867,8 @@ struct cfg80211_cached_keys; | |||
2834 | * by cfg80211 on change_interface | 2867 | * by cfg80211 on change_interface |
2835 | * @mgmt_registrations: list of registrations for management frames | 2868 | * @mgmt_registrations: list of registrations for management frames |
2836 | * @mgmt_registrations_lock: lock for the list | 2869 | * @mgmt_registrations_lock: lock for the list |
2837 | * @mtx: mutex used to lock data in this struct | 2870 | * @mtx: mutex used to lock data in this struct, may be used by drivers |
2838 | * @cleanup_work: work struct used for cleanup that can't be done directly | 2871 | * and some API functions require it held |
2839 | * @beacon_interval: beacon interval used on this device for transmitting | 2872 | * @beacon_interval: beacon interval used on this device for transmitting |
2840 | * beacons, 0 when not valid | 2873 | * beacons, 0 when not valid |
2841 | * @address: The address for this device, valid only if @netdev is %NULL | 2874 | * @address: The address for this device, valid only if @netdev is %NULL |
@@ -2858,8 +2891,6 @@ struct wireless_dev { | |||
2858 | 2891 | ||
2859 | struct mutex mtx; | 2892 | struct mutex mtx; |
2860 | 2893 | ||
2861 | struct work_struct cleanup_work; | ||
2862 | |||
2863 | bool use_4addr, p2p_started; | 2894 | bool use_4addr, p2p_started; |
2864 | 2895 | ||
2865 | u8 address[ETH_ALEN] __aligned(sizeof(u16)); | 2896 | u8 address[ETH_ALEN] __aligned(sizeof(u16)); |
@@ -2989,6 +3020,15 @@ struct ieee80211_rate * | |||
2989 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | 3020 | ieee80211_get_response_rate(struct ieee80211_supported_band *sband, |
2990 | u32 basic_rates, int bitrate); | 3021 | u32 basic_rates, int bitrate); |
2991 | 3022 | ||
3023 | /** | ||
3024 | * ieee80211_mandatory_rates - get mandatory rates for a given band | ||
3025 | * @sband: the band to look for rates in | ||
3026 | * | ||
3027 | * This function returns a bitmap of the mandatory rates for the given | ||
3028 | * band, bits are set according to the rate position in the bitrates array. | ||
3029 | */ | ||
3030 | u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband); | ||
3031 | |||
2992 | /* | 3032 | /* |
2993 | * Radiotap parsing functions -- for controlled injection support | 3033 | * Radiotap parsing functions -- for controlled injection support |
2994 | * | 3034 | * |
@@ -3400,7 +3440,8 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); | |||
3400 | * This function is called whenever an authentication has been processed in | 3440 | * This function is called whenever an authentication has been processed in |
3401 | * station mode. The driver is required to call either this function or | 3441 | * station mode. The driver is required to call either this function or |
3402 | * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() | 3442 | * cfg80211_send_auth_timeout() to indicate the result of cfg80211_ops::auth() |
3403 | * call. This function may sleep. | 3443 | * call. This function may sleep. The caller must hold the corresponding wdev's |
3444 | * mutex. | ||
3404 | */ | 3445 | */ |
3405 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 3446 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
3406 | 3447 | ||
@@ -3409,7 +3450,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | |||
3409 | * @dev: network device | 3450 | * @dev: network device |
3410 | * @addr: The MAC address of the device with which the authentication timed out | 3451 | * @addr: The MAC address of the device with which the authentication timed out |
3411 | * | 3452 | * |
3412 | * This function may sleep. | 3453 | * This function may sleep. The caller must hold the corresponding wdev's |
3454 | * mutex. | ||
3413 | */ | 3455 | */ |
3414 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); | 3456 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); |
3415 | 3457 | ||
@@ -3424,7 +3466,8 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr); | |||
3424 | * This function is called whenever a (re)association response has been | 3466 | * This function is called whenever a (re)association response has been |
3425 | * processed in station mode. The driver is required to call either this | 3467 | * processed in station mode. The driver is required to call either this |
3426 | * function or cfg80211_send_assoc_timeout() to indicate the result of | 3468 | * function or cfg80211_send_assoc_timeout() to indicate the result of |
3427 | * cfg80211_ops::assoc() call. This function may sleep. | 3469 | * cfg80211_ops::assoc() call. This function may sleep. The caller must hold |
3470 | * the corresponding wdev's mutex. | ||
3428 | */ | 3471 | */ |
3429 | void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | 3472 | void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, |
3430 | const u8 *buf, size_t len); | 3473 | const u8 *buf, size_t len); |
@@ -3434,7 +3477,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
3434 | * @dev: network device | 3477 | * @dev: network device |
3435 | * @addr: The MAC address of the device with which the association timed out | 3478 | * @addr: The MAC address of the device with which the association timed out |
3436 | * | 3479 | * |
3437 | * This function may sleep. | 3480 | * This function may sleep. The caller must hold the corresponding wdev's mutex. |
3438 | */ | 3481 | */ |
3439 | void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); | 3482 | void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); |
3440 | 3483 | ||
@@ -3446,21 +3489,12 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr); | |||
3446 | * | 3489 | * |
3447 | * This function is called whenever deauthentication has been processed in | 3490 | * This function is called whenever deauthentication has been processed in |
3448 | * station mode. This includes both received deauthentication frames and | 3491 | * station mode. This includes both received deauthentication frames and |
3449 | * locally generated ones. This function may sleep. | 3492 | * locally generated ones. This function may sleep. The caller must hold the |
3493 | * corresponding wdev's mutex. | ||
3450 | */ | 3494 | */ |
3451 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); | 3495 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); |
3452 | 3496 | ||
3453 | /** | 3497 | /** |
3454 | * __cfg80211_send_deauth - notification of processed deauthentication | ||
3455 | * @dev: network device | ||
3456 | * @buf: deauthentication frame (header + body) | ||
3457 | * @len: length of the frame data | ||
3458 | * | ||
3459 | * Like cfg80211_send_deauth(), but doesn't take the wdev lock. | ||
3460 | */ | ||
3461 | void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); | ||
3462 | |||
3463 | /** | ||
3464 | * cfg80211_send_disassoc - notification of processed disassociation | 3498 | * cfg80211_send_disassoc - notification of processed disassociation |
3465 | * @dev: network device | 3499 | * @dev: network device |
3466 | * @buf: disassociation response frame (header + body) | 3500 | * @buf: disassociation response frame (header + body) |
@@ -3468,22 +3502,12 @@ void __cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); | |||
3468 | * | 3502 | * |
3469 | * This function is called whenever disassociation has been processed in | 3503 | * This function is called whenever disassociation has been processed in |
3470 | * station mode. This includes both received disassociation frames and locally | 3504 | * station mode. This includes both received disassociation frames and locally |
3471 | * generated ones. This function may sleep. | 3505 | * generated ones. This function may sleep. The caller must hold the |
3506 | * corresponding wdev's mutex. | ||
3472 | */ | 3507 | */ |
3473 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); | 3508 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); |
3474 | 3509 | ||
3475 | /** | 3510 | /** |
3476 | * __cfg80211_send_disassoc - notification of processed disassociation | ||
3477 | * @dev: network device | ||
3478 | * @buf: disassociation response frame (header + body) | ||
3479 | * @len: length of the frame data | ||
3480 | * | ||
3481 | * Like cfg80211_send_disassoc(), but doesn't take the wdev lock. | ||
3482 | */ | ||
3483 | void __cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, | ||
3484 | size_t len); | ||
3485 | |||
3486 | /** | ||
3487 | * cfg80211_send_unprot_deauth - notification of unprotected deauthentication | 3511 | * cfg80211_send_unprot_deauth - notification of unprotected deauthentication |
3488 | * @dev: network device | 3512 | * @dev: network device |
3489 | * @buf: deauthentication frame (header + body) | 3513 | * @buf: deauthentication frame (header + body) |
@@ -4153,6 +4177,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
4153 | * cfg80211_crit_proto_stopped() - indicate critical protocol stopped by driver. | 4177 | * cfg80211_crit_proto_stopped() - indicate critical protocol stopped by driver. |
4154 | * | 4178 | * |
4155 | * @wdev: the wireless device for which critical protocol is stopped. | 4179 | * @wdev: the wireless device for which critical protocol is stopped. |
4180 | * @gfp: allocation flags | ||
4156 | * | 4181 | * |
4157 | * This function can be called by the driver to indicate it has reverted | 4182 | * This function can be called by the driver to indicate it has reverted |
4158 | * operation back to normal. One reason could be that the duration given | 4183 | * operation back to normal. One reason could be that the duration given |
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index c3999632e616..c6d07cb074bc 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h | |||
@@ -269,6 +269,7 @@ enum ieee80211_radiotap_type { | |||
269 | #define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 | 269 | #define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 |
270 | #define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 | 270 | #define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 |
271 | #define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 | 271 | #define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 |
272 | #define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20 | ||
272 | 273 | ||
273 | #define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 | 274 | #define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 |
274 | #define IEEE80211_RADIOTAP_MCS_BW_20 0 | 275 | #define IEEE80211_RADIOTAP_MCS_BW_20 0 |
@@ -278,6 +279,12 @@ enum ieee80211_radiotap_type { | |||
278 | #define IEEE80211_RADIOTAP_MCS_SGI 0x04 | 279 | #define IEEE80211_RADIOTAP_MCS_SGI 0x04 |
279 | #define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 | 280 | #define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 |
280 | #define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 | 281 | #define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 |
282 | #define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 | ||
283 | #define IEEE80211_RADIOTAP_MCS_STBC_1 1 | ||
284 | #define IEEE80211_RADIOTAP_MCS_STBC_2 2 | ||
285 | #define IEEE80211_RADIOTAP_MCS_STBC_3 3 | ||
286 | |||
287 | #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 | ||
281 | 288 | ||
282 | /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ | 289 | /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ |
283 | #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 | 290 | #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 885898a40d13..1f0014bd4d87 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -805,6 +805,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) | |||
805 | * on this subframe | 805 | * on this subframe |
806 | * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC | 806 | * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC |
807 | * is stored in the @ampdu_delimiter_crc field) | 807 | * is stored in the @ampdu_delimiter_crc field) |
808 | * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3 | ||
808 | */ | 809 | */ |
809 | enum mac80211_rx_flags { | 810 | enum mac80211_rx_flags { |
810 | RX_FLAG_MMIC_ERROR = BIT(0), | 811 | RX_FLAG_MMIC_ERROR = BIT(0), |
@@ -832,8 +833,11 @@ enum mac80211_rx_flags { | |||
832 | RX_FLAG_80MHZ = BIT(23), | 833 | RX_FLAG_80MHZ = BIT(23), |
833 | RX_FLAG_80P80MHZ = BIT(24), | 834 | RX_FLAG_80P80MHZ = BIT(24), |
834 | RX_FLAG_160MHZ = BIT(25), | 835 | RX_FLAG_160MHZ = BIT(25), |
836 | RX_FLAG_STBC_MASK = BIT(26) | BIT(27), | ||
835 | }; | 837 | }; |
836 | 838 | ||
839 | #define RX_FLAG_STBC_SHIFT 26 | ||
840 | |||
837 | /** | 841 | /** |
838 | * struct ieee80211_rx_status - receive status | 842 | * struct ieee80211_rx_status - receive status |
839 | * | 843 | * |
@@ -850,6 +854,10 @@ enum mac80211_rx_flags { | |||
850 | * @signal: signal strength when receiving this frame, either in dBm, in dB or | 854 | * @signal: signal strength when receiving this frame, either in dBm, in dB or |
851 | * unspecified depending on the hardware capabilities flags | 855 | * unspecified depending on the hardware capabilities flags |
852 | * @IEEE80211_HW_SIGNAL_* | 856 | * @IEEE80211_HW_SIGNAL_* |
857 | * @chains: bitmask of receive chains for which separate signal strength | ||
858 | * values were filled. | ||
859 | * @chain_signal: per-chain signal strength, in dBm (unlike @signal, doesn't | ||
860 | * support dB or unspecified units) | ||
853 | * @antenna: antenna used | 861 | * @antenna: antenna used |
854 | * @rate_idx: index of data rate into band's supported rates or MCS index if | 862 | * @rate_idx: index of data rate into band's supported rates or MCS index if |
855 | * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) | 863 | * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) |
@@ -881,6 +889,8 @@ struct ieee80211_rx_status { | |||
881 | u8 band; | 889 | u8 band; |
882 | u8 antenna; | 890 | u8 antenna; |
883 | s8 signal; | 891 | s8 signal; |
892 | u8 chains; | ||
893 | s8 chain_signal[IEEE80211_MAX_CHAINS]; | ||
884 | u8 ampdu_delimiter_crc; | 894 | u8 ampdu_delimiter_crc; |
885 | u8 vendor_radiotap_align; | 895 | u8 vendor_radiotap_align; |
886 | u8 vendor_radiotap_oui[3]; | 896 | u8 vendor_radiotap_oui[3]; |
@@ -1235,7 +1245,7 @@ enum ieee80211_sta_rx_bandwidth { | |||
1235 | * struct ieee80211_sta_rates - station rate selection table | 1245 | * struct ieee80211_sta_rates - station rate selection table |
1236 | * | 1246 | * |
1237 | * @rcu_head: RCU head used for freeing the table on update | 1247 | * @rcu_head: RCU head used for freeing the table on update |
1238 | * @rates: transmit rates/flags to be used by default. | 1248 | * @rate: transmit rates/flags to be used by default. |
1239 | * Overriding entries per-packet is possible by using cb tx control. | 1249 | * Overriding entries per-packet is possible by using cb tx control. |
1240 | */ | 1250 | */ |
1241 | struct ieee80211_sta_rates { | 1251 | struct ieee80211_sta_rates { |
@@ -1276,7 +1286,7 @@ struct ieee80211_sta_rates { | |||
1276 | * notifications and capabilities. The value is only valid after | 1286 | * notifications and capabilities. The value is only valid after |
1277 | * the station moves to associated state. | 1287 | * the station moves to associated state. |
1278 | * @smps_mode: current SMPS mode (off, static or dynamic) | 1288 | * @smps_mode: current SMPS mode (off, static or dynamic) |
1279 | * @tx_rates: rate control selection table | 1289 | * @rates: rate control selection table |
1280 | */ | 1290 | */ |
1281 | struct ieee80211_sta { | 1291 | struct ieee80211_sta { |
1282 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1292 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d1e48b5e348f..5920715278c2 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | 29 | ||
30 | #define NL80211_GENL_NAME "nl80211" | ||
31 | |||
30 | /** | 32 | /** |
31 | * DOC: Station handling | 33 | * DOC: Station handling |
32 | * | 34 | * |
@@ -1429,6 +1431,11 @@ enum nl80211_commands { | |||
1429 | * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which | 1431 | * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which |
1430 | * the connection should have increased reliability (u16). | 1432 | * the connection should have increased reliability (u16). |
1431 | * | 1433 | * |
1434 | * @NL80211_ATTR_PEER_AID: Association ID for the peer TDLS station (u16). | ||
1435 | * This is similar to @NL80211_ATTR_STA_AID but with a difference of being | ||
1436 | * allowed to be used with the first @NL80211_CMD_SET_STATION command to | ||
1437 | * update a TDLS peer STA entry. | ||
1438 | * | ||
1432 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1439 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1433 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1440 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1434 | */ | 1441 | */ |
@@ -1727,6 +1734,8 @@ enum nl80211_attrs { | |||
1727 | NL80211_ATTR_CRIT_PROT_ID, | 1734 | NL80211_ATTR_CRIT_PROT_ID, |
1728 | NL80211_ATTR_MAX_CRIT_PROT_DURATION, | 1735 | NL80211_ATTR_MAX_CRIT_PROT_DURATION, |
1729 | 1736 | ||
1737 | NL80211_ATTR_PEER_AID, | ||
1738 | |||
1730 | /* add attributes here, update the policy in nl80211.c */ | 1739 | /* add attributes here, update the policy in nl80211.c */ |
1731 | 1740 | ||
1732 | __NL80211_ATTR_AFTER_LAST, | 1741 | __NL80211_ATTR_AFTER_LAST, |
@@ -1991,6 +2000,10 @@ enum nl80211_sta_bss_param { | |||
1991 | * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode | 2000 | * @NL80211_STA_INFO_PEER_PM: peer mesh STA link-specific power mode |
1992 | * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards | 2001 | * @NL80211_STA_INFO_NONPEER_PM: neighbor mesh STA power save mode towards |
1993 | * non-peer STA | 2002 | * non-peer STA |
2003 | * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU | ||
2004 | * Contains a nested array of signal strength attributes (u8, dBm) | ||
2005 | * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average | ||
2006 | * Same format as NL80211_STA_INFO_CHAIN_SIGNAL. | ||
1994 | * @__NL80211_STA_INFO_AFTER_LAST: internal | 2007 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
1995 | * @NL80211_STA_INFO_MAX: highest possible station info attribute | 2008 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
1996 | */ | 2009 | */ |
@@ -2020,6 +2033,8 @@ enum nl80211_sta_info { | |||
2020 | NL80211_STA_INFO_NONPEER_PM, | 2033 | NL80211_STA_INFO_NONPEER_PM, |
2021 | NL80211_STA_INFO_RX_BYTES64, | 2034 | NL80211_STA_INFO_RX_BYTES64, |
2022 | NL80211_STA_INFO_TX_BYTES64, | 2035 | NL80211_STA_INFO_TX_BYTES64, |
2036 | NL80211_STA_INFO_CHAIN_SIGNAL, | ||
2037 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG, | ||
2023 | 2038 | ||
2024 | /* keep last */ | 2039 | /* keep last */ |
2025 | __NL80211_STA_INFO_AFTER_LAST, | 2040 | __NL80211_STA_INFO_AFTER_LAST, |
@@ -2413,6 +2428,8 @@ enum nl80211_survey_info { | |||
2413 | * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering | 2428 | * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering |
2414 | * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. | 2429 | * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. |
2415 | * overrides all other flags. | 2430 | * overrides all other flags. |
2431 | * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address | ||
2432 | * and ACK incoming unicast packets. | ||
2416 | * | 2433 | * |
2417 | * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use | 2434 | * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use |
2418 | * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag | 2435 | * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag |
@@ -2424,6 +2441,7 @@ enum nl80211_mntr_flags { | |||
2424 | NL80211_MNTR_FLAG_CONTROL, | 2441 | NL80211_MNTR_FLAG_CONTROL, |
2425 | NL80211_MNTR_FLAG_OTHER_BSS, | 2442 | NL80211_MNTR_FLAG_OTHER_BSS, |
2426 | NL80211_MNTR_FLAG_COOK_FRAMES, | 2443 | NL80211_MNTR_FLAG_COOK_FRAMES, |
2444 | NL80211_MNTR_FLAG_ACTIVE, | ||
2427 | 2445 | ||
2428 | /* keep last */ | 2446 | /* keep last */ |
2429 | __NL80211_MNTR_FLAG_AFTER_LAST, | 2447 | __NL80211_MNTR_FLAG_AFTER_LAST, |
@@ -2637,6 +2655,10 @@ enum nl80211_meshconf_params { | |||
2637 | * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will | 2655 | * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will |
2638 | * implement an MPM which handles peer allocation and state. | 2656 | * implement an MPM which handles peer allocation and state. |
2639 | * | 2657 | * |
2658 | * @NL80211_MESH_SETUP_AUTH_PROTOCOL: Inform the kernel of the authentication | ||
2659 | * method (u8, as defined in IEEE 8.4.2.100.6, e.g. 0x1 for SAE). | ||
2660 | * Default is no authentication method required. | ||
2661 | * | ||
2640 | * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number | 2662 | * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number |
2641 | * | 2663 | * |
2642 | * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use | 2664 | * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use |
@@ -2650,6 +2672,7 @@ enum nl80211_mesh_setup_params { | |||
2650 | NL80211_MESH_SETUP_USERSPACE_AMPE, | 2672 | NL80211_MESH_SETUP_USERSPACE_AMPE, |
2651 | NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, | 2673 | NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC, |
2652 | NL80211_MESH_SETUP_USERSPACE_MPM, | 2674 | NL80211_MESH_SETUP_USERSPACE_MPM, |
2675 | NL80211_MESH_SETUP_AUTH_PROTOCOL, | ||
2653 | 2676 | ||
2654 | /* keep last */ | 2677 | /* keep last */ |
2655 | __NL80211_MESH_SETUP_ATTR_AFTER_LAST, | 2678 | __NL80211_MESH_SETUP_ATTR_AFTER_LAST, |
@@ -3575,6 +3598,7 @@ enum nl80211_feature_flags { | |||
3575 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, | 3598 | NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, |
3576 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, | 3599 | NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, |
3577 | NL80211_FEATURE_USERSPACE_MPM = 1 << 16, | 3600 | NL80211_FEATURE_USERSPACE_MPM = 1 << 16, |
3601 | NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, | ||
3578 | }; | 3602 | }; |
3579 | 3603 | ||
3580 | /** | 3604 | /** |
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 0785e95c9924..be7614b9ed27 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c | |||
@@ -85,7 +85,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, | |||
85 | *cpos++ = *pos++ ^ e[i]; | 85 | *cpos++ = *pos++ ^ e[i]; |
86 | } | 86 | } |
87 | 87 | ||
88 | for (i = 0; i < CCMP_MIC_LEN; i++) | 88 | for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) |
89 | mic[i] = b[i] ^ s_0[i]; | 89 | mic[i] = b[i] ^ s_0[i]; |
90 | } | 90 | } |
91 | 91 | ||
@@ -123,7 +123,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, | |||
123 | crypto_cipher_encrypt_one(tfm, a, a); | 123 | crypto_cipher_encrypt_one(tfm, a, a); |
124 | } | 124 | } |
125 | 125 | ||
126 | for (i = 0; i < CCMP_MIC_LEN; i++) { | 126 | for (i = 0; i < IEEE80211_CCMP_MIC_LEN; i++) { |
127 | if ((mic[i] ^ s_0[i]) != a[i]) | 127 | if ((mic[i] ^ s_0[i]) != a[i]) |
128 | return -1; | 128 | return -1; |
129 | } | 129 | } |
@@ -138,7 +138,7 @@ struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) | |||
138 | 138 | ||
139 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | 139 | tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); |
140 | if (!IS_ERR(tfm)) | 140 | if (!IS_ERR(tfm)) |
141 | crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN); | 141 | crypto_cipher_setkey(tfm, key, WLAN_KEY_LEN_CCMP); |
142 | 142 | ||
143 | return tfm; | 143 | return tfm; |
144 | } | 144 | } |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1a89c80e6407..30622101d3b5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
73 | struct ieee80211_local *local = sdata->local; | 73 | struct ieee80211_local *local = sdata->local; |
74 | 74 | ||
75 | if (ieee80211_sdata_running(sdata)) { | 75 | if (ieee80211_sdata_running(sdata)) { |
76 | u32 mask = MONITOR_FLAG_COOK_FRAMES | | ||
77 | MONITOR_FLAG_ACTIVE; | ||
78 | |||
76 | /* | 79 | /* |
77 | * Prohibit MONITOR_FLAG_COOK_FRAMES to be | 80 | * Prohibit MONITOR_FLAG_COOK_FRAMES and |
78 | * changed while the interface is up. | 81 | * MONITOR_FLAG_ACTIVE to be changed while the |
82 | * interface is up. | ||
79 | * Else we would need to add a lot of cruft | 83 | * Else we would need to add a lot of cruft |
80 | * to update everything: | 84 | * to update everything: |
81 | * cooked_mntrs, monitor and all fif_* counters | 85 | * cooked_mntrs, monitor and all fif_* counters |
82 | * reconfigure hardware | 86 | * reconfigure hardware |
83 | */ | 87 | */ |
84 | if ((*flags & MONITOR_FLAG_COOK_FRAMES) != | 88 | if ((*flags & mask) != (sdata->u.mntr_flags & mask)) |
85 | (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) | ||
86 | return -EBUSY; | 89 | return -EBUSY; |
87 | 90 | ||
88 | ieee80211_adjust_monitor_flags(sdata, -1); | 91 | ieee80211_adjust_monitor_flags(sdata, -1); |
@@ -444,7 +447,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
444 | struct ieee80211_local *local = sdata->local; | 447 | struct ieee80211_local *local = sdata->local; |
445 | struct timespec uptime; | 448 | struct timespec uptime; |
446 | u64 packets = 0; | 449 | u64 packets = 0; |
447 | int ac; | 450 | int i, ac; |
448 | 451 | ||
449 | sinfo->generation = sdata->local->sta_generation; | 452 | sinfo->generation = sdata->local->sta_generation; |
450 | 453 | ||
@@ -488,6 +491,17 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
488 | sinfo->signal = (s8)sta->last_signal; | 491 | sinfo->signal = (s8)sta->last_signal; |
489 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | 492 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); |
490 | } | 493 | } |
494 | if (sta->chains) { | ||
495 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
496 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
497 | |||
498 | sinfo->chains = sta->chains; | ||
499 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
500 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
501 | sinfo->chain_signal_avg[i] = | ||
502 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
503 | } | ||
504 | } | ||
491 | 505 | ||
492 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | 506 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
493 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | 507 | sta_set_rate_info_rx(sta, &sinfo->rxrate); |
@@ -728,7 +742,7 @@ static void ieee80211_get_et_strings(struct wiphy *wiphy, | |||
728 | 742 | ||
729 | if (sset == ETH_SS_STATS) { | 743 | if (sset == ETH_SS_STATS) { |
730 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); | 744 | sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats); |
731 | memcpy(data, *ieee80211_gstrings_sta_stats, sz_sta_stats); | 745 | memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats); |
732 | } | 746 | } |
733 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); | 747 | drv_get_et_strings(sdata, sset, &(data[sz_sta_stats])); |
734 | } | 748 | } |
@@ -1735,6 +1749,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, | |||
1735 | ifmsh->mesh_pp_id = setup->path_sel_proto; | 1749 | ifmsh->mesh_pp_id = setup->path_sel_proto; |
1736 | ifmsh->mesh_pm_id = setup->path_metric; | 1750 | ifmsh->mesh_pm_id = setup->path_metric; |
1737 | ifmsh->user_mpm = setup->user_mpm; | 1751 | ifmsh->user_mpm = setup->user_mpm; |
1752 | ifmsh->mesh_auth_id = setup->auth_id; | ||
1738 | ifmsh->security = IEEE80211_MESH_SEC_NONE; | 1753 | ifmsh->security = IEEE80211_MESH_SEC_NONE; |
1739 | if (setup->is_authenticated) | 1754 | if (setup->is_authenticated) |
1740 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; | 1755 | ifmsh->security |= IEEE80211_MESH_SEC_AUTHED; |
@@ -2306,7 +2321,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | |||
2306 | enum ieee80211_smps_mode old_req; | 2321 | enum ieee80211_smps_mode old_req; |
2307 | int err; | 2322 | int err; |
2308 | 2323 | ||
2309 | lockdep_assert_held(&sdata->u.mgd.mtx); | 2324 | lockdep_assert_held(&sdata->wdev.mtx); |
2310 | 2325 | ||
2311 | old_req = sdata->u.mgd.req_smps; | 2326 | old_req = sdata->u.mgd.req_smps; |
2312 | sdata->u.mgd.req_smps = smps_mode; | 2327 | sdata->u.mgd.req_smps = smps_mode; |
@@ -2363,9 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
2363 | local->dynamic_ps_forced_timeout = timeout; | 2378 | local->dynamic_ps_forced_timeout = timeout; |
2364 | 2379 | ||
2365 | /* no change, but if automatic follow powersave */ | 2380 | /* no change, but if automatic follow powersave */ |
2366 | mutex_lock(&sdata->u.mgd.mtx); | 2381 | sdata_lock(sdata); |
2367 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); | 2382 | __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); |
2368 | mutex_unlock(&sdata->u.mgd.mtx); | 2383 | sdata_unlock(sdata); |
2369 | 2384 | ||
2370 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) | 2385 | if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) |
2371 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 2386 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 14abcf44f974..cafe614ef93d 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -228,9 +228,9 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, | |||
228 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 228 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
229 | return -EOPNOTSUPP; | 229 | return -EOPNOTSUPP; |
230 | 230 | ||
231 | mutex_lock(&sdata->u.mgd.mtx); | 231 | sdata_lock(sdata); |
232 | err = __ieee80211_request_smps(sdata, smps_mode); | 232 | err = __ieee80211_request_smps(sdata, smps_mode); |
233 | mutex_unlock(&sdata->u.mgd.mtx); | 233 | sdata_unlock(sdata); |
234 | 234 | ||
235 | return err; | 235 | return err; |
236 | } | 236 | } |
@@ -313,16 +313,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
313 | case NL80211_IFTYPE_STATION: | 313 | case NL80211_IFTYPE_STATION: |
314 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 314 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
315 | /* BSSID SA DA */ | 315 | /* BSSID SA DA */ |
316 | mutex_lock(&sdata->u.mgd.mtx); | 316 | sdata_lock(sdata); |
317 | if (!sdata->u.mgd.associated) { | 317 | if (!sdata->u.mgd.associated) { |
318 | mutex_unlock(&sdata->u.mgd.mtx); | 318 | sdata_unlock(sdata); |
319 | dev_kfree_skb(skb); | 319 | dev_kfree_skb(skb); |
320 | return -ENOTCONN; | 320 | return -ENOTCONN; |
321 | } | 321 | } |
322 | memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); | 322 | memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); |
323 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 323 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
324 | memcpy(hdr->addr3, addr, ETH_ALEN); | 324 | memcpy(hdr->addr3, addr, ETH_ALEN); |
325 | mutex_unlock(&sdata->u.mgd.mtx); | 325 | sdata_unlock(sdata); |
326 | break; | 326 | break; |
327 | default: | 327 | default: |
328 | dev_kfree_skb(skb); | 328 | dev_kfree_skb(skb); |
@@ -471,6 +471,8 @@ __IEEE80211_IF_FILE_W(tsf); | |||
471 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); | 471 | IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); |
472 | 472 | ||
473 | #ifdef CONFIG_MAC80211_MESH | 473 | #ifdef CONFIG_MAC80211_MESH |
474 | IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC); | ||
475 | |||
474 | /* Mesh stats attributes */ | 476 | /* Mesh stats attributes */ |
475 | IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); | 477 | IEEE80211_IF_FILE(fwded_mcast, u.mesh.mshstats.fwded_mcast, DEC); |
476 | IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); | 478 | IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); |
@@ -480,7 +482,6 @@ IEEE80211_IF_FILE(dropped_frames_congestion, | |||
480 | u.mesh.mshstats.dropped_frames_congestion, DEC); | 482 | u.mesh.mshstats.dropped_frames_congestion, DEC); |
481 | IEEE80211_IF_FILE(dropped_frames_no_route, | 483 | IEEE80211_IF_FILE(dropped_frames_no_route, |
482 | u.mesh.mshstats.dropped_frames_no_route, DEC); | 484 | u.mesh.mshstats.dropped_frames_no_route, DEC); |
483 | IEEE80211_IF_FILE(estab_plinks, u.mesh.estab_plinks, ATOMIC); | ||
484 | 485 | ||
485 | /* Mesh parameters */ | 486 | /* Mesh parameters */ |
486 | IEEE80211_IF_FILE(dot11MeshMaxRetries, | 487 | IEEE80211_IF_FILE(dot11MeshMaxRetries, |
@@ -583,6 +584,7 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) | |||
583 | static void add_mesh_files(struct ieee80211_sub_if_data *sdata) | 584 | static void add_mesh_files(struct ieee80211_sub_if_data *sdata) |
584 | { | 585 | { |
585 | DEBUGFS_ADD_MODE(tsf, 0600); | 586 | DEBUGFS_ADD_MODE(tsf, 0600); |
587 | DEBUGFS_ADD_MODE(estab_plinks, 0400); | ||
586 | } | 588 | } |
587 | 589 | ||
588 | static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) | 590 | static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) |
@@ -598,7 +600,6 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) | |||
598 | MESHSTATS_ADD(dropped_frames_ttl); | 600 | MESHSTATS_ADD(dropped_frames_ttl); |
599 | MESHSTATS_ADD(dropped_frames_no_route); | 601 | MESHSTATS_ADD(dropped_frames_no_route); |
600 | MESHSTATS_ADD(dropped_frames_congestion); | 602 | MESHSTATS_ADD(dropped_frames_congestion); |
601 | MESHSTATS_ADD(estab_plinks); | ||
602 | #undef MESHSTATS_ADD | 603 | #undef MESHSTATS_ADD |
603 | } | 604 | } |
604 | 605 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 169664c122e2..b931c96a596f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local, | |||
146 | 146 | ||
147 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 147 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
148 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && | 148 | (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
149 | !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) | 149 | !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) && |
150 | !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)))) | ||
150 | return -EINVAL; | 151 | return -EINVAL; |
151 | 152 | ||
152 | trace_drv_add_interface(local, sdata); | 153 | trace_drv_add_interface(local, sdata); |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index af8cee06e4f3..75dff338f581 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -429,9 +429,9 @@ void ieee80211_request_smps_work(struct work_struct *work) | |||
429 | container_of(work, struct ieee80211_sub_if_data, | 429 | container_of(work, struct ieee80211_sub_if_data, |
430 | u.mgd.request_smps_work); | 430 | u.mgd.request_smps_work); |
431 | 431 | ||
432 | mutex_lock(&sdata->u.mgd.mtx); | 432 | sdata_lock(sdata); |
433 | __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode); | 433 | __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode); |
434 | mutex_unlock(&sdata->u.mgd.mtx); | 434 | sdata_unlock(sdata); |
435 | } | 435 | } |
436 | 436 | ||
437 | void ieee80211_request_smps(struct ieee80211_vif *vif, | 437 | void ieee80211_request_smps(struct ieee80211_vif *vif, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 170f9a7fa319..caa4b4f7f6e4 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -54,7 +54,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
54 | struct beacon_data *presp; | 54 | struct beacon_data *presp; |
55 | int frame_len; | 55 | int frame_len; |
56 | 56 | ||
57 | lockdep_assert_held(&ifibss->mtx); | 57 | sdata_assert_lock(sdata); |
58 | 58 | ||
59 | /* Reset own TSF to allow time synchronization work. */ | 59 | /* Reset own TSF to allow time synchronization work. */ |
60 | drv_reset_tsf(local, sdata); | 60 | drv_reset_tsf(local, sdata); |
@@ -74,7 +74,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
74 | } | 74 | } |
75 | 75 | ||
76 | presp = rcu_dereference_protected(ifibss->presp, | 76 | presp = rcu_dereference_protected(ifibss->presp, |
77 | lockdep_is_held(&ifibss->mtx)); | 77 | lockdep_is_held(&sdata->wdev.mtx)); |
78 | rcu_assign_pointer(ifibss->presp, NULL); | 78 | rcu_assign_pointer(ifibss->presp, NULL); |
79 | if (presp) | 79 | if (presp) |
80 | kfree_rcu(presp, rcu_head); | 80 | kfree_rcu(presp, rcu_head); |
@@ -263,7 +263,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
263 | const struct cfg80211_bss_ies *ies; | 263 | const struct cfg80211_bss_ies *ies; |
264 | u64 tsf; | 264 | u64 tsf; |
265 | 265 | ||
266 | lockdep_assert_held(&sdata->u.ibss.mtx); | 266 | sdata_assert_lock(sdata); |
267 | 267 | ||
268 | if (beacon_int < 10) | 268 | if (beacon_int < 10) |
269 | beacon_int = 10; | 269 | beacon_int = 10; |
@@ -341,6 +341,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
341 | struct ieee80211_local *local = sdata->local; | 341 | struct ieee80211_local *local = sdata->local; |
342 | struct sta_info *sta; | 342 | struct sta_info *sta; |
343 | struct ieee80211_chanctx_conf *chanctx_conf; | 343 | struct ieee80211_chanctx_conf *chanctx_conf; |
344 | struct ieee80211_supported_band *sband; | ||
344 | int band; | 345 | int band; |
345 | 346 | ||
346 | /* | 347 | /* |
@@ -380,8 +381,9 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
380 | sta->last_rx = jiffies; | 381 | sta->last_rx = jiffies; |
381 | 382 | ||
382 | /* make sure mandatory rates are always added */ | 383 | /* make sure mandatory rates are always added */ |
384 | sband = local->hw.wiphy->bands[band]; | ||
383 | sta->sta.supp_rates[band] = supp_rates | | 385 | sta->sta.supp_rates[band] = supp_rates | |
384 | ieee80211_mandatory_rates(local, band); | 386 | ieee80211_mandatory_rates(sband); |
385 | 387 | ||
386 | return ieee80211_ibss_finish_sta(sta, auth); | 388 | return ieee80211_ibss_finish_sta(sta, auth); |
387 | } | 389 | } |
@@ -408,7 +410,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | |||
408 | struct sta_info *sta; | 410 | struct sta_info *sta; |
409 | u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 411 | u8 deauth_frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
410 | 412 | ||
411 | lockdep_assert_held(&sdata->u.ibss.mtx); | 413 | sdata_assert_lock(sdata); |
412 | 414 | ||
413 | if (len < 24 + 6) | 415 | if (len < 24 + 6) |
414 | return; | 416 | return; |
@@ -492,7 +494,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
492 | prev_rates = sta->sta.supp_rates[band]; | 494 | prev_rates = sta->sta.supp_rates[band]; |
493 | /* make sure mandatory rates are always added */ | 495 | /* make sure mandatory rates are always added */ |
494 | sta->sta.supp_rates[band] = supp_rates | | 496 | sta->sta.supp_rates[band] = supp_rates | |
495 | ieee80211_mandatory_rates(local, band); | 497 | ieee80211_mandatory_rates(sband); |
496 | 498 | ||
497 | if (sta->sta.supp_rates[band] != prev_rates) { | 499 | if (sta->sta.supp_rates[band] != prev_rates) { |
498 | ibss_dbg(sdata, | 500 | ibss_dbg(sdata, |
@@ -624,6 +626,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
624 | struct ieee80211_local *local = sdata->local; | 626 | struct ieee80211_local *local = sdata->local; |
625 | struct sta_info *sta; | 627 | struct sta_info *sta; |
626 | struct ieee80211_chanctx_conf *chanctx_conf; | 628 | struct ieee80211_chanctx_conf *chanctx_conf; |
629 | struct ieee80211_supported_band *sband; | ||
627 | int band; | 630 | int band; |
628 | 631 | ||
629 | /* | 632 | /* |
@@ -658,8 +661,9 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
658 | sta->last_rx = jiffies; | 661 | sta->last_rx = jiffies; |
659 | 662 | ||
660 | /* make sure mandatory rates are always added */ | 663 | /* make sure mandatory rates are always added */ |
664 | sband = local->hw.wiphy->bands[band]; | ||
661 | sta->sta.supp_rates[band] = supp_rates | | 665 | sta->sta.supp_rates[band] = supp_rates | |
662 | ieee80211_mandatory_rates(local, band); | 666 | ieee80211_mandatory_rates(sband); |
663 | 667 | ||
664 | spin_lock(&ifibss->incomplete_lock); | 668 | spin_lock(&ifibss->incomplete_lock); |
665 | list_add(&sta->list, &ifibss->incomplete_stations); | 669 | list_add(&sta->list, &ifibss->incomplete_stations); |
@@ -673,7 +677,7 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
673 | int active = 0; | 677 | int active = 0; |
674 | struct sta_info *sta; | 678 | struct sta_info *sta; |
675 | 679 | ||
676 | lockdep_assert_held(&sdata->u.ibss.mtx); | 680 | sdata_assert_lock(sdata); |
677 | 681 | ||
678 | rcu_read_lock(); | 682 | rcu_read_lock(); |
679 | 683 | ||
@@ -699,7 +703,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
699 | { | 703 | { |
700 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 704 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
701 | 705 | ||
702 | lockdep_assert_held(&ifibss->mtx); | 706 | sdata_assert_lock(sdata); |
703 | 707 | ||
704 | mod_timer(&ifibss->timer, | 708 | mod_timer(&ifibss->timer, |
705 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 709 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
@@ -730,7 +734,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
730 | u16 capability; | 734 | u16 capability; |
731 | int i; | 735 | int i; |
732 | 736 | ||
733 | lockdep_assert_held(&ifibss->mtx); | 737 | sdata_assert_lock(sdata); |
734 | 738 | ||
735 | if (ifibss->fixed_bssid) { | 739 | if (ifibss->fixed_bssid) { |
736 | memcpy(bssid, ifibss->bssid, ETH_ALEN); | 740 | memcpy(bssid, ifibss->bssid, ETH_ALEN); |
@@ -773,7 +777,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
773 | int active_ibss; | 777 | int active_ibss; |
774 | u16 capability; | 778 | u16 capability; |
775 | 779 | ||
776 | lockdep_assert_held(&ifibss->mtx); | 780 | sdata_assert_lock(sdata); |
777 | 781 | ||
778 | active_ibss = ieee80211_sta_active_ibss(sdata); | 782 | active_ibss = ieee80211_sta_active_ibss(sdata); |
779 | ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss); | 783 | ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss); |
@@ -843,10 +847,10 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
843 | struct beacon_data *presp; | 847 | struct beacon_data *presp; |
844 | u8 *pos, *end; | 848 | u8 *pos, *end; |
845 | 849 | ||
846 | lockdep_assert_held(&ifibss->mtx); | 850 | sdata_assert_lock(sdata); |
847 | 851 | ||
848 | presp = rcu_dereference_protected(ifibss->presp, | 852 | presp = rcu_dereference_protected(ifibss->presp, |
849 | lockdep_is_held(&ifibss->mtx)); | 853 | lockdep_is_held(&sdata->wdev.mtx)); |
850 | 854 | ||
851 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | 855 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || |
852 | len < 24 + 2 || !presp) | 856 | len < 24 + 2 || !presp) |
@@ -930,7 +934,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
930 | mgmt = (struct ieee80211_mgmt *) skb->data; | 934 | mgmt = (struct ieee80211_mgmt *) skb->data; |
931 | fc = le16_to_cpu(mgmt->frame_control); | 935 | fc = le16_to_cpu(mgmt->frame_control); |
932 | 936 | ||
933 | mutex_lock(&sdata->u.ibss.mtx); | 937 | sdata_lock(sdata); |
934 | 938 | ||
935 | if (!sdata->u.ibss.ssid_len) | 939 | if (!sdata->u.ibss.ssid_len) |
936 | goto mgmt_out; /* not ready to merge yet */ | 940 | goto mgmt_out; /* not ready to merge yet */ |
@@ -953,7 +957,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
953 | } | 957 | } |
954 | 958 | ||
955 | mgmt_out: | 959 | mgmt_out: |
956 | mutex_unlock(&sdata->u.ibss.mtx); | 960 | sdata_unlock(sdata); |
957 | } | 961 | } |
958 | 962 | ||
959 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | 963 | void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) |
@@ -961,7 +965,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | |||
961 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 965 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
962 | struct sta_info *sta; | 966 | struct sta_info *sta; |
963 | 967 | ||
964 | mutex_lock(&ifibss->mtx); | 968 | sdata_lock(sdata); |
965 | 969 | ||
966 | /* | 970 | /* |
967 | * Work could be scheduled after scan or similar | 971 | * Work could be scheduled after scan or similar |
@@ -997,7 +1001,7 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata) | |||
997 | } | 1001 | } |
998 | 1002 | ||
999 | out: | 1003 | out: |
1000 | mutex_unlock(&ifibss->mtx); | 1004 | sdata_unlock(sdata); |
1001 | } | 1005 | } |
1002 | 1006 | ||
1003 | static void ieee80211_ibss_timer(unsigned long data) | 1007 | static void ieee80211_ibss_timer(unsigned long data) |
@@ -1014,7 +1018,6 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1014 | 1018 | ||
1015 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | 1019 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, |
1016 | (unsigned long) sdata); | 1020 | (unsigned long) sdata); |
1017 | mutex_init(&ifibss->mtx); | ||
1018 | INIT_LIST_HEAD(&ifibss->incomplete_stations); | 1021 | INIT_LIST_HEAD(&ifibss->incomplete_stations); |
1019 | spin_lock_init(&ifibss->incomplete_lock); | 1022 | spin_lock_init(&ifibss->incomplete_lock); |
1020 | } | 1023 | } |
@@ -1041,8 +1044,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1041 | { | 1044 | { |
1042 | u32 changed = 0; | 1045 | u32 changed = 0; |
1043 | 1046 | ||
1044 | mutex_lock(&sdata->u.ibss.mtx); | ||
1045 | |||
1046 | if (params->bssid) { | 1047 | if (params->bssid) { |
1047 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | 1048 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); |
1048 | sdata->u.ibss.fixed_bssid = true; | 1049 | sdata->u.ibss.fixed_bssid = true; |
@@ -1075,8 +1076,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1075 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); | 1076 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); |
1076 | sdata->u.ibss.ssid_len = params->ssid_len; | 1077 | sdata->u.ibss.ssid_len = params->ssid_len; |
1077 | 1078 | ||
1078 | mutex_unlock(&sdata->u.ibss.mtx); | ||
1079 | |||
1080 | /* | 1079 | /* |
1081 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is | 1080 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is |
1082 | * reserved, but an HT STA shall protect HT transmissions as though | 1081 | * reserved, but an HT STA shall protect HT transmissions as though |
@@ -1112,8 +1111,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1112 | struct sta_info *sta; | 1111 | struct sta_info *sta; |
1113 | struct beacon_data *presp; | 1112 | struct beacon_data *presp; |
1114 | 1113 | ||
1115 | mutex_lock(&sdata->u.ibss.mtx); | ||
1116 | |||
1117 | active_ibss = ieee80211_sta_active_ibss(sdata); | 1114 | active_ibss = ieee80211_sta_active_ibss(sdata); |
1118 | 1115 | ||
1119 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { | 1116 | if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) { |
@@ -1157,7 +1154,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1157 | /* remove beacon */ | 1154 | /* remove beacon */ |
1158 | kfree(sdata->u.ibss.ie); | 1155 | kfree(sdata->u.ibss.ie); |
1159 | presp = rcu_dereference_protected(ifibss->presp, | 1156 | presp = rcu_dereference_protected(ifibss->presp, |
1160 | lockdep_is_held(&sdata->u.ibss.mtx)); | 1157 | lockdep_is_held(&sdata->wdev.mtx)); |
1161 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1158 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
1162 | sdata->vif.bss_conf.ibss_joined = false; | 1159 | sdata->vif.bss_conf.ibss_joined = false; |
1163 | sdata->vif.bss_conf.ibss_creator = false; | 1160 | sdata->vif.bss_conf.ibss_creator = false; |
@@ -1173,7 +1170,5 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1173 | 1170 | ||
1174 | del_timer_sync(&sdata->u.ibss.timer); | 1171 | del_timer_sync(&sdata->u.ibss.timer); |
1175 | 1172 | ||
1176 | mutex_unlock(&sdata->u.ibss.mtx); | ||
1177 | |||
1178 | return 0; | 1173 | return 0; |
1179 | } | 1174 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 44be28cfc6c4..9eed6f1d1614 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -394,7 +394,6 @@ struct ieee80211_if_managed { | |||
394 | bool nullfunc_failed; | 394 | bool nullfunc_failed; |
395 | bool connection_loss; | 395 | bool connection_loss; |
396 | 396 | ||
397 | struct mutex mtx; | ||
398 | struct cfg80211_bss *associated; | 397 | struct cfg80211_bss *associated; |
399 | struct ieee80211_mgd_auth_data *auth_data; | 398 | struct ieee80211_mgd_auth_data *auth_data; |
400 | struct ieee80211_mgd_assoc_data *assoc_data; | 399 | struct ieee80211_mgd_assoc_data *assoc_data; |
@@ -488,8 +487,6 @@ struct ieee80211_if_managed { | |||
488 | struct ieee80211_if_ibss { | 487 | struct ieee80211_if_ibss { |
489 | struct timer_list timer; | 488 | struct timer_list timer; |
490 | 489 | ||
491 | struct mutex mtx; | ||
492 | |||
493 | unsigned long last_scan_completed; | 490 | unsigned long last_scan_completed; |
494 | 491 | ||
495 | u32 basic_rates; | 492 | u32 basic_rates; |
@@ -580,8 +577,6 @@ struct ieee80211_if_mesh { | |||
580 | bool accepting_plinks; | 577 | bool accepting_plinks; |
581 | int num_gates; | 578 | int num_gates; |
582 | struct beacon_data __rcu *beacon; | 579 | struct beacon_data __rcu *beacon; |
583 | /* just protects beacon updates for now */ | ||
584 | struct mutex mtx; | ||
585 | const u8 *ie; | 580 | const u8 *ie; |
586 | u8 ie_len; | 581 | u8 ie_len; |
587 | enum { | 582 | enum { |
@@ -778,6 +773,26 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) | |||
778 | return container_of(p, struct ieee80211_sub_if_data, vif); | 773 | return container_of(p, struct ieee80211_sub_if_data, vif); |
779 | } | 774 | } |
780 | 775 | ||
776 | static inline void sdata_lock(struct ieee80211_sub_if_data *sdata) | ||
777 | __acquires(&sdata->wdev.mtx) | ||
778 | { | ||
779 | mutex_lock(&sdata->wdev.mtx); | ||
780 | __acquire(&sdata->wdev.mtx); | ||
781 | } | ||
782 | |||
783 | static inline void sdata_unlock(struct ieee80211_sub_if_data *sdata) | ||
784 | __releases(&sdata->wdev.mtx) | ||
785 | { | ||
786 | mutex_unlock(&sdata->wdev.mtx); | ||
787 | __release(&sdata->wdev.mtx); | ||
788 | } | ||
789 | |||
790 | static inline void | ||
791 | sdata_assert_lock(struct ieee80211_sub_if_data *sdata) | ||
792 | { | ||
793 | lockdep_assert_held(&sdata->wdev.mtx); | ||
794 | } | ||
795 | |||
781 | static inline enum ieee80211_band | 796 | static inline enum ieee80211_band |
782 | ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) | 797 | ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) |
783 | { | 798 | { |
@@ -1506,9 +1521,6 @@ static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action, | |||
1506 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); | 1521 | ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); |
1507 | } | 1522 | } |
1508 | 1523 | ||
1509 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | ||
1510 | enum ieee80211_band band); | ||
1511 | |||
1512 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1524 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
1513 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1525 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
1514 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1526 | void ieee80211_dynamic_ps_timer(unsigned long data); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7c3ba8628d4e..cc117591f678 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
161 | 161 | ||
162 | static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr) | 162 | static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr, |
163 | bool check_dup) | ||
163 | { | 164 | { |
164 | struct ieee80211_local *local = sdata->local; | 165 | struct ieee80211_local *local = sdata->local; |
165 | struct ieee80211_sub_if_data *iter; | 166 | struct ieee80211_sub_if_data *iter; |
@@ -180,13 +181,16 @@ static int ieee80211_verify_mac(struct ieee80211_sub_if_data *sdata, u8 *addr) | |||
180 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | 181 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | |
181 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | 182 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); |
182 | 183 | ||
184 | if (!check_dup) | ||
185 | return ret; | ||
183 | 186 | ||
184 | mutex_lock(&local->iflist_mtx); | 187 | mutex_lock(&local->iflist_mtx); |
185 | list_for_each_entry(iter, &local->interfaces, list) { | 188 | list_for_each_entry(iter, &local->interfaces, list) { |
186 | if (iter == sdata) | 189 | if (iter == sdata) |
187 | continue; | 190 | continue; |
188 | 191 | ||
189 | if (iter->vif.type == NL80211_IFTYPE_MONITOR) | 192 | if (iter->vif.type == NL80211_IFTYPE_MONITOR && |
193 | !(iter->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | ||
190 | continue; | 194 | continue; |
191 | 195 | ||
192 | m = iter->vif.addr; | 196 | m = iter->vif.addr; |
@@ -208,12 +212,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) | |||
208 | { | 212 | { |
209 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 213 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
210 | struct sockaddr *sa = addr; | 214 | struct sockaddr *sa = addr; |
215 | bool check_dup = true; | ||
211 | int ret; | 216 | int ret; |
212 | 217 | ||
213 | if (ieee80211_sdata_running(sdata)) | 218 | if (ieee80211_sdata_running(sdata)) |
214 | return -EBUSY; | 219 | return -EBUSY; |
215 | 220 | ||
216 | ret = ieee80211_verify_mac(sdata, sa->sa_data); | 221 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR && |
222 | !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | ||
223 | check_dup = false; | ||
224 | |||
225 | ret = ieee80211_verify_mac(sdata, sa->sa_data, check_dup); | ||
217 | if (ret) | 226 | if (ret) |
218 | return ret; | 227 | return ret; |
219 | 228 | ||
@@ -545,7 +554,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
545 | break; | 554 | break; |
546 | } | 555 | } |
547 | 556 | ||
548 | if (local->monitors == 0 && local->open_count == 0) { | 557 | if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) { |
558 | res = drv_add_interface(local, sdata); | ||
559 | if (res) | ||
560 | goto err_stop; | ||
561 | } else if (local->monitors == 0 && local->open_count == 0) { | ||
549 | res = ieee80211_add_virtual_monitor(local); | 562 | res = ieee80211_add_virtual_monitor(local); |
550 | if (res) | 563 | if (res) |
551 | goto err_stop; | 564 | goto err_stop; |
@@ -923,7 +936,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
923 | mutex_lock(&local->mtx); | 936 | mutex_lock(&local->mtx); |
924 | ieee80211_recalc_idle(local); | 937 | ieee80211_recalc_idle(local); |
925 | mutex_unlock(&local->mtx); | 938 | mutex_unlock(&local->mtx); |
926 | break; | 939 | |
940 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | ||
941 | break; | ||
942 | |||
943 | /* fall through */ | ||
927 | default: | 944 | default: |
928 | if (going_down) | 945 | if (going_down) |
929 | drv_remove_interface(local, sdata); | 946 | drv_remove_interface(local, sdata); |
@@ -1072,7 +1089,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { | |||
1072 | .ndo_start_xmit = ieee80211_monitor_start_xmit, | 1089 | .ndo_start_xmit = ieee80211_monitor_start_xmit, |
1073 | .ndo_set_rx_mode = ieee80211_set_multicast_list, | 1090 | .ndo_set_rx_mode = ieee80211_set_multicast_list, |
1074 | .ndo_change_mtu = ieee80211_change_mtu, | 1091 | .ndo_change_mtu = ieee80211_change_mtu, |
1075 | .ndo_set_mac_address = eth_mac_addr, | 1092 | .ndo_set_mac_address = ieee80211_change_mac, |
1076 | .ndo_select_queue = ieee80211_monitor_select_queue, | 1093 | .ndo_select_queue = ieee80211_monitor_select_queue, |
1077 | }; | 1094 | }; |
1078 | 1095 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 67059b88fea5..e39cc91d0cf1 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -335,12 +335,12 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
335 | switch (cipher) { | 335 | switch (cipher) { |
336 | case WLAN_CIPHER_SUITE_WEP40: | 336 | case WLAN_CIPHER_SUITE_WEP40: |
337 | case WLAN_CIPHER_SUITE_WEP104: | 337 | case WLAN_CIPHER_SUITE_WEP104: |
338 | key->conf.iv_len = WEP_IV_LEN; | 338 | key->conf.iv_len = IEEE80211_WEP_IV_LEN; |
339 | key->conf.icv_len = WEP_ICV_LEN; | 339 | key->conf.icv_len = IEEE80211_WEP_ICV_LEN; |
340 | break; | 340 | break; |
341 | case WLAN_CIPHER_SUITE_TKIP: | 341 | case WLAN_CIPHER_SUITE_TKIP: |
342 | key->conf.iv_len = TKIP_IV_LEN; | 342 | key->conf.iv_len = IEEE80211_TKIP_IV_LEN; |
343 | key->conf.icv_len = TKIP_ICV_LEN; | 343 | key->conf.icv_len = IEEE80211_TKIP_ICV_LEN; |
344 | if (seq) { | 344 | if (seq) { |
345 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { | 345 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) { |
346 | key->u.tkip.rx[i].iv32 = | 346 | key->u.tkip.rx[i].iv32 = |
@@ -352,13 +352,13 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
352 | spin_lock_init(&key->u.tkip.txlock); | 352 | spin_lock_init(&key->u.tkip.txlock); |
353 | break; | 353 | break; |
354 | case WLAN_CIPHER_SUITE_CCMP: | 354 | case WLAN_CIPHER_SUITE_CCMP: |
355 | key->conf.iv_len = CCMP_HDR_LEN; | 355 | key->conf.iv_len = IEEE80211_CCMP_HDR_LEN; |
356 | key->conf.icv_len = CCMP_MIC_LEN; | 356 | key->conf.icv_len = IEEE80211_CCMP_MIC_LEN; |
357 | if (seq) { | 357 | if (seq) { |
358 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) | 358 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) |
359 | for (j = 0; j < CCMP_PN_LEN; j++) | 359 | for (j = 0; j < IEEE80211_CCMP_PN_LEN; j++) |
360 | key->u.ccmp.rx_pn[i][j] = | 360 | key->u.ccmp.rx_pn[i][j] = |
361 | seq[CCMP_PN_LEN - j - 1]; | 361 | seq[IEEE80211_CCMP_PN_LEN - j - 1]; |
362 | } | 362 | } |
363 | /* | 363 | /* |
364 | * Initialize AES key state here as an optimization so that | 364 | * Initialize AES key state here as an optimization so that |
@@ -375,9 +375,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
375 | key->conf.iv_len = 0; | 375 | key->conf.iv_len = 0; |
376 | key->conf.icv_len = sizeof(struct ieee80211_mmie); | 376 | key->conf.icv_len = sizeof(struct ieee80211_mmie); |
377 | if (seq) | 377 | if (seq) |
378 | for (j = 0; j < CMAC_PN_LEN; j++) | 378 | for (j = 0; j < IEEE80211_CMAC_PN_LEN; j++) |
379 | key->u.aes_cmac.rx_pn[j] = | 379 | key->u.aes_cmac.rx_pn[j] = |
380 | seq[CMAC_PN_LEN - j - 1]; | 380 | seq[IEEE80211_CMAC_PN_LEN - j - 1]; |
381 | /* | 381 | /* |
382 | * Initialize AES key state here as an optimization so that | 382 | * Initialize AES key state here as an optimization so that |
383 | * it does not need to be initialized for every packet. | 383 | * it does not need to be initialized for every packet. |
@@ -740,13 +740,13 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, | |||
740 | pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; | 740 | pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS]; |
741 | else | 741 | else |
742 | pn = key->u.ccmp.rx_pn[tid]; | 742 | pn = key->u.ccmp.rx_pn[tid]; |
743 | memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN); | 743 | memcpy(seq->ccmp.pn, pn, IEEE80211_CCMP_PN_LEN); |
744 | break; | 744 | break; |
745 | case WLAN_CIPHER_SUITE_AES_CMAC: | 745 | case WLAN_CIPHER_SUITE_AES_CMAC: |
746 | if (WARN_ON(tid != 0)) | 746 | if (WARN_ON(tid != 0)) |
747 | return; | 747 | return; |
748 | pn = key->u.aes_cmac.rx_pn; | 748 | pn = key->u.aes_cmac.rx_pn; |
749 | memcpy(seq->aes_cmac.pn, pn, CMAC_PN_LEN); | 749 | memcpy(seq->aes_cmac.pn, pn, IEEE80211_CMAC_PN_LEN); |
750 | break; | 750 | break; |
751 | } | 751 | } |
752 | } | 752 | } |
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index e8de3e6d7804..036d57e76a5e 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -19,17 +19,6 @@ | |||
19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
21 | 21 | ||
22 | #define WEP_IV_LEN 4 | ||
23 | #define WEP_ICV_LEN 4 | ||
24 | #define ALG_CCMP_KEY_LEN 16 | ||
25 | #define CCMP_HDR_LEN 8 | ||
26 | #define CCMP_MIC_LEN 8 | ||
27 | #define CCMP_TK_LEN 16 | ||
28 | #define CCMP_PN_LEN 6 | ||
29 | #define TKIP_IV_LEN 8 | ||
30 | #define TKIP_ICV_LEN 4 | ||
31 | #define CMAC_PN_LEN 6 | ||
32 | |||
33 | struct ieee80211_local; | 22 | struct ieee80211_local; |
34 | struct ieee80211_sub_if_data; | 23 | struct ieee80211_sub_if_data; |
35 | struct sta_info; | 24 | struct sta_info; |
@@ -93,13 +82,13 @@ struct ieee80211_key { | |||
93 | * frames and the last counter is used with Robust | 82 | * frames and the last counter is used with Robust |
94 | * Management frames. | 83 | * Management frames. |
95 | */ | 84 | */ |
96 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN]; | 85 | u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN]; |
97 | struct crypto_cipher *tfm; | 86 | struct crypto_cipher *tfm; |
98 | u32 replays; /* dot11RSNAStatsCCMPReplays */ | 87 | u32 replays; /* dot11RSNAStatsCCMPReplays */ |
99 | } ccmp; | 88 | } ccmp; |
100 | struct { | 89 | struct { |
101 | atomic64_t tx_pn; | 90 | atomic64_t tx_pn; |
102 | u8 rx_pn[CMAC_PN_LEN]; | 91 | u8 rx_pn[IEEE80211_CMAC_PN_LEN]; |
103 | struct crypto_cipher *tfm; | 92 | struct crypto_cipher *tfm; |
104 | u32 replays; /* dot11RSNAStatsCMACReplays */ | 93 | u32 replays; /* dot11RSNAStatsCMACReplays */ |
105 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ | 94 | u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 8a7bfc47d577..1998f1475267 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -331,7 +331,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
331 | return NOTIFY_DONE; | 331 | return NOTIFY_DONE; |
332 | 332 | ||
333 | ifmgd = &sdata->u.mgd; | 333 | ifmgd = &sdata->u.mgd; |
334 | mutex_lock(&ifmgd->mtx); | 334 | sdata_lock(sdata); |
335 | 335 | ||
336 | /* Copy the addresses to the bss_conf list */ | 336 | /* Copy the addresses to the bss_conf list */ |
337 | ifa = idev->ifa_list; | 337 | ifa = idev->ifa_list; |
@@ -349,7 +349,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
349 | ieee80211_bss_info_change_notify(sdata, | 349 | ieee80211_bss_info_change_notify(sdata, |
350 | BSS_CHANGED_ARP_FILTER); | 350 | BSS_CHANGED_ARP_FILTER); |
351 | 351 | ||
352 | mutex_unlock(&ifmgd->mtx); | 352 | sdata_unlock(sdata); |
353 | 353 | ||
354 | return NOTIFY_DONE; | 354 | return NOTIFY_DONE; |
355 | } | 355 | } |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 6952760881c8..b3d1fdd46368 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -161,8 +161,11 @@ void mesh_sta_cleanup(struct sta_info *sta) | |||
161 | del_timer_sync(&sta->plink_timer); | 161 | del_timer_sync(&sta->plink_timer); |
162 | } | 162 | } |
163 | 163 | ||
164 | if (changed) | 164 | if (changed) { |
165 | sdata_lock(sdata); | ||
165 | ieee80211_mbss_info_change_notify(sdata, changed); | 166 | ieee80211_mbss_info_change_notify(sdata, changed); |
167 | sdata_unlock(sdata); | ||
168 | } | ||
166 | } | 169 | } |
167 | 170 | ||
168 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 171 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -577,7 +580,9 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) | |||
577 | mesh_path_expire(sdata); | 580 | mesh_path_expire(sdata); |
578 | 581 | ||
579 | changed = mesh_accept_plinks_update(sdata); | 582 | changed = mesh_accept_plinks_update(sdata); |
583 | sdata_lock(sdata); | ||
580 | ieee80211_mbss_info_change_notify(sdata, changed); | 584 | ieee80211_mbss_info_change_notify(sdata, changed); |
585 | sdata_unlock(sdata); | ||
581 | 586 | ||
582 | mod_timer(&ifmsh->housekeeping_timer, | 587 | mod_timer(&ifmsh->housekeeping_timer, |
583 | round_jiffies(jiffies + | 588 | round_jiffies(jiffies + |
@@ -697,25 +702,21 @@ out_free: | |||
697 | } | 702 | } |
698 | 703 | ||
699 | static int | 704 | static int |
700 | ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh) | 705 | ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata) |
701 | { | 706 | { |
702 | struct beacon_data *old_bcn; | 707 | struct beacon_data *old_bcn; |
703 | int ret; | 708 | int ret; |
704 | 709 | ||
705 | mutex_lock(&ifmsh->mtx); | 710 | old_bcn = rcu_dereference_protected(sdata->u.mesh.beacon, |
706 | 711 | lockdep_is_held(&sdata->wdev.mtx)); | |
707 | old_bcn = rcu_dereference_protected(ifmsh->beacon, | 712 | ret = ieee80211_mesh_build_beacon(&sdata->u.mesh); |
708 | lockdep_is_held(&ifmsh->mtx)); | ||
709 | ret = ieee80211_mesh_build_beacon(ifmsh); | ||
710 | if (ret) | 713 | if (ret) |
711 | /* just reuse old beacon */ | 714 | /* just reuse old beacon */ |
712 | goto out; | 715 | return ret; |
713 | 716 | ||
714 | if (old_bcn) | 717 | if (old_bcn) |
715 | kfree_rcu(old_bcn, rcu_head); | 718 | kfree_rcu(old_bcn, rcu_head); |
716 | out: | 719 | return 0; |
717 | mutex_unlock(&ifmsh->mtx); | ||
718 | return ret; | ||
719 | } | 720 | } |
720 | 721 | ||
721 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 722 | void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
@@ -726,7 +727,7 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
726 | BSS_CHANGED_HT | | 727 | BSS_CHANGED_HT | |
727 | BSS_CHANGED_BASIC_RATES | | 728 | BSS_CHANGED_BASIC_RATES | |
728 | BSS_CHANGED_BEACON_INT))) | 729 | BSS_CHANGED_BEACON_INT))) |
729 | if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh)) | 730 | if (ieee80211_mesh_rebuild_beacon(sdata)) |
730 | return; | 731 | return; |
731 | ieee80211_bss_info_change_notify(sdata, changed); | 732 | ieee80211_bss_info_change_notify(sdata, changed); |
732 | } | 733 | } |
@@ -741,6 +742,8 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
741 | BSS_CHANGED_BASIC_RATES | | 742 | BSS_CHANGED_BASIC_RATES | |
742 | BSS_CHANGED_BEACON_INT; | 743 | BSS_CHANGED_BEACON_INT; |
743 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | 744 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); |
745 | struct ieee80211_supported_band *sband = | ||
746 | sdata->local->hw.wiphy->bands[band]; | ||
744 | 747 | ||
745 | local->fif_other_bss++; | 748 | local->fif_other_bss++; |
746 | /* mesh ifaces must set allmulti to forward mcast traffic */ | 749 | /* mesh ifaces must set allmulti to forward mcast traffic */ |
@@ -748,7 +751,6 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
748 | ieee80211_configure_filter(local); | 751 | ieee80211_configure_filter(local); |
749 | 752 | ||
750 | ifmsh->mesh_cc_id = 0; /* Disabled */ | 753 | ifmsh->mesh_cc_id = 0; /* Disabled */ |
751 | ifmsh->mesh_auth_id = 0; /* Disabled */ | ||
752 | /* register sync ops from extensible synchronization framework */ | 754 | /* register sync ops from extensible synchronization framework */ |
753 | ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); | 755 | ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); |
754 | ifmsh->adjusting_tbtt = false; | 756 | ifmsh->adjusting_tbtt = false; |
@@ -759,8 +761,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
759 | sdata->vif.bss_conf.ht_operation_mode = | 761 | sdata->vif.bss_conf.ht_operation_mode = |
760 | ifmsh->mshcfg.ht_opmode; | 762 | ifmsh->mshcfg.ht_opmode; |
761 | sdata->vif.bss_conf.enable_beacon = true; | 763 | sdata->vif.bss_conf.enable_beacon = true; |
762 | sdata->vif.bss_conf.basic_rates = | 764 | sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sband); |
763 | ieee80211_mandatory_rates(local, band); | ||
764 | 765 | ||
765 | changed |= ieee80211_mps_local_status_update(sdata); | 766 | changed |= ieee80211_mps_local_status_update(sdata); |
766 | 767 | ||
@@ -788,12 +789,12 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | |||
788 | sdata->vif.bss_conf.enable_beacon = false; | 789 | sdata->vif.bss_conf.enable_beacon = false; |
789 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 790 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
790 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 791 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
791 | mutex_lock(&ifmsh->mtx); | 792 | sdata_lock(sdata); |
792 | bcn = rcu_dereference_protected(ifmsh->beacon, | 793 | bcn = rcu_dereference_protected(ifmsh->beacon, |
793 | lockdep_is_held(&ifmsh->mtx)); | 794 | lockdep_is_held(&sdata->wdev.mtx)); |
794 | rcu_assign_pointer(ifmsh->beacon, NULL); | 795 | rcu_assign_pointer(ifmsh->beacon, NULL); |
795 | kfree_rcu(bcn, rcu_head); | 796 | kfree_rcu(bcn, rcu_head); |
796 | mutex_unlock(&ifmsh->mtx); | 797 | sdata_unlock(sdata); |
797 | 798 | ||
798 | /* flush STAs and mpaths on this iface */ | 799 | /* flush STAs and mpaths on this iface */ |
799 | sta_info_flush(sdata); | 800 | sta_info_flush(sdata); |
@@ -1041,7 +1042,6 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
1041 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 1042 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
1042 | spin_lock_init(&ifmsh->sync_offset_lock); | 1043 | spin_lock_init(&ifmsh->sync_offset_lock); |
1043 | RCU_INIT_POINTER(ifmsh->beacon, NULL); | 1044 | RCU_INIT_POINTER(ifmsh->beacon, NULL); |
1044 | mutex_init(&ifmsh->mtx); | ||
1045 | 1045 | ||
1046 | sdata->vif.bss_conf.bssid = zero_addr; | 1046 | sdata->vif.bss_conf.bssid = zero_addr; |
1047 | } | 1047 | } |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 09bebed99416..6c4da99bc4fb 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -517,7 +517,9 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | |||
517 | ieee80211_mps_frame_release(sta, elems); | 517 | ieee80211_mps_frame_release(sta, elems); |
518 | out: | 518 | out: |
519 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
520 | sdata_lock(sdata); | ||
520 | ieee80211_mbss_info_change_notify(sdata, changed); | 521 | ieee80211_mbss_info_change_notify(sdata, changed); |
522 | sdata_unlock(sdata); | ||
521 | } | 523 | } |
522 | 524 | ||
523 | static void mesh_plink_timer(unsigned long data) | 525 | static void mesh_plink_timer(unsigned long data) |
@@ -1068,6 +1070,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | |||
1068 | 1070 | ||
1069 | rcu_read_unlock(); | 1071 | rcu_read_unlock(); |
1070 | 1072 | ||
1071 | if (changed) | 1073 | if (changed) { |
1074 | sdata_lock(sdata); | ||
1072 | ieee80211_mbss_info_change_notify(sdata, changed); | 1075 | ieee80211_mbss_info_change_notify(sdata, changed); |
1076 | sdata_unlock(sdata); | ||
1077 | } | ||
1073 | } | 1078 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a8c2130c8ba4..f44f4caa69ee 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -91,41 +91,6 @@ MODULE_PARM_DESC(probe_wait_ms, | |||
91 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 | 91 | #define IEEE80211_SIGNAL_AVE_MIN_COUNT 4 |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * All cfg80211 functions have to be called outside a locked | ||
95 | * section so that they can acquire a lock themselves... This | ||
96 | * is much simpler than queuing up things in cfg80211, but we | ||
97 | * do need some indirection for that here. | ||
98 | */ | ||
99 | enum rx_mgmt_action { | ||
100 | /* no action required */ | ||
101 | RX_MGMT_NONE, | ||
102 | |||
103 | /* caller must call cfg80211_send_deauth() */ | ||
104 | RX_MGMT_CFG80211_DEAUTH, | ||
105 | |||
106 | /* caller must call cfg80211_send_disassoc() */ | ||
107 | RX_MGMT_CFG80211_DISASSOC, | ||
108 | |||
109 | /* caller must call cfg80211_send_rx_auth() */ | ||
110 | RX_MGMT_CFG80211_RX_AUTH, | ||
111 | |||
112 | /* caller must call cfg80211_send_rx_assoc() */ | ||
113 | RX_MGMT_CFG80211_RX_ASSOC, | ||
114 | |||
115 | /* caller must call cfg80211_send_assoc_timeout() */ | ||
116 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, | ||
117 | |||
118 | /* used when a processed beacon causes a deauth */ | ||
119 | RX_MGMT_CFG80211_TX_DEAUTH, | ||
120 | }; | ||
121 | |||
122 | /* utils */ | ||
123 | static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | ||
124 | { | ||
125 | lockdep_assert_held(&ifmgd->mtx); | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * We can have multiple work items (and connection probing) | 94 | * We can have multiple work items (and connection probing) |
130 | * scheduling this timer, but we need to take care to only | 95 | * scheduling this timer, but we need to take care to only |
131 | * reschedule it when it should fire _earlier_ than it was | 96 | * reschedule it when it should fire _earlier_ than it was |
@@ -135,13 +100,14 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | |||
135 | * has happened -- the work that runs from this timer will | 100 | * has happened -- the work that runs from this timer will |
136 | * do that. | 101 | * do that. |
137 | */ | 102 | */ |
138 | static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout) | 103 | static void run_again(struct ieee80211_sub_if_data *sdata, |
104 | unsigned long timeout) | ||
139 | { | 105 | { |
140 | ASSERT_MGD_MTX(ifmgd); | 106 | sdata_assert_lock(sdata); |
141 | 107 | ||
142 | if (!timer_pending(&ifmgd->timer) || | 108 | if (!timer_pending(&sdata->u.mgd.timer) || |
143 | time_before(timeout, ifmgd->timer.expires)) | 109 | time_before(timeout, sdata->u.mgd.timer.expires)) |
144 | mod_timer(&ifmgd->timer, timeout); | 110 | mod_timer(&sdata->u.mgd.timer, timeout); |
145 | } | 111 | } |
146 | 112 | ||
147 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) | 113 | void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) |
@@ -652,7 +618,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
652 | struct ieee80211_channel *chan; | 618 | struct ieee80211_channel *chan; |
653 | u32 rates = 0; | 619 | u32 rates = 0; |
654 | 620 | ||
655 | lockdep_assert_held(&ifmgd->mtx); | 621 | sdata_assert_lock(sdata); |
656 | 622 | ||
657 | rcu_read_lock(); | 623 | rcu_read_lock(); |
658 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 624 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
@@ -962,7 +928,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
962 | if (!ieee80211_sdata_running(sdata)) | 928 | if (!ieee80211_sdata_running(sdata)) |
963 | return; | 929 | return; |
964 | 930 | ||
965 | mutex_lock(&ifmgd->mtx); | 931 | sdata_lock(sdata); |
966 | if (!ifmgd->associated) | 932 | if (!ifmgd->associated) |
967 | goto out; | 933 | goto out; |
968 | 934 | ||
@@ -985,7 +951,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
985 | IEEE80211_QUEUE_STOP_REASON_CSA); | 951 | IEEE80211_QUEUE_STOP_REASON_CSA); |
986 | out: | 952 | out: |
987 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 953 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
988 | mutex_unlock(&ifmgd->mtx); | 954 | sdata_unlock(sdata); |
989 | } | 955 | } |
990 | 956 | ||
991 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 957 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
@@ -1036,7 +1002,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1036 | const struct ieee80211_ht_operation *ht_oper; | 1002 | const struct ieee80211_ht_operation *ht_oper; |
1037 | int secondary_channel_offset = -1; | 1003 | int secondary_channel_offset = -1; |
1038 | 1004 | ||
1039 | ASSERT_MGD_MTX(ifmgd); | 1005 | sdata_assert_lock(sdata); |
1040 | 1006 | ||
1041 | if (!cbss) | 1007 | if (!cbss) |
1042 | return; | 1008 | return; |
@@ -1390,6 +1356,9 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | |||
1390 | IEEE80211_STA_CONNECTION_POLL)) | 1356 | IEEE80211_STA_CONNECTION_POLL)) |
1391 | return false; | 1357 | return false; |
1392 | 1358 | ||
1359 | if (!sdata->vif.bss_conf.dtim_period) | ||
1360 | return false; | ||
1361 | |||
1393 | rcu_read_lock(); | 1362 | rcu_read_lock(); |
1394 | sta = sta_info_get(sdata, mgd->bssid); | 1363 | sta = sta_info_get(sdata, mgd->bssid); |
1395 | if (sta) | 1364 | if (sta) |
@@ -1842,7 +1811,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1842 | struct ieee80211_local *local = sdata->local; | 1811 | struct ieee80211_local *local = sdata->local; |
1843 | u32 changed = 0; | 1812 | u32 changed = 0; |
1844 | 1813 | ||
1845 | ASSERT_MGD_MTX(ifmgd); | 1814 | sdata_assert_lock(sdata); |
1846 | 1815 | ||
1847 | if (WARN_ON_ONCE(tx && !frame_buf)) | 1816 | if (WARN_ON_ONCE(tx && !frame_buf)) |
1848 | return; | 1817 | return; |
@@ -2051,7 +2020,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2051 | } | 2020 | } |
2052 | 2021 | ||
2053 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 2022 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
2054 | run_again(ifmgd, ifmgd->probe_timeout); | 2023 | run_again(sdata, ifmgd->probe_timeout); |
2055 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 2024 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
2056 | ieee80211_flush_queues(sdata->local, sdata); | 2025 | ieee80211_flush_queues(sdata->local, sdata); |
2057 | } | 2026 | } |
@@ -2065,7 +2034,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
2065 | if (!ieee80211_sdata_running(sdata)) | 2034 | if (!ieee80211_sdata_running(sdata)) |
2066 | return; | 2035 | return; |
2067 | 2036 | ||
2068 | mutex_lock(&ifmgd->mtx); | 2037 | sdata_lock(sdata); |
2069 | 2038 | ||
2070 | if (!ifmgd->associated) | 2039 | if (!ifmgd->associated) |
2071 | goto out; | 2040 | goto out; |
@@ -2119,7 +2088,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
2119 | ifmgd->probe_send_count = 0; | 2088 | ifmgd->probe_send_count = 0; |
2120 | ieee80211_mgd_probe_ap_send(sdata); | 2089 | ieee80211_mgd_probe_ap_send(sdata); |
2121 | out: | 2090 | out: |
2122 | mutex_unlock(&ifmgd->mtx); | 2091 | sdata_unlock(sdata); |
2123 | } | 2092 | } |
2124 | 2093 | ||
2125 | struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | 2094 | struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, |
@@ -2135,7 +2104,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2135 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | 2104 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2136 | return NULL; | 2105 | return NULL; |
2137 | 2106 | ||
2138 | ASSERT_MGD_MTX(ifmgd); | 2107 | sdata_assert_lock(sdata); |
2139 | 2108 | ||
2140 | if (ifmgd->associated) | 2109 | if (ifmgd->associated) |
2141 | cbss = ifmgd->associated; | 2110 | cbss = ifmgd->associated; |
@@ -2168,9 +2137,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2168 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2137 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2169 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 2138 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
2170 | 2139 | ||
2171 | mutex_lock(&ifmgd->mtx); | 2140 | sdata_lock(sdata); |
2172 | if (!ifmgd->associated) { | 2141 | if (!ifmgd->associated) { |
2173 | mutex_unlock(&ifmgd->mtx); | 2142 | sdata_unlock(sdata); |
2174 | return; | 2143 | return; |
2175 | } | 2144 | } |
2176 | 2145 | ||
@@ -2181,13 +2150,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2181 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 2150 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
2182 | IEEE80211_MAX_QUEUE_MAP, | 2151 | IEEE80211_MAX_QUEUE_MAP, |
2183 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2152 | IEEE80211_QUEUE_STOP_REASON_CSA); |
2184 | mutex_unlock(&ifmgd->mtx); | ||
2185 | 2153 | ||
2186 | /* | ||
2187 | * must be outside lock due to cfg80211, | ||
2188 | * but that's not a problem. | ||
2189 | */ | ||
2190 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 2154 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
2155 | sdata_unlock(sdata); | ||
2191 | } | 2156 | } |
2192 | 2157 | ||
2193 | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | 2158 | static void ieee80211_beacon_connection_loss_work(struct work_struct *work) |
@@ -2254,7 +2219,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | |||
2254 | { | 2219 | { |
2255 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | 2220 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; |
2256 | 2221 | ||
2257 | lockdep_assert_held(&sdata->u.mgd.mtx); | 2222 | sdata_assert_lock(sdata); |
2258 | 2223 | ||
2259 | if (!assoc) { | 2224 | if (!assoc) { |
2260 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); | 2225 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); |
@@ -2295,27 +2260,26 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
2295 | auth_data->key_idx, tx_flags); | 2260 | auth_data->key_idx, tx_flags); |
2296 | } | 2261 | } |
2297 | 2262 | ||
2298 | static enum rx_mgmt_action __must_check | 2263 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
2299 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 2264 | struct ieee80211_mgmt *mgmt, size_t len) |
2300 | struct ieee80211_mgmt *mgmt, size_t len) | ||
2301 | { | 2265 | { |
2302 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2266 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2303 | u8 bssid[ETH_ALEN]; | 2267 | u8 bssid[ETH_ALEN]; |
2304 | u16 auth_alg, auth_transaction, status_code; | 2268 | u16 auth_alg, auth_transaction, status_code; |
2305 | struct sta_info *sta; | 2269 | struct sta_info *sta; |
2306 | 2270 | ||
2307 | lockdep_assert_held(&ifmgd->mtx); | 2271 | sdata_assert_lock(sdata); |
2308 | 2272 | ||
2309 | if (len < 24 + 6) | 2273 | if (len < 24 + 6) |
2310 | return RX_MGMT_NONE; | 2274 | return; |
2311 | 2275 | ||
2312 | if (!ifmgd->auth_data || ifmgd->auth_data->done) | 2276 | if (!ifmgd->auth_data || ifmgd->auth_data->done) |
2313 | return RX_MGMT_NONE; | 2277 | return; |
2314 | 2278 | ||
2315 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | 2279 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); |
2316 | 2280 | ||
2317 | if (!ether_addr_equal(bssid, mgmt->bssid)) | 2281 | if (!ether_addr_equal(bssid, mgmt->bssid)) |
2318 | return RX_MGMT_NONE; | 2282 | return; |
2319 | 2283 | ||
2320 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 2284 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
2321 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 2285 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
@@ -2327,14 +2291,15 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2327 | mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, | 2291 | mgmt->sa, auth_alg, ifmgd->auth_data->algorithm, |
2328 | auth_transaction, | 2292 | auth_transaction, |
2329 | ifmgd->auth_data->expected_transaction); | 2293 | ifmgd->auth_data->expected_transaction); |
2330 | return RX_MGMT_NONE; | 2294 | return; |
2331 | } | 2295 | } |
2332 | 2296 | ||
2333 | if (status_code != WLAN_STATUS_SUCCESS) { | 2297 | if (status_code != WLAN_STATUS_SUCCESS) { |
2334 | sdata_info(sdata, "%pM denied authentication (status %d)\n", | 2298 | sdata_info(sdata, "%pM denied authentication (status %d)\n", |
2335 | mgmt->sa, status_code); | 2299 | mgmt->sa, status_code); |
2336 | ieee80211_destroy_auth_data(sdata, false); | 2300 | ieee80211_destroy_auth_data(sdata, false); |
2337 | return RX_MGMT_CFG80211_RX_AUTH; | 2301 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); |
2302 | return; | ||
2338 | } | 2303 | } |
2339 | 2304 | ||
2340 | switch (ifmgd->auth_data->algorithm) { | 2305 | switch (ifmgd->auth_data->algorithm) { |
@@ -2347,20 +2312,20 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2347 | if (ifmgd->auth_data->expected_transaction != 4) { | 2312 | if (ifmgd->auth_data->expected_transaction != 4) { |
2348 | ieee80211_auth_challenge(sdata, mgmt, len); | 2313 | ieee80211_auth_challenge(sdata, mgmt, len); |
2349 | /* need another frame */ | 2314 | /* need another frame */ |
2350 | return RX_MGMT_NONE; | 2315 | return; |
2351 | } | 2316 | } |
2352 | break; | 2317 | break; |
2353 | default: | 2318 | default: |
2354 | WARN_ONCE(1, "invalid auth alg %d", | 2319 | WARN_ONCE(1, "invalid auth alg %d", |
2355 | ifmgd->auth_data->algorithm); | 2320 | ifmgd->auth_data->algorithm); |
2356 | return RX_MGMT_NONE; | 2321 | return; |
2357 | } | 2322 | } |
2358 | 2323 | ||
2359 | sdata_info(sdata, "authenticated\n"); | 2324 | sdata_info(sdata, "authenticated\n"); |
2360 | ifmgd->auth_data->done = true; | 2325 | ifmgd->auth_data->done = true; |
2361 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | 2326 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; |
2362 | ifmgd->auth_data->timeout_started = true; | 2327 | ifmgd->auth_data->timeout_started = true; |
2363 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2328 | run_again(sdata, ifmgd->auth_data->timeout); |
2364 | 2329 | ||
2365 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && | 2330 | if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE && |
2366 | ifmgd->auth_data->expected_transaction != 2) { | 2331 | ifmgd->auth_data->expected_transaction != 2) { |
@@ -2368,7 +2333,8 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2368 | * Report auth frame to user space for processing since another | 2333 | * Report auth frame to user space for processing since another |
2369 | * round of Authentication frames is still needed. | 2334 | * round of Authentication frames is still needed. |
2370 | */ | 2335 | */ |
2371 | return RX_MGMT_CFG80211_RX_AUTH; | 2336 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); |
2337 | return; | ||
2372 | } | 2338 | } |
2373 | 2339 | ||
2374 | /* move station state to auth */ | 2340 | /* move station state to auth */ |
@@ -2384,30 +2350,29 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
2384 | } | 2350 | } |
2385 | mutex_unlock(&sdata->local->sta_mtx); | 2351 | mutex_unlock(&sdata->local->sta_mtx); |
2386 | 2352 | ||
2387 | return RX_MGMT_CFG80211_RX_AUTH; | 2353 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, len); |
2354 | return; | ||
2388 | out_err: | 2355 | out_err: |
2389 | mutex_unlock(&sdata->local->sta_mtx); | 2356 | mutex_unlock(&sdata->local->sta_mtx); |
2390 | /* ignore frame -- wait for timeout */ | 2357 | /* ignore frame -- wait for timeout */ |
2391 | return RX_MGMT_NONE; | ||
2392 | } | 2358 | } |
2393 | 2359 | ||
2394 | 2360 | ||
2395 | static enum rx_mgmt_action __must_check | 2361 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
2396 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 2362 | struct ieee80211_mgmt *mgmt, size_t len) |
2397 | struct ieee80211_mgmt *mgmt, size_t len) | ||
2398 | { | 2363 | { |
2399 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2364 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2400 | const u8 *bssid = NULL; | 2365 | const u8 *bssid = NULL; |
2401 | u16 reason_code; | 2366 | u16 reason_code; |
2402 | 2367 | ||
2403 | lockdep_assert_held(&ifmgd->mtx); | 2368 | sdata_assert_lock(sdata); |
2404 | 2369 | ||
2405 | if (len < 24 + 2) | 2370 | if (len < 24 + 2) |
2406 | return RX_MGMT_NONE; | 2371 | return; |
2407 | 2372 | ||
2408 | if (!ifmgd->associated || | 2373 | if (!ifmgd->associated || |
2409 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) | 2374 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
2410 | return RX_MGMT_NONE; | 2375 | return; |
2411 | 2376 | ||
2412 | bssid = ifmgd->associated->bssid; | 2377 | bssid = ifmgd->associated->bssid; |
2413 | 2378 | ||
@@ -2418,25 +2383,24 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
2418 | 2383 | ||
2419 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2384 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2420 | 2385 | ||
2421 | return RX_MGMT_CFG80211_DEAUTH; | 2386 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, len); |
2422 | } | 2387 | } |
2423 | 2388 | ||
2424 | 2389 | ||
2425 | static enum rx_mgmt_action __must_check | 2390 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
2426 | ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 2391 | struct ieee80211_mgmt *mgmt, size_t len) |
2427 | struct ieee80211_mgmt *mgmt, size_t len) | ||
2428 | { | 2392 | { |
2429 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2393 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2430 | u16 reason_code; | 2394 | u16 reason_code; |
2431 | 2395 | ||
2432 | lockdep_assert_held(&ifmgd->mtx); | 2396 | sdata_assert_lock(sdata); |
2433 | 2397 | ||
2434 | if (len < 24 + 2) | 2398 | if (len < 24 + 2) |
2435 | return RX_MGMT_NONE; | 2399 | return; |
2436 | 2400 | ||
2437 | if (!ifmgd->associated || | 2401 | if (!ifmgd->associated || |
2438 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) | 2402 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
2439 | return RX_MGMT_NONE; | 2403 | return; |
2440 | 2404 | ||
2441 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 2405 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
2442 | 2406 | ||
@@ -2445,7 +2409,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
2445 | 2409 | ||
2446 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); | 2410 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
2447 | 2411 | ||
2448 | return RX_MGMT_CFG80211_DISASSOC; | 2412 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, len); |
2449 | } | 2413 | } |
2450 | 2414 | ||
2451 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | 2415 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, |
@@ -2495,7 +2459,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, | |||
2495 | { | 2459 | { |
2496 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | 2460 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; |
2497 | 2461 | ||
2498 | lockdep_assert_held(&sdata->u.mgd.mtx); | 2462 | sdata_assert_lock(sdata); |
2499 | 2463 | ||
2500 | if (!assoc) { | 2464 | if (!assoc) { |
2501 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); | 2465 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); |
@@ -2676,10 +2640,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2676 | return true; | 2640 | return true; |
2677 | } | 2641 | } |
2678 | 2642 | ||
2679 | static enum rx_mgmt_action __must_check | 2643 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
2680 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 2644 | struct ieee80211_mgmt *mgmt, |
2681 | struct ieee80211_mgmt *mgmt, size_t len, | 2645 | size_t len) |
2682 | struct cfg80211_bss **bss) | ||
2683 | { | 2646 | { |
2684 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2647 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2685 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | 2648 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; |
@@ -2687,13 +2650,14 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2687 | struct ieee802_11_elems elems; | 2650 | struct ieee802_11_elems elems; |
2688 | u8 *pos; | 2651 | u8 *pos; |
2689 | bool reassoc; | 2652 | bool reassoc; |
2653 | struct cfg80211_bss *bss; | ||
2690 | 2654 | ||
2691 | lockdep_assert_held(&ifmgd->mtx); | 2655 | sdata_assert_lock(sdata); |
2692 | 2656 | ||
2693 | if (!assoc_data) | 2657 | if (!assoc_data) |
2694 | return RX_MGMT_NONE; | 2658 | return; |
2695 | if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) | 2659 | if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid)) |
2696 | return RX_MGMT_NONE; | 2660 | return; |
2697 | 2661 | ||
2698 | /* | 2662 | /* |
2699 | * AssocResp and ReassocResp have identical structure, so process both | 2663 | * AssocResp and ReassocResp have identical structure, so process both |
@@ -2701,7 +2665,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2701 | */ | 2665 | */ |
2702 | 2666 | ||
2703 | if (len < 24 + 6) | 2667 | if (len < 24 + 6) |
2704 | return RX_MGMT_NONE; | 2668 | return; |
2705 | 2669 | ||
2706 | reassoc = ieee80211_is_reassoc_req(mgmt->frame_control); | 2670 | reassoc = ieee80211_is_reassoc_req(mgmt->frame_control); |
2707 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 2671 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
@@ -2728,22 +2692,23 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2728 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); | 2692 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); |
2729 | assoc_data->timeout_started = true; | 2693 | assoc_data->timeout_started = true; |
2730 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 2694 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
2731 | run_again(ifmgd, assoc_data->timeout); | 2695 | run_again(sdata, assoc_data->timeout); |
2732 | return RX_MGMT_NONE; | 2696 | return; |
2733 | } | 2697 | } |
2734 | 2698 | ||
2735 | *bss = assoc_data->bss; | 2699 | bss = assoc_data->bss; |
2736 | 2700 | ||
2737 | if (status_code != WLAN_STATUS_SUCCESS) { | 2701 | if (status_code != WLAN_STATUS_SUCCESS) { |
2738 | sdata_info(sdata, "%pM denied association (code=%d)\n", | 2702 | sdata_info(sdata, "%pM denied association (code=%d)\n", |
2739 | mgmt->sa, status_code); | 2703 | mgmt->sa, status_code); |
2740 | ieee80211_destroy_assoc_data(sdata, false); | 2704 | ieee80211_destroy_assoc_data(sdata, false); |
2741 | } else { | 2705 | } else { |
2742 | if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { | 2706 | if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) { |
2743 | /* oops -- internal error -- send timeout for now */ | 2707 | /* oops -- internal error -- send timeout for now */ |
2744 | ieee80211_destroy_assoc_data(sdata, false); | 2708 | ieee80211_destroy_assoc_data(sdata, false); |
2745 | cfg80211_put_bss(sdata->local->hw.wiphy, *bss); | 2709 | cfg80211_put_bss(sdata->local->hw.wiphy, bss); |
2746 | return RX_MGMT_CFG80211_ASSOC_TIMEOUT; | 2710 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); |
2711 | return; | ||
2747 | } | 2712 | } |
2748 | sdata_info(sdata, "associated\n"); | 2713 | sdata_info(sdata, "associated\n"); |
2749 | 2714 | ||
@@ -2755,7 +2720,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
2755 | ieee80211_destroy_assoc_data(sdata, true); | 2720 | ieee80211_destroy_assoc_data(sdata, true); |
2756 | } | 2721 | } |
2757 | 2722 | ||
2758 | return RX_MGMT_CFG80211_RX_ASSOC; | 2723 | cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, len); |
2759 | } | 2724 | } |
2760 | 2725 | ||
2761 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2726 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
@@ -2769,7 +2734,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2769 | struct ieee80211_channel *channel; | 2734 | struct ieee80211_channel *channel; |
2770 | bool need_ps = false; | 2735 | bool need_ps = false; |
2771 | 2736 | ||
2772 | lockdep_assert_held(&sdata->u.mgd.mtx); | 2737 | sdata_assert_lock(sdata); |
2773 | 2738 | ||
2774 | if ((sdata->u.mgd.associated && | 2739 | if ((sdata->u.mgd.associated && |
2775 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || | 2740 | ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) || |
@@ -2828,7 +2793,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
2828 | 2793 | ||
2829 | ifmgd = &sdata->u.mgd; | 2794 | ifmgd = &sdata->u.mgd; |
2830 | 2795 | ||
2831 | ASSERT_MGD_MTX(ifmgd); | 2796 | sdata_assert_lock(sdata); |
2832 | 2797 | ||
2833 | if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) | 2798 | if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) |
2834 | return; /* ignore ProbeResp to foreign address */ | 2799 | return; /* ignore ProbeResp to foreign address */ |
@@ -2853,7 +2818,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
2853 | ifmgd->auth_data->tries = 0; | 2818 | ifmgd->auth_data->tries = 0; |
2854 | ifmgd->auth_data->timeout = jiffies; | 2819 | ifmgd->auth_data->timeout = jiffies; |
2855 | ifmgd->auth_data->timeout_started = true; | 2820 | ifmgd->auth_data->timeout_started = true; |
2856 | run_again(ifmgd, ifmgd->auth_data->timeout); | 2821 | run_again(sdata, ifmgd->auth_data->timeout); |
2857 | } | 2822 | } |
2858 | } | 2823 | } |
2859 | 2824 | ||
@@ -2878,10 +2843,9 @@ static const u64 care_about_ies = | |||
2878 | (1ULL << WLAN_EID_HT_CAPABILITY) | | 2843 | (1ULL << WLAN_EID_HT_CAPABILITY) | |
2879 | (1ULL << WLAN_EID_HT_OPERATION); | 2844 | (1ULL << WLAN_EID_HT_OPERATION); |
2880 | 2845 | ||
2881 | static enum rx_mgmt_action | 2846 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
2882 | ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 2847 | struct ieee80211_mgmt *mgmt, size_t len, |
2883 | struct ieee80211_mgmt *mgmt, size_t len, | 2848 | struct ieee80211_rx_status *rx_status) |
2884 | u8 *deauth_buf, struct ieee80211_rx_status *rx_status) | ||
2885 | { | 2849 | { |
2886 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2850 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2887 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2851 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
@@ -2896,24 +2860,25 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2896 | u8 erp_value = 0; | 2860 | u8 erp_value = 0; |
2897 | u32 ncrc; | 2861 | u32 ncrc; |
2898 | u8 *bssid; | 2862 | u8 *bssid; |
2863 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
2899 | 2864 | ||
2900 | lockdep_assert_held(&ifmgd->mtx); | 2865 | sdata_assert_lock(sdata); |
2901 | 2866 | ||
2902 | /* Process beacon from the current BSS */ | 2867 | /* Process beacon from the current BSS */ |
2903 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 2868 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
2904 | if (baselen > len) | 2869 | if (baselen > len) |
2905 | return RX_MGMT_NONE; | 2870 | return; |
2906 | 2871 | ||
2907 | rcu_read_lock(); | 2872 | rcu_read_lock(); |
2908 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2873 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2909 | if (!chanctx_conf) { | 2874 | if (!chanctx_conf) { |
2910 | rcu_read_unlock(); | 2875 | rcu_read_unlock(); |
2911 | return RX_MGMT_NONE; | 2876 | return; |
2912 | } | 2877 | } |
2913 | 2878 | ||
2914 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { | 2879 | if (rx_status->freq != chanctx_conf->def.chan->center_freq) { |
2915 | rcu_read_unlock(); | 2880 | rcu_read_unlock(); |
2916 | return RX_MGMT_NONE; | 2881 | return; |
2917 | } | 2882 | } |
2918 | chan = chanctx_conf->def.chan; | 2883 | chan = chanctx_conf->def.chan; |
2919 | rcu_read_unlock(); | 2884 | rcu_read_unlock(); |
@@ -2940,13 +2905,13 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2940 | /* continue assoc process */ | 2905 | /* continue assoc process */ |
2941 | ifmgd->assoc_data->timeout = jiffies; | 2906 | ifmgd->assoc_data->timeout = jiffies; |
2942 | ifmgd->assoc_data->timeout_started = true; | 2907 | ifmgd->assoc_data->timeout_started = true; |
2943 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 2908 | run_again(sdata, ifmgd->assoc_data->timeout); |
2944 | return RX_MGMT_NONE; | 2909 | return; |
2945 | } | 2910 | } |
2946 | 2911 | ||
2947 | if (!ifmgd->associated || | 2912 | if (!ifmgd->associated || |
2948 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) | 2913 | !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) |
2949 | return RX_MGMT_NONE; | 2914 | return; |
2950 | bssid = ifmgd->associated->bssid; | 2915 | bssid = ifmgd->associated->bssid; |
2951 | 2916 | ||
2952 | /* Track average RSSI from the Beacon frames of the current AP */ | 2917 | /* Track average RSSI from the Beacon frames of the current AP */ |
@@ -3092,7 +3057,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3092 | } | 3057 | } |
3093 | 3058 | ||
3094 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3059 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3095 | return RX_MGMT_NONE; | 3060 | return; |
3096 | ifmgd->beacon_crc = ncrc; | 3061 | ifmgd->beacon_crc = ncrc; |
3097 | ifmgd->beacon_crc_valid = true; | 3062 | ifmgd->beacon_crc_valid = true; |
3098 | 3063 | ||
@@ -3126,6 +3091,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3126 | } | 3091 | } |
3127 | 3092 | ||
3128 | changed |= BSS_CHANGED_DTIM_PERIOD; | 3093 | changed |= BSS_CHANGED_DTIM_PERIOD; |
3094 | ieee80211_recalc_ps_vif(sdata); | ||
3129 | } | 3095 | } |
3130 | 3096 | ||
3131 | if (elems.erp_info) { | 3097 | if (elems.erp_info) { |
@@ -3147,7 +3113,9 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3147 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 3113 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
3148 | WLAN_REASON_DEAUTH_LEAVING, | 3114 | WLAN_REASON_DEAUTH_LEAVING, |
3149 | true, deauth_buf); | 3115 | true, deauth_buf); |
3150 | return RX_MGMT_CFG80211_TX_DEAUTH; | 3116 | cfg80211_send_deauth(sdata->dev, deauth_buf, |
3117 | sizeof(deauth_buf)); | ||
3118 | return; | ||
3151 | } | 3119 | } |
3152 | 3120 | ||
3153 | if (sta && elems.opmode_notif) | 3121 | if (sta && elems.opmode_notif) |
@@ -3164,19 +3132,13 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3164 | elems.pwr_constr_elem); | 3132 | elems.pwr_constr_elem); |
3165 | 3133 | ||
3166 | ieee80211_bss_info_change_notify(sdata, changed); | 3134 | ieee80211_bss_info_change_notify(sdata, changed); |
3167 | |||
3168 | return RX_MGMT_NONE; | ||
3169 | } | 3135 | } |
3170 | 3136 | ||
3171 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 3137 | void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
3172 | struct sk_buff *skb) | 3138 | struct sk_buff *skb) |
3173 | { | 3139 | { |
3174 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3175 | struct ieee80211_rx_status *rx_status; | 3140 | struct ieee80211_rx_status *rx_status; |
3176 | struct ieee80211_mgmt *mgmt; | 3141 | struct ieee80211_mgmt *mgmt; |
3177 | struct cfg80211_bss *bss = NULL; | ||
3178 | enum rx_mgmt_action rma = RX_MGMT_NONE; | ||
3179 | u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||
3180 | u16 fc; | 3142 | u16 fc; |
3181 | struct ieee802_11_elems elems; | 3143 | struct ieee802_11_elems elems; |
3182 | int ies_len; | 3144 | int ies_len; |
@@ -3185,28 +3147,27 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3185 | mgmt = (struct ieee80211_mgmt *) skb->data; | 3147 | mgmt = (struct ieee80211_mgmt *) skb->data; |
3186 | fc = le16_to_cpu(mgmt->frame_control); | 3148 | fc = le16_to_cpu(mgmt->frame_control); |
3187 | 3149 | ||
3188 | mutex_lock(&ifmgd->mtx); | 3150 | sdata_lock(sdata); |
3189 | 3151 | ||
3190 | switch (fc & IEEE80211_FCTL_STYPE) { | 3152 | switch (fc & IEEE80211_FCTL_STYPE) { |
3191 | case IEEE80211_STYPE_BEACON: | 3153 | case IEEE80211_STYPE_BEACON: |
3192 | rma = ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 3154 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); |
3193 | deauth_buf, rx_status); | ||
3194 | break; | 3155 | break; |
3195 | case IEEE80211_STYPE_PROBE_RESP: | 3156 | case IEEE80211_STYPE_PROBE_RESP: |
3196 | ieee80211_rx_mgmt_probe_resp(sdata, skb); | 3157 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
3197 | break; | 3158 | break; |
3198 | case IEEE80211_STYPE_AUTH: | 3159 | case IEEE80211_STYPE_AUTH: |
3199 | rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); | 3160 | ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
3200 | break; | 3161 | break; |
3201 | case IEEE80211_STYPE_DEAUTH: | 3162 | case IEEE80211_STYPE_DEAUTH: |
3202 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); | 3163 | ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
3203 | break; | 3164 | break; |
3204 | case IEEE80211_STYPE_DISASSOC: | 3165 | case IEEE80211_STYPE_DISASSOC: |
3205 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 3166 | ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
3206 | break; | 3167 | break; |
3207 | case IEEE80211_STYPE_ASSOC_RESP: | 3168 | case IEEE80211_STYPE_ASSOC_RESP: |
3208 | case IEEE80211_STYPE_REASSOC_RESP: | 3169 | case IEEE80211_STYPE_REASSOC_RESP: |
3209 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); | 3170 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len); |
3210 | break; | 3171 | break; |
3211 | case IEEE80211_STYPE_ACTION: | 3172 | case IEEE80211_STYPE_ACTION: |
3212 | if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { | 3173 | if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { |
@@ -3252,34 +3213,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3252 | } | 3213 | } |
3253 | break; | 3214 | break; |
3254 | } | 3215 | } |
3255 | mutex_unlock(&ifmgd->mtx); | 3216 | sdata_unlock(sdata); |
3256 | |||
3257 | switch (rma) { | ||
3258 | case RX_MGMT_NONE: | ||
3259 | /* no action */ | ||
3260 | break; | ||
3261 | case RX_MGMT_CFG80211_DEAUTH: | ||
3262 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | ||
3263 | break; | ||
3264 | case RX_MGMT_CFG80211_DISASSOC: | ||
3265 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); | ||
3266 | break; | ||
3267 | case RX_MGMT_CFG80211_RX_AUTH: | ||
3268 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len); | ||
3269 | break; | ||
3270 | case RX_MGMT_CFG80211_RX_ASSOC: | ||
3271 | cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len); | ||
3272 | break; | ||
3273 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: | ||
3274 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | ||
3275 | break; | ||
3276 | case RX_MGMT_CFG80211_TX_DEAUTH: | ||
3277 | cfg80211_send_deauth(sdata->dev, deauth_buf, | ||
3278 | sizeof(deauth_buf)); | ||
3279 | break; | ||
3280 | default: | ||
3281 | WARN(1, "unexpected: %d", rma); | ||
3282 | } | ||
3283 | } | 3217 | } |
3284 | 3218 | ||
3285 | static void ieee80211_sta_timer(unsigned long data) | 3219 | static void ieee80211_sta_timer(unsigned long data) |
@@ -3293,20 +3227,12 @@ static void ieee80211_sta_timer(unsigned long data) | |||
3293 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | 3227 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, |
3294 | u8 *bssid, u8 reason, bool tx) | 3228 | u8 *bssid, u8 reason, bool tx) |
3295 | { | 3229 | { |
3296 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3297 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3230 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3298 | 3231 | ||
3299 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, | 3232 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, |
3300 | tx, frame_buf); | 3233 | tx, frame_buf); |
3301 | mutex_unlock(&ifmgd->mtx); | ||
3302 | 3234 | ||
3303 | /* | ||
3304 | * must be outside lock due to cfg80211, | ||
3305 | * but that's not a problem. | ||
3306 | */ | ||
3307 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); | 3235 | cfg80211_send_deauth(sdata->dev, frame_buf, IEEE80211_DEAUTH_FRAME_LEN); |
3308 | |||
3309 | mutex_lock(&ifmgd->mtx); | ||
3310 | } | 3236 | } |
3311 | 3237 | ||
3312 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | 3238 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) |
@@ -3316,7 +3242,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3316 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; | 3242 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; |
3317 | u32 tx_flags = 0; | 3243 | u32 tx_flags = 0; |
3318 | 3244 | ||
3319 | lockdep_assert_held(&ifmgd->mtx); | 3245 | sdata_assert_lock(sdata); |
3320 | 3246 | ||
3321 | if (WARN_ON_ONCE(!auth_data)) | 3247 | if (WARN_ON_ONCE(!auth_data)) |
3322 | return -EINVAL; | 3248 | return -EINVAL; |
@@ -3389,7 +3315,7 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3389 | if (tx_flags == 0) { | 3315 | if (tx_flags == 0) { |
3390 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | 3316 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; |
3391 | ifmgd->auth_data->timeout_started = true; | 3317 | ifmgd->auth_data->timeout_started = true; |
3392 | run_again(ifmgd, auth_data->timeout); | 3318 | run_again(sdata, auth_data->timeout); |
3393 | } else { | 3319 | } else { |
3394 | auth_data->timeout_started = false; | 3320 | auth_data->timeout_started = false; |
3395 | } | 3321 | } |
@@ -3402,7 +3328,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | |||
3402 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | 3328 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; |
3403 | struct ieee80211_local *local = sdata->local; | 3329 | struct ieee80211_local *local = sdata->local; |
3404 | 3330 | ||
3405 | lockdep_assert_held(&sdata->u.mgd.mtx); | 3331 | sdata_assert_lock(sdata); |
3406 | 3332 | ||
3407 | assoc_data->tries++; | 3333 | assoc_data->tries++; |
3408 | if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { | 3334 | if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { |
@@ -3426,7 +3352,7 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | |||
3426 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | 3352 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
3427 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | 3353 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; |
3428 | assoc_data->timeout_started = true; | 3354 | assoc_data->timeout_started = true; |
3429 | run_again(&sdata->u.mgd, assoc_data->timeout); | 3355 | run_again(sdata, assoc_data->timeout); |
3430 | } else { | 3356 | } else { |
3431 | assoc_data->timeout_started = false; | 3357 | assoc_data->timeout_started = false; |
3432 | } | 3358 | } |
@@ -3451,7 +3377,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3451 | struct ieee80211_local *local = sdata->local; | 3377 | struct ieee80211_local *local = sdata->local; |
3452 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3378 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3453 | 3379 | ||
3454 | mutex_lock(&ifmgd->mtx); | 3380 | sdata_lock(sdata); |
3455 | 3381 | ||
3456 | if (ifmgd->status_received) { | 3382 | if (ifmgd->status_received) { |
3457 | __le16 fc = ifmgd->status_fc; | 3383 | __le16 fc = ifmgd->status_fc; |
@@ -3463,7 +3389,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3463 | if (status_acked) { | 3389 | if (status_acked) { |
3464 | ifmgd->auth_data->timeout = | 3390 | ifmgd->auth_data->timeout = |
3465 | jiffies + IEEE80211_AUTH_TIMEOUT_SHORT; | 3391 | jiffies + IEEE80211_AUTH_TIMEOUT_SHORT; |
3466 | run_again(ifmgd, ifmgd->auth_data->timeout); | 3392 | run_again(sdata, ifmgd->auth_data->timeout); |
3467 | } else { | 3393 | } else { |
3468 | ifmgd->auth_data->timeout = jiffies - 1; | 3394 | ifmgd->auth_data->timeout = jiffies - 1; |
3469 | } | 3395 | } |
@@ -3474,7 +3400,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3474 | if (status_acked) { | 3400 | if (status_acked) { |
3475 | ifmgd->assoc_data->timeout = | 3401 | ifmgd->assoc_data->timeout = |
3476 | jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT; | 3402 | jiffies + IEEE80211_ASSOC_TIMEOUT_SHORT; |
3477 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 3403 | run_again(sdata, ifmgd->assoc_data->timeout); |
3478 | } else { | 3404 | } else { |
3479 | ifmgd->assoc_data->timeout = jiffies - 1; | 3405 | ifmgd->assoc_data->timeout = jiffies - 1; |
3480 | } | 3406 | } |
@@ -3497,12 +3423,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3497 | 3423 | ||
3498 | ieee80211_destroy_auth_data(sdata, false); | 3424 | ieee80211_destroy_auth_data(sdata, false); |
3499 | 3425 | ||
3500 | mutex_unlock(&ifmgd->mtx); | ||
3501 | cfg80211_send_auth_timeout(sdata->dev, bssid); | 3426 | cfg80211_send_auth_timeout(sdata->dev, bssid); |
3502 | mutex_lock(&ifmgd->mtx); | ||
3503 | } | 3427 | } |
3504 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) | 3428 | } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started) |
3505 | run_again(ifmgd, ifmgd->auth_data->timeout); | 3429 | run_again(sdata, ifmgd->auth_data->timeout); |
3506 | 3430 | ||
3507 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && | 3431 | if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started && |
3508 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | 3432 | time_after(jiffies, ifmgd->assoc_data->timeout)) { |
@@ -3515,12 +3439,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3515 | 3439 | ||
3516 | ieee80211_destroy_assoc_data(sdata, false); | 3440 | ieee80211_destroy_assoc_data(sdata, false); |
3517 | 3441 | ||
3518 | mutex_unlock(&ifmgd->mtx); | ||
3519 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | 3442 | cfg80211_send_assoc_timeout(sdata->dev, bssid); |
3520 | mutex_lock(&ifmgd->mtx); | ||
3521 | } | 3443 | } |
3522 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) | 3444 | } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started) |
3523 | run_again(ifmgd, ifmgd->assoc_data->timeout); | 3445 | run_again(sdata, ifmgd->assoc_data->timeout); |
3524 | 3446 | ||
3525 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 3447 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
3526 | IEEE80211_STA_CONNECTION_POLL) && | 3448 | IEEE80211_STA_CONNECTION_POLL) && |
@@ -3554,7 +3476,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3554 | false); | 3476 | false); |
3555 | } | 3477 | } |
3556 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | 3478 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) |
3557 | run_again(ifmgd, ifmgd->probe_timeout); | 3479 | run_again(sdata, ifmgd->probe_timeout); |
3558 | else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | 3480 | else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
3559 | mlme_dbg(sdata, | 3481 | mlme_dbg(sdata, |
3560 | "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", | 3482 | "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", |
@@ -3583,7 +3505,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
3583 | } | 3505 | } |
3584 | } | 3506 | } |
3585 | 3507 | ||
3586 | mutex_unlock(&ifmgd->mtx); | 3508 | sdata_unlock(sdata); |
3587 | } | 3509 | } |
3588 | 3510 | ||
3589 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 3511 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -3644,9 +3566,9 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
3644 | { | 3566 | { |
3645 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3567 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3646 | 3568 | ||
3647 | mutex_lock(&ifmgd->mtx); | 3569 | sdata_lock(sdata); |
3648 | if (!ifmgd->associated) { | 3570 | if (!ifmgd->associated) { |
3649 | mutex_unlock(&ifmgd->mtx); | 3571 | sdata_unlock(sdata); |
3650 | return; | 3572 | return; |
3651 | } | 3573 | } |
3652 | 3574 | ||
@@ -3657,10 +3579,10 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
3657 | ifmgd->associated->bssid, | 3579 | ifmgd->associated->bssid, |
3658 | WLAN_REASON_UNSPECIFIED, | 3580 | WLAN_REASON_UNSPECIFIED, |
3659 | true); | 3581 | true); |
3660 | mutex_unlock(&ifmgd->mtx); | 3582 | sdata_unlock(sdata); |
3661 | return; | 3583 | return; |
3662 | } | 3584 | } |
3663 | mutex_unlock(&ifmgd->mtx); | 3585 | sdata_unlock(sdata); |
3664 | } | 3586 | } |
3665 | #endif | 3587 | #endif |
3666 | 3588 | ||
@@ -3692,8 +3614,6 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3692 | ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len; | 3614 | ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len; |
3693 | ifmgd->p2p_noa_index = -1; | 3615 | ifmgd->p2p_noa_index = -1; |
3694 | 3616 | ||
3695 | mutex_init(&ifmgd->mtx); | ||
3696 | |||
3697 | if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) | 3617 | if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS) |
3698 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; | 3618 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; |
3699 | else | 3619 | else |
@@ -4049,8 +3969,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4049 | 3969 | ||
4050 | /* try to authenticate/probe */ | 3970 | /* try to authenticate/probe */ |
4051 | 3971 | ||
4052 | mutex_lock(&ifmgd->mtx); | ||
4053 | |||
4054 | if ((ifmgd->auth_data && !ifmgd->auth_data->done) || | 3972 | if ((ifmgd->auth_data && !ifmgd->auth_data->done) || |
4055 | ifmgd->assoc_data) { | 3973 | ifmgd->assoc_data) { |
4056 | err = -EBUSY; | 3974 | err = -EBUSY; |
@@ -4070,8 +3988,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4070 | WLAN_REASON_UNSPECIFIED, | 3988 | WLAN_REASON_UNSPECIFIED, |
4071 | false, frame_buf); | 3989 | false, frame_buf); |
4072 | 3990 | ||
4073 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 3991 | cfg80211_send_deauth(sdata->dev, frame_buf, |
4074 | sizeof(frame_buf)); | 3992 | sizeof(frame_buf)); |
4075 | } | 3993 | } |
4076 | 3994 | ||
4077 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); | 3995 | sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); |
@@ -4088,8 +4006,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4088 | 4006 | ||
4089 | /* hold our own reference */ | 4007 | /* hold our own reference */ |
4090 | cfg80211_ref_bss(local->hw.wiphy, auth_data->bss); | 4008 | cfg80211_ref_bss(local->hw.wiphy, auth_data->bss); |
4091 | err = 0; | 4009 | return 0; |
4092 | goto out_unlock; | ||
4093 | 4010 | ||
4094 | err_clear: | 4011 | err_clear: |
4095 | memset(ifmgd->bssid, 0, ETH_ALEN); | 4012 | memset(ifmgd->bssid, 0, ETH_ALEN); |
@@ -4097,9 +4014,6 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4097 | ifmgd->auth_data = NULL; | 4014 | ifmgd->auth_data = NULL; |
4098 | err_free: | 4015 | err_free: |
4099 | kfree(auth_data); | 4016 | kfree(auth_data); |
4100 | out_unlock: | ||
4101 | mutex_unlock(&ifmgd->mtx); | ||
4102 | |||
4103 | return err; | 4017 | return err; |
4104 | } | 4018 | } |
4105 | 4019 | ||
@@ -4130,8 +4044,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4130 | assoc_data->ssid_len = ssidie[1]; | 4044 | assoc_data->ssid_len = ssidie[1]; |
4131 | rcu_read_unlock(); | 4045 | rcu_read_unlock(); |
4132 | 4046 | ||
4133 | mutex_lock(&ifmgd->mtx); | ||
4134 | |||
4135 | if (ifmgd->associated) { | 4047 | if (ifmgd->associated) { |
4136 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4048 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4137 | 4049 | ||
@@ -4139,8 +4051,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4139 | WLAN_REASON_UNSPECIFIED, | 4051 | WLAN_REASON_UNSPECIFIED, |
4140 | false, frame_buf); | 4052 | false, frame_buf); |
4141 | 4053 | ||
4142 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 4054 | cfg80211_send_deauth(sdata->dev, frame_buf, |
4143 | sizeof(frame_buf)); | 4055 | sizeof(frame_buf)); |
4144 | } | 4056 | } |
4145 | 4057 | ||
4146 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | 4058 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { |
@@ -4334,7 +4246,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4334 | } | 4246 | } |
4335 | rcu_read_unlock(); | 4247 | rcu_read_unlock(); |
4336 | 4248 | ||
4337 | run_again(ifmgd, assoc_data->timeout); | 4249 | run_again(sdata, assoc_data->timeout); |
4338 | 4250 | ||
4339 | if (bss->corrupt_data) { | 4251 | if (bss->corrupt_data) { |
4340 | char *corrupt_type = "data"; | 4252 | char *corrupt_type = "data"; |
@@ -4350,17 +4262,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4350 | corrupt_type); | 4262 | corrupt_type); |
4351 | } | 4263 | } |
4352 | 4264 | ||
4353 | err = 0; | 4265 | return 0; |
4354 | goto out; | ||
4355 | err_clear: | 4266 | err_clear: |
4356 | memset(ifmgd->bssid, 0, ETH_ALEN); | 4267 | memset(ifmgd->bssid, 0, ETH_ALEN); |
4357 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | 4268 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
4358 | ifmgd->assoc_data = NULL; | 4269 | ifmgd->assoc_data = NULL; |
4359 | err_free: | 4270 | err_free: |
4360 | kfree(assoc_data); | 4271 | kfree(assoc_data); |
4361 | out: | ||
4362 | mutex_unlock(&ifmgd->mtx); | ||
4363 | |||
4364 | return err; | 4272 | return err; |
4365 | } | 4273 | } |
4366 | 4274 | ||
@@ -4372,8 +4280,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4372 | bool tx = !req->local_state_change; | 4280 | bool tx = !req->local_state_change; |
4373 | bool report_frame = false; | 4281 | bool report_frame = false; |
4374 | 4282 | ||
4375 | mutex_lock(&ifmgd->mtx); | ||
4376 | |||
4377 | sdata_info(sdata, | 4283 | sdata_info(sdata, |
4378 | "deauthenticating from %pM by local choice (reason=%d)\n", | 4284 | "deauthenticating from %pM by local choice (reason=%d)\n", |
4379 | req->bssid, req->reason_code); | 4285 | req->bssid, req->reason_code); |
@@ -4385,7 +4291,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4385 | req->reason_code, tx, | 4291 | req->reason_code, tx, |
4386 | frame_buf); | 4292 | frame_buf); |
4387 | ieee80211_destroy_auth_data(sdata, false); | 4293 | ieee80211_destroy_auth_data(sdata, false); |
4388 | mutex_unlock(&ifmgd->mtx); | ||
4389 | 4294 | ||
4390 | report_frame = true; | 4295 | report_frame = true; |
4391 | goto out; | 4296 | goto out; |
@@ -4397,12 +4302,11 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
4397 | req->reason_code, tx, frame_buf); | 4302 | req->reason_code, tx, frame_buf); |
4398 | report_frame = true; | 4303 | report_frame = true; |
4399 | } | 4304 | } |
4400 | mutex_unlock(&ifmgd->mtx); | ||
4401 | 4305 | ||
4402 | out: | 4306 | out: |
4403 | if (report_frame) | 4307 | if (report_frame) |
4404 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 4308 | cfg80211_send_deauth(sdata->dev, frame_buf, |
4405 | IEEE80211_DEAUTH_FRAME_LEN); | 4309 | IEEE80211_DEAUTH_FRAME_LEN); |
4406 | 4310 | ||
4407 | return 0; | 4311 | return 0; |
4408 | } | 4312 | } |
@@ -4414,18 +4318,14 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4414 | u8 bssid[ETH_ALEN]; | 4318 | u8 bssid[ETH_ALEN]; |
4415 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 4319 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
4416 | 4320 | ||
4417 | mutex_lock(&ifmgd->mtx); | ||
4418 | |||
4419 | /* | 4321 | /* |
4420 | * cfg80211 should catch this ... but it's racy since | 4322 | * cfg80211 should catch this ... but it's racy since |
4421 | * we can receive a disassoc frame, process it, hand it | 4323 | * we can receive a disassoc frame, process it, hand it |
4422 | * to cfg80211 while that's in a locked section already | 4324 | * to cfg80211 while that's in a locked section already |
4423 | * trying to tell us that the user wants to disconnect. | 4325 | * trying to tell us that the user wants to disconnect. |
4424 | */ | 4326 | */ |
4425 | if (ifmgd->associated != req->bss) { | 4327 | if (ifmgd->associated != req->bss) |
4426 | mutex_unlock(&ifmgd->mtx); | ||
4427 | return -ENOLINK; | 4328 | return -ENOLINK; |
4428 | } | ||
4429 | 4329 | ||
4430 | sdata_info(sdata, | 4330 | sdata_info(sdata, |
4431 | "disassociating from %pM by local choice (reason=%d)\n", | 4331 | "disassociating from %pM by local choice (reason=%d)\n", |
@@ -4435,10 +4335,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, | |||
4435 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, | 4335 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, |
4436 | req->reason_code, !req->local_state_change, | 4336 | req->reason_code, !req->local_state_change, |
4437 | frame_buf); | 4337 | frame_buf); |
4438 | mutex_unlock(&ifmgd->mtx); | ||
4439 | 4338 | ||
4440 | __cfg80211_send_disassoc(sdata->dev, frame_buf, | 4339 | cfg80211_send_disassoc(sdata->dev, frame_buf, |
4441 | IEEE80211_DEAUTH_FRAME_LEN); | 4340 | IEEE80211_DEAUTH_FRAME_LEN); |
4442 | 4341 | ||
4443 | return 0; | 4342 | return 0; |
4444 | } | 4343 | } |
@@ -4458,13 +4357,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4458 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | 4357 | cancel_work_sync(&ifmgd->csa_connection_drop_work); |
4459 | cancel_work_sync(&ifmgd->chswitch_work); | 4358 | cancel_work_sync(&ifmgd->chswitch_work); |
4460 | 4359 | ||
4461 | mutex_lock(&ifmgd->mtx); | 4360 | sdata_lock(sdata); |
4462 | if (ifmgd->assoc_data) | 4361 | if (ifmgd->assoc_data) |
4463 | ieee80211_destroy_assoc_data(sdata, false); | 4362 | ieee80211_destroy_assoc_data(sdata, false); |
4464 | if (ifmgd->auth_data) | 4363 | if (ifmgd->auth_data) |
4465 | ieee80211_destroy_auth_data(sdata, false); | 4364 | ieee80211_destroy_auth_data(sdata, false); |
4466 | del_timer_sync(&ifmgd->timer); | 4365 | del_timer_sync(&ifmgd->timer); |
4467 | mutex_unlock(&ifmgd->mtx); | 4366 | sdata_unlock(sdata); |
4468 | } | 4367 | } |
4469 | 4368 | ||
4470 | void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, | 4369 | void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8e2952620256..bdd7b4a719e9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -258,6 +258,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
258 | pos += 2; | 258 | pos += 2; |
259 | 259 | ||
260 | if (status->flag & RX_FLAG_HT) { | 260 | if (status->flag & RX_FLAG_HT) { |
261 | unsigned int stbc; | ||
262 | |||
261 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); | 263 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); |
262 | *pos++ = local->hw.radiotap_mcs_details; | 264 | *pos++ = local->hw.radiotap_mcs_details; |
263 | *pos = 0; | 265 | *pos = 0; |
@@ -267,6 +269,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
267 | *pos |= IEEE80211_RADIOTAP_MCS_BW_40; | 269 | *pos |= IEEE80211_RADIOTAP_MCS_BW_40; |
268 | if (status->flag & RX_FLAG_HT_GF) | 270 | if (status->flag & RX_FLAG_HT_GF) |
269 | *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; | 271 | *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; |
272 | stbc = (status->flag & RX_FLAG_STBC_MASK) >> RX_FLAG_STBC_SHIFT; | ||
273 | *pos |= stbc << IEEE80211_RADIOTAP_MCS_STBC_SHIFT; | ||
270 | pos++; | 274 | pos++; |
271 | *pos++ = status->rate_idx; | 275 | *pos++ = status->rate_idx; |
272 | } | 276 | } |
@@ -1372,6 +1376,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1372 | struct sk_buff *skb = rx->skb; | 1376 | struct sk_buff *skb = rx->skb; |
1373 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1377 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
1374 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1378 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1379 | int i; | ||
1375 | 1380 | ||
1376 | if (!sta) | 1381 | if (!sta) |
1377 | return RX_CONTINUE; | 1382 | return RX_CONTINUE; |
@@ -1422,6 +1427,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1422 | ewma_add(&sta->avg_signal, -status->signal); | 1427 | ewma_add(&sta->avg_signal, -status->signal); |
1423 | } | 1428 | } |
1424 | 1429 | ||
1430 | if (status->chains) { | ||
1431 | sta->chains = status->chains; | ||
1432 | for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { | ||
1433 | int signal = status->chain_signal[i]; | ||
1434 | |||
1435 | if (!(status->chains & BIT(i))) | ||
1436 | continue; | ||
1437 | |||
1438 | sta->chain_signal_last[i] = signal; | ||
1439 | ewma_add(&sta->chain_signal_avg[i], -signal); | ||
1440 | } | ||
1441 | } | ||
1442 | |||
1425 | /* | 1443 | /* |
1426 | * Change STA power saving mode only at the end of a frame | 1444 | * Change STA power saving mode only at the end of a frame |
1427 | * exchange sequence. | 1445 | * exchange sequence. |
@@ -1608,7 +1626,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1608 | entry->ccmp = 1; | 1626 | entry->ccmp = 1; |
1609 | memcpy(entry->last_pn, | 1627 | memcpy(entry->last_pn, |
1610 | rx->key->u.ccmp.rx_pn[queue], | 1628 | rx->key->u.ccmp.rx_pn[queue], |
1611 | CCMP_PN_LEN); | 1629 | IEEE80211_CCMP_PN_LEN); |
1612 | } | 1630 | } |
1613 | return RX_QUEUED; | 1631 | return RX_QUEUED; |
1614 | } | 1632 | } |
@@ -1627,21 +1645,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1627 | * (IEEE 802.11i, 8.3.3.4.5) */ | 1645 | * (IEEE 802.11i, 8.3.3.4.5) */ |
1628 | if (entry->ccmp) { | 1646 | if (entry->ccmp) { |
1629 | int i; | 1647 | int i; |
1630 | u8 pn[CCMP_PN_LEN], *rpn; | 1648 | u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; |
1631 | int queue; | 1649 | int queue; |
1632 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP) | 1650 | if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP) |
1633 | return RX_DROP_UNUSABLE; | 1651 | return RX_DROP_UNUSABLE; |
1634 | memcpy(pn, entry->last_pn, CCMP_PN_LEN); | 1652 | memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); |
1635 | for (i = CCMP_PN_LEN - 1; i >= 0; i--) { | 1653 | for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { |
1636 | pn[i]++; | 1654 | pn[i]++; |
1637 | if (pn[i]) | 1655 | if (pn[i]) |
1638 | break; | 1656 | break; |
1639 | } | 1657 | } |
1640 | queue = rx->security_idx; | 1658 | queue = rx->security_idx; |
1641 | rpn = rx->key->u.ccmp.rx_pn[queue]; | 1659 | rpn = rx->key->u.ccmp.rx_pn[queue]; |
1642 | if (memcmp(pn, rpn, CCMP_PN_LEN)) | 1660 | if (memcmp(pn, rpn, IEEE80211_CCMP_PN_LEN)) |
1643 | return RX_DROP_UNUSABLE; | 1661 | return RX_DROP_UNUSABLE; |
1644 | memcpy(entry->last_pn, pn, CCMP_PN_LEN); | 1662 | memcpy(entry->last_pn, pn, IEEE80211_CCMP_PN_LEN); |
1645 | } | 1663 | } |
1646 | 1664 | ||
1647 | skb_pull(rx->skb, ieee80211_hdrlen(fc)); | 1665 | skb_pull(rx->skb, ieee80211_hdrlen(fc)); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 11216bc13b27..a04c5671d7fd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -358,6 +358,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
358 | do_posix_clock_monotonic_gettime(&uptime); | 358 | do_posix_clock_monotonic_gettime(&uptime); |
359 | sta->last_connected = uptime.tv_sec; | 359 | sta->last_connected = uptime.tv_sec; |
360 | ewma_init(&sta->avg_signal, 1024, 8); | 360 | ewma_init(&sta->avg_signal, 1024, 8); |
361 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | ||
362 | ewma_init(&sta->chain_signal_avg[i], 1024, 8); | ||
361 | 363 | ||
362 | if (sta_prepare_rate_control(local, sta, gfp)) { | 364 | if (sta_prepare_rate_control(local, sta, gfp)) { |
363 | kfree(sta); | 365 | kfree(sta); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index adc30045f99e..41c28b977f7c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -344,6 +344,11 @@ struct sta_info { | |||
344 | int last_signal; | 344 | int last_signal; |
345 | struct ewma avg_signal; | 345 | struct ewma avg_signal; |
346 | int last_ack_signal; | 346 | int last_ack_signal; |
347 | |||
348 | u8 chains; | ||
349 | s8 chain_signal_last[IEEE80211_MAX_CHAINS]; | ||
350 | struct ewma chain_signal_avg[IEEE80211_MAX_CHAINS]; | ||
351 | |||
347 | /* Plus 1 for non-QoS frames */ | 352 | /* Plus 1 for non-QoS frames */ |
348 | __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; | 353 | __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; |
349 | 354 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9972e07a2f96..34be9336b5d1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) | |||
398 | if (ieee80211_has_order(hdr->frame_control)) | 398 | if (ieee80211_has_order(hdr->frame_control)) |
399 | return TX_CONTINUE; | 399 | return TX_CONTINUE; |
400 | 400 | ||
401 | if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) | ||
402 | info->hw_queue = tx->sdata->vif.cab_queue; | ||
403 | |||
401 | /* no stations in PS mode */ | 404 | /* no stations in PS mode */ |
402 | if (!atomic_read(&ps->num_sta_ps)) | 405 | if (!atomic_read(&ps->num_sta_ps)) |
403 | return TX_CONTINUE; | 406 | return TX_CONTINUE; |
404 | 407 | ||
405 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; | 408 | info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; |
406 | if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) | ||
407 | info->hw_queue = tx->sdata->vif.cab_queue; | ||
408 | 409 | ||
409 | /* device releases frame after DTIM beacon */ | 410 | /* device releases frame after DTIM beacon */ |
410 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) | 411 | if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 27e07150eb46..89a83770d152 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces( | |||
560 | list_for_each_entry(sdata, &local->interfaces, list) { | 560 | list_for_each_entry(sdata, &local->interfaces, list) { |
561 | switch (sdata->vif.type) { | 561 | switch (sdata->vif.type) { |
562 | case NL80211_IFTYPE_MONITOR: | 562 | case NL80211_IFTYPE_MONITOR: |
563 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | ||
564 | continue; | ||
565 | break; | ||
563 | case NL80211_IFTYPE_AP_VLAN: | 566 | case NL80211_IFTYPE_AP_VLAN: |
564 | continue; | 567 | continue; |
565 | default: | 568 | default: |
@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
598 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 601 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
599 | switch (sdata->vif.type) { | 602 | switch (sdata->vif.type) { |
600 | case NL80211_IFTYPE_MONITOR: | 603 | case NL80211_IFTYPE_MONITOR: |
604 | if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) | ||
605 | continue; | ||
606 | break; | ||
601 | case NL80211_IFTYPE_AP_VLAN: | 607 | case NL80211_IFTYPE_AP_VLAN: |
602 | continue; | 608 | continue; |
603 | default: | 609 | default: |
@@ -1072,32 +1078,6 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | |||
1072 | ieee80211_set_wmm_default(sdata, true); | 1078 | ieee80211_set_wmm_default(sdata, true); |
1073 | } | 1079 | } |
1074 | 1080 | ||
1075 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | ||
1076 | enum ieee80211_band band) | ||
1077 | { | ||
1078 | struct ieee80211_supported_band *sband; | ||
1079 | struct ieee80211_rate *bitrates; | ||
1080 | u32 mandatory_rates; | ||
1081 | enum ieee80211_rate_flags mandatory_flag; | ||
1082 | int i; | ||
1083 | |||
1084 | sband = local->hw.wiphy->bands[band]; | ||
1085 | if (WARN_ON(!sband)) | ||
1086 | return 1; | ||
1087 | |||
1088 | if (band == IEEE80211_BAND_2GHZ) | ||
1089 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | ||
1090 | else | ||
1091 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; | ||
1092 | |||
1093 | bitrates = sband->bitrates; | ||
1094 | mandatory_rates = 0; | ||
1095 | for (i = 0; i < sband->n_bitrates; i++) | ||
1096 | if (bitrates[i].flags & mandatory_flag) | ||
1097 | mandatory_rates |= BIT(i); | ||
1098 | return mandatory_rates; | ||
1099 | } | ||
1100 | |||
1101 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1081 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1102 | u16 transaction, u16 auth_alg, u16 status, | 1082 | u16 transaction, u16 auth_alg, u16 status, |
1103 | const u8 *extra, size_t extra_len, const u8 *da, | 1083 | const u8 *extra, size_t extra_len, const u8 *da, |
@@ -1607,9 +1587,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1607 | if (sdata->u.mgd.dtim_period) | 1587 | if (sdata->u.mgd.dtim_period) |
1608 | changed |= BSS_CHANGED_DTIM_PERIOD; | 1588 | changed |= BSS_CHANGED_DTIM_PERIOD; |
1609 | 1589 | ||
1610 | mutex_lock(&sdata->u.mgd.mtx); | 1590 | sdata_lock(sdata); |
1611 | ieee80211_bss_info_change_notify(sdata, changed); | 1591 | ieee80211_bss_info_change_notify(sdata, changed); |
1612 | mutex_unlock(&sdata->u.mgd.mtx); | 1592 | sdata_unlock(sdata); |
1613 | break; | 1593 | break; |
1614 | case NL80211_IFTYPE_ADHOC: | 1594 | case NL80211_IFTYPE_ADHOC: |
1615 | changed |= BSS_CHANGED_IBSS; | 1595 | changed |= BSS_CHANGED_IBSS; |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index c04d401dae92..6ee2b5863572 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -28,7 +28,7 @@ | |||
28 | int ieee80211_wep_init(struct ieee80211_local *local) | 28 | int ieee80211_wep_init(struct ieee80211_local *local) |
29 | { | 29 | { |
30 | /* start WEP IV from a random value */ | 30 | /* start WEP IV from a random value */ |
31 | get_random_bytes(&local->wep_iv, WEP_IV_LEN); | 31 | get_random_bytes(&local->wep_iv, IEEE80211_WEP_IV_LEN); |
32 | 32 | ||
33 | local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); | 33 | local->wep_tx_tfm = crypto_alloc_cipher("arc4", 0, CRYPTO_ALG_ASYNC); |
34 | if (IS_ERR(local->wep_tx_tfm)) { | 34 | if (IS_ERR(local->wep_tx_tfm)) { |
@@ -98,20 +98,21 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, | |||
98 | 98 | ||
99 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 99 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
100 | 100 | ||
101 | if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN || | 101 | if (WARN_ON(skb_tailroom(skb) < IEEE80211_WEP_ICV_LEN || |
102 | skb_headroom(skb) < WEP_IV_LEN)) | 102 | skb_headroom(skb) < IEEE80211_WEP_IV_LEN)) |
103 | return NULL; | 103 | return NULL; |
104 | 104 | ||
105 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 105 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
106 | newhdr = skb_push(skb, WEP_IV_LEN); | 106 | newhdr = skb_push(skb, IEEE80211_WEP_IV_LEN); |
107 | memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); | 107 | memmove(newhdr, newhdr + IEEE80211_WEP_IV_LEN, hdrlen); |
108 | 108 | ||
109 | /* the HW only needs room for the IV, but not the actual IV */ | 109 | /* the HW only needs room for the IV, but not the actual IV */ |
110 | if (info->control.hw_key && | 110 | if (info->control.hw_key && |
111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) | 111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) |
112 | return newhdr + hdrlen; | 112 | return newhdr + hdrlen; |
113 | 113 | ||
114 | skb_set_network_header(skb, skb_network_offset(skb) + WEP_IV_LEN); | 114 | skb_set_network_header(skb, skb_network_offset(skb) + |
115 | IEEE80211_WEP_IV_LEN); | ||
115 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); | 116 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); |
116 | return newhdr + hdrlen; | 117 | return newhdr + hdrlen; |
117 | } | 118 | } |
@@ -125,8 +126,8 @@ static void ieee80211_wep_remove_iv(struct ieee80211_local *local, | |||
125 | unsigned int hdrlen; | 126 | unsigned int hdrlen; |
126 | 127 | ||
127 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 128 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
128 | memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen); | 129 | memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen); |
129 | skb_pull(skb, WEP_IV_LEN); | 130 | skb_pull(skb, IEEE80211_WEP_IV_LEN); |
130 | } | 131 | } |
131 | 132 | ||
132 | 133 | ||
@@ -146,7 +147,7 @@ int ieee80211_wep_encrypt_data(struct crypto_cipher *tfm, u8 *rc4key, | |||
146 | put_unaligned(icv, (__le32 *)(data + data_len)); | 147 | put_unaligned(icv, (__le32 *)(data + data_len)); |
147 | 148 | ||
148 | crypto_cipher_setkey(tfm, rc4key, klen); | 149 | crypto_cipher_setkey(tfm, rc4key, klen); |
149 | for (i = 0; i < data_len + WEP_ICV_LEN; i++) | 150 | for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++) |
150 | crypto_cipher_encrypt_one(tfm, data + i, data + i); | 151 | crypto_cipher_encrypt_one(tfm, data + i, data + i); |
151 | 152 | ||
152 | return 0; | 153 | return 0; |
@@ -172,7 +173,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, | |||
172 | if (!iv) | 173 | if (!iv) |
173 | return -1; | 174 | return -1; |
174 | 175 | ||
175 | len = skb->len - (iv + WEP_IV_LEN - skb->data); | 176 | len = skb->len - (iv + IEEE80211_WEP_IV_LEN - skb->data); |
176 | 177 | ||
177 | /* Prepend 24-bit IV to RC4 key */ | 178 | /* Prepend 24-bit IV to RC4 key */ |
178 | memcpy(rc4key, iv, 3); | 179 | memcpy(rc4key, iv, 3); |
@@ -181,10 +182,10 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, | |||
181 | memcpy(rc4key + 3, key, keylen); | 182 | memcpy(rc4key + 3, key, keylen); |
182 | 183 | ||
183 | /* Add room for ICV */ | 184 | /* Add room for ICV */ |
184 | skb_put(skb, WEP_ICV_LEN); | 185 | skb_put(skb, IEEE80211_WEP_ICV_LEN); |
185 | 186 | ||
186 | return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3, | 187 | return ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3, |
187 | iv + WEP_IV_LEN, len); | 188 | iv + IEEE80211_WEP_IV_LEN, len); |
188 | } | 189 | } |
189 | 190 | ||
190 | 191 | ||
@@ -201,11 +202,11 @@ int ieee80211_wep_decrypt_data(struct crypto_cipher *tfm, u8 *rc4key, | |||
201 | return -1; | 202 | return -1; |
202 | 203 | ||
203 | crypto_cipher_setkey(tfm, rc4key, klen); | 204 | crypto_cipher_setkey(tfm, rc4key, klen); |
204 | for (i = 0; i < data_len + WEP_ICV_LEN; i++) | 205 | for (i = 0; i < data_len + IEEE80211_WEP_ICV_LEN; i++) |
205 | crypto_cipher_decrypt_one(tfm, data + i, data + i); | 206 | crypto_cipher_decrypt_one(tfm, data + i, data + i); |
206 | 207 | ||
207 | crc = cpu_to_le32(~crc32_le(~0, data, data_len)); | 208 | crc = cpu_to_le32(~crc32_le(~0, data, data_len)); |
208 | if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0) | 209 | if (memcmp(&crc, data + data_len, IEEE80211_WEP_ICV_LEN) != 0) |
209 | /* ICV mismatch */ | 210 | /* ICV mismatch */ |
210 | return -1; | 211 | return -1; |
211 | 212 | ||
@@ -237,10 +238,10 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, | |||
237 | return -1; | 238 | return -1; |
238 | 239 | ||
239 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 240 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
240 | if (skb->len < hdrlen + WEP_IV_LEN + WEP_ICV_LEN) | 241 | if (skb->len < hdrlen + IEEE80211_WEP_IV_LEN + IEEE80211_WEP_ICV_LEN) |
241 | return -1; | 242 | return -1; |
242 | 243 | ||
243 | len = skb->len - hdrlen - WEP_IV_LEN - WEP_ICV_LEN; | 244 | len = skb->len - hdrlen - IEEE80211_WEP_IV_LEN - IEEE80211_WEP_ICV_LEN; |
244 | 245 | ||
245 | keyidx = skb->data[hdrlen + 3] >> 6; | 246 | keyidx = skb->data[hdrlen + 3] >> 6; |
246 | 247 | ||
@@ -256,16 +257,16 @@ static int ieee80211_wep_decrypt(struct ieee80211_local *local, | |||
256 | memcpy(rc4key + 3, key->conf.key, key->conf.keylen); | 257 | memcpy(rc4key + 3, key->conf.key, key->conf.keylen); |
257 | 258 | ||
258 | if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, | 259 | if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, |
259 | skb->data + hdrlen + WEP_IV_LEN, | 260 | skb->data + hdrlen + |
260 | len)) | 261 | IEEE80211_WEP_IV_LEN, len)) |
261 | ret = -1; | 262 | ret = -1; |
262 | 263 | ||
263 | /* Trim ICV */ | 264 | /* Trim ICV */ |
264 | skb_trim(skb, skb->len - WEP_ICV_LEN); | 265 | skb_trim(skb, skb->len - IEEE80211_WEP_ICV_LEN); |
265 | 266 | ||
266 | /* Remove IV */ | 267 | /* Remove IV */ |
267 | memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen); | 268 | memmove(skb->data + IEEE80211_WEP_IV_LEN, skb->data, hdrlen); |
268 | skb_pull(skb, WEP_IV_LEN); | 269 | skb_pull(skb, IEEE80211_WEP_IV_LEN); |
269 | 270 | ||
270 | return ret; | 271 | return ret; |
271 | } | 272 | } |
@@ -305,13 +306,14 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) | |||
305 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) | 306 | if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) |
306 | return RX_DROP_UNUSABLE; | 307 | return RX_DROP_UNUSABLE; |
307 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { | 308 | } else if (!(status->flag & RX_FLAG_IV_STRIPPED)) { |
308 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + WEP_IV_LEN)) | 309 | if (!pskb_may_pull(rx->skb, ieee80211_hdrlen(fc) + |
310 | IEEE80211_WEP_IV_LEN)) | ||
309 | return RX_DROP_UNUSABLE; | 311 | return RX_DROP_UNUSABLE; |
310 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) | 312 | if (rx->sta && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) |
311 | rx->sta->wep_weak_iv_count++; | 313 | rx->sta->wep_weak_iv_count++; |
312 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); | 314 | ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); |
313 | /* remove ICV */ | 315 | /* remove ICV */ |
314 | if (pskb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN)) | 316 | if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN)) |
315 | return RX_DROP_UNUSABLE; | 317 | return RX_DROP_UNUSABLE; |
316 | } | 318 | } |
317 | 319 | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index c7c6d644486f..c9edfcb7a13b 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -62,10 +62,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
62 | 62 | ||
63 | tail = MICHAEL_MIC_LEN; | 63 | tail = MICHAEL_MIC_LEN; |
64 | if (!info->control.hw_key) | 64 | if (!info->control.hw_key) |
65 | tail += TKIP_ICV_LEN; | 65 | tail += IEEE80211_TKIP_ICV_LEN; |
66 | 66 | ||
67 | if (WARN_ON(skb_tailroom(skb) < tail || | 67 | if (WARN_ON(skb_tailroom(skb) < tail || |
68 | skb_headroom(skb) < TKIP_IV_LEN)) | 68 | skb_headroom(skb) < IEEE80211_TKIP_IV_LEN)) |
69 | return TX_DROP; | 69 | return TX_DROP; |
70 | 70 | ||
71 | key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; | 71 | key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; |
@@ -198,15 +198,16 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
198 | if (info->control.hw_key) | 198 | if (info->control.hw_key) |
199 | tail = 0; | 199 | tail = 0; |
200 | else | 200 | else |
201 | tail = TKIP_ICV_LEN; | 201 | tail = IEEE80211_TKIP_ICV_LEN; |
202 | 202 | ||
203 | if (WARN_ON(skb_tailroom(skb) < tail || | 203 | if (WARN_ON(skb_tailroom(skb) < tail || |
204 | skb_headroom(skb) < TKIP_IV_LEN)) | 204 | skb_headroom(skb) < IEEE80211_TKIP_IV_LEN)) |
205 | return -1; | 205 | return -1; |
206 | 206 | ||
207 | pos = skb_push(skb, TKIP_IV_LEN); | 207 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); |
208 | memmove(pos, pos + TKIP_IV_LEN, hdrlen); | 208 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); |
209 | skb_set_network_header(skb, skb_network_offset(skb) + TKIP_IV_LEN); | 209 | skb_set_network_header(skb, skb_network_offset(skb) + |
210 | IEEE80211_TKIP_IV_LEN); | ||
210 | pos += hdrlen; | 211 | pos += hdrlen; |
211 | 212 | ||
212 | /* the HW only needs room for the IV, but not the actual IV */ | 213 | /* the HW only needs room for the IV, but not the actual IV */ |
@@ -227,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
227 | return 0; | 228 | return 0; |
228 | 229 | ||
229 | /* Add room for ICV */ | 230 | /* Add room for ICV */ |
230 | skb_put(skb, TKIP_ICV_LEN); | 231 | skb_put(skb, IEEE80211_TKIP_ICV_LEN); |
231 | 232 | ||
232 | return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm, | 233 | return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm, |
233 | key, skb, pos, len); | 234 | key, skb, pos, len); |
@@ -290,11 +291,11 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
290 | return RX_DROP_UNUSABLE; | 291 | return RX_DROP_UNUSABLE; |
291 | 292 | ||
292 | /* Trim ICV */ | 293 | /* Trim ICV */ |
293 | skb_trim(skb, skb->len - TKIP_ICV_LEN); | 294 | skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN); |
294 | 295 | ||
295 | /* Remove IV */ | 296 | /* Remove IV */ |
296 | memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen); | 297 | memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen); |
297 | skb_pull(skb, TKIP_IV_LEN); | 298 | skb_pull(skb, IEEE80211_TKIP_IV_LEN); |
298 | 299 | ||
299 | return RX_CONTINUE; | 300 | return RX_CONTINUE; |
300 | } | 301 | } |
@@ -337,9 +338,9 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
337 | else | 338 | else |
338 | qos_tid = 0; | 339 | qos_tid = 0; |
339 | 340 | ||
340 | data_len = skb->len - hdrlen - CCMP_HDR_LEN; | 341 | data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN; |
341 | if (encrypted) | 342 | if (encrypted) |
342 | data_len -= CCMP_MIC_LEN; | 343 | data_len -= IEEE80211_CCMP_MIC_LEN; |
343 | 344 | ||
344 | /* First block, b_0 */ | 345 | /* First block, b_0 */ |
345 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ | 346 | b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ |
@@ -348,7 +349,7 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch, | |||
348 | */ | 349 | */ |
349 | b_0[1] = qos_tid | (mgmt << 4); | 350 | b_0[1] = qos_tid | (mgmt << 4); |
350 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); | 351 | memcpy(&b_0[2], hdr->addr2, ETH_ALEN); |
351 | memcpy(&b_0[8], pn, CCMP_PN_LEN); | 352 | memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); |
352 | /* l(m) */ | 353 | /* l(m) */ |
353 | put_unaligned_be16(data_len, &b_0[14]); | 354 | put_unaligned_be16(data_len, &b_0[14]); |
354 | 355 | ||
@@ -424,15 +425,16 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
424 | if (info->control.hw_key) | 425 | if (info->control.hw_key) |
425 | tail = 0; | 426 | tail = 0; |
426 | else | 427 | else |
427 | tail = CCMP_MIC_LEN; | 428 | tail = IEEE80211_CCMP_MIC_LEN; |
428 | 429 | ||
429 | if (WARN_ON(skb_tailroom(skb) < tail || | 430 | if (WARN_ON(skb_tailroom(skb) < tail || |
430 | skb_headroom(skb) < CCMP_HDR_LEN)) | 431 | skb_headroom(skb) < IEEE80211_CCMP_HDR_LEN)) |
431 | return -1; | 432 | return -1; |
432 | 433 | ||
433 | pos = skb_push(skb, CCMP_HDR_LEN); | 434 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); |
434 | memmove(pos, pos + CCMP_HDR_LEN, hdrlen); | 435 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); |
435 | skb_set_network_header(skb, skb_network_offset(skb) + CCMP_HDR_LEN); | 436 | skb_set_network_header(skb, skb_network_offset(skb) + |
437 | IEEE80211_CCMP_HDR_LEN); | ||
436 | 438 | ||
437 | /* the HW only needs room for the IV, but not the actual IV */ | 439 | /* the HW only needs room for the IV, but not the actual IV */ |
438 | if (info->control.hw_key && | 440 | if (info->control.hw_key && |
@@ -457,10 +459,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
457 | if (info->control.hw_key) | 459 | if (info->control.hw_key) |
458 | return 0; | 460 | return 0; |
459 | 461 | ||
460 | pos += CCMP_HDR_LEN; | 462 | pos += IEEE80211_CCMP_HDR_LEN; |
461 | ccmp_special_blocks(skb, pn, scratch, 0); | 463 | ccmp_special_blocks(skb, pn, scratch, 0); |
462 | ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len, | 464 | ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len, |
463 | pos, skb_put(skb, CCMP_MIC_LEN)); | 465 | pos, skb_put(skb, IEEE80211_CCMP_MIC_LEN)); |
464 | 466 | ||
465 | return 0; | 467 | return 0; |
466 | } | 468 | } |
@@ -490,7 +492,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
490 | struct ieee80211_key *key = rx->key; | 492 | struct ieee80211_key *key = rx->key; |
491 | struct sk_buff *skb = rx->skb; | 493 | struct sk_buff *skb = rx->skb; |
492 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 494 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
493 | u8 pn[CCMP_PN_LEN]; | 495 | u8 pn[IEEE80211_CCMP_PN_LEN]; |
494 | int data_len; | 496 | int data_len; |
495 | int queue; | 497 | int queue; |
496 | 498 | ||
@@ -500,12 +502,13 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
500 | !ieee80211_is_robust_mgmt_frame(hdr)) | 502 | !ieee80211_is_robust_mgmt_frame(hdr)) |
501 | return RX_CONTINUE; | 503 | return RX_CONTINUE; |
502 | 504 | ||
503 | data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; | 505 | data_len = skb->len - hdrlen - IEEE80211_CCMP_HDR_LEN - |
506 | IEEE80211_CCMP_MIC_LEN; | ||
504 | if (!rx->sta || data_len < 0) | 507 | if (!rx->sta || data_len < 0) |
505 | return RX_DROP_UNUSABLE; | 508 | return RX_DROP_UNUSABLE; |
506 | 509 | ||
507 | if (status->flag & RX_FLAG_DECRYPTED) { | 510 | if (status->flag & RX_FLAG_DECRYPTED) { |
508 | if (!pskb_may_pull(rx->skb, hdrlen + CCMP_HDR_LEN)) | 511 | if (!pskb_may_pull(rx->skb, hdrlen + IEEE80211_CCMP_HDR_LEN)) |
509 | return RX_DROP_UNUSABLE; | 512 | return RX_DROP_UNUSABLE; |
510 | } else { | 513 | } else { |
511 | if (skb_linearize(rx->skb)) | 514 | if (skb_linearize(rx->skb)) |
@@ -516,7 +519,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
516 | 519 | ||
517 | queue = rx->security_idx; | 520 | queue = rx->security_idx; |
518 | 521 | ||
519 | if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) { | 522 | if (memcmp(pn, key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN) <= 0) { |
520 | key->u.ccmp.replays++; | 523 | key->u.ccmp.replays++; |
521 | return RX_DROP_UNUSABLE; | 524 | return RX_DROP_UNUSABLE; |
522 | } | 525 | } |
@@ -528,19 +531,20 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) | |||
528 | 531 | ||
529 | if (ieee80211_aes_ccm_decrypt( | 532 | if (ieee80211_aes_ccm_decrypt( |
530 | key->u.ccmp.tfm, scratch, | 533 | key->u.ccmp.tfm, scratch, |
531 | skb->data + hdrlen + CCMP_HDR_LEN, data_len, | 534 | skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, |
532 | skb->data + skb->len - CCMP_MIC_LEN, | 535 | data_len, |
533 | skb->data + hdrlen + CCMP_HDR_LEN)) | 536 | skb->data + skb->len - IEEE80211_CCMP_MIC_LEN, |
537 | skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN)) | ||
534 | return RX_DROP_UNUSABLE; | 538 | return RX_DROP_UNUSABLE; |
535 | } | 539 | } |
536 | 540 | ||
537 | memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN); | 541 | memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); |
538 | 542 | ||
539 | /* Remove CCMP header and MIC */ | 543 | /* Remove CCMP header and MIC */ |
540 | if (pskb_trim(skb, skb->len - CCMP_MIC_LEN)) | 544 | if (pskb_trim(skb, skb->len - IEEE80211_CCMP_MIC_LEN)) |
541 | return RX_DROP_UNUSABLE; | 545 | return RX_DROP_UNUSABLE; |
542 | memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); | 546 | memmove(skb->data + IEEE80211_CCMP_HDR_LEN, skb->data, hdrlen); |
543 | skb_pull(skb, CCMP_HDR_LEN); | 547 | skb_pull(skb, IEEE80211_CCMP_HDR_LEN); |
544 | 548 | ||
545 | return RX_CONTINUE; | 549 | return RX_CONTINUE; |
546 | } | 550 | } |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 01e41191f1bf..e4df77490229 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -34,13 +34,12 @@ | |||
34 | MODULE_AUTHOR("Johannes Berg"); | 34 | MODULE_AUTHOR("Johannes Berg"); |
35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
36 | MODULE_DESCRIPTION("wireless configuration support"); | 36 | MODULE_DESCRIPTION("wireless configuration support"); |
37 | MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME); | ||
37 | 38 | ||
38 | /* RCU-protected (and cfg80211_mutex for writers) */ | 39 | /* RCU-protected (and RTNL for writers) */ |
39 | LIST_HEAD(cfg80211_rdev_list); | 40 | LIST_HEAD(cfg80211_rdev_list); |
40 | int cfg80211_rdev_list_generation; | 41 | int cfg80211_rdev_list_generation; |
41 | 42 | ||
42 | DEFINE_MUTEX(cfg80211_mutex); | ||
43 | |||
44 | /* for debugfs */ | 43 | /* for debugfs */ |
45 | static struct dentry *ieee80211_debugfs_dir; | 44 | static struct dentry *ieee80211_debugfs_dir; |
46 | 45 | ||
@@ -52,12 +51,11 @@ module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); | |||
52 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, | 51 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, |
53 | "Disable 40MHz support in the 2.4GHz band"); | 52 | "Disable 40MHz support in the 2.4GHz band"); |
54 | 53 | ||
55 | /* requires cfg80211_mutex to be held! */ | ||
56 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 54 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
57 | { | 55 | { |
58 | struct cfg80211_registered_device *result = NULL, *rdev; | 56 | struct cfg80211_registered_device *result = NULL, *rdev; |
59 | 57 | ||
60 | assert_cfg80211_lock(); | 58 | ASSERT_RTNL(); |
61 | 59 | ||
62 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 60 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
63 | if (rdev->wiphy_idx == wiphy_idx) { | 61 | if (rdev->wiphy_idx == wiphy_idx) { |
@@ -76,12 +74,11 @@ int get_wiphy_idx(struct wiphy *wiphy) | |||
76 | return rdev->wiphy_idx; | 74 | return rdev->wiphy_idx; |
77 | } | 75 | } |
78 | 76 | ||
79 | /* requires cfg80211_rdev_mutex to be held! */ | ||
80 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | 77 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) |
81 | { | 78 | { |
82 | struct cfg80211_registered_device *rdev; | 79 | struct cfg80211_registered_device *rdev; |
83 | 80 | ||
84 | assert_cfg80211_lock(); | 81 | ASSERT_RTNL(); |
85 | 82 | ||
86 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); | 83 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); |
87 | if (!rdev) | 84 | if (!rdev) |
@@ -89,35 +86,13 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
89 | return &rdev->wiphy; | 86 | return &rdev->wiphy; |
90 | } | 87 | } |
91 | 88 | ||
92 | struct cfg80211_registered_device * | ||
93 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | ||
94 | { | ||
95 | struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); | ||
96 | struct net_device *dev; | ||
97 | |||
98 | mutex_lock(&cfg80211_mutex); | ||
99 | dev = dev_get_by_index(net, ifindex); | ||
100 | if (!dev) | ||
101 | goto out; | ||
102 | if (dev->ieee80211_ptr) { | ||
103 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
104 | mutex_lock(&rdev->mtx); | ||
105 | } else | ||
106 | rdev = ERR_PTR(-ENODEV); | ||
107 | dev_put(dev); | ||
108 | out: | ||
109 | mutex_unlock(&cfg80211_mutex); | ||
110 | return rdev; | ||
111 | } | ||
112 | |||
113 | /* requires cfg80211_mutex to be held */ | ||
114 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 89 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
115 | char *newname) | 90 | char *newname) |
116 | { | 91 | { |
117 | struct cfg80211_registered_device *rdev2; | 92 | struct cfg80211_registered_device *rdev2; |
118 | int wiphy_idx, taken = -1, result, digits; | 93 | int wiphy_idx, taken = -1, result, digits; |
119 | 94 | ||
120 | assert_cfg80211_lock(); | 95 | ASSERT_RTNL(); |
121 | 96 | ||
122 | /* prohibit calling the thing phy%d when %d is not its number */ | 97 | /* prohibit calling the thing phy%d when %d is not its number */ |
123 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | 98 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
@@ -215,8 +190,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | |||
215 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | 190 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, |
216 | struct wireless_dev *wdev) | 191 | struct wireless_dev *wdev) |
217 | { | 192 | { |
218 | lockdep_assert_held(&rdev->devlist_mtx); | 193 | ASSERT_RTNL(); |
219 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
220 | 194 | ||
221 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) | 195 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) |
222 | return; | 196 | return; |
@@ -230,18 +204,15 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
230 | rdev->opencount--; | 204 | rdev->opencount--; |
231 | 205 | ||
232 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | 206 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
233 | bool busy = work_busy(&rdev->scan_done_wk); | ||
234 | |||
235 | /* | 207 | /* |
236 | * If the work isn't pending or running (in which case it would | 208 | * If the scan request wasn't notified as done, set it |
237 | * be waiting for the lock we hold) the driver didn't properly | 209 | * to aborted and leak it after a warning. The driver |
238 | * cancel the scan when the interface was removed. In this case | 210 | * should have notified us that it ended at the latest |
239 | * warn and leak the scan request object to not crash later. | 211 | * during rdev_stop_p2p_device(). |
240 | */ | 212 | */ |
241 | WARN_ON(!busy); | 213 | if (WARN_ON(!rdev->scan_req->notified)) |
242 | 214 | rdev->scan_req->aborted = true; | |
243 | rdev->scan_req->aborted = true; | 215 | ___cfg80211_scan_done(rdev, !rdev->scan_req->notified); |
244 | ___cfg80211_scan_done(rdev, !busy); | ||
245 | } | 216 | } |
246 | } | 217 | } |
247 | 218 | ||
@@ -255,8 +226,6 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
255 | 226 | ||
256 | rtnl_lock(); | 227 | rtnl_lock(); |
257 | 228 | ||
258 | /* read-only iteration need not hold the devlist_mtx */ | ||
259 | |||
260 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 229 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
261 | if (wdev->netdev) { | 230 | if (wdev->netdev) { |
262 | dev_close(wdev->netdev); | 231 | dev_close(wdev->netdev); |
@@ -265,12 +234,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
265 | /* otherwise, check iftype */ | 234 | /* otherwise, check iftype */ |
266 | switch (wdev->iftype) { | 235 | switch (wdev->iftype) { |
267 | case NL80211_IFTYPE_P2P_DEVICE: | 236 | case NL80211_IFTYPE_P2P_DEVICE: |
268 | /* but this requires it */ | ||
269 | mutex_lock(&rdev->devlist_mtx); | ||
270 | mutex_lock(&rdev->sched_scan_mtx); | ||
271 | cfg80211_stop_p2p_device(rdev, wdev); | 237 | cfg80211_stop_p2p_device(rdev, wdev); |
272 | mutex_unlock(&rdev->sched_scan_mtx); | ||
273 | mutex_unlock(&rdev->devlist_mtx); | ||
274 | break; | 238 | break; |
275 | default: | 239 | default: |
276 | break; | 240 | break; |
@@ -298,10 +262,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
298 | event_work); | 262 | event_work); |
299 | 263 | ||
300 | rtnl_lock(); | 264 | rtnl_lock(); |
301 | cfg80211_lock_rdev(rdev); | ||
302 | |||
303 | cfg80211_process_rdev_events(rdev); | 265 | cfg80211_process_rdev_events(rdev); |
304 | cfg80211_unlock_rdev(rdev); | ||
305 | rtnl_unlock(); | 266 | rtnl_unlock(); |
306 | } | 267 | } |
307 | 268 | ||
@@ -309,7 +270,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
309 | 270 | ||
310 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 271 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
311 | { | 272 | { |
312 | static int wiphy_counter; | 273 | static atomic_t wiphy_counter = ATOMIC_INIT(0); |
313 | 274 | ||
314 | struct cfg80211_registered_device *rdev; | 275 | struct cfg80211_registered_device *rdev; |
315 | int alloc_size; | 276 | int alloc_size; |
@@ -331,26 +292,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
331 | 292 | ||
332 | rdev->ops = ops; | 293 | rdev->ops = ops; |
333 | 294 | ||
334 | mutex_lock(&cfg80211_mutex); | 295 | rdev->wiphy_idx = atomic_inc_return(&wiphy_counter); |
335 | |||
336 | rdev->wiphy_idx = wiphy_counter++; | ||
337 | 296 | ||
338 | if (unlikely(rdev->wiphy_idx < 0)) { | 297 | if (unlikely(rdev->wiphy_idx < 0)) { |
339 | wiphy_counter--; | ||
340 | mutex_unlock(&cfg80211_mutex); | ||
341 | /* ugh, wrapped! */ | 298 | /* ugh, wrapped! */ |
299 | atomic_dec(&wiphy_counter); | ||
342 | kfree(rdev); | 300 | kfree(rdev); |
343 | return NULL; | 301 | return NULL; |
344 | } | 302 | } |
345 | 303 | ||
346 | mutex_unlock(&cfg80211_mutex); | ||
347 | |||
348 | /* give it a proper name */ | 304 | /* give it a proper name */ |
349 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 305 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); |
350 | 306 | ||
351 | mutex_init(&rdev->mtx); | ||
352 | mutex_init(&rdev->devlist_mtx); | ||
353 | mutex_init(&rdev->sched_scan_mtx); | ||
354 | INIT_LIST_HEAD(&rdev->wdev_list); | 307 | INIT_LIST_HEAD(&rdev->wdev_list); |
355 | INIT_LIST_HEAD(&rdev->beacon_registrations); | 308 | INIT_LIST_HEAD(&rdev->beacon_registrations); |
356 | spin_lock_init(&rdev->beacon_registrations_lock); | 309 | spin_lock_init(&rdev->beacon_registrations_lock); |
@@ -598,11 +551,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
598 | /* check and set up bitrates */ | 551 | /* check and set up bitrates */ |
599 | ieee80211_set_bitrate_flags(wiphy); | 552 | ieee80211_set_bitrate_flags(wiphy); |
600 | 553 | ||
601 | mutex_lock(&cfg80211_mutex); | 554 | rtnl_lock(); |
602 | 555 | ||
603 | res = device_add(&rdev->wiphy.dev); | 556 | res = device_add(&rdev->wiphy.dev); |
604 | if (res) { | 557 | if (res) { |
605 | mutex_unlock(&cfg80211_mutex); | 558 | rtnl_unlock(); |
606 | return res; | 559 | return res; |
607 | } | 560 | } |
608 | 561 | ||
@@ -631,25 +584,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
631 | } | 584 | } |
632 | 585 | ||
633 | cfg80211_debugfs_rdev_add(rdev); | 586 | cfg80211_debugfs_rdev_add(rdev); |
634 | mutex_unlock(&cfg80211_mutex); | ||
635 | 587 | ||
636 | /* | ||
637 | * due to a locking dependency this has to be outside of the | ||
638 | * cfg80211_mutex lock | ||
639 | */ | ||
640 | res = rfkill_register(rdev->rfkill); | 588 | res = rfkill_register(rdev->rfkill); |
641 | if (res) { | 589 | if (res) { |
642 | device_del(&rdev->wiphy.dev); | 590 | device_del(&rdev->wiphy.dev); |
643 | 591 | ||
644 | mutex_lock(&cfg80211_mutex); | ||
645 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); | 592 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); |
646 | list_del_rcu(&rdev->list); | 593 | list_del_rcu(&rdev->list); |
647 | wiphy_regulatory_deregister(wiphy); | 594 | wiphy_regulatory_deregister(wiphy); |
648 | mutex_unlock(&cfg80211_mutex); | 595 | rtnl_unlock(); |
649 | return res; | 596 | return res; |
650 | } | 597 | } |
651 | 598 | ||
652 | rtnl_lock(); | ||
653 | rdev->wiphy.registered = true; | 599 | rdev->wiphy.registered = true; |
654 | rtnl_unlock(); | 600 | rtnl_unlock(); |
655 | return 0; | 601 | return 0; |
@@ -679,25 +625,19 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
679 | { | 625 | { |
680 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 626 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
681 | 627 | ||
682 | rtnl_lock(); | ||
683 | rdev->wiphy.registered = false; | ||
684 | rtnl_unlock(); | ||
685 | |||
686 | rfkill_unregister(rdev->rfkill); | ||
687 | |||
688 | /* protect the device list */ | ||
689 | mutex_lock(&cfg80211_mutex); | ||
690 | |||
691 | wait_event(rdev->dev_wait, ({ | 628 | wait_event(rdev->dev_wait, ({ |
692 | int __count; | 629 | int __count; |
693 | mutex_lock(&rdev->devlist_mtx); | 630 | rtnl_lock(); |
694 | __count = rdev->opencount; | 631 | __count = rdev->opencount; |
695 | mutex_unlock(&rdev->devlist_mtx); | 632 | rtnl_unlock(); |
696 | __count == 0; })); | 633 | __count == 0; })); |
697 | 634 | ||
698 | mutex_lock(&rdev->devlist_mtx); | 635 | rtnl_lock(); |
636 | rdev->wiphy.registered = false; | ||
637 | |||
638 | rfkill_unregister(rdev->rfkill); | ||
639 | |||
699 | BUG_ON(!list_empty(&rdev->wdev_list)); | 640 | BUG_ON(!list_empty(&rdev->wdev_list)); |
700 | mutex_unlock(&rdev->devlist_mtx); | ||
701 | 641 | ||
702 | /* | 642 | /* |
703 | * First remove the hardware from everywhere, this makes | 643 | * First remove the hardware from everywhere, this makes |
@@ -708,20 +648,6 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
708 | synchronize_rcu(); | 648 | synchronize_rcu(); |
709 | 649 | ||
710 | /* | 650 | /* |
711 | * Try to grab rdev->mtx. If a command is still in progress, | ||
712 | * hopefully the driver will refuse it since it's tearing | ||
713 | * down the device already. We wait for this command to complete | ||
714 | * before unlinking the item from the list. | ||
715 | * Note: as codified by the BUG_ON above we cannot get here if | ||
716 | * a virtual interface is still present. Hence, we can only get | ||
717 | * to lock contention here if userspace issues a command that | ||
718 | * identified the hardware by wiphy index. | ||
719 | */ | ||
720 | cfg80211_lock_rdev(rdev); | ||
721 | /* nothing */ | ||
722 | cfg80211_unlock_rdev(rdev); | ||
723 | |||
724 | /* | ||
725 | * If this device got a regulatory hint tell core its | 651 | * If this device got a regulatory hint tell core its |
726 | * free to listen now to a new shiny device regulatory hint | 652 | * free to listen now to a new shiny device regulatory hint |
727 | */ | 653 | */ |
@@ -730,15 +656,17 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
730 | cfg80211_rdev_list_generation++; | 656 | cfg80211_rdev_list_generation++; |
731 | device_del(&rdev->wiphy.dev); | 657 | device_del(&rdev->wiphy.dev); |
732 | 658 | ||
733 | mutex_unlock(&cfg80211_mutex); | 659 | rtnl_unlock(); |
734 | 660 | ||
735 | flush_work(&rdev->scan_done_wk); | 661 | flush_work(&rdev->scan_done_wk); |
736 | cancel_work_sync(&rdev->conn_work); | 662 | cancel_work_sync(&rdev->conn_work); |
737 | flush_work(&rdev->event_work); | 663 | flush_work(&rdev->event_work); |
738 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | 664 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
739 | 665 | ||
740 | if (rdev->wowlan && rdev->ops->set_wakeup) | 666 | #ifdef CONFIG_PM |
667 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) | ||
741 | rdev_set_wakeup(rdev, false); | 668 | rdev_set_wakeup(rdev, false); |
669 | #endif | ||
742 | cfg80211_rdev_free_wowlan(rdev); | 670 | cfg80211_rdev_free_wowlan(rdev); |
743 | } | 671 | } |
744 | EXPORT_SYMBOL(wiphy_unregister); | 672 | EXPORT_SYMBOL(wiphy_unregister); |
@@ -748,9 +676,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
748 | struct cfg80211_internal_bss *scan, *tmp; | 676 | struct cfg80211_internal_bss *scan, *tmp; |
749 | struct cfg80211_beacon_registration *reg, *treg; | 677 | struct cfg80211_beacon_registration *reg, *treg; |
750 | rfkill_destroy(rdev->rfkill); | 678 | rfkill_destroy(rdev->rfkill); |
751 | mutex_destroy(&rdev->mtx); | ||
752 | mutex_destroy(&rdev->devlist_mtx); | ||
753 | mutex_destroy(&rdev->sched_scan_mtx); | ||
754 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | 679 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { |
755 | list_del(®->list); | 680 | list_del(®->list); |
756 | kfree(reg); | 681 | kfree(reg); |
@@ -775,36 +700,6 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) | |||
775 | } | 700 | } |
776 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); | 701 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
777 | 702 | ||
778 | static void wdev_cleanup_work(struct work_struct *work) | ||
779 | { | ||
780 | struct wireless_dev *wdev; | ||
781 | struct cfg80211_registered_device *rdev; | ||
782 | |||
783 | wdev = container_of(work, struct wireless_dev, cleanup_work); | ||
784 | rdev = wiphy_to_dev(wdev->wiphy); | ||
785 | |||
786 | mutex_lock(&rdev->sched_scan_mtx); | ||
787 | |||
788 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { | ||
789 | rdev->scan_req->aborted = true; | ||
790 | ___cfg80211_scan_done(rdev, true); | ||
791 | } | ||
792 | |||
793 | if (WARN_ON(rdev->sched_scan_req && | ||
794 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
795 | __cfg80211_stop_sched_scan(rdev, false); | ||
796 | } | ||
797 | |||
798 | mutex_unlock(&rdev->sched_scan_mtx); | ||
799 | |||
800 | mutex_lock(&rdev->devlist_mtx); | ||
801 | rdev->opencount--; | ||
802 | mutex_unlock(&rdev->devlist_mtx); | ||
803 | wake_up(&rdev->dev_wait); | ||
804 | |||
805 | dev_put(wdev->netdev); | ||
806 | } | ||
807 | |||
808 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) | 703 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
809 | { | 704 | { |
810 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 705 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
@@ -814,8 +709,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
814 | if (WARN_ON(wdev->netdev)) | 709 | if (WARN_ON(wdev->netdev)) |
815 | return; | 710 | return; |
816 | 711 | ||
817 | mutex_lock(&rdev->devlist_mtx); | ||
818 | mutex_lock(&rdev->sched_scan_mtx); | ||
819 | list_del_rcu(&wdev->list); | 712 | list_del_rcu(&wdev->list); |
820 | rdev->devlist_generation++; | 713 | rdev->devlist_generation++; |
821 | 714 | ||
@@ -827,8 +720,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
827 | WARN_ON_ONCE(1); | 720 | WARN_ON_ONCE(1); |
828 | break; | 721 | break; |
829 | } | 722 | } |
830 | mutex_unlock(&rdev->sched_scan_mtx); | ||
831 | mutex_unlock(&rdev->devlist_mtx); | ||
832 | } | 723 | } |
833 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 724 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
834 | 725 | ||
@@ -847,7 +738,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
847 | } | 738 | } |
848 | 739 | ||
849 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 740 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
850 | struct wireless_dev *wdev) | 741 | struct wireless_dev *wdev) |
851 | { | 742 | { |
852 | struct net_device *dev = wdev->netdev; | 743 | struct net_device *dev = wdev->netdev; |
853 | 744 | ||
@@ -857,9 +748,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
857 | break; | 748 | break; |
858 | case NL80211_IFTYPE_P2P_CLIENT: | 749 | case NL80211_IFTYPE_P2P_CLIENT: |
859 | case NL80211_IFTYPE_STATION: | 750 | case NL80211_IFTYPE_STATION: |
860 | mutex_lock(&rdev->sched_scan_mtx); | ||
861 | __cfg80211_stop_sched_scan(rdev, false); | 751 | __cfg80211_stop_sched_scan(rdev, false); |
862 | mutex_unlock(&rdev->sched_scan_mtx); | ||
863 | 752 | ||
864 | wdev_lock(wdev); | 753 | wdev_lock(wdev); |
865 | #ifdef CONFIG_CFG80211_WEXT | 754 | #ifdef CONFIG_CFG80211_WEXT |
@@ -868,8 +757,8 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
868 | wdev->wext.ie_len = 0; | 757 | wdev->wext.ie_len = 0; |
869 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 758 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
870 | #endif | 759 | #endif |
871 | __cfg80211_disconnect(rdev, dev, | 760 | cfg80211_disconnect(rdev, dev, |
872 | WLAN_REASON_DEAUTH_LEAVING, true); | 761 | WLAN_REASON_DEAUTH_LEAVING, true); |
873 | wdev_unlock(wdev); | 762 | wdev_unlock(wdev); |
874 | break; | 763 | break; |
875 | case NL80211_IFTYPE_MESH_POINT: | 764 | case NL80211_IFTYPE_MESH_POINT: |
@@ -911,13 +800,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
911 | * are added with nl80211. | 800 | * are added with nl80211. |
912 | */ | 801 | */ |
913 | mutex_init(&wdev->mtx); | 802 | mutex_init(&wdev->mtx); |
914 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | ||
915 | INIT_LIST_HEAD(&wdev->event_list); | 803 | INIT_LIST_HEAD(&wdev->event_list); |
916 | spin_lock_init(&wdev->event_lock); | 804 | spin_lock_init(&wdev->event_lock); |
917 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 805 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
918 | spin_lock_init(&wdev->mgmt_registrations_lock); | 806 | spin_lock_init(&wdev->mgmt_registrations_lock); |
919 | 807 | ||
920 | mutex_lock(&rdev->devlist_mtx); | ||
921 | wdev->identifier = ++rdev->wdev_id; | 808 | wdev->identifier = ++rdev->wdev_id; |
922 | list_add_rcu(&wdev->list, &rdev->wdev_list); | 809 | list_add_rcu(&wdev->list, &rdev->wdev_list); |
923 | rdev->devlist_generation++; | 810 | rdev->devlist_generation++; |
@@ -930,7 +817,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
930 | } | 817 | } |
931 | wdev->netdev = dev; | 818 | wdev->netdev = dev; |
932 | wdev->sme_state = CFG80211_SME_IDLE; | 819 | wdev->sme_state = CFG80211_SME_IDLE; |
933 | mutex_unlock(&rdev->devlist_mtx); | ||
934 | #ifdef CONFIG_CFG80211_WEXT | 820 | #ifdef CONFIG_CFG80211_WEXT |
935 | wdev->wext.default_key = -1; | 821 | wdev->wext.default_key = -1; |
936 | wdev->wext.default_mgmt_key = -1; | 822 | wdev->wext.default_mgmt_key = -1; |
@@ -956,26 +842,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
956 | break; | 842 | break; |
957 | case NETDEV_DOWN: | 843 | case NETDEV_DOWN: |
958 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 844 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
959 | dev_hold(dev); | 845 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
960 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 846 | if (WARN_ON(!rdev->scan_req->notified)) |
847 | rdev->scan_req->aborted = true; | ||
848 | ___cfg80211_scan_done(rdev, true); | ||
849 | } | ||
850 | |||
851 | if (WARN_ON(rdev->sched_scan_req && | ||
852 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
853 | __cfg80211_stop_sched_scan(rdev, false); | ||
854 | } | ||
855 | |||
856 | rdev->opencount--; | ||
857 | wake_up(&rdev->dev_wait); | ||
961 | break; | 858 | break; |
962 | case NETDEV_UP: | 859 | case NETDEV_UP: |
963 | /* | ||
964 | * If we have a really quick DOWN/UP succession we may | ||
965 | * have this work still pending ... cancel it and see | ||
966 | * if it was pending, in which case we need to account | ||
967 | * for some of the work it would have done. | ||
968 | */ | ||
969 | if (cancel_work_sync(&wdev->cleanup_work)) { | ||
970 | mutex_lock(&rdev->devlist_mtx); | ||
971 | rdev->opencount--; | ||
972 | mutex_unlock(&rdev->devlist_mtx); | ||
973 | dev_put(dev); | ||
974 | } | ||
975 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | 860 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); |
976 | cfg80211_lock_rdev(rdev); | ||
977 | mutex_lock(&rdev->devlist_mtx); | ||
978 | mutex_lock(&rdev->sched_scan_mtx); | ||
979 | wdev_lock(wdev); | 861 | wdev_lock(wdev); |
980 | switch (wdev->iftype) { | 862 | switch (wdev->iftype) { |
981 | #ifdef CONFIG_CFG80211_WEXT | 863 | #ifdef CONFIG_CFG80211_WEXT |
@@ -1007,10 +889,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1007 | break; | 889 | break; |
1008 | } | 890 | } |
1009 | wdev_unlock(wdev); | 891 | wdev_unlock(wdev); |
1010 | mutex_unlock(&rdev->sched_scan_mtx); | ||
1011 | rdev->opencount++; | 892 | rdev->opencount++; |
1012 | mutex_unlock(&rdev->devlist_mtx); | ||
1013 | cfg80211_unlock_rdev(rdev); | ||
1014 | 893 | ||
1015 | /* | 894 | /* |
1016 | * Configure power management to the driver here so that its | 895 | * Configure power management to the driver here so that its |
@@ -1027,12 +906,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1027 | break; | 906 | break; |
1028 | case NETDEV_UNREGISTER: | 907 | case NETDEV_UNREGISTER: |
1029 | /* | 908 | /* |
1030 | * NB: cannot take rdev->mtx here because this may be | ||
1031 | * called within code protected by it when interfaces | ||
1032 | * are removed with nl80211. | ||
1033 | */ | ||
1034 | mutex_lock(&rdev->devlist_mtx); | ||
1035 | /* | ||
1036 | * It is possible to get NETDEV_UNREGISTER | 909 | * It is possible to get NETDEV_UNREGISTER |
1037 | * multiple times. To detect that, check | 910 | * multiple times. To detect that, check |
1038 | * that the interface is still on the list | 911 | * that the interface is still on the list |
@@ -1048,7 +921,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1048 | kfree(wdev->wext.keys); | 921 | kfree(wdev->wext.keys); |
1049 | #endif | 922 | #endif |
1050 | } | 923 | } |
1051 | mutex_unlock(&rdev->devlist_mtx); | ||
1052 | /* | 924 | /* |
1053 | * synchronise (so that we won't find this netdev | 925 | * synchronise (so that we won't find this netdev |
1054 | * from other code any more) and then clear the list | 926 | * from other code any more) and then clear the list |
@@ -1068,9 +940,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1068 | return notifier_from_errno(-EOPNOTSUPP); | 940 | return notifier_from_errno(-EOPNOTSUPP); |
1069 | if (rfkill_blocked(rdev->rfkill)) | 941 | if (rfkill_blocked(rdev->rfkill)) |
1070 | return notifier_from_errno(-ERFKILL); | 942 | return notifier_from_errno(-ERFKILL); |
1071 | mutex_lock(&rdev->devlist_mtx); | ||
1072 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 943 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
1073 | mutex_unlock(&rdev->devlist_mtx); | ||
1074 | if (ret) | 944 | if (ret) |
1075 | return notifier_from_errno(ret); | 945 | return notifier_from_errno(ret); |
1076 | break; | 946 | break; |
@@ -1088,12 +958,10 @@ static void __net_exit cfg80211_pernet_exit(struct net *net) | |||
1088 | struct cfg80211_registered_device *rdev; | 958 | struct cfg80211_registered_device *rdev; |
1089 | 959 | ||
1090 | rtnl_lock(); | 960 | rtnl_lock(); |
1091 | mutex_lock(&cfg80211_mutex); | ||
1092 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 961 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
1093 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 962 | if (net_eq(wiphy_net(&rdev->wiphy), net)) |
1094 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); | 963 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); |
1095 | } | 964 | } |
1096 | mutex_unlock(&cfg80211_mutex); | ||
1097 | rtnl_unlock(); | 965 | rtnl_unlock(); |
1098 | } | 966 | } |
1099 | 967 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index fd35dae547c4..a65eaf8a84c1 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -5,7 +5,6 @@ | |||
5 | */ | 5 | */ |
6 | #ifndef __NET_WIRELESS_CORE_H | 6 | #ifndef __NET_WIRELESS_CORE_H |
7 | #define __NET_WIRELESS_CORE_H | 7 | #define __NET_WIRELESS_CORE_H |
8 | #include <linux/mutex.h> | ||
9 | #include <linux/list.h> | 8 | #include <linux/list.h> |
10 | #include <linux/netdevice.h> | 9 | #include <linux/netdevice.h> |
11 | #include <linux/rbtree.h> | 10 | #include <linux/rbtree.h> |
@@ -23,11 +22,6 @@ | |||
23 | struct cfg80211_registered_device { | 22 | struct cfg80211_registered_device { |
24 | const struct cfg80211_ops *ops; | 23 | const struct cfg80211_ops *ops; |
25 | struct list_head list; | 24 | struct list_head list; |
26 | /* we hold this mutex during any call so that | ||
27 | * we cannot do multiple calls at once, and also | ||
28 | * to avoid the deregister call to proceed while | ||
29 | * any call is in progress */ | ||
30 | struct mutex mtx; | ||
31 | 25 | ||
32 | /* rfkill support */ | 26 | /* rfkill support */ |
33 | struct rfkill_ops rfkill_ops; | 27 | struct rfkill_ops rfkill_ops; |
@@ -49,9 +43,7 @@ struct cfg80211_registered_device { | |||
49 | /* wiphy index, internal only */ | 43 | /* wiphy index, internal only */ |
50 | int wiphy_idx; | 44 | int wiphy_idx; |
51 | 45 | ||
52 | /* associated wireless interfaces */ | 46 | /* associated wireless interfaces, protected by rtnl or RCU */ |
53 | struct mutex devlist_mtx; | ||
54 | /* protected by devlist_mtx or RCU */ | ||
55 | struct list_head wdev_list; | 47 | struct list_head wdev_list; |
56 | int devlist_generation, wdev_id; | 48 | int devlist_generation, wdev_id; |
57 | int opencount; /* also protected by devlist_mtx */ | 49 | int opencount; /* also protected by devlist_mtx */ |
@@ -75,8 +67,6 @@ struct cfg80211_registered_device { | |||
75 | struct work_struct scan_done_wk; | 67 | struct work_struct scan_done_wk; |
76 | struct work_struct sched_scan_results_wk; | 68 | struct work_struct sched_scan_results_wk; |
77 | 69 | ||
78 | struct mutex sched_scan_mtx; | ||
79 | |||
80 | #ifdef CONFIG_NL80211_TESTMODE | 70 | #ifdef CONFIG_NL80211_TESTMODE |
81 | struct genl_info *testmode_info; | 71 | struct genl_info *testmode_info; |
82 | #endif | 72 | #endif |
@@ -84,8 +74,6 @@ struct cfg80211_registered_device { | |||
84 | struct work_struct conn_work; | 74 | struct work_struct conn_work; |
85 | struct work_struct event_work; | 75 | struct work_struct event_work; |
86 | 76 | ||
87 | struct cfg80211_wowlan *wowlan; | ||
88 | |||
89 | struct delayed_work dfs_update_channels_wk; | 77 | struct delayed_work dfs_update_channels_wk; |
90 | 78 | ||
91 | /* netlink port which started critical protocol (0 means not started) */ | 79 | /* netlink port which started critical protocol (0 means not started) */ |
@@ -106,29 +94,26 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | |||
106 | static inline void | 94 | static inline void |
107 | cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) | 95 | cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev) |
108 | { | 96 | { |
97 | #ifdef CONFIG_PM | ||
109 | int i; | 98 | int i; |
110 | 99 | ||
111 | if (!rdev->wowlan) | 100 | if (!rdev->wiphy.wowlan_config) |
112 | return; | 101 | return; |
113 | for (i = 0; i < rdev->wowlan->n_patterns; i++) | 102 | for (i = 0; i < rdev->wiphy.wowlan_config->n_patterns; i++) |
114 | kfree(rdev->wowlan->patterns[i].mask); | 103 | kfree(rdev->wiphy.wowlan_config->patterns[i].mask); |
115 | kfree(rdev->wowlan->patterns); | 104 | kfree(rdev->wiphy.wowlan_config->patterns); |
116 | if (rdev->wowlan->tcp && rdev->wowlan->tcp->sock) | 105 | if (rdev->wiphy.wowlan_config->tcp && |
117 | sock_release(rdev->wowlan->tcp->sock); | 106 | rdev->wiphy.wowlan_config->tcp->sock) |
118 | kfree(rdev->wowlan->tcp); | 107 | sock_release(rdev->wiphy.wowlan_config->tcp->sock); |
119 | kfree(rdev->wowlan); | 108 | kfree(rdev->wiphy.wowlan_config->tcp); |
109 | kfree(rdev->wiphy.wowlan_config); | ||
110 | #endif | ||
120 | } | 111 | } |
121 | 112 | ||
122 | extern struct workqueue_struct *cfg80211_wq; | 113 | extern struct workqueue_struct *cfg80211_wq; |
123 | extern struct mutex cfg80211_mutex; | ||
124 | extern struct list_head cfg80211_rdev_list; | 114 | extern struct list_head cfg80211_rdev_list; |
125 | extern int cfg80211_rdev_list_generation; | 115 | extern int cfg80211_rdev_list_generation; |
126 | 116 | ||
127 | static inline void assert_cfg80211_lock(void) | ||
128 | { | ||
129 | lockdep_assert_held(&cfg80211_mutex); | ||
130 | } | ||
131 | |||
132 | struct cfg80211_internal_bss { | 117 | struct cfg80211_internal_bss { |
133 | struct list_head list; | 118 | struct list_head list; |
134 | struct list_head hidden_list; | 119 | struct list_head hidden_list; |
@@ -161,27 +146,11 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | |||
161 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); | 146 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); |
162 | int get_wiphy_idx(struct wiphy *wiphy); | 147 | int get_wiphy_idx(struct wiphy *wiphy); |
163 | 148 | ||
164 | /* requires cfg80211_rdev_mutex to be held! */ | ||
165 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | 149 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); |
166 | 150 | ||
167 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ | ||
168 | extern struct cfg80211_registered_device * | ||
169 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex); | ||
170 | |||
171 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, | 151 | int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, |
172 | struct net *net); | 152 | struct net *net); |
173 | 153 | ||
174 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *rdev) | ||
175 | { | ||
176 | mutex_lock(&rdev->mtx); | ||
177 | } | ||
178 | |||
179 | static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *rdev) | ||
180 | { | ||
181 | BUG_ON(IS_ERR(rdev) || !rdev); | ||
182 | mutex_unlock(&rdev->mtx); | ||
183 | } | ||
184 | |||
185 | static inline void wdev_lock(struct wireless_dev *wdev) | 154 | static inline void wdev_lock(struct wireless_dev *wdev) |
186 | __acquires(wdev) | 155 | __acquires(wdev) |
187 | { | 156 | { |
@@ -196,7 +165,7 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
196 | mutex_unlock(&wdev->mtx); | 165 | mutex_unlock(&wdev->mtx); |
197 | } | 166 | } |
198 | 167 | ||
199 | #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) | 168 | #define ASSERT_RDEV_LOCK(rdev) ASSERT_RTNL() |
200 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | 169 | #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) |
201 | 170 | ||
202 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) | 171 | static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) |
@@ -314,38 +283,21 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
314 | struct net_device *dev); | 283 | struct net_device *dev); |
315 | 284 | ||
316 | /* MLME */ | 285 | /* MLME */ |
317 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | ||
318 | struct net_device *dev, | ||
319 | struct ieee80211_channel *chan, | ||
320 | enum nl80211_auth_type auth_type, | ||
321 | const u8 *bssid, | ||
322 | const u8 *ssid, int ssid_len, | ||
323 | const u8 *ie, int ie_len, | ||
324 | const u8 *key, int key_len, int key_idx, | ||
325 | const u8 *sae_data, int sae_data_len); | ||
326 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 286 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
327 | struct net_device *dev, struct ieee80211_channel *chan, | 287 | struct net_device *dev, |
328 | enum nl80211_auth_type auth_type, const u8 *bssid, | 288 | struct ieee80211_channel *chan, |
289 | enum nl80211_auth_type auth_type, | ||
290 | const u8 *bssid, | ||
329 | const u8 *ssid, int ssid_len, | 291 | const u8 *ssid, int ssid_len, |
330 | const u8 *ie, int ie_len, | 292 | const u8 *ie, int ie_len, |
331 | const u8 *key, int key_len, int key_idx, | 293 | const u8 *key, int key_len, int key_idx, |
332 | const u8 *sae_data, int sae_data_len); | 294 | const u8 *sae_data, int sae_data_len); |
333 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | ||
334 | struct net_device *dev, | ||
335 | struct ieee80211_channel *chan, | ||
336 | const u8 *bssid, | ||
337 | const u8 *ssid, int ssid_len, | ||
338 | struct cfg80211_assoc_request *req); | ||
339 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 295 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, | 296 | struct net_device *dev, |
341 | struct ieee80211_channel *chan, | 297 | struct ieee80211_channel *chan, |
342 | const u8 *bssid, | 298 | const u8 *bssid, |
343 | const u8 *ssid, int ssid_len, | 299 | const u8 *ssid, int ssid_len, |
344 | struct cfg80211_assoc_request *req); | 300 | struct cfg80211_assoc_request *req); |
345 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
346 | struct net_device *dev, const u8 *bssid, | ||
347 | const u8 *ie, int ie_len, u16 reason, | ||
348 | bool local_state_change); | ||
349 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 301 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
350 | struct net_device *dev, const u8 *bssid, | 302 | struct net_device *dev, const u8 *bssid, |
351 | const u8 *ie, int ie_len, u16 reason, | 303 | const u8 *ie, int ie_len, u16 reason, |
@@ -377,18 +329,11 @@ void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | |||
377 | const struct ieee80211_vht_cap *vht_capa_mask); | 329 | const struct ieee80211_vht_cap *vht_capa_mask); |
378 | 330 | ||
379 | /* SME */ | 331 | /* SME */ |
380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | ||
381 | struct net_device *dev, | ||
382 | struct cfg80211_connect_params *connect, | ||
383 | struct cfg80211_cached_keys *connkeys, | ||
384 | const u8 *prev_bssid); | ||
385 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 332 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
386 | struct net_device *dev, | 333 | struct net_device *dev, |
387 | struct cfg80211_connect_params *connect, | 334 | struct cfg80211_connect_params *connect, |
388 | struct cfg80211_cached_keys *connkeys); | 335 | struct cfg80211_cached_keys *connkeys, |
389 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 336 | const u8 *prev_bssid); |
390 | struct net_device *dev, u16 reason, | ||
391 | bool wextev); | ||
392 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 337 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
393 | struct net_device *dev, u16 reason, | 338 | struct net_device *dev, u16 reason, |
394 | bool wextev); | 339 | bool wextev); |
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 920cabe0461b..90d050036624 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c | |||
@@ -74,7 +74,7 @@ static ssize_t ht40allow_map_read(struct file *file, | |||
74 | if (!buf) | 74 | if (!buf) |
75 | return -ENOMEM; | 75 | return -ENOMEM; |
76 | 76 | ||
77 | mutex_lock(&cfg80211_mutex); | 77 | rtnl_lock(); |
78 | 78 | ||
79 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 79 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
80 | sband = wiphy->bands[band]; | 80 | sband = wiphy->bands[band]; |
@@ -85,7 +85,7 @@ static ssize_t ht40allow_map_read(struct file *file, | |||
85 | buf, buf_size, offset); | 85 | buf, buf_size, offset); |
86 | } | 86 | } |
87 | 87 | ||
88 | mutex_unlock(&cfg80211_mutex); | 88 | rtnl_unlock(); |
89 | 89 | ||
90 | r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); | 90 | r = simple_read_from_buffer(user_buf, count, ppos, buf, offset); |
91 | 91 | ||
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index d80e47194d49..5449c5a6de84 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
@@ -152,11 +152,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | |||
152 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 152 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
153 | int err; | 153 | int err; |
154 | 154 | ||
155 | mutex_lock(&rdev->devlist_mtx); | 155 | ASSERT_RTNL(); |
156 | |||
156 | wdev_lock(wdev); | 157 | wdev_lock(wdev); |
157 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); | 158 | err = __cfg80211_join_ibss(rdev, dev, params, connkeys); |
158 | wdev_unlock(wdev); | 159 | wdev_unlock(wdev); |
159 | mutex_unlock(&rdev->devlist_mtx); | ||
160 | 160 | ||
161 | return err; | 161 | return err; |
162 | } | 162 | } |
@@ -359,11 +359,9 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | |||
359 | wdev->wext.ibss.channel_fixed = false; | 359 | wdev->wext.ibss.channel_fixed = false; |
360 | } | 360 | } |
361 | 361 | ||
362 | mutex_lock(&rdev->devlist_mtx); | ||
363 | wdev_lock(wdev); | 362 | wdev_lock(wdev); |
364 | err = cfg80211_ibss_wext_join(rdev, wdev); | 363 | err = cfg80211_ibss_wext_join(rdev, wdev); |
365 | wdev_unlock(wdev); | 364 | wdev_unlock(wdev); |
366 | mutex_unlock(&rdev->devlist_mtx); | ||
367 | 365 | ||
368 | return err; | 366 | return err; |
369 | } | 367 | } |
@@ -429,11 +427,9 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev, | |||
429 | memcpy(wdev->wext.ibss.ssid, ssid, len); | 427 | memcpy(wdev->wext.ibss.ssid, ssid, len); |
430 | wdev->wext.ibss.ssid_len = len; | 428 | wdev->wext.ibss.ssid_len = len; |
431 | 429 | ||
432 | mutex_lock(&rdev->devlist_mtx); | ||
433 | wdev_lock(wdev); | 430 | wdev_lock(wdev); |
434 | err = cfg80211_ibss_wext_join(rdev, wdev); | 431 | err = cfg80211_ibss_wext_join(rdev, wdev); |
435 | wdev_unlock(wdev); | 432 | wdev_unlock(wdev); |
436 | mutex_unlock(&rdev->devlist_mtx); | ||
437 | 433 | ||
438 | return err; | 434 | return err; |
439 | } | 435 | } |
@@ -512,11 +508,9 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev, | |||
512 | } else | 508 | } else |
513 | wdev->wext.ibss.bssid = NULL; | 509 | wdev->wext.ibss.bssid = NULL; |
514 | 510 | ||
515 | mutex_lock(&rdev->devlist_mtx); | ||
516 | wdev_lock(wdev); | 511 | wdev_lock(wdev); |
517 | err = cfg80211_ibss_wext_join(rdev, wdev); | 512 | err = cfg80211_ibss_wext_join(rdev, wdev); |
518 | wdev_unlock(wdev); | 513 | wdev_unlock(wdev); |
519 | mutex_unlock(&rdev->devlist_mtx); | ||
520 | 514 | ||
521 | return err; | 515 | return err; |
522 | } | 516 | } |
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0bb93f3061a4..5dfb289ab761 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c | |||
@@ -82,6 +82,7 @@ const struct mesh_setup default_mesh_setup = { | |||
82 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | 82 | .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, |
83 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, | 83 | .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, |
84 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, | 84 | .path_metric = IEEE80211_PATH_METRIC_AIRTIME, |
85 | .auth_id = 0, /* open */ | ||
85 | .ie = NULL, | 86 | .ie = NULL, |
86 | .ie_len = 0, | 87 | .ie_len = 0, |
87 | .is_secure = false, | 88 | .is_secure = false, |
@@ -185,11 +186,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, | |||
185 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 186 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
186 | int err; | 187 | int err; |
187 | 188 | ||
188 | mutex_lock(&rdev->devlist_mtx); | ||
189 | wdev_lock(wdev); | 189 | wdev_lock(wdev); |
190 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); | 190 | err = __cfg80211_join_mesh(rdev, dev, setup, conf); |
191 | wdev_unlock(wdev); | 191 | wdev_unlock(wdev); |
192 | mutex_unlock(&rdev->devlist_mtx); | ||
193 | 192 | ||
194 | return err; | 193 | return err; |
195 | } | 194 | } |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 0c7b7dd855f6..7bde5d9c0003 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -25,12 +25,9 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
25 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 25 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
26 | 26 | ||
27 | trace_cfg80211_send_rx_auth(dev); | 27 | trace_cfg80211_send_rx_auth(dev); |
28 | wdev_lock(wdev); | ||
29 | 28 | ||
30 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | 29 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); |
31 | cfg80211_sme_rx_auth(dev, buf, len); | 30 | cfg80211_sme_rx_auth(dev, buf, len); |
32 | |||
33 | wdev_unlock(wdev); | ||
34 | } | 31 | } |
35 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | 32 | EXPORT_SYMBOL(cfg80211_send_rx_auth); |
36 | 33 | ||
@@ -46,7 +43,6 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
46 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 43 | int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
47 | 44 | ||
48 | trace_cfg80211_send_rx_assoc(dev, bss); | 45 | trace_cfg80211_send_rx_assoc(dev, bss); |
49 | wdev_lock(wdev); | ||
50 | 46 | ||
51 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 47 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
52 | 48 | ||
@@ -59,7 +55,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
59 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && | 55 | if (status_code != WLAN_STATUS_SUCCESS && wdev->conn && |
60 | cfg80211_sme_failed_reassoc(wdev)) { | 56 | cfg80211_sme_failed_reassoc(wdev)) { |
61 | cfg80211_put_bss(wiphy, bss); | 57 | cfg80211_put_bss(wiphy, bss); |
62 | goto out; | 58 | return; |
63 | } | 59 | } |
64 | 60 | ||
65 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 61 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
@@ -71,7 +67,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
71 | * sme will schedule work that does it later. | 67 | * sme will schedule work that does it later. |
72 | */ | 68 | */ |
73 | cfg80211_put_bss(wiphy, bss); | 69 | cfg80211_put_bss(wiphy, bss); |
74 | goto out; | 70 | return; |
75 | } | 71 | } |
76 | 72 | ||
77 | if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { | 73 | if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { |
@@ -87,13 +83,11 @@ void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss, | |||
87 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 83 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
88 | status_code, | 84 | status_code, |
89 | status_code == WLAN_STATUS_SUCCESS, bss); | 85 | status_code == WLAN_STATUS_SUCCESS, bss); |
90 | out: | ||
91 | wdev_unlock(wdev); | ||
92 | } | 86 | } |
93 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 87 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
94 | 88 | ||
95 | void __cfg80211_send_deauth(struct net_device *dev, | 89 | void cfg80211_send_deauth(struct net_device *dev, |
96 | const u8 *buf, size_t len) | 90 | const u8 *buf, size_t len) |
97 | { | 91 | { |
98 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 92 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
99 | struct wiphy *wiphy = wdev->wiphy; | 93 | struct wiphy *wiphy = wdev->wiphy; |
@@ -102,7 +96,7 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
102 | const u8 *bssid = mgmt->bssid; | 96 | const u8 *bssid = mgmt->bssid; |
103 | bool was_current = false; | 97 | bool was_current = false; |
104 | 98 | ||
105 | trace___cfg80211_send_deauth(dev); | 99 | trace_cfg80211_send_deauth(dev); |
106 | ASSERT_WDEV_LOCK(wdev); | 100 | ASSERT_WDEV_LOCK(wdev); |
107 | 101 | ||
108 | if (wdev->current_bss && | 102 | if (wdev->current_bss && |
@@ -129,20 +123,10 @@ void __cfg80211_send_deauth(struct net_device *dev, | |||
129 | false, NULL); | 123 | false, NULL); |
130 | } | 124 | } |
131 | } | 125 | } |
132 | EXPORT_SYMBOL(__cfg80211_send_deauth); | ||
133 | |||
134 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) | ||
135 | { | ||
136 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
137 | |||
138 | wdev_lock(wdev); | ||
139 | __cfg80211_send_deauth(dev, buf, len); | ||
140 | wdev_unlock(wdev); | ||
141 | } | ||
142 | EXPORT_SYMBOL(cfg80211_send_deauth); | 126 | EXPORT_SYMBOL(cfg80211_send_deauth); |
143 | 127 | ||
144 | void __cfg80211_send_disassoc(struct net_device *dev, | 128 | void cfg80211_send_disassoc(struct net_device *dev, |
145 | const u8 *buf, size_t len) | 129 | const u8 *buf, size_t len) |
146 | { | 130 | { |
147 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 131 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
148 | struct wiphy *wiphy = wdev->wiphy; | 132 | struct wiphy *wiphy = wdev->wiphy; |
@@ -152,7 +136,7 @@ void __cfg80211_send_disassoc(struct net_device *dev, | |||
152 | u16 reason_code; | 136 | u16 reason_code; |
153 | bool from_ap; | 137 | bool from_ap; |
154 | 138 | ||
155 | trace___cfg80211_send_disassoc(dev); | 139 | trace_cfg80211_send_disassoc(dev); |
156 | ASSERT_WDEV_LOCK(wdev); | 140 | ASSERT_WDEV_LOCK(wdev); |
157 | 141 | ||
158 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); | 142 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); |
@@ -175,16 +159,6 @@ void __cfg80211_send_disassoc(struct net_device *dev, | |||
175 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); | 159 | from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr); |
176 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); | 160 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
177 | } | 161 | } |
178 | EXPORT_SYMBOL(__cfg80211_send_disassoc); | ||
179 | |||
180 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | ||
181 | { | ||
182 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
183 | |||
184 | wdev_lock(wdev); | ||
185 | __cfg80211_send_disassoc(dev, buf, len); | ||
186 | wdev_unlock(wdev); | ||
187 | } | ||
188 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 162 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
189 | 163 | ||
190 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | 164 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) |
@@ -194,15 +168,12 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
194 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 168 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
195 | 169 | ||
196 | trace_cfg80211_send_auth_timeout(dev, addr); | 170 | trace_cfg80211_send_auth_timeout(dev, addr); |
197 | wdev_lock(wdev); | ||
198 | 171 | ||
199 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | 172 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); |
200 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 173 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
201 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 174 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
202 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 175 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
203 | false, NULL); | 176 | false, NULL); |
204 | |||
205 | wdev_unlock(wdev); | ||
206 | } | 177 | } |
207 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | 178 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); |
208 | 179 | ||
@@ -213,15 +184,12 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
213 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 184 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
214 | 185 | ||
215 | trace_cfg80211_send_assoc_timeout(dev, addr); | 186 | trace_cfg80211_send_assoc_timeout(dev, addr); |
216 | wdev_lock(wdev); | ||
217 | 187 | ||
218 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); | 188 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); |
219 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 189 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
220 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 190 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
221 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 191 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
222 | false, NULL); | 192 | false, NULL); |
223 | |||
224 | wdev_unlock(wdev); | ||
225 | } | 193 | } |
226 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | 194 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); |
227 | 195 | ||
@@ -253,18 +221,27 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | |||
253 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); | 221 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); |
254 | 222 | ||
255 | /* some MLME handling for userspace SME */ | 223 | /* some MLME handling for userspace SME */ |
256 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 224 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
257 | struct net_device *dev, | 225 | struct net_device *dev, |
258 | struct ieee80211_channel *chan, | 226 | struct ieee80211_channel *chan, |
259 | enum nl80211_auth_type auth_type, | 227 | enum nl80211_auth_type auth_type, |
260 | const u8 *bssid, | 228 | const u8 *bssid, |
261 | const u8 *ssid, int ssid_len, | 229 | const u8 *ssid, int ssid_len, |
262 | const u8 *ie, int ie_len, | 230 | const u8 *ie, int ie_len, |
263 | const u8 *key, int key_len, int key_idx, | 231 | const u8 *key, int key_len, int key_idx, |
264 | const u8 *sae_data, int sae_data_len) | 232 | const u8 *sae_data, int sae_data_len) |
265 | { | 233 | { |
266 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 234 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
267 | struct cfg80211_auth_request req; | 235 | struct cfg80211_auth_request req = { |
236 | .ie = ie, | ||
237 | .ie_len = ie_len, | ||
238 | .sae_data = sae_data, | ||
239 | .sae_data_len = sae_data_len, | ||
240 | .auth_type = auth_type, | ||
241 | .key = key, | ||
242 | .key_len = key_len, | ||
243 | .key_idx = key_idx, | ||
244 | }; | ||
268 | int err; | 245 | int err; |
269 | 246 | ||
270 | ASSERT_WDEV_LOCK(wdev); | 247 | ASSERT_WDEV_LOCK(wdev); |
@@ -277,18 +254,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
277 | ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) | 254 | ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) |
278 | return -EALREADY; | 255 | return -EALREADY; |
279 | 256 | ||
280 | memset(&req, 0, sizeof(req)); | ||
281 | |||
282 | req.ie = ie; | ||
283 | req.ie_len = ie_len; | ||
284 | req.sae_data = sae_data; | ||
285 | req.sae_data_len = sae_data_len; | ||
286 | req.auth_type = auth_type; | ||
287 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 257 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
288 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 258 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
289 | req.key = key; | ||
290 | req.key_len = key_len; | ||
291 | req.key_idx = key_idx; | ||
292 | if (!req.bss) | 259 | if (!req.bss) |
293 | return -ENOENT; | 260 | return -ENOENT; |
294 | 261 | ||
@@ -304,28 +271,6 @@ out: | |||
304 | return err; | 271 | return err; |
305 | } | 272 | } |
306 | 273 | ||
307 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | ||
308 | struct net_device *dev, struct ieee80211_channel *chan, | ||
309 | enum nl80211_auth_type auth_type, const u8 *bssid, | ||
310 | const u8 *ssid, int ssid_len, | ||
311 | const u8 *ie, int ie_len, | ||
312 | const u8 *key, int key_len, int key_idx, | ||
313 | const u8 *sae_data, int sae_data_len) | ||
314 | { | ||
315 | int err; | ||
316 | |||
317 | mutex_lock(&rdev->devlist_mtx); | ||
318 | wdev_lock(dev->ieee80211_ptr); | ||
319 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | ||
320 | ssid, ssid_len, ie, ie_len, | ||
321 | key, key_len, key_idx, | ||
322 | sae_data, sae_data_len); | ||
323 | wdev_unlock(dev->ieee80211_ptr); | ||
324 | mutex_unlock(&rdev->devlist_mtx); | ||
325 | |||
326 | return err; | ||
327 | } | ||
328 | |||
329 | /* Do a logical ht_capa &= ht_capa_mask. */ | 274 | /* Do a logical ht_capa &= ht_capa_mask. */ |
330 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 275 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
331 | const struct ieee80211_ht_cap *ht_capa_mask) | 276 | const struct ieee80211_ht_cap *ht_capa_mask) |
@@ -360,12 +305,12 @@ void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | |||
360 | p1[i] &= p2[i]; | 305 | p1[i] &= p2[i]; |
361 | } | 306 | } |
362 | 307 | ||
363 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 308 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
364 | struct net_device *dev, | 309 | struct net_device *dev, |
365 | struct ieee80211_channel *chan, | 310 | struct ieee80211_channel *chan, |
366 | const u8 *bssid, | 311 | const u8 *bssid, |
367 | const u8 *ssid, int ssid_len, | 312 | const u8 *ssid, int ssid_len, |
368 | struct cfg80211_assoc_request *req) | 313 | struct cfg80211_assoc_request *req) |
369 | { | 314 | { |
370 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 315 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
371 | int err; | 316 | int err; |
@@ -415,30 +360,10 @@ out: | |||
415 | return err; | 360 | return err; |
416 | } | 361 | } |
417 | 362 | ||
418 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 363 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
419 | struct net_device *dev, | 364 | struct net_device *dev, const u8 *bssid, |
420 | struct ieee80211_channel *chan, | 365 | const u8 *ie, int ie_len, u16 reason, |
421 | const u8 *bssid, | 366 | bool local_state_change) |
422 | const u8 *ssid, int ssid_len, | ||
423 | struct cfg80211_assoc_request *req) | ||
424 | { | ||
425 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
426 | int err; | ||
427 | |||
428 | mutex_lock(&rdev->devlist_mtx); | ||
429 | wdev_lock(wdev); | ||
430 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, | ||
431 | ssid, ssid_len, req); | ||
432 | wdev_unlock(wdev); | ||
433 | mutex_unlock(&rdev->devlist_mtx); | ||
434 | |||
435 | return err; | ||
436 | } | ||
437 | |||
438 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
439 | struct net_device *dev, const u8 *bssid, | ||
440 | const u8 *ie, int ie_len, u16 reason, | ||
441 | bool local_state_change) | ||
442 | { | 367 | { |
443 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 368 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
444 | struct cfg80211_deauth_request req = { | 369 | struct cfg80211_deauth_request req = { |
@@ -458,29 +383,18 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | |||
458 | return rdev_deauth(rdev, dev, &req); | 383 | return rdev_deauth(rdev, dev, &req); |
459 | } | 384 | } |
460 | 385 | ||
461 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 386 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, |
462 | struct net_device *dev, const u8 *bssid, | 387 | struct net_device *dev, const u8 *bssid, |
463 | const u8 *ie, int ie_len, u16 reason, | 388 | const u8 *ie, int ie_len, u16 reason, |
464 | bool local_state_change) | 389 | bool local_state_change) |
465 | { | ||
466 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
467 | int err; | ||
468 | |||
469 | wdev_lock(wdev); | ||
470 | err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason, | ||
471 | local_state_change); | ||
472 | wdev_unlock(wdev); | ||
473 | |||
474 | return err; | ||
475 | } | ||
476 | |||
477 | static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
478 | struct net_device *dev, const u8 *bssid, | ||
479 | const u8 *ie, int ie_len, u16 reason, | ||
480 | bool local_state_change) | ||
481 | { | 390 | { |
482 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 391 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
483 | struct cfg80211_disassoc_request req; | 392 | struct cfg80211_disassoc_request req = { |
393 | .reason_code = reason, | ||
394 | .local_state_change = local_state_change, | ||
395 | .ie = ie, | ||
396 | .ie_len = ie_len, | ||
397 | }; | ||
484 | 398 | ||
485 | ASSERT_WDEV_LOCK(wdev); | 399 | ASSERT_WDEV_LOCK(wdev); |
486 | 400 | ||
@@ -490,11 +404,6 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
490 | if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state)) | 404 | if (WARN(!wdev->current_bss, "sme_state=%d\n", wdev->sme_state)) |
491 | return -ENOTCONN; | 405 | return -ENOTCONN; |
492 | 406 | ||
493 | memset(&req, 0, sizeof(req)); | ||
494 | req.reason_code = reason; | ||
495 | req.local_state_change = local_state_change; | ||
496 | req.ie = ie; | ||
497 | req.ie_len = ie_len; | ||
498 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) | 407 | if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) |
499 | req.bss = &wdev->current_bss->pub; | 408 | req.bss = &wdev->current_bss->pub; |
500 | else | 409 | else |
@@ -503,44 +412,25 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
503 | return rdev_disassoc(rdev, dev, &req); | 412 | return rdev_disassoc(rdev, dev, &req); |
504 | } | 413 | } |
505 | 414 | ||
506 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
507 | struct net_device *dev, const u8 *bssid, | ||
508 | const u8 *ie, int ie_len, u16 reason, | ||
509 | bool local_state_change) | ||
510 | { | ||
511 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
512 | int err; | ||
513 | |||
514 | wdev_lock(wdev); | ||
515 | err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason, | ||
516 | local_state_change); | ||
517 | wdev_unlock(wdev); | ||
518 | |||
519 | return err; | ||
520 | } | ||
521 | |||
522 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 415 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
523 | struct net_device *dev) | 416 | struct net_device *dev) |
524 | { | 417 | { |
525 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 418 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
526 | struct cfg80211_deauth_request req; | ||
527 | u8 bssid[ETH_ALEN]; | 419 | u8 bssid[ETH_ALEN]; |
420 | struct cfg80211_deauth_request req = { | ||
421 | .reason_code = WLAN_REASON_DEAUTH_LEAVING, | ||
422 | .bssid = bssid, | ||
423 | }; | ||
528 | 424 | ||
529 | ASSERT_WDEV_LOCK(wdev); | 425 | ASSERT_WDEV_LOCK(wdev); |
530 | 426 | ||
531 | if (!rdev->ops->deauth) | 427 | if (!rdev->ops->deauth) |
532 | return; | 428 | return; |
533 | 429 | ||
534 | memset(&req, 0, sizeof(req)); | ||
535 | req.reason_code = WLAN_REASON_DEAUTH_LEAVING; | ||
536 | req.ie = NULL; | ||
537 | req.ie_len = 0; | ||
538 | |||
539 | if (!wdev->current_bss) | 430 | if (!wdev->current_bss) |
540 | return; | 431 | return; |
541 | 432 | ||
542 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); | 433 | memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); |
543 | req.bssid = bssid; | ||
544 | rdev_deauth(rdev, dev, &req); | 434 | rdev_deauth(rdev, dev, &req); |
545 | 435 | ||
546 | if (wdev->current_bss) { | 436 | if (wdev->current_bss) { |
@@ -848,7 +738,7 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) | |||
848 | dfs_update_channels_wk); | 738 | dfs_update_channels_wk); |
849 | wiphy = &rdev->wiphy; | 739 | wiphy = &rdev->wiphy; |
850 | 740 | ||
851 | mutex_lock(&cfg80211_mutex); | 741 | rtnl_lock(); |
852 | for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) { | 742 | for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) { |
853 | sband = wiphy->bands[bandid]; | 743 | sband = wiphy->bands[bandid]; |
854 | if (!sband) | 744 | if (!sband) |
@@ -881,7 +771,7 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) | |||
881 | check_again = true; | 771 | check_again = true; |
882 | } | 772 | } |
883 | } | 773 | } |
884 | mutex_unlock(&cfg80211_mutex); | 774 | rtnl_unlock(); |
885 | 775 | ||
886 | /* reschedule if there are other channels waiting to be cleared again */ | 776 | /* reschedule if there are other channels waiting to be cleared again */ |
887 | if (check_again) | 777 | if (check_again) |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d5aed3bb3945..31d265f36d2c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -37,10 +37,10 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
37 | 37 | ||
38 | /* the netlink family */ | 38 | /* the netlink family */ |
39 | static struct genl_family nl80211_fam = { | 39 | static struct genl_family nl80211_fam = { |
40 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ | 40 | .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ |
41 | .name = "nl80211", /* have users key off the name instead */ | 41 | .name = NL80211_GENL_NAME, /* have users key off the name instead */ |
42 | .hdrsize = 0, /* no private header */ | 42 | .hdrsize = 0, /* no private header */ |
43 | .version = 1, /* no particular meaning now */ | 43 | .version = 1, /* no particular meaning now */ |
44 | .maxattr = NL80211_ATTR_MAX, | 44 | .maxattr = NL80211_ATTR_MAX, |
45 | .netnsok = true, | 45 | .netnsok = true, |
46 | .pre_doit = nl80211_pre_doit, | 46 | .pre_doit = nl80211_pre_doit, |
@@ -59,7 +59,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
59 | int wiphy_idx = -1; | 59 | int wiphy_idx = -1; |
60 | int ifidx = -1; | 60 | int ifidx = -1; |
61 | 61 | ||
62 | assert_cfg80211_lock(); | 62 | ASSERT_RTNL(); |
63 | 63 | ||
64 | if (!have_ifidx && !have_wdev_id) | 64 | if (!have_ifidx && !have_wdev_id) |
65 | return ERR_PTR(-EINVAL); | 65 | return ERR_PTR(-EINVAL); |
@@ -80,7 +80,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
80 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) | 80 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) |
81 | continue; | 81 | continue; |
82 | 82 | ||
83 | mutex_lock(&rdev->devlist_mtx); | ||
84 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 83 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
85 | if (have_ifidx && wdev->netdev && | 84 | if (have_ifidx && wdev->netdev && |
86 | wdev->netdev->ifindex == ifidx) { | 85 | wdev->netdev->ifindex == ifidx) { |
@@ -92,7 +91,6 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
92 | break; | 91 | break; |
93 | } | 92 | } |
94 | } | 93 | } |
95 | mutex_unlock(&rdev->devlist_mtx); | ||
96 | 94 | ||
97 | if (result) | 95 | if (result) |
98 | break; | 96 | break; |
@@ -109,7 +107,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
109 | struct cfg80211_registered_device *rdev = NULL, *tmp; | 107 | struct cfg80211_registered_device *rdev = NULL, *tmp; |
110 | struct net_device *netdev; | 108 | struct net_device *netdev; |
111 | 109 | ||
112 | assert_cfg80211_lock(); | 110 | ASSERT_RTNL(); |
113 | 111 | ||
114 | if (!attrs[NL80211_ATTR_WIPHY] && | 112 | if (!attrs[NL80211_ATTR_WIPHY] && |
115 | !attrs[NL80211_ATTR_IFINDEX] && | 113 | !attrs[NL80211_ATTR_IFINDEX] && |
@@ -128,14 +126,12 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
128 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); | 126 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); |
129 | if (tmp) { | 127 | if (tmp) { |
130 | /* make sure wdev exists */ | 128 | /* make sure wdev exists */ |
131 | mutex_lock(&tmp->devlist_mtx); | ||
132 | list_for_each_entry(wdev, &tmp->wdev_list, list) { | 129 | list_for_each_entry(wdev, &tmp->wdev_list, list) { |
133 | if (wdev->identifier != (u32)wdev_id) | 130 | if (wdev->identifier != (u32)wdev_id) |
134 | continue; | 131 | continue; |
135 | found = true; | 132 | found = true; |
136 | break; | 133 | break; |
137 | } | 134 | } |
138 | mutex_unlock(&tmp->devlist_mtx); | ||
139 | 135 | ||
140 | if (!found) | 136 | if (!found) |
141 | tmp = NULL; | 137 | tmp = NULL; |
@@ -182,19 +178,6 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
182 | /* | 178 | /* |
183 | * This function returns a pointer to the driver | 179 | * This function returns a pointer to the driver |
184 | * that the genl_info item that is passed refers to. | 180 | * that the genl_info item that is passed refers to. |
185 | * If successful, it returns non-NULL and also locks | ||
186 | * the driver's mutex! | ||
187 | * | ||
188 | * This means that you need to call cfg80211_unlock_rdev() | ||
189 | * before being allowed to acquire &cfg80211_mutex! | ||
190 | * | ||
191 | * This is necessary because we need to lock the global | ||
192 | * mutex to get an item off the list safely, and then | ||
193 | * we lock the rdev mutex so it doesn't go away under us. | ||
194 | * | ||
195 | * We don't want to keep cfg80211_mutex locked | ||
196 | * for all the time in order to allow requests on | ||
197 | * other interfaces to go through at the same time. | ||
198 | * | 181 | * |
199 | * The result of this can be a PTR_ERR and hence must | 182 | * The result of this can be a PTR_ERR and hence must |
200 | * be checked with IS_ERR() for errors. | 183 | * be checked with IS_ERR() for errors. |
@@ -202,20 +185,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
202 | static struct cfg80211_registered_device * | 185 | static struct cfg80211_registered_device * |
203 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | 186 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) |
204 | { | 187 | { |
205 | struct cfg80211_registered_device *rdev; | 188 | return __cfg80211_rdev_from_attrs(netns, info->attrs); |
206 | |||
207 | mutex_lock(&cfg80211_mutex); | ||
208 | rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); | ||
209 | |||
210 | /* if it is not an error we grab the lock on | ||
211 | * it to assure it won't be going away while | ||
212 | * we operate on it */ | ||
213 | if (!IS_ERR(rdev)) | ||
214 | mutex_lock(&rdev->mtx); | ||
215 | |||
216 | mutex_unlock(&cfg80211_mutex); | ||
217 | |||
218 | return rdev; | ||
219 | } | 189 | } |
220 | 190 | ||
221 | /* policy for the attributes */ | 191 | /* policy for the attributes */ |
@@ -378,6 +348,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
378 | [NL80211_ATTR_MDID] = { .type = NLA_U16 }, | 348 | [NL80211_ATTR_MDID] = { .type = NLA_U16 }, |
379 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, | 349 | [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY, |
380 | .len = IEEE80211_MAX_DATA_LEN }, | 350 | .len = IEEE80211_MAX_DATA_LEN }, |
351 | [NL80211_ATTR_PEER_AID] = { .type = NLA_U16 }, | ||
381 | }; | 352 | }; |
382 | 353 | ||
383 | /* policy for the key attributes */ | 354 | /* policy for the key attributes */ |
@@ -455,7 +426,6 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
455 | int err; | 426 | int err; |
456 | 427 | ||
457 | rtnl_lock(); | 428 | rtnl_lock(); |
458 | mutex_lock(&cfg80211_mutex); | ||
459 | 429 | ||
460 | if (!cb->args[0]) { | 430 | if (!cb->args[0]) { |
461 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 431 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
@@ -484,14 +454,12 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
484 | *rdev = wiphy_to_dev(wiphy); | 454 | *rdev = wiphy_to_dev(wiphy); |
485 | *wdev = NULL; | 455 | *wdev = NULL; |
486 | 456 | ||
487 | mutex_lock(&(*rdev)->devlist_mtx); | ||
488 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { | 457 | list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { |
489 | if (tmp->identifier == cb->args[1]) { | 458 | if (tmp->identifier == cb->args[1]) { |
490 | *wdev = tmp; | 459 | *wdev = tmp; |
491 | break; | 460 | break; |
492 | } | 461 | } |
493 | } | 462 | } |
494 | mutex_unlock(&(*rdev)->devlist_mtx); | ||
495 | 463 | ||
496 | if (!*wdev) { | 464 | if (!*wdev) { |
497 | err = -ENODEV; | 465 | err = -ENODEV; |
@@ -499,19 +467,14 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, | |||
499 | } | 467 | } |
500 | } | 468 | } |
501 | 469 | ||
502 | cfg80211_lock_rdev(*rdev); | ||
503 | |||
504 | mutex_unlock(&cfg80211_mutex); | ||
505 | return 0; | 470 | return 0; |
506 | out_unlock: | 471 | out_unlock: |
507 | mutex_unlock(&cfg80211_mutex); | ||
508 | rtnl_unlock(); | 472 | rtnl_unlock(); |
509 | return err; | 473 | return err; |
510 | } | 474 | } |
511 | 475 | ||
512 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) | 476 | static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev) |
513 | { | 477 | { |
514 | cfg80211_unlock_rdev(rdev); | ||
515 | rtnl_unlock(); | 478 | rtnl_unlock(); |
516 | } | 479 | } |
517 | 480 | ||
@@ -1567,7 +1530,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1567 | struct nlattr **tb = nl80211_fam.attrbuf; | 1530 | struct nlattr **tb = nl80211_fam.attrbuf; |
1568 | int res; | 1531 | int res; |
1569 | 1532 | ||
1570 | mutex_lock(&cfg80211_mutex); | 1533 | rtnl_lock(); |
1571 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1534 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, |
1572 | tb, nl80211_fam.maxattr, nl80211_policy); | 1535 | tb, nl80211_fam.maxattr, nl80211_policy); |
1573 | if (res == 0) { | 1536 | if (res == 0) { |
@@ -1581,10 +1544,8 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1581 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); | 1544 | int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); |
1582 | 1545 | ||
1583 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); | 1546 | netdev = dev_get_by_index(sock_net(skb->sk), ifidx); |
1584 | if (!netdev) { | 1547 | if (!netdev) |
1585 | mutex_unlock(&cfg80211_mutex); | ||
1586 | return -ENODEV; | 1548 | return -ENODEV; |
1587 | } | ||
1588 | if (netdev->ieee80211_ptr) { | 1549 | if (netdev->ieee80211_ptr) { |
1589 | dev = wiphy_to_dev( | 1550 | dev = wiphy_to_dev( |
1590 | netdev->ieee80211_ptr->wiphy); | 1551 | netdev->ieee80211_ptr->wiphy); |
@@ -1628,7 +1589,6 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1628 | !skb->len && | 1589 | !skb->len && |
1629 | cb->min_dump_alloc < 4096) { | 1590 | cb->min_dump_alloc < 4096) { |
1630 | cb->min_dump_alloc = 4096; | 1591 | cb->min_dump_alloc = 4096; |
1631 | mutex_unlock(&cfg80211_mutex); | ||
1632 | return 1; | 1592 | return 1; |
1633 | } | 1593 | } |
1634 | idx--; | 1594 | idx--; |
@@ -1637,7 +1597,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
1637 | } while (cb->args[1] > 0); | 1597 | } while (cb->args[1] > 0); |
1638 | break; | 1598 | break; |
1639 | } | 1599 | } |
1640 | mutex_unlock(&cfg80211_mutex); | 1600 | rtnl_unlock(); |
1641 | 1601 | ||
1642 | cb->args[0] = idx; | 1602 | cb->args[0] = idx; |
1643 | 1603 | ||
@@ -1792,7 +1752,6 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1792 | if (result) | 1752 | if (result) |
1793 | return result; | 1753 | return result; |
1794 | 1754 | ||
1795 | mutex_lock(&rdev->devlist_mtx); | ||
1796 | switch (iftype) { | 1755 | switch (iftype) { |
1797 | case NL80211_IFTYPE_AP: | 1756 | case NL80211_IFTYPE_AP: |
1798 | case NL80211_IFTYPE_P2P_GO: | 1757 | case NL80211_IFTYPE_P2P_GO: |
@@ -1816,7 +1775,6 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1816 | default: | 1775 | default: |
1817 | result = -EINVAL; | 1776 | result = -EINVAL; |
1818 | } | 1777 | } |
1819 | mutex_unlock(&rdev->devlist_mtx); | ||
1820 | 1778 | ||
1821 | return result; | 1779 | return result; |
1822 | } | 1780 | } |
@@ -1865,6 +1823,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1865 | u32 frag_threshold = 0, rts_threshold = 0; | 1823 | u32 frag_threshold = 0, rts_threshold = 0; |
1866 | u8 coverage_class = 0; | 1824 | u8 coverage_class = 0; |
1867 | 1825 | ||
1826 | ASSERT_RTNL(); | ||
1827 | |||
1868 | /* | 1828 | /* |
1869 | * Try to find the wiphy and netdev. Normally this | 1829 | * Try to find the wiphy and netdev. Normally this |
1870 | * function shouldn't need the netdev, but this is | 1830 | * function shouldn't need the netdev, but this is |
@@ -1874,31 +1834,25 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1874 | * also passed a netdev to set_wiphy, so that it is | 1834 | * also passed a netdev to set_wiphy, so that it is |
1875 | * possible to let that go to the right netdev! | 1835 | * possible to let that go to the right netdev! |
1876 | */ | 1836 | */ |
1877 | mutex_lock(&cfg80211_mutex); | ||
1878 | 1837 | ||
1879 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | 1838 | if (info->attrs[NL80211_ATTR_IFINDEX]) { |
1880 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | 1839 | int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); |
1881 | 1840 | ||
1882 | netdev = dev_get_by_index(genl_info_net(info), ifindex); | 1841 | netdev = dev_get_by_index(genl_info_net(info), ifindex); |
1883 | if (netdev && netdev->ieee80211_ptr) { | 1842 | if (netdev && netdev->ieee80211_ptr) |
1884 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); | 1843 | rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy); |
1885 | mutex_lock(&rdev->mtx); | 1844 | else |
1886 | } else | ||
1887 | netdev = NULL; | 1845 | netdev = NULL; |
1888 | } | 1846 | } |
1889 | 1847 | ||
1890 | if (!netdev) { | 1848 | if (!netdev) { |
1891 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), | 1849 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), |
1892 | info->attrs); | 1850 | info->attrs); |
1893 | if (IS_ERR(rdev)) { | 1851 | if (IS_ERR(rdev)) |
1894 | mutex_unlock(&cfg80211_mutex); | ||
1895 | return PTR_ERR(rdev); | 1852 | return PTR_ERR(rdev); |
1896 | } | ||
1897 | wdev = NULL; | 1853 | wdev = NULL; |
1898 | netdev = NULL; | 1854 | netdev = NULL; |
1899 | result = 0; | 1855 | result = 0; |
1900 | |||
1901 | mutex_lock(&rdev->mtx); | ||
1902 | } else | 1856 | } else |
1903 | wdev = netdev->ieee80211_ptr; | 1857 | wdev = netdev->ieee80211_ptr; |
1904 | 1858 | ||
@@ -1911,8 +1865,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1911 | result = cfg80211_dev_rename( | 1865 | result = cfg80211_dev_rename( |
1912 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 1866 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
1913 | 1867 | ||
1914 | mutex_unlock(&cfg80211_mutex); | ||
1915 | |||
1916 | if (result) | 1868 | if (result) |
1917 | goto bad_res; | 1869 | goto bad_res; |
1918 | 1870 | ||
@@ -2119,7 +2071,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
2119 | } | 2071 | } |
2120 | 2072 | ||
2121 | bad_res: | 2073 | bad_res: |
2122 | mutex_unlock(&rdev->mtx); | ||
2123 | if (netdev) | 2074 | if (netdev) |
2124 | dev_put(netdev); | 2075 | dev_put(netdev); |
2125 | return result; | 2076 | return result; |
@@ -2217,7 +2168,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2217 | struct cfg80211_registered_device *rdev; | 2168 | struct cfg80211_registered_device *rdev; |
2218 | struct wireless_dev *wdev; | 2169 | struct wireless_dev *wdev; |
2219 | 2170 | ||
2220 | mutex_lock(&cfg80211_mutex); | 2171 | rtnl_lock(); |
2221 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 2172 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
2222 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) | 2173 | if (!net_eq(wiphy_net(&rdev->wiphy), sock_net(skb->sk))) |
2223 | continue; | 2174 | continue; |
@@ -2227,7 +2178,6 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2227 | } | 2178 | } |
2228 | if_idx = 0; | 2179 | if_idx = 0; |
2229 | 2180 | ||
2230 | mutex_lock(&rdev->devlist_mtx); | ||
2231 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 2181 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2232 | if (if_idx < if_start) { | 2182 | if (if_idx < if_start) { |
2233 | if_idx++; | 2183 | if_idx++; |
@@ -2236,17 +2186,15 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
2236 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, | 2186 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid, |
2237 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 2187 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
2238 | rdev, wdev) < 0) { | 2188 | rdev, wdev) < 0) { |
2239 | mutex_unlock(&rdev->devlist_mtx); | ||
2240 | goto out; | 2189 | goto out; |
2241 | } | 2190 | } |
2242 | if_idx++; | 2191 | if_idx++; |
2243 | } | 2192 | } |
2244 | mutex_unlock(&rdev->devlist_mtx); | ||
2245 | 2193 | ||
2246 | wp_idx++; | 2194 | wp_idx++; |
2247 | } | 2195 | } |
2248 | out: | 2196 | out: |
2249 | mutex_unlock(&cfg80211_mutex); | 2197 | rtnl_unlock(); |
2250 | 2198 | ||
2251 | cb->args[0] = wp_idx; | 2199 | cb->args[0] = wp_idx; |
2252 | cb->args[1] = if_idx; | 2200 | cb->args[1] = if_idx; |
@@ -2279,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { | |||
2279 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, | 2227 | [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, |
2280 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, | 2228 | [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, |
2281 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, | 2229 | [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, |
2230 | [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG }, | ||
2282 | }; | 2231 | }; |
2283 | 2232 | ||
2284 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | 2233 | static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) |
@@ -2390,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
2390 | change = true; | 2339 | change = true; |
2391 | } | 2340 | } |
2392 | 2341 | ||
2342 | if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) && | ||
2343 | !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) | ||
2344 | return -EOPNOTSUPP; | ||
2345 | |||
2393 | if (change) | 2346 | if (change) |
2394 | err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); | 2347 | err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); |
2395 | else | 2348 | else |
@@ -2447,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2447 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 2400 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
2448 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 2401 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
2449 | &flags); | 2402 | &flags); |
2403 | |||
2404 | if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) && | ||
2405 | !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) | ||
2406 | return -EOPNOTSUPP; | ||
2407 | |||
2450 | wdev = rdev_add_virtual_intf(rdev, | 2408 | wdev = rdev_add_virtual_intf(rdev, |
2451 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2409 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
2452 | type, err ? NULL : &flags, ¶ms); | 2410 | type, err ? NULL : &flags, ¶ms); |
@@ -2479,11 +2437,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2479 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 2437 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
2480 | spin_lock_init(&wdev->mgmt_registrations_lock); | 2438 | spin_lock_init(&wdev->mgmt_registrations_lock); |
2481 | 2439 | ||
2482 | mutex_lock(&rdev->devlist_mtx); | ||
2483 | wdev->identifier = ++rdev->wdev_id; | 2440 | wdev->identifier = ++rdev->wdev_id; |
2484 | list_add_rcu(&wdev->list, &rdev->wdev_list); | 2441 | list_add_rcu(&wdev->list, &rdev->wdev_list); |
2485 | rdev->devlist_generation++; | 2442 | rdev->devlist_generation++; |
2486 | mutex_unlock(&rdev->devlist_mtx); | ||
2487 | break; | 2443 | break; |
2488 | default: | 2444 | default: |
2489 | break; | 2445 | break; |
@@ -2992,8 +2948,6 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
2992 | struct wireless_dev *wdev; | 2948 | struct wireless_dev *wdev; |
2993 | bool ret = false; | 2949 | bool ret = false; |
2994 | 2950 | ||
2995 | mutex_lock(&rdev->devlist_mtx); | ||
2996 | |||
2997 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 2951 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2998 | if (wdev->iftype != NL80211_IFTYPE_AP && | 2952 | if (wdev->iftype != NL80211_IFTYPE_AP && |
2999 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 2953 | wdev->iftype != NL80211_IFTYPE_P2P_GO) |
@@ -3007,8 +2961,6 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
3007 | break; | 2961 | break; |
3008 | } | 2962 | } |
3009 | 2963 | ||
3010 | mutex_unlock(&rdev->devlist_mtx); | ||
3011 | |||
3012 | return ret; | 2964 | return ret; |
3013 | } | 2965 | } |
3014 | 2966 | ||
@@ -3170,13 +3122,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
3170 | params.radar_required = true; | 3122 | params.radar_required = true; |
3171 | } | 3123 | } |
3172 | 3124 | ||
3173 | mutex_lock(&rdev->devlist_mtx); | ||
3174 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 3125 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
3175 | params.chandef.chan, | 3126 | params.chandef.chan, |
3176 | CHAN_MODE_SHARED, | 3127 | CHAN_MODE_SHARED, |
3177 | radar_detect_width); | 3128 | radar_detect_width); |
3178 | mutex_unlock(&rdev->devlist_mtx); | ||
3179 | |||
3180 | if (err) | 3129 | if (err) |
3181 | return err; | 3130 | return err; |
3182 | 3131 | ||
@@ -3376,6 +3325,32 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
3376 | return true; | 3325 | return true; |
3377 | } | 3326 | } |
3378 | 3327 | ||
3328 | static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal, | ||
3329 | int id) | ||
3330 | { | ||
3331 | void *attr; | ||
3332 | int i = 0; | ||
3333 | |||
3334 | if (!mask) | ||
3335 | return true; | ||
3336 | |||
3337 | attr = nla_nest_start(msg, id); | ||
3338 | if (!attr) | ||
3339 | return false; | ||
3340 | |||
3341 | for (i = 0; i < IEEE80211_MAX_CHAINS; i++) { | ||
3342 | if (!(mask & BIT(i))) | ||
3343 | continue; | ||
3344 | |||
3345 | if (nla_put_u8(msg, i, signal[i])) | ||
3346 | return false; | ||
3347 | } | ||
3348 | |||
3349 | nla_nest_end(msg, attr); | ||
3350 | |||
3351 | return true; | ||
3352 | } | ||
3353 | |||
3379 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | 3354 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, |
3380 | int flags, | 3355 | int flags, |
3381 | struct cfg80211_registered_device *rdev, | 3356 | struct cfg80211_registered_device *rdev, |
@@ -3447,6 +3422,18 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3447 | default: | 3422 | default: |
3448 | break; | 3423 | break; |
3449 | } | 3424 | } |
3425 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) { | ||
3426 | if (!nl80211_put_signal(msg, sinfo->chains, | ||
3427 | sinfo->chain_signal, | ||
3428 | NL80211_STA_INFO_CHAIN_SIGNAL)) | ||
3429 | goto nla_put_failure; | ||
3430 | } | ||
3431 | if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) { | ||
3432 | if (!nl80211_put_signal(msg, sinfo->chains, | ||
3433 | sinfo->chain_signal_avg, | ||
3434 | NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) | ||
3435 | goto nla_put_failure; | ||
3436 | } | ||
3450 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { | 3437 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
3451 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, | 3438 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, |
3452 | NL80211_STA_INFO_TX_BITRATE)) | 3439 | NL80211_STA_INFO_TX_BITRATE)) |
@@ -3834,6 +3821,8 @@ static int nl80211_set_station_tdls(struct genl_info *info, | |||
3834 | struct station_parameters *params) | 3821 | struct station_parameters *params) |
3835 | { | 3822 | { |
3836 | /* Dummy STA entry gets updated once the peer capabilities are known */ | 3823 | /* Dummy STA entry gets updated once the peer capabilities are known */ |
3824 | if (info->attrs[NL80211_ATTR_PEER_AID]) | ||
3825 | params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); | ||
3837 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3826 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
3838 | params->ht_capa = | 3827 | params->ht_capa = |
3839 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 3828 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
@@ -3974,7 +3963,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3974 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) | 3963 | if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) |
3975 | return -EINVAL; | 3964 | return -EINVAL; |
3976 | 3965 | ||
3977 | if (!info->attrs[NL80211_ATTR_STA_AID]) | 3966 | if (!info->attrs[NL80211_ATTR_STA_AID] && |
3967 | !info->attrs[NL80211_ATTR_PEER_AID]) | ||
3978 | return -EINVAL; | 3968 | return -EINVAL; |
3979 | 3969 | ||
3980 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3970 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
@@ -3985,7 +3975,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3985 | params.listen_interval = | 3975 | params.listen_interval = |
3986 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 3976 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
3987 | 3977 | ||
3988 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 3978 | if (info->attrs[NL80211_ATTR_STA_AID]) |
3979 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | ||
3980 | else | ||
3981 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); | ||
3989 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 3982 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
3990 | return -EINVAL; | 3983 | return -EINVAL; |
3991 | 3984 | ||
@@ -4634,6 +4627,7 @@ static const struct nla_policy | |||
4634 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | 4627 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, |
4635 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 4628 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
4636 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 4629 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
4630 | [NL80211_MESH_SETUP_AUTH_PROTOCOL] = { .type = NLA_U8 }, | ||
4637 | [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, | 4631 | [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG }, |
4638 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 4632 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
4639 | .len = IEEE80211_MAX_DATA_LEN }, | 4633 | .len = IEEE80211_MAX_DATA_LEN }, |
@@ -4819,6 +4813,13 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
4819 | if (setup->is_secure) | 4813 | if (setup->is_secure) |
4820 | setup->user_mpm = true; | 4814 | setup->user_mpm = true; |
4821 | 4815 | ||
4816 | if (tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]) { | ||
4817 | if (!setup->user_mpm) | ||
4818 | return -EINVAL; | ||
4819 | setup->auth_id = | ||
4820 | nla_get_u8(tb[NL80211_MESH_SETUP_AUTH_PROTOCOL]); | ||
4821 | } | ||
4822 | |||
4822 | return 0; | 4823 | return 0; |
4823 | } | 4824 | } |
4824 | 4825 | ||
@@ -4861,18 +4862,13 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
4861 | void *hdr = NULL; | 4862 | void *hdr = NULL; |
4862 | struct nlattr *nl_reg_rules; | 4863 | struct nlattr *nl_reg_rules; |
4863 | unsigned int i; | 4864 | unsigned int i; |
4864 | int err = -EINVAL; | ||
4865 | |||
4866 | mutex_lock(&cfg80211_mutex); | ||
4867 | 4865 | ||
4868 | if (!cfg80211_regdomain) | 4866 | if (!cfg80211_regdomain) |
4869 | goto out; | 4867 | return -EINVAL; |
4870 | 4868 | ||
4871 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 4869 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
4872 | if (!msg) { | 4870 | if (!msg) |
4873 | err = -ENOBUFS; | 4871 | return -ENOBUFS; |
4874 | goto out; | ||
4875 | } | ||
4876 | 4872 | ||
4877 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, | 4873 | hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0, |
4878 | NL80211_CMD_GET_REG); | 4874 | NL80211_CMD_GET_REG); |
@@ -4931,8 +4927,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
4931 | nla_nest_end(msg, nl_reg_rules); | 4927 | nla_nest_end(msg, nl_reg_rules); |
4932 | 4928 | ||
4933 | genlmsg_end(msg, hdr); | 4929 | genlmsg_end(msg, hdr); |
4934 | err = genlmsg_reply(msg, info); | 4930 | return genlmsg_reply(msg, info); |
4935 | goto out; | ||
4936 | 4931 | ||
4937 | nla_put_failure_rcu: | 4932 | nla_put_failure_rcu: |
4938 | rcu_read_unlock(); | 4933 | rcu_read_unlock(); |
@@ -4940,10 +4935,7 @@ nla_put_failure: | |||
4940 | genlmsg_cancel(msg, hdr); | 4935 | genlmsg_cancel(msg, hdr); |
4941 | put_failure: | 4936 | put_failure: |
4942 | nlmsg_free(msg); | 4937 | nlmsg_free(msg); |
4943 | err = -EMSGSIZE; | 4938 | return -EMSGSIZE; |
4944 | out: | ||
4945 | mutex_unlock(&cfg80211_mutex); | ||
4946 | return err; | ||
4947 | } | 4939 | } |
4948 | 4940 | ||
4949 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 4941 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
@@ -5009,12 +5001,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5009 | } | 5001 | } |
5010 | } | 5002 | } |
5011 | 5003 | ||
5012 | mutex_lock(&cfg80211_mutex); | ||
5013 | |||
5014 | r = set_regdom(rd); | 5004 | r = set_regdom(rd); |
5015 | /* set_regdom took ownership */ | 5005 | /* set_regdom took ownership */ |
5016 | rd = NULL; | 5006 | rd = NULL; |
5017 | mutex_unlock(&cfg80211_mutex); | ||
5018 | 5007 | ||
5019 | bad_reg: | 5008 | bad_reg: |
5020 | kfree(rd); | 5009 | kfree(rd); |
@@ -5064,7 +5053,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5064 | if (!rdev->ops->scan) | 5053 | if (!rdev->ops->scan) |
5065 | return -EOPNOTSUPP; | 5054 | return -EOPNOTSUPP; |
5066 | 5055 | ||
5067 | mutex_lock(&rdev->sched_scan_mtx); | ||
5068 | if (rdev->scan_req) { | 5056 | if (rdev->scan_req) { |
5069 | err = -EBUSY; | 5057 | err = -EBUSY; |
5070 | goto unlock; | 5058 | goto unlock; |
@@ -5250,7 +5238,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
5250 | } | 5238 | } |
5251 | 5239 | ||
5252 | unlock: | 5240 | unlock: |
5253 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5254 | return err; | 5241 | return err; |
5255 | } | 5242 | } |
5256 | 5243 | ||
@@ -5322,8 +5309,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5322 | if (ie_len > wiphy->max_sched_scan_ie_len) | 5309 | if (ie_len > wiphy->max_sched_scan_ie_len) |
5323 | return -EINVAL; | 5310 | return -EINVAL; |
5324 | 5311 | ||
5325 | mutex_lock(&rdev->sched_scan_mtx); | ||
5326 | |||
5327 | if (rdev->sched_scan_req) { | 5312 | if (rdev->sched_scan_req) { |
5328 | err = -EINPROGRESS; | 5313 | err = -EINPROGRESS; |
5329 | goto out; | 5314 | goto out; |
@@ -5491,7 +5476,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
5491 | out_free: | 5476 | out_free: |
5492 | kfree(request); | 5477 | kfree(request); |
5493 | out: | 5478 | out: |
5494 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5495 | return err; | 5479 | return err; |
5496 | } | 5480 | } |
5497 | 5481 | ||
@@ -5499,17 +5483,12 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
5499 | struct genl_info *info) | 5483 | struct genl_info *info) |
5500 | { | 5484 | { |
5501 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5485 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5502 | int err; | ||
5503 | 5486 | ||
5504 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | 5487 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || |
5505 | !rdev->ops->sched_scan_stop) | 5488 | !rdev->ops->sched_scan_stop) |
5506 | return -EOPNOTSUPP; | 5489 | return -EOPNOTSUPP; |
5507 | 5490 | ||
5508 | mutex_lock(&rdev->sched_scan_mtx); | 5491 | return __cfg80211_stop_sched_scan(rdev, false); |
5509 | err = __cfg80211_stop_sched_scan(rdev, false); | ||
5510 | mutex_unlock(&rdev->sched_scan_mtx); | ||
5511 | |||
5512 | return err; | ||
5513 | } | 5492 | } |
5514 | 5493 | ||
5515 | static int nl80211_start_radar_detection(struct sk_buff *skb, | 5494 | static int nl80211_start_radar_detection(struct sk_buff *skb, |
@@ -5541,12 +5520,11 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5541 | if (!rdev->ops->start_radar_detection) | 5520 | if (!rdev->ops->start_radar_detection) |
5542 | return -EOPNOTSUPP; | 5521 | return -EOPNOTSUPP; |
5543 | 5522 | ||
5544 | mutex_lock(&rdev->devlist_mtx); | ||
5545 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | 5523 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
5546 | chandef.chan, CHAN_MODE_SHARED, | 5524 | chandef.chan, CHAN_MODE_SHARED, |
5547 | BIT(chandef.width)); | 5525 | BIT(chandef.width)); |
5548 | if (err) | 5526 | if (err) |
5549 | goto err_locked; | 5527 | return err; |
5550 | 5528 | ||
5551 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | 5529 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); |
5552 | if (!err) { | 5530 | if (!err) { |
@@ -5554,9 +5532,6 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5554 | wdev->cac_started = true; | 5532 | wdev->cac_started = true; |
5555 | wdev->cac_start_time = jiffies; | 5533 | wdev->cac_start_time = jiffies; |
5556 | } | 5534 | } |
5557 | err_locked: | ||
5558 | mutex_unlock(&rdev->devlist_mtx); | ||
5559 | |||
5560 | return err; | 5535 | return err; |
5561 | } | 5536 | } |
5562 | 5537 | ||
@@ -5939,10 +5914,13 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
5939 | if (local_state_change) | 5914 | if (local_state_change) |
5940 | return 0; | 5915 | return 0; |
5941 | 5916 | ||
5942 | return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | 5917 | wdev_lock(dev->ieee80211_ptr); |
5943 | ssid, ssid_len, ie, ie_len, | 5918 | err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, |
5944 | key.p.key, key.p.key_len, key.idx, | 5919 | ssid, ssid_len, ie, ie_len, |
5945 | sae_data, sae_data_len); | 5920 | key.p.key, key.p.key_len, key.idx, |
5921 | sae_data, sae_data_len); | ||
5922 | wdev_unlock(dev->ieee80211_ptr); | ||
5923 | return err; | ||
5946 | } | 5924 | } |
5947 | 5925 | ||
5948 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | 5926 | static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, |
@@ -6109,9 +6087,12 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
6109 | } | 6087 | } |
6110 | 6088 | ||
6111 | err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); | 6089 | err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); |
6112 | if (!err) | 6090 | if (!err) { |
6091 | wdev_lock(dev->ieee80211_ptr); | ||
6113 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, | 6092 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, |
6114 | ssid, ssid_len, &req); | 6093 | ssid, ssid_len, &req); |
6094 | wdev_unlock(dev->ieee80211_ptr); | ||
6095 | } | ||
6115 | 6096 | ||
6116 | return err; | 6097 | return err; |
6117 | } | 6098 | } |
@@ -6121,7 +6102,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
6121 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6102 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6122 | struct net_device *dev = info->user_ptr[1]; | 6103 | struct net_device *dev = info->user_ptr[1]; |
6123 | const u8 *ie = NULL, *bssid; | 6104 | const u8 *ie = NULL, *bssid; |
6124 | int ie_len = 0; | 6105 | int ie_len = 0, err; |
6125 | u16 reason_code; | 6106 | u16 reason_code; |
6126 | bool local_state_change; | 6107 | bool local_state_change; |
6127 | 6108 | ||
@@ -6156,8 +6137,11 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
6156 | 6137 | ||
6157 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 6138 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
6158 | 6139 | ||
6159 | return cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, | 6140 | wdev_lock(dev->ieee80211_ptr); |
6160 | local_state_change); | 6141 | err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code, |
6142 | local_state_change); | ||
6143 | wdev_unlock(dev->ieee80211_ptr); | ||
6144 | return err; | ||
6161 | } | 6145 | } |
6162 | 6146 | ||
6163 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | 6147 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) |
@@ -6165,7 +6149,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
6165 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6149 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6166 | struct net_device *dev = info->user_ptr[1]; | 6150 | struct net_device *dev = info->user_ptr[1]; |
6167 | const u8 *ie = NULL, *bssid; | 6151 | const u8 *ie = NULL, *bssid; |
6168 | int ie_len = 0; | 6152 | int ie_len = 0, err; |
6169 | u16 reason_code; | 6153 | u16 reason_code; |
6170 | bool local_state_change; | 6154 | bool local_state_change; |
6171 | 6155 | ||
@@ -6200,8 +6184,11 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
6200 | 6184 | ||
6201 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; | 6185 | local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE]; |
6202 | 6186 | ||
6203 | return cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, | 6187 | wdev_lock(dev->ieee80211_ptr); |
6204 | local_state_change); | 6188 | err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code, |
6189 | local_state_change); | ||
6190 | wdev_unlock(dev->ieee80211_ptr); | ||
6191 | return err; | ||
6205 | } | 6192 | } |
6206 | 6193 | ||
6207 | static bool | 6194 | static bool |
@@ -6419,6 +6406,8 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6419 | void *data = NULL; | 6406 | void *data = NULL; |
6420 | int data_len = 0; | 6407 | int data_len = 0; |
6421 | 6408 | ||
6409 | rtnl_lock(); | ||
6410 | |||
6422 | if (cb->args[0]) { | 6411 | if (cb->args[0]) { |
6423 | /* | 6412 | /* |
6424 | * 0 is a valid index, but not valid for args[0], | 6413 | * 0 is a valid index, but not valid for args[0], |
@@ -6430,18 +6419,16 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6430 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 6419 | nl80211_fam.attrbuf, nl80211_fam.maxattr, |
6431 | nl80211_policy); | 6420 | nl80211_policy); |
6432 | if (err) | 6421 | if (err) |
6433 | return err; | 6422 | goto out_err; |
6434 | 6423 | ||
6435 | mutex_lock(&cfg80211_mutex); | ||
6436 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), | 6424 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), |
6437 | nl80211_fam.attrbuf); | 6425 | nl80211_fam.attrbuf); |
6438 | if (IS_ERR(rdev)) { | 6426 | if (IS_ERR(rdev)) { |
6439 | mutex_unlock(&cfg80211_mutex); | 6427 | err = PTR_ERR(rdev); |
6440 | return PTR_ERR(rdev); | 6428 | goto out_err; |
6441 | } | 6429 | } |
6442 | phy_idx = rdev->wiphy_idx; | 6430 | phy_idx = rdev->wiphy_idx; |
6443 | rdev = NULL; | 6431 | rdev = NULL; |
6444 | mutex_unlock(&cfg80211_mutex); | ||
6445 | 6432 | ||
6446 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | 6433 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) |
6447 | cb->args[1] = | 6434 | cb->args[1] = |
@@ -6453,14 +6440,11 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6453 | data_len = nla_len((void *)cb->args[1]); | 6440 | data_len = nla_len((void *)cb->args[1]); |
6454 | } | 6441 | } |
6455 | 6442 | ||
6456 | mutex_lock(&cfg80211_mutex); | ||
6457 | rdev = cfg80211_rdev_by_wiphy_idx(phy_idx); | 6443 | rdev = cfg80211_rdev_by_wiphy_idx(phy_idx); |
6458 | if (!rdev) { | 6444 | if (!rdev) { |
6459 | mutex_unlock(&cfg80211_mutex); | 6445 | err = -ENOENT; |
6460 | return -ENOENT; | 6446 | goto out_err; |
6461 | } | 6447 | } |
6462 | cfg80211_lock_rdev(rdev); | ||
6463 | mutex_unlock(&cfg80211_mutex); | ||
6464 | 6448 | ||
6465 | if (!rdev->ops->testmode_dump) { | 6449 | if (!rdev->ops->testmode_dump) { |
6466 | err = -EOPNOTSUPP; | 6450 | err = -EOPNOTSUPP; |
@@ -6501,7 +6485,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
6501 | /* see above */ | 6485 | /* see above */ |
6502 | cb->args[0] = phy_idx + 1; | 6486 | cb->args[0] = phy_idx + 1; |
6503 | out_err: | 6487 | out_err: |
6504 | cfg80211_unlock_rdev(rdev); | 6488 | rtnl_unlock(); |
6505 | return err; | 6489 | return err; |
6506 | } | 6490 | } |
6507 | 6491 | ||
@@ -6709,7 +6693,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6709 | sizeof(connect.vht_capa)); | 6693 | sizeof(connect.vht_capa)); |
6710 | } | 6694 | } |
6711 | 6695 | ||
6712 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 6696 | wdev_lock(dev->ieee80211_ptr); |
6697 | err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL); | ||
6698 | wdev_unlock(dev->ieee80211_ptr); | ||
6713 | if (err) | 6699 | if (err) |
6714 | kfree(connkeys); | 6700 | kfree(connkeys); |
6715 | return err; | 6701 | return err; |
@@ -6720,6 +6706,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
6720 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6706 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6721 | struct net_device *dev = info->user_ptr[1]; | 6707 | struct net_device *dev = info->user_ptr[1]; |
6722 | u16 reason; | 6708 | u16 reason; |
6709 | int ret; | ||
6723 | 6710 | ||
6724 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | 6711 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) |
6725 | reason = WLAN_REASON_DEAUTH_LEAVING; | 6712 | reason = WLAN_REASON_DEAUTH_LEAVING; |
@@ -6733,7 +6720,10 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | |||
6733 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) | 6720 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
6734 | return -EOPNOTSUPP; | 6721 | return -EOPNOTSUPP; |
6735 | 6722 | ||
6736 | return cfg80211_disconnect(rdev, dev, reason, true); | 6723 | wdev_lock(dev->ieee80211_ptr); |
6724 | ret = cfg80211_disconnect(rdev, dev, reason, true); | ||
6725 | wdev_unlock(dev->ieee80211_ptr); | ||
6726 | return ret; | ||
6737 | } | 6727 | } |
6738 | 6728 | ||
6739 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) | 6729 | static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) |
@@ -7509,28 +7499,29 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
7509 | static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | 7499 | static int nl80211_send_wowlan_patterns(struct sk_buff *msg, |
7510 | struct cfg80211_registered_device *rdev) | 7500 | struct cfg80211_registered_device *rdev) |
7511 | { | 7501 | { |
7502 | struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config; | ||
7512 | struct nlattr *nl_pats, *nl_pat; | 7503 | struct nlattr *nl_pats, *nl_pat; |
7513 | int i, pat_len; | 7504 | int i, pat_len; |
7514 | 7505 | ||
7515 | if (!rdev->wowlan->n_patterns) | 7506 | if (!wowlan->n_patterns) |
7516 | return 0; | 7507 | return 0; |
7517 | 7508 | ||
7518 | nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN); | 7509 | nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN); |
7519 | if (!nl_pats) | 7510 | if (!nl_pats) |
7520 | return -ENOBUFS; | 7511 | return -ENOBUFS; |
7521 | 7512 | ||
7522 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | 7513 | for (i = 0; i < wowlan->n_patterns; i++) { |
7523 | nl_pat = nla_nest_start(msg, i + 1); | 7514 | nl_pat = nla_nest_start(msg, i + 1); |
7524 | if (!nl_pat) | 7515 | if (!nl_pat) |
7525 | return -ENOBUFS; | 7516 | return -ENOBUFS; |
7526 | pat_len = rdev->wowlan->patterns[i].pattern_len; | 7517 | pat_len = wowlan->patterns[i].pattern_len; |
7527 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | 7518 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, |
7528 | DIV_ROUND_UP(pat_len, 8), | 7519 | DIV_ROUND_UP(pat_len, 8), |
7529 | rdev->wowlan->patterns[i].mask) || | 7520 | wowlan->patterns[i].mask) || |
7530 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | 7521 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, |
7531 | pat_len, rdev->wowlan->patterns[i].pattern) || | 7522 | pat_len, wowlan->patterns[i].pattern) || |
7532 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, | 7523 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, |
7533 | rdev->wowlan->patterns[i].pkt_offset)) | 7524 | wowlan->patterns[i].pkt_offset)) |
7534 | return -ENOBUFS; | 7525 | return -ENOBUFS; |
7535 | nla_nest_end(msg, nl_pat); | 7526 | nla_nest_end(msg, nl_pat); |
7536 | } | 7527 | } |
@@ -7593,12 +7584,12 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7593 | !rdev->wiphy.wowlan.tcp) | 7584 | !rdev->wiphy.wowlan.tcp) |
7594 | return -EOPNOTSUPP; | 7585 | return -EOPNOTSUPP; |
7595 | 7586 | ||
7596 | if (rdev->wowlan && rdev->wowlan->tcp) { | 7587 | if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) { |
7597 | /* adjust size to have room for all the data */ | 7588 | /* adjust size to have room for all the data */ |
7598 | size += rdev->wowlan->tcp->tokens_size + | 7589 | size += rdev->wiphy.wowlan_config->tcp->tokens_size + |
7599 | rdev->wowlan->tcp->payload_len + | 7590 | rdev->wiphy.wowlan_config->tcp->payload_len + |
7600 | rdev->wowlan->tcp->wake_len + | 7591 | rdev->wiphy.wowlan_config->tcp->wake_len + |
7601 | rdev->wowlan->tcp->wake_len / 8; | 7592 | rdev->wiphy.wowlan_config->tcp->wake_len / 8; |
7602 | } | 7593 | } |
7603 | 7594 | ||
7604 | msg = nlmsg_new(size, GFP_KERNEL); | 7595 | msg = nlmsg_new(size, GFP_KERNEL); |
@@ -7610,33 +7601,34 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7610 | if (!hdr) | 7601 | if (!hdr) |
7611 | goto nla_put_failure; | 7602 | goto nla_put_failure; |
7612 | 7603 | ||
7613 | if (rdev->wowlan) { | 7604 | if (rdev->wiphy.wowlan_config) { |
7614 | struct nlattr *nl_wowlan; | 7605 | struct nlattr *nl_wowlan; |
7615 | 7606 | ||
7616 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); | 7607 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); |
7617 | if (!nl_wowlan) | 7608 | if (!nl_wowlan) |
7618 | goto nla_put_failure; | 7609 | goto nla_put_failure; |
7619 | 7610 | ||
7620 | if ((rdev->wowlan->any && | 7611 | if ((rdev->wiphy.wowlan_config->any && |
7621 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || | 7612 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) || |
7622 | (rdev->wowlan->disconnect && | 7613 | (rdev->wiphy.wowlan_config->disconnect && |
7623 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || | 7614 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) || |
7624 | (rdev->wowlan->magic_pkt && | 7615 | (rdev->wiphy.wowlan_config->magic_pkt && |
7625 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || | 7616 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) || |
7626 | (rdev->wowlan->gtk_rekey_failure && | 7617 | (rdev->wiphy.wowlan_config->gtk_rekey_failure && |
7627 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || | 7618 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) || |
7628 | (rdev->wowlan->eap_identity_req && | 7619 | (rdev->wiphy.wowlan_config->eap_identity_req && |
7629 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || | 7620 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) || |
7630 | (rdev->wowlan->four_way_handshake && | 7621 | (rdev->wiphy.wowlan_config->four_way_handshake && |
7631 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || | 7622 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) || |
7632 | (rdev->wowlan->rfkill_release && | 7623 | (rdev->wiphy.wowlan_config->rfkill_release && |
7633 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 7624 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
7634 | goto nla_put_failure; | 7625 | goto nla_put_failure; |
7635 | 7626 | ||
7636 | if (nl80211_send_wowlan_patterns(msg, rdev)) | 7627 | if (nl80211_send_wowlan_patterns(msg, rdev)) |
7637 | goto nla_put_failure; | 7628 | goto nla_put_failure; |
7638 | 7629 | ||
7639 | if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp)) | 7630 | if (nl80211_send_wowlan_tcp(msg, |
7631 | rdev->wiphy.wowlan_config->tcp)) | ||
7640 | goto nla_put_failure; | 7632 | goto nla_put_failure; |
7641 | 7633 | ||
7642 | nla_nest_end(msg, nl_wowlan); | 7634 | nla_nest_end(msg, nl_wowlan); |
@@ -7803,7 +7795,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7803 | struct cfg80211_wowlan *ntrig; | 7795 | struct cfg80211_wowlan *ntrig; |
7804 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 7796 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; |
7805 | int err, i; | 7797 | int err, i; |
7806 | bool prev_enabled = rdev->wowlan; | 7798 | bool prev_enabled = rdev->wiphy.wowlan_config; |
7807 | 7799 | ||
7808 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && | 7800 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7809 | !rdev->wiphy.wowlan.tcp) | 7801 | !rdev->wiphy.wowlan.tcp) |
@@ -7811,7 +7803,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7811 | 7803 | ||
7812 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7804 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
7813 | cfg80211_rdev_free_wowlan(rdev); | 7805 | cfg80211_rdev_free_wowlan(rdev); |
7814 | rdev->wowlan = NULL; | 7806 | rdev->wiphy.wowlan_config = NULL; |
7815 | goto set_wakeup; | 7807 | goto set_wakeup; |
7816 | } | 7808 | } |
7817 | 7809 | ||
@@ -7947,11 +7939,12 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7947 | goto error; | 7939 | goto error; |
7948 | } | 7940 | } |
7949 | cfg80211_rdev_free_wowlan(rdev); | 7941 | cfg80211_rdev_free_wowlan(rdev); |
7950 | rdev->wowlan = ntrig; | 7942 | rdev->wiphy.wowlan_config = ntrig; |
7951 | 7943 | ||
7952 | set_wakeup: | 7944 | set_wakeup: |
7953 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) | 7945 | if (rdev->ops->set_wakeup && |
7954 | rdev_set_wakeup(rdev, rdev->wowlan); | 7946 | prev_enabled != !!rdev->wiphy.wowlan_config) |
7947 | rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config); | ||
7955 | 7948 | ||
7956 | return 0; | 7949 | return 0; |
7957 | error: | 7950 | error: |
@@ -8136,9 +8129,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8136 | if (wdev->p2p_started) | 8129 | if (wdev->p2p_started) |
8137 | return 0; | 8130 | return 0; |
8138 | 8131 | ||
8139 | mutex_lock(&rdev->devlist_mtx); | ||
8140 | err = cfg80211_can_add_interface(rdev, wdev->iftype); | 8132 | err = cfg80211_can_add_interface(rdev, wdev->iftype); |
8141 | mutex_unlock(&rdev->devlist_mtx); | ||
8142 | if (err) | 8133 | if (err) |
8143 | return err; | 8134 | return err; |
8144 | 8135 | ||
@@ -8147,9 +8138,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8147 | return err; | 8138 | return err; |
8148 | 8139 | ||
8149 | wdev->p2p_started = true; | 8140 | wdev->p2p_started = true; |
8150 | mutex_lock(&rdev->devlist_mtx); | ||
8151 | rdev->opencount++; | 8141 | rdev->opencount++; |
8152 | mutex_unlock(&rdev->devlist_mtx); | ||
8153 | 8142 | ||
8154 | return 0; | 8143 | return 0; |
8155 | } | 8144 | } |
@@ -8165,11 +8154,7 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info) | |||
8165 | if (!rdev->ops->stop_p2p_device) | 8154 | if (!rdev->ops->stop_p2p_device) |
8166 | return -EOPNOTSUPP; | 8155 | return -EOPNOTSUPP; |
8167 | 8156 | ||
8168 | mutex_lock(&rdev->devlist_mtx); | ||
8169 | mutex_lock(&rdev->sched_scan_mtx); | ||
8170 | cfg80211_stop_p2p_device(rdev, wdev); | 8157 | cfg80211_stop_p2p_device(rdev, wdev); |
8171 | mutex_unlock(&rdev->sched_scan_mtx); | ||
8172 | mutex_unlock(&rdev->devlist_mtx); | ||
8173 | 8158 | ||
8174 | return 0; | 8159 | return 0; |
8175 | } | 8160 | } |
@@ -8312,11 +8297,11 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8312 | info->user_ptr[0] = rdev; | 8297 | info->user_ptr[0] = rdev; |
8313 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || | 8298 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
8314 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { | 8299 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
8315 | mutex_lock(&cfg80211_mutex); | 8300 | ASSERT_RTNL(); |
8301 | |||
8316 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), | 8302 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
8317 | info->attrs); | 8303 | info->attrs); |
8318 | if (IS_ERR(wdev)) { | 8304 | if (IS_ERR(wdev)) { |
8319 | mutex_unlock(&cfg80211_mutex); | ||
8320 | if (rtnl) | 8305 | if (rtnl) |
8321 | rtnl_unlock(); | 8306 | rtnl_unlock(); |
8322 | return PTR_ERR(wdev); | 8307 | return PTR_ERR(wdev); |
@@ -8327,7 +8312,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8327 | 8312 | ||
8328 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 8313 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
8329 | if (!dev) { | 8314 | if (!dev) { |
8330 | mutex_unlock(&cfg80211_mutex); | ||
8331 | if (rtnl) | 8315 | if (rtnl) |
8332 | rtnl_unlock(); | 8316 | rtnl_unlock(); |
8333 | return -EINVAL; | 8317 | return -EINVAL; |
@@ -8341,7 +8325,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8341 | if (dev) { | 8325 | if (dev) { |
8342 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 8326 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && |
8343 | !netif_running(dev)) { | 8327 | !netif_running(dev)) { |
8344 | mutex_unlock(&cfg80211_mutex); | ||
8345 | if (rtnl) | 8328 | if (rtnl) |
8346 | rtnl_unlock(); | 8329 | rtnl_unlock(); |
8347 | return -ENETDOWN; | 8330 | return -ENETDOWN; |
@@ -8350,17 +8333,12 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8350 | dev_hold(dev); | 8333 | dev_hold(dev); |
8351 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { | 8334 | } else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) { |
8352 | if (!wdev->p2p_started) { | 8335 | if (!wdev->p2p_started) { |
8353 | mutex_unlock(&cfg80211_mutex); | ||
8354 | if (rtnl) | 8336 | if (rtnl) |
8355 | rtnl_unlock(); | 8337 | rtnl_unlock(); |
8356 | return -ENETDOWN; | 8338 | return -ENETDOWN; |
8357 | } | 8339 | } |
8358 | } | 8340 | } |
8359 | 8341 | ||
8360 | cfg80211_lock_rdev(rdev); | ||
8361 | |||
8362 | mutex_unlock(&cfg80211_mutex); | ||
8363 | |||
8364 | info->user_ptr[0] = rdev; | 8342 | info->user_ptr[0] = rdev; |
8365 | } | 8343 | } |
8366 | 8344 | ||
@@ -8370,8 +8348,6 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
8370 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | 8348 | static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, |
8371 | struct genl_info *info) | 8349 | struct genl_info *info) |
8372 | { | 8350 | { |
8373 | if (info->user_ptr[0]) | ||
8374 | cfg80211_unlock_rdev(info->user_ptr[0]); | ||
8375 | if (info->user_ptr[1]) { | 8351 | if (info->user_ptr[1]) { |
8376 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { | 8352 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
8377 | struct wireless_dev *wdev = info->user_ptr[1]; | 8353 | struct wireless_dev *wdev = info->user_ptr[1]; |
@@ -8393,7 +8369,8 @@ static struct genl_ops nl80211_ops[] = { | |||
8393 | .dumpit = nl80211_dump_wiphy, | 8369 | .dumpit = nl80211_dump_wiphy, |
8394 | .policy = nl80211_policy, | 8370 | .policy = nl80211_policy, |
8395 | /* can be retrieved by unprivileged users */ | 8371 | /* can be retrieved by unprivileged users */ |
8396 | .internal_flags = NL80211_FLAG_NEED_WIPHY, | 8372 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
8373 | NL80211_FLAG_NEED_RTNL, | ||
8397 | }, | 8374 | }, |
8398 | { | 8375 | { |
8399 | .cmd = NL80211_CMD_SET_WIPHY, | 8376 | .cmd = NL80211_CMD_SET_WIPHY, |
@@ -8408,7 +8385,8 @@ static struct genl_ops nl80211_ops[] = { | |||
8408 | .dumpit = nl80211_dump_interface, | 8385 | .dumpit = nl80211_dump_interface, |
8409 | .policy = nl80211_policy, | 8386 | .policy = nl80211_policy, |
8410 | /* can be retrieved by unprivileged users */ | 8387 | /* can be retrieved by unprivileged users */ |
8411 | .internal_flags = NL80211_FLAG_NEED_WDEV, | 8388 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
8389 | NL80211_FLAG_NEED_RTNL, | ||
8412 | }, | 8390 | }, |
8413 | { | 8391 | { |
8414 | .cmd = NL80211_CMD_SET_INTERFACE, | 8392 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -8567,6 +8545,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8567 | .cmd = NL80211_CMD_GET_REG, | 8545 | .cmd = NL80211_CMD_GET_REG, |
8568 | .doit = nl80211_get_reg, | 8546 | .doit = nl80211_get_reg, |
8569 | .policy = nl80211_policy, | 8547 | .policy = nl80211_policy, |
8548 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
8570 | /* can be retrieved by unprivileged users */ | 8549 | /* can be retrieved by unprivileged users */ |
8571 | }, | 8550 | }, |
8572 | { | 8551 | { |
@@ -8574,6 +8553,7 @@ static struct genl_ops nl80211_ops[] = { | |||
8574 | .doit = nl80211_set_reg, | 8553 | .doit = nl80211_set_reg, |
8575 | .policy = nl80211_policy, | 8554 | .policy = nl80211_policy, |
8576 | .flags = GENL_ADMIN_PERM, | 8555 | .flags = GENL_ADMIN_PERM, |
8556 | .internal_flags = NL80211_FLAG_NEED_RTNL, | ||
8577 | }, | 8557 | }, |
8578 | { | 8558 | { |
8579 | .cmd = NL80211_CMD_REQ_SET_REG, | 8559 | .cmd = NL80211_CMD_REQ_SET_REG, |
@@ -9029,8 +9009,6 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
9029 | struct nlattr *nest; | 9009 | struct nlattr *nest; |
9030 | int i; | 9010 | int i; |
9031 | 9011 | ||
9032 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
9033 | |||
9034 | if (WARN_ON(!req)) | 9012 | if (WARN_ON(!req)) |
9035 | return 0; | 9013 | return 0; |
9036 | 9014 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index cc35fbaa4578..e1d6749234c6 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -81,7 +81,10 @@ static struct regulatory_request core_request_world = { | |||
81 | .country_ie_env = ENVIRON_ANY, | 81 | .country_ie_env = ENVIRON_ANY, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | /* Receipt of information from last regulatory request */ | 84 | /* |
85 | * Receipt of information from last regulatory request, | ||
86 | * protected by RTNL (and can be accessed with RCU protection) | ||
87 | */ | ||
85 | static struct regulatory_request __rcu *last_request = | 88 | static struct regulatory_request __rcu *last_request = |
86 | (void __rcu *)&core_request_world; | 89 | (void __rcu *)&core_request_world; |
87 | 90 | ||
@@ -96,39 +99,25 @@ static struct device_type reg_device_type = { | |||
96 | * Central wireless core regulatory domains, we only need two, | 99 | * Central wireless core regulatory domains, we only need two, |
97 | * the current one and a world regulatory domain in case we have no | 100 | * the current one and a world regulatory domain in case we have no |
98 | * information to give us an alpha2. | 101 | * information to give us an alpha2. |
102 | * (protected by RTNL, can be read under RCU) | ||
99 | */ | 103 | */ |
100 | const struct ieee80211_regdomain __rcu *cfg80211_regdomain; | 104 | const struct ieee80211_regdomain __rcu *cfg80211_regdomain; |
101 | 105 | ||
102 | /* | 106 | /* |
103 | * Protects static reg.c components: | ||
104 | * - cfg80211_regdomain (if not used with RCU) | ||
105 | * - cfg80211_world_regdom | ||
106 | * - last_request (if not used with RCU) | ||
107 | * - reg_num_devs_support_basehint | ||
108 | */ | ||
109 | static DEFINE_MUTEX(reg_mutex); | ||
110 | |||
111 | /* | ||
112 | * Number of devices that registered to the core | 107 | * Number of devices that registered to the core |
113 | * that support cellular base station regulatory hints | 108 | * that support cellular base station regulatory hints |
109 | * (protected by RTNL) | ||
114 | */ | 110 | */ |
115 | static int reg_num_devs_support_basehint; | 111 | static int reg_num_devs_support_basehint; |
116 | 112 | ||
117 | static inline void assert_reg_lock(void) | ||
118 | { | ||
119 | lockdep_assert_held(®_mutex); | ||
120 | } | ||
121 | |||
122 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | 113 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
123 | { | 114 | { |
124 | return rcu_dereference_protected(cfg80211_regdomain, | 115 | return rtnl_dereference(cfg80211_regdomain); |
125 | lockdep_is_held(®_mutex)); | ||
126 | } | 116 | } |
127 | 117 | ||
128 | static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) | 118 | static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) |
129 | { | 119 | { |
130 | return rcu_dereference_protected(wiphy->regd, | 120 | return rtnl_dereference(wiphy->regd); |
131 | lockdep_is_held(®_mutex)); | ||
132 | } | 121 | } |
133 | 122 | ||
134 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) | 123 | static void rcu_free_regdom(const struct ieee80211_regdomain *r) |
@@ -140,8 +129,7 @@ static void rcu_free_regdom(const struct ieee80211_regdomain *r) | |||
140 | 129 | ||
141 | static struct regulatory_request *get_last_request(void) | 130 | static struct regulatory_request *get_last_request(void) |
142 | { | 131 | { |
143 | return rcu_dereference_check(last_request, | 132 | return rcu_dereference_rtnl(last_request); |
144 | lockdep_is_held(®_mutex)); | ||
145 | } | 133 | } |
146 | 134 | ||
147 | /* Used to queue up regulatory hints */ | 135 | /* Used to queue up regulatory hints */ |
@@ -200,6 +188,7 @@ static const struct ieee80211_regdomain world_regdom = { | |||
200 | } | 188 | } |
201 | }; | 189 | }; |
202 | 190 | ||
191 | /* protected by RTNL */ | ||
203 | static const struct ieee80211_regdomain *cfg80211_world_regdom = | 192 | static const struct ieee80211_regdomain *cfg80211_world_regdom = |
204 | &world_regdom; | 193 | &world_regdom; |
205 | 194 | ||
@@ -215,7 +204,7 @@ static void reset_regdomains(bool full_reset, | |||
215 | const struct ieee80211_regdomain *r; | 204 | const struct ieee80211_regdomain *r; |
216 | struct regulatory_request *lr; | 205 | struct regulatory_request *lr; |
217 | 206 | ||
218 | assert_reg_lock(); | 207 | ASSERT_RTNL(); |
219 | 208 | ||
220 | r = get_cfg80211_regdom(); | 209 | r = get_cfg80211_regdom(); |
221 | 210 | ||
@@ -377,7 +366,7 @@ static void reg_regdb_search(struct work_struct *work) | |||
377 | const struct ieee80211_regdomain *curdom, *regdom = NULL; | 366 | const struct ieee80211_regdomain *curdom, *regdom = NULL; |
378 | int i; | 367 | int i; |
379 | 368 | ||
380 | mutex_lock(&cfg80211_mutex); | 369 | rtnl_lock(); |
381 | 370 | ||
382 | mutex_lock(®_regdb_search_mutex); | 371 | mutex_lock(®_regdb_search_mutex); |
383 | while (!list_empty(®_regdb_search_list)) { | 372 | while (!list_empty(®_regdb_search_list)) { |
@@ -402,7 +391,7 @@ static void reg_regdb_search(struct work_struct *work) | |||
402 | if (!IS_ERR_OR_NULL(regdom)) | 391 | if (!IS_ERR_OR_NULL(regdom)) |
403 | set_regdom(regdom); | 392 | set_regdom(regdom); |
404 | 393 | ||
405 | mutex_unlock(&cfg80211_mutex); | 394 | rtnl_unlock(); |
406 | } | 395 | } |
407 | 396 | ||
408 | static DECLARE_WORK(reg_regdb_work, reg_regdb_search); | 397 | static DECLARE_WORK(reg_regdb_work, reg_regdb_search); |
@@ -936,13 +925,7 @@ static bool reg_request_cell_base(struct regulatory_request *request) | |||
936 | 925 | ||
937 | bool reg_last_request_cell_base(void) | 926 | bool reg_last_request_cell_base(void) |
938 | { | 927 | { |
939 | bool val; | 928 | return reg_request_cell_base(get_last_request()); |
940 | |||
941 | mutex_lock(®_mutex); | ||
942 | val = reg_request_cell_base(get_last_request()); | ||
943 | mutex_unlock(®_mutex); | ||
944 | |||
945 | return val; | ||
946 | } | 929 | } |
947 | 930 | ||
948 | #ifdef CONFIG_CFG80211_CERTIFICATION_ONUS | 931 | #ifdef CONFIG_CFG80211_CERTIFICATION_ONUS |
@@ -1225,7 +1208,7 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) | |||
1225 | struct cfg80211_registered_device *rdev; | 1208 | struct cfg80211_registered_device *rdev; |
1226 | struct wiphy *wiphy; | 1209 | struct wiphy *wiphy; |
1227 | 1210 | ||
1228 | assert_cfg80211_lock(); | 1211 | ASSERT_RTNL(); |
1229 | 1212 | ||
1230 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 1213 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
1231 | wiphy = &rdev->wiphy; | 1214 | wiphy = &rdev->wiphy; |
@@ -1444,8 +1427,6 @@ static void reg_set_request_processed(void) | |||
1444 | * what it believes should be the current regulatory domain. | 1427 | * what it believes should be the current regulatory domain. |
1445 | * | 1428 | * |
1446 | * Returns one of the different reg request treatment values. | 1429 | * Returns one of the different reg request treatment values. |
1447 | * | ||
1448 | * Caller must hold ®_mutex | ||
1449 | */ | 1430 | */ |
1450 | static enum reg_request_treatment | 1431 | static enum reg_request_treatment |
1451 | __regulatory_hint(struct wiphy *wiphy, | 1432 | __regulatory_hint(struct wiphy *wiphy, |
@@ -1570,21 +1551,19 @@ static void reg_process_pending_hints(void) | |||
1570 | { | 1551 | { |
1571 | struct regulatory_request *reg_request, *lr; | 1552 | struct regulatory_request *reg_request, *lr; |
1572 | 1553 | ||
1573 | mutex_lock(&cfg80211_mutex); | ||
1574 | mutex_lock(®_mutex); | ||
1575 | lr = get_last_request(); | 1554 | lr = get_last_request(); |
1576 | 1555 | ||
1577 | /* When last_request->processed becomes true this will be rescheduled */ | 1556 | /* When last_request->processed becomes true this will be rescheduled */ |
1578 | if (lr && !lr->processed) { | 1557 | if (lr && !lr->processed) { |
1579 | REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); | 1558 | REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); |
1580 | goto out; | 1559 | return; |
1581 | } | 1560 | } |
1582 | 1561 | ||
1583 | spin_lock(®_requests_lock); | 1562 | spin_lock(®_requests_lock); |
1584 | 1563 | ||
1585 | if (list_empty(®_requests_list)) { | 1564 | if (list_empty(®_requests_list)) { |
1586 | spin_unlock(®_requests_lock); | 1565 | spin_unlock(®_requests_lock); |
1587 | goto out; | 1566 | return; |
1588 | } | 1567 | } |
1589 | 1568 | ||
1590 | reg_request = list_first_entry(®_requests_list, | 1569 | reg_request = list_first_entry(®_requests_list, |
@@ -1595,10 +1574,6 @@ static void reg_process_pending_hints(void) | |||
1595 | spin_unlock(®_requests_lock); | 1574 | spin_unlock(®_requests_lock); |
1596 | 1575 | ||
1597 | reg_process_hint(reg_request, reg_request->initiator); | 1576 | reg_process_hint(reg_request, reg_request->initiator); |
1598 | |||
1599 | out: | ||
1600 | mutex_unlock(®_mutex); | ||
1601 | mutex_unlock(&cfg80211_mutex); | ||
1602 | } | 1577 | } |
1603 | 1578 | ||
1604 | /* Processes beacon hints -- this has nothing to do with country IEs */ | 1579 | /* Processes beacon hints -- this has nothing to do with country IEs */ |
@@ -1607,9 +1582,6 @@ static void reg_process_pending_beacon_hints(void) | |||
1607 | struct cfg80211_registered_device *rdev; | 1582 | struct cfg80211_registered_device *rdev; |
1608 | struct reg_beacon *pending_beacon, *tmp; | 1583 | struct reg_beacon *pending_beacon, *tmp; |
1609 | 1584 | ||
1610 | mutex_lock(&cfg80211_mutex); | ||
1611 | mutex_lock(®_mutex); | ||
1612 | |||
1613 | /* This goes through the _pending_ beacon list */ | 1585 | /* This goes through the _pending_ beacon list */ |
1614 | spin_lock_bh(®_pending_beacons_lock); | 1586 | spin_lock_bh(®_pending_beacons_lock); |
1615 | 1587 | ||
@@ -1626,14 +1598,14 @@ static void reg_process_pending_beacon_hints(void) | |||
1626 | } | 1598 | } |
1627 | 1599 | ||
1628 | spin_unlock_bh(®_pending_beacons_lock); | 1600 | spin_unlock_bh(®_pending_beacons_lock); |
1629 | mutex_unlock(®_mutex); | ||
1630 | mutex_unlock(&cfg80211_mutex); | ||
1631 | } | 1601 | } |
1632 | 1602 | ||
1633 | static void reg_todo(struct work_struct *work) | 1603 | static void reg_todo(struct work_struct *work) |
1634 | { | 1604 | { |
1605 | rtnl_lock(); | ||
1635 | reg_process_pending_hints(); | 1606 | reg_process_pending_hints(); |
1636 | reg_process_pending_beacon_hints(); | 1607 | reg_process_pending_beacon_hints(); |
1608 | rtnl_unlock(); | ||
1637 | } | 1609 | } |
1638 | 1610 | ||
1639 | static void queue_regulatory_request(struct regulatory_request *request) | 1611 | static void queue_regulatory_request(struct regulatory_request *request) |
@@ -1717,29 +1689,23 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
1717 | } | 1689 | } |
1718 | EXPORT_SYMBOL(regulatory_hint); | 1690 | EXPORT_SYMBOL(regulatory_hint); |
1719 | 1691 | ||
1720 | /* | ||
1721 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and | ||
1722 | * therefore cannot iterate over the rdev list here. | ||
1723 | */ | ||
1724 | void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, | 1692 | void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, |
1725 | const u8 *country_ie, u8 country_ie_len) | 1693 | const u8 *country_ie, u8 country_ie_len) |
1726 | { | 1694 | { |
1727 | char alpha2[2]; | 1695 | char alpha2[2]; |
1728 | enum environment_cap env = ENVIRON_ANY; | 1696 | enum environment_cap env = ENVIRON_ANY; |
1729 | struct regulatory_request *request, *lr; | 1697 | struct regulatory_request *request = NULL, *lr; |
1730 | |||
1731 | mutex_lock(®_mutex); | ||
1732 | lr = get_last_request(); | ||
1733 | |||
1734 | if (unlikely(!lr)) | ||
1735 | goto out; | ||
1736 | 1698 | ||
1737 | /* IE len must be evenly divisible by 2 */ | 1699 | /* IE len must be evenly divisible by 2 */ |
1738 | if (country_ie_len & 0x01) | 1700 | if (country_ie_len & 0x01) |
1739 | goto out; | 1701 | return; |
1740 | 1702 | ||
1741 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1703 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
1742 | goto out; | 1704 | return; |
1705 | |||
1706 | request = kzalloc(sizeof(*request), GFP_KERNEL); | ||
1707 | if (!request) | ||
1708 | return; | ||
1743 | 1709 | ||
1744 | alpha2[0] = country_ie[0]; | 1710 | alpha2[0] = country_ie[0]; |
1745 | alpha2[1] = country_ie[1]; | 1711 | alpha2[1] = country_ie[1]; |
@@ -1749,19 +1715,21 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, | |||
1749 | else if (country_ie[2] == 'O') | 1715 | else if (country_ie[2] == 'O') |
1750 | env = ENVIRON_OUTDOOR; | 1716 | env = ENVIRON_OUTDOOR; |
1751 | 1717 | ||
1718 | rcu_read_lock(); | ||
1719 | lr = get_last_request(); | ||
1720 | |||
1721 | if (unlikely(!lr)) | ||
1722 | goto out; | ||
1723 | |||
1752 | /* | 1724 | /* |
1753 | * We will run this only upon a successful connection on cfg80211. | 1725 | * We will run this only upon a successful connection on cfg80211. |
1754 | * We leave conflict resolution to the workqueue, where can hold | 1726 | * We leave conflict resolution to the workqueue, where can hold |
1755 | * cfg80211_mutex. | 1727 | * the RTNL. |
1756 | */ | 1728 | */ |
1757 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1729 | if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && |
1758 | lr->wiphy_idx != WIPHY_IDX_INVALID) | 1730 | lr->wiphy_idx != WIPHY_IDX_INVALID) |
1759 | goto out; | 1731 | goto out; |
1760 | 1732 | ||
1761 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1762 | if (!request) | ||
1763 | goto out; | ||
1764 | |||
1765 | request->wiphy_idx = get_wiphy_idx(wiphy); | 1733 | request->wiphy_idx = get_wiphy_idx(wiphy); |
1766 | request->alpha2[0] = alpha2[0]; | 1734 | request->alpha2[0] = alpha2[0]; |
1767 | request->alpha2[1] = alpha2[1]; | 1735 | request->alpha2[1] = alpha2[1]; |
@@ -1769,8 +1737,10 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, | |||
1769 | request->country_ie_env = env; | 1737 | request->country_ie_env = env; |
1770 | 1738 | ||
1771 | queue_regulatory_request(request); | 1739 | queue_regulatory_request(request); |
1740 | request = NULL; | ||
1772 | out: | 1741 | out: |
1773 | mutex_unlock(®_mutex); | 1742 | kfree(request); |
1743 | rcu_read_unlock(); | ||
1774 | } | 1744 | } |
1775 | 1745 | ||
1776 | static void restore_alpha2(char *alpha2, bool reset_user) | 1746 | static void restore_alpha2(char *alpha2, bool reset_user) |
@@ -1858,8 +1828,7 @@ static void restore_regulatory_settings(bool reset_user) | |||
1858 | LIST_HEAD(tmp_reg_req_list); | 1828 | LIST_HEAD(tmp_reg_req_list); |
1859 | struct cfg80211_registered_device *rdev; | 1829 | struct cfg80211_registered_device *rdev; |
1860 | 1830 | ||
1861 | mutex_lock(&cfg80211_mutex); | 1831 | ASSERT_RTNL(); |
1862 | mutex_lock(®_mutex); | ||
1863 | 1832 | ||
1864 | reset_regdomains(true, &world_regdom); | 1833 | reset_regdomains(true, &world_regdom); |
1865 | restore_alpha2(alpha2, reset_user); | 1834 | restore_alpha2(alpha2, reset_user); |
@@ -1914,9 +1883,6 @@ static void restore_regulatory_settings(bool reset_user) | |||
1914 | list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); | 1883 | list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); |
1915 | spin_unlock(®_requests_lock); | 1884 | spin_unlock(®_requests_lock); |
1916 | 1885 | ||
1917 | mutex_unlock(®_mutex); | ||
1918 | mutex_unlock(&cfg80211_mutex); | ||
1919 | |||
1920 | REG_DBG_PRINT("Kicking the queue\n"); | 1886 | REG_DBG_PRINT("Kicking the queue\n"); |
1921 | 1887 | ||
1922 | schedule_work(®_work); | 1888 | schedule_work(®_work); |
@@ -2231,7 +2197,6 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2231 | struct regulatory_request *lr; | 2197 | struct regulatory_request *lr; |
2232 | int r; | 2198 | int r; |
2233 | 2199 | ||
2234 | mutex_lock(®_mutex); | ||
2235 | lr = get_last_request(); | 2200 | lr = get_last_request(); |
2236 | 2201 | ||
2237 | /* Note that this doesn't update the wiphys, this is done below */ | 2202 | /* Note that this doesn't update the wiphys, this is done below */ |
@@ -2241,14 +2206,12 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2241 | reg_set_request_processed(); | 2206 | reg_set_request_processed(); |
2242 | 2207 | ||
2243 | kfree(rd); | 2208 | kfree(rd); |
2244 | goto out; | 2209 | return r; |
2245 | } | 2210 | } |
2246 | 2211 | ||
2247 | /* This would make this whole thing pointless */ | 2212 | /* This would make this whole thing pointless */ |
2248 | if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) { | 2213 | if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) |
2249 | r = -EINVAL; | 2214 | return -EINVAL; |
2250 | goto out; | ||
2251 | } | ||
2252 | 2215 | ||
2253 | /* update all wiphys now with the new established regulatory domain */ | 2216 | /* update all wiphys now with the new established regulatory domain */ |
2254 | update_all_wiphy_regulatory(lr->initiator); | 2217 | update_all_wiphy_regulatory(lr->initiator); |
@@ -2259,10 +2222,7 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2259 | 2222 | ||
2260 | reg_set_request_processed(); | 2223 | reg_set_request_processed(); |
2261 | 2224 | ||
2262 | out: | 2225 | return 0; |
2263 | mutex_unlock(®_mutex); | ||
2264 | |||
2265 | return r; | ||
2266 | } | 2226 | } |
2267 | 2227 | ||
2268 | int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) | 2228 | int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) |
@@ -2287,23 +2247,17 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
2287 | 2247 | ||
2288 | void wiphy_regulatory_register(struct wiphy *wiphy) | 2248 | void wiphy_regulatory_register(struct wiphy *wiphy) |
2289 | { | 2249 | { |
2290 | mutex_lock(®_mutex); | ||
2291 | |||
2292 | if (!reg_dev_ignore_cell_hint(wiphy)) | 2250 | if (!reg_dev_ignore_cell_hint(wiphy)) |
2293 | reg_num_devs_support_basehint++; | 2251 | reg_num_devs_support_basehint++; |
2294 | 2252 | ||
2295 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 2253 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
2296 | |||
2297 | mutex_unlock(®_mutex); | ||
2298 | } | 2254 | } |
2299 | 2255 | ||
2300 | /* Caller must hold cfg80211_mutex */ | ||
2301 | void wiphy_regulatory_deregister(struct wiphy *wiphy) | 2256 | void wiphy_regulatory_deregister(struct wiphy *wiphy) |
2302 | { | 2257 | { |
2303 | struct wiphy *request_wiphy = NULL; | 2258 | struct wiphy *request_wiphy = NULL; |
2304 | struct regulatory_request *lr; | 2259 | struct regulatory_request *lr; |
2305 | 2260 | ||
2306 | mutex_lock(®_mutex); | ||
2307 | lr = get_last_request(); | 2261 | lr = get_last_request(); |
2308 | 2262 | ||
2309 | if (!reg_dev_ignore_cell_hint(wiphy)) | 2263 | if (!reg_dev_ignore_cell_hint(wiphy)) |
@@ -2316,12 +2270,10 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) | |||
2316 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); | 2270 | request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); |
2317 | 2271 | ||
2318 | if (!request_wiphy || request_wiphy != wiphy) | 2272 | if (!request_wiphy || request_wiphy != wiphy) |
2319 | goto out; | 2273 | return; |
2320 | 2274 | ||
2321 | lr->wiphy_idx = WIPHY_IDX_INVALID; | 2275 | lr->wiphy_idx = WIPHY_IDX_INVALID; |
2322 | lr->country_ie_env = ENVIRON_ANY; | 2276 | lr->country_ie_env = ENVIRON_ANY; |
2323 | out: | ||
2324 | mutex_unlock(®_mutex); | ||
2325 | } | 2277 | } |
2326 | 2278 | ||
2327 | static void reg_timeout_work(struct work_struct *work) | 2279 | static void reg_timeout_work(struct work_struct *work) |
@@ -2385,9 +2337,9 @@ void regulatory_exit(void) | |||
2385 | cancel_delayed_work_sync(®_timeout); | 2337 | cancel_delayed_work_sync(®_timeout); |
2386 | 2338 | ||
2387 | /* Lock to suppress warnings */ | 2339 | /* Lock to suppress warnings */ |
2388 | mutex_lock(®_mutex); | 2340 | rtnl_lock(); |
2389 | reset_regdomains(true, NULL); | 2341 | reset_regdomains(true, NULL); |
2390 | mutex_unlock(®_mutex); | 2342 | rtnl_unlock(); |
2391 | 2343 | ||
2392 | dev_set_uevent_suppress(®_pdev->dev, true); | 2344 | dev_set_uevent_suppress(®_pdev->dev, true); |
2393 | 2345 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index fd99ea495b7e..dd01b58fa78c 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) | |||
169 | union iwreq_data wrqu; | 169 | union iwreq_data wrqu; |
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | lockdep_assert_held(&rdev->sched_scan_mtx); | 172 | ASSERT_RTNL(); |
173 | 173 | ||
174 | request = rdev->scan_req; | 174 | request = rdev->scan_req; |
175 | 175 | ||
@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk) | |||
230 | rdev = container_of(wk, struct cfg80211_registered_device, | 230 | rdev = container_of(wk, struct cfg80211_registered_device, |
231 | scan_done_wk); | 231 | scan_done_wk); |
232 | 232 | ||
233 | mutex_lock(&rdev->sched_scan_mtx); | 233 | rtnl_lock(); |
234 | ___cfg80211_scan_done(rdev, false); | 234 | ___cfg80211_scan_done(rdev, false); |
235 | mutex_unlock(&rdev->sched_scan_mtx); | 235 | rtnl_unlock(); |
236 | } | 236 | } |
237 | 237 | ||
238 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 238 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) |
@@ -241,6 +241,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | |||
241 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 241 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); |
242 | 242 | ||
243 | request->aborted = aborted; | 243 | request->aborted = aborted; |
244 | request->notified = true; | ||
244 | queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); | 245 | queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); |
245 | } | 246 | } |
246 | EXPORT_SYMBOL(cfg80211_scan_done); | 247 | EXPORT_SYMBOL(cfg80211_scan_done); |
@@ -255,7 +256,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) | |||
255 | 256 | ||
256 | request = rdev->sched_scan_req; | 257 | request = rdev->sched_scan_req; |
257 | 258 | ||
258 | mutex_lock(&rdev->sched_scan_mtx); | 259 | rtnl_lock(); |
259 | 260 | ||
260 | /* we don't have sched_scan_req anymore if the scan is stopping */ | 261 | /* we don't have sched_scan_req anymore if the scan is stopping */ |
261 | if (request) { | 262 | if (request) { |
@@ -270,7 +271,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) | |||
270 | nl80211_send_sched_scan_results(rdev, request->dev); | 271 | nl80211_send_sched_scan_results(rdev, request->dev); |
271 | } | 272 | } |
272 | 273 | ||
273 | mutex_unlock(&rdev->sched_scan_mtx); | 274 | rtnl_unlock(); |
274 | } | 275 | } |
275 | 276 | ||
276 | void cfg80211_sched_scan_results(struct wiphy *wiphy) | 277 | void cfg80211_sched_scan_results(struct wiphy *wiphy) |
@@ -289,9 +290,9 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy) | |||
289 | 290 | ||
290 | trace_cfg80211_sched_scan_stopped(wiphy); | 291 | trace_cfg80211_sched_scan_stopped(wiphy); |
291 | 292 | ||
292 | mutex_lock(&rdev->sched_scan_mtx); | 293 | rtnl_lock(); |
293 | __cfg80211_stop_sched_scan(rdev, true); | 294 | __cfg80211_stop_sched_scan(rdev, true); |
294 | mutex_unlock(&rdev->sched_scan_mtx); | 295 | rtnl_unlock(); |
295 | } | 296 | } |
296 | EXPORT_SYMBOL(cfg80211_sched_scan_stopped); | 297 | EXPORT_SYMBOL(cfg80211_sched_scan_stopped); |
297 | 298 | ||
@@ -300,7 +301,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, | |||
300 | { | 301 | { |
301 | struct net_device *dev; | 302 | struct net_device *dev; |
302 | 303 | ||
303 | lockdep_assert_held(&rdev->sched_scan_mtx); | 304 | ASSERT_RTNL(); |
304 | 305 | ||
305 | if (!rdev->sched_scan_req) | 306 | if (!rdev->sched_scan_req) |
306 | return -ENOENT; | 307 | return -ENOENT; |
@@ -1040,6 +1041,25 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
1040 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 1041 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
1041 | 1042 | ||
1042 | #ifdef CONFIG_CFG80211_WEXT | 1043 | #ifdef CONFIG_CFG80211_WEXT |
1044 | static struct cfg80211_registered_device * | ||
1045 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | ||
1046 | { | ||
1047 | struct cfg80211_registered_device *rdev; | ||
1048 | struct net_device *dev; | ||
1049 | |||
1050 | ASSERT_RTNL(); | ||
1051 | |||
1052 | dev = dev_get_by_index(net, ifindex); | ||
1053 | if (!dev) | ||
1054 | return ERR_PTR(-ENODEV); | ||
1055 | if (dev->ieee80211_ptr) | ||
1056 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
1057 | else | ||
1058 | rdev = ERR_PTR(-ENODEV); | ||
1059 | dev_put(dev); | ||
1060 | return rdev; | ||
1061 | } | ||
1062 | |||
1043 | int cfg80211_wext_siwscan(struct net_device *dev, | 1063 | int cfg80211_wext_siwscan(struct net_device *dev, |
1044 | struct iw_request_info *info, | 1064 | struct iw_request_info *info, |
1045 | union iwreq_data *wrqu, char *extra) | 1065 | union iwreq_data *wrqu, char *extra) |
@@ -1062,7 +1082,6 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1062 | if (IS_ERR(rdev)) | 1082 | if (IS_ERR(rdev)) |
1063 | return PTR_ERR(rdev); | 1083 | return PTR_ERR(rdev); |
1064 | 1084 | ||
1065 | mutex_lock(&rdev->sched_scan_mtx); | ||
1066 | if (rdev->scan_req) { | 1085 | if (rdev->scan_req) { |
1067 | err = -EBUSY; | 1086 | err = -EBUSY; |
1068 | goto out; | 1087 | goto out; |
@@ -1169,9 +1188,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
1169 | dev_hold(dev); | 1188 | dev_hold(dev); |
1170 | } | 1189 | } |
1171 | out: | 1190 | out: |
1172 | mutex_unlock(&rdev->sched_scan_mtx); | ||
1173 | kfree(creq); | 1191 | kfree(creq); |
1174 | cfg80211_unlock_rdev(rdev); | ||
1175 | return err; | 1192 | return err; |
1176 | } | 1193 | } |
1177 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); | 1194 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); |
@@ -1470,10 +1487,8 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
1470 | if (IS_ERR(rdev)) | 1487 | if (IS_ERR(rdev)) |
1471 | return PTR_ERR(rdev); | 1488 | return PTR_ERR(rdev); |
1472 | 1489 | ||
1473 | if (rdev->scan_req) { | 1490 | if (rdev->scan_req) |
1474 | res = -EAGAIN; | 1491 | return -EAGAIN; |
1475 | goto out; | ||
1476 | } | ||
1477 | 1492 | ||
1478 | res = ieee80211_scan_results(rdev, info, extra, data->length); | 1493 | res = ieee80211_scan_results(rdev, info, extra, data->length); |
1479 | data->length = 0; | 1494 | data->length = 0; |
@@ -1482,8 +1497,6 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
1482 | res = 0; | 1497 | res = 0; |
1483 | } | 1498 | } |
1484 | 1499 | ||
1485 | out: | ||
1486 | cfg80211_unlock_rdev(rdev); | ||
1487 | return res; | 1500 | return res; |
1488 | } | 1501 | } |
1489 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); | 1502 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 3ed35c345cae..81be95f3be74 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -43,35 +43,29 @@ static bool cfg80211_is_all_idle(void) | |||
43 | struct wireless_dev *wdev; | 43 | struct wireless_dev *wdev; |
44 | bool is_all_idle = true; | 44 | bool is_all_idle = true; |
45 | 45 | ||
46 | mutex_lock(&cfg80211_mutex); | ||
47 | |||
48 | /* | 46 | /* |
49 | * All devices must be idle as otherwise if you are actively | 47 | * All devices must be idle as otherwise if you are actively |
50 | * scanning some new beacon hints could be learned and would | 48 | * scanning some new beacon hints could be learned and would |
51 | * count as new regulatory hints. | 49 | * count as new regulatory hints. |
52 | */ | 50 | */ |
53 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 51 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
54 | cfg80211_lock_rdev(rdev); | ||
55 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 52 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
56 | wdev_lock(wdev); | 53 | wdev_lock(wdev); |
57 | if (wdev->sme_state != CFG80211_SME_IDLE) | 54 | if (wdev->sme_state != CFG80211_SME_IDLE) |
58 | is_all_idle = false; | 55 | is_all_idle = false; |
59 | wdev_unlock(wdev); | 56 | wdev_unlock(wdev); |
60 | } | 57 | } |
61 | cfg80211_unlock_rdev(rdev); | ||
62 | } | 58 | } |
63 | 59 | ||
64 | mutex_unlock(&cfg80211_mutex); | ||
65 | |||
66 | return is_all_idle; | 60 | return is_all_idle; |
67 | } | 61 | } |
68 | 62 | ||
69 | static void disconnect_work(struct work_struct *work) | 63 | static void disconnect_work(struct work_struct *work) |
70 | { | 64 | { |
71 | if (!cfg80211_is_all_idle()) | 65 | rtnl_lock(); |
72 | return; | 66 | if (cfg80211_is_all_idle()) |
73 | 67 | regulatory_hint_disconnect(); | |
74 | regulatory_hint_disconnect(); | 68 | rtnl_unlock(); |
75 | } | 69 | } |
76 | 70 | ||
77 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | 71 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); |
@@ -85,7 +79,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
85 | ASSERT_RTNL(); | 79 | ASSERT_RTNL(); |
86 | ASSERT_RDEV_LOCK(rdev); | 80 | ASSERT_RDEV_LOCK(rdev); |
87 | ASSERT_WDEV_LOCK(wdev); | 81 | ASSERT_WDEV_LOCK(wdev); |
88 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
89 | 82 | ||
90 | if (rdev->scan_req) | 83 | if (rdev->scan_req) |
91 | return -EBUSY; | 84 | return -EBUSY; |
@@ -176,13 +169,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
176 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 169 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
177 | BUG_ON(!rdev->ops->auth); | 170 | BUG_ON(!rdev->ops->auth); |
178 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; | 171 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; |
179 | return __cfg80211_mlme_auth(rdev, wdev->netdev, | 172 | return cfg80211_mlme_auth(rdev, wdev->netdev, |
180 | params->channel, params->auth_type, | 173 | params->channel, params->auth_type, |
181 | params->bssid, | 174 | params->bssid, |
182 | params->ssid, params->ssid_len, | 175 | params->ssid, params->ssid_len, |
183 | NULL, 0, | 176 | NULL, 0, |
184 | params->key, params->key_len, | 177 | params->key, params->key_len, |
185 | params->key_idx, NULL, 0); | 178 | params->key_idx, NULL, 0); |
186 | case CFG80211_CONN_ASSOCIATE_NEXT: | 179 | case CFG80211_CONN_ASSOCIATE_NEXT: |
187 | BUG_ON(!rdev->ops->assoc); | 180 | BUG_ON(!rdev->ops->assoc); |
188 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 181 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
@@ -198,19 +191,19 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
198 | req.vht_capa = params->vht_capa; | 191 | req.vht_capa = params->vht_capa; |
199 | req.vht_capa_mask = params->vht_capa_mask; | 192 | req.vht_capa_mask = params->vht_capa_mask; |
200 | 193 | ||
201 | err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, | 194 | err = cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel, |
202 | params->bssid, params->ssid, | 195 | params->bssid, params->ssid, |
203 | params->ssid_len, &req); | 196 | params->ssid_len, &req); |
204 | if (err) | 197 | if (err) |
205 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 198 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
206 | NULL, 0, | 199 | NULL, 0, |
207 | WLAN_REASON_DEAUTH_LEAVING, | 200 | WLAN_REASON_DEAUTH_LEAVING, |
208 | false); | 201 | false); |
209 | return err; | 202 | return err; |
210 | case CFG80211_CONN_DEAUTH_ASSOC_FAIL: | 203 | case CFG80211_CONN_DEAUTH_ASSOC_FAIL: |
211 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 204 | cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
212 | NULL, 0, | 205 | NULL, 0, |
213 | WLAN_REASON_DEAUTH_LEAVING, false); | 206 | WLAN_REASON_DEAUTH_LEAVING, false); |
214 | /* return an error so that we call __cfg80211_connect_result() */ | 207 | /* return an error so that we call __cfg80211_connect_result() */ |
215 | return -EINVAL; | 208 | return -EINVAL; |
216 | default: | 209 | default: |
@@ -226,9 +219,6 @@ void cfg80211_conn_work(struct work_struct *work) | |||
226 | u8 bssid_buf[ETH_ALEN], *bssid = NULL; | 219 | u8 bssid_buf[ETH_ALEN], *bssid = NULL; |
227 | 220 | ||
228 | rtnl_lock(); | 221 | rtnl_lock(); |
229 | cfg80211_lock_rdev(rdev); | ||
230 | mutex_lock(&rdev->devlist_mtx); | ||
231 | mutex_lock(&rdev->sched_scan_mtx); | ||
232 | 222 | ||
233 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 223 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
234 | if (!wdev->netdev) | 224 | if (!wdev->netdev) |
@@ -256,9 +246,6 @@ void cfg80211_conn_work(struct work_struct *work) | |||
256 | wdev_unlock(wdev); | 246 | wdev_unlock(wdev); |
257 | } | 247 | } |
258 | 248 | ||
259 | mutex_unlock(&rdev->sched_scan_mtx); | ||
260 | mutex_unlock(&rdev->devlist_mtx); | ||
261 | cfg80211_unlock_rdev(rdev); | ||
262 | rtnl_unlock(); | 249 | rtnl_unlock(); |
263 | } | 250 | } |
264 | 251 | ||
@@ -773,11 +760,11 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, | |||
773 | } | 760 | } |
774 | EXPORT_SYMBOL(cfg80211_disconnected); | 761 | EXPORT_SYMBOL(cfg80211_disconnected); |
775 | 762 | ||
776 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 763 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
777 | struct net_device *dev, | 764 | struct net_device *dev, |
778 | struct cfg80211_connect_params *connect, | 765 | struct cfg80211_connect_params *connect, |
779 | struct cfg80211_cached_keys *connkeys, | 766 | struct cfg80211_cached_keys *connkeys, |
780 | const u8 *prev_bssid) | 767 | const u8 *prev_bssid) |
781 | { | 768 | { |
782 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 769 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
783 | struct cfg80211_bss *bss = NULL; | 770 | struct cfg80211_bss *bss = NULL; |
@@ -924,27 +911,8 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
924 | } | 911 | } |
925 | } | 912 | } |
926 | 913 | ||
927 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 914 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
928 | struct net_device *dev, | 915 | struct net_device *dev, u16 reason, bool wextev) |
929 | struct cfg80211_connect_params *connect, | ||
930 | struct cfg80211_cached_keys *connkeys) | ||
931 | { | ||
932 | int err; | ||
933 | |||
934 | mutex_lock(&rdev->devlist_mtx); | ||
935 | /* might request scan - scan_mtx -> wdev_mtx dependency */ | ||
936 | mutex_lock(&rdev->sched_scan_mtx); | ||
937 | wdev_lock(dev->ieee80211_ptr); | ||
938 | err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); | ||
939 | wdev_unlock(dev->ieee80211_ptr); | ||
940 | mutex_unlock(&rdev->sched_scan_mtx); | ||
941 | mutex_unlock(&rdev->devlist_mtx); | ||
942 | |||
943 | return err; | ||
944 | } | ||
945 | |||
946 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
947 | struct net_device *dev, u16 reason, bool wextev) | ||
948 | { | 916 | { |
949 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 917 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
950 | int err; | 918 | int err; |
@@ -979,7 +947,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
979 | } | 947 | } |
980 | 948 | ||
981 | /* wdev->conn->params.bssid must be set if > SCANNING */ | 949 | /* wdev->conn->params.bssid must be set if > SCANNING */ |
982 | err = __cfg80211_mlme_deauth(rdev, dev, | 950 | err = cfg80211_mlme_deauth(rdev, dev, |
983 | wdev->conn->params.bssid, | 951 | wdev->conn->params.bssid, |
984 | NULL, 0, reason, false); | 952 | NULL, 0, reason, false); |
985 | if (err) | 953 | if (err) |
@@ -1001,19 +969,6 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
1001 | return 0; | 969 | return 0; |
1002 | } | 970 | } |
1003 | 971 | ||
1004 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
1005 | struct net_device *dev, | ||
1006 | u16 reason, bool wextev) | ||
1007 | { | ||
1008 | int err; | ||
1009 | |||
1010 | wdev_lock(dev->ieee80211_ptr); | ||
1011 | err = __cfg80211_disconnect(rdev, dev, reason, wextev); | ||
1012 | wdev_unlock(dev->ieee80211_ptr); | ||
1013 | |||
1014 | return err; | ||
1015 | } | ||
1016 | |||
1017 | void cfg80211_sme_disassoc(struct net_device *dev, | 972 | void cfg80211_sme_disassoc(struct net_device *dev, |
1018 | struct cfg80211_internal_bss *bss) | 973 | struct cfg80211_internal_bss *bss) |
1019 | { | 974 | { |
@@ -1036,6 +991,6 @@ void cfg80211_sme_disassoc(struct net_device *dev, | |||
1036 | 991 | ||
1037 | memcpy(bssid, bss->pub.bssid, ETH_ALEN); | 992 | memcpy(bssid, bss->pub.bssid, ETH_ALEN); |
1038 | 993 | ||
1039 | __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, | 994 | cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, |
1040 | WLAN_REASON_DEAUTH_LEAVING, false); | 995 | WLAN_REASON_DEAUTH_LEAVING, false); |
1041 | } | 996 | } |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 8f28b9f798d8..360a42c6f694 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -91,6 +91,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) | |||
91 | cfg80211_leave(rdev, wdev); | 91 | cfg80211_leave(rdev, wdev); |
92 | } | 92 | } |
93 | 93 | ||
94 | #ifdef CONFIG_PM | ||
94 | static int wiphy_suspend(struct device *dev, pm_message_t state) | 95 | static int wiphy_suspend(struct device *dev, pm_message_t state) |
95 | { | 96 | { |
96 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 97 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
@@ -100,10 +101,10 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
100 | 101 | ||
101 | rtnl_lock(); | 102 | rtnl_lock(); |
102 | if (rdev->wiphy.registered) { | 103 | if (rdev->wiphy.registered) { |
103 | if (!rdev->wowlan) | 104 | if (!rdev->wiphy.wowlan_config) |
104 | cfg80211_leave_all(rdev); | 105 | cfg80211_leave_all(rdev); |
105 | if (rdev->ops->suspend) | 106 | if (rdev->ops->suspend) |
106 | ret = rdev_suspend(rdev, rdev->wowlan); | 107 | ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); |
107 | if (ret == 1) { | 108 | if (ret == 1) { |
108 | /* Driver refuse to configure wowlan */ | 109 | /* Driver refuse to configure wowlan */ |
109 | cfg80211_leave_all(rdev); | 110 | cfg80211_leave_all(rdev); |
@@ -132,6 +133,7 @@ static int wiphy_resume(struct device *dev) | |||
132 | 133 | ||
133 | return ret; | 134 | return ret; |
134 | } | 135 | } |
136 | #endif | ||
135 | 137 | ||
136 | static const void *wiphy_namespace(struct device *d) | 138 | static const void *wiphy_namespace(struct device *d) |
137 | { | 139 | { |
@@ -146,8 +148,10 @@ struct class ieee80211_class = { | |||
146 | .dev_release = wiphy_dev_release, | 148 | .dev_release = wiphy_dev_release, |
147 | .dev_attrs = ieee80211_dev_attrs, | 149 | .dev_attrs = ieee80211_dev_attrs, |
148 | .dev_uevent = wiphy_uevent, | 150 | .dev_uevent = wiphy_uevent, |
151 | #ifdef CONFIG_PM | ||
149 | .suspend = wiphy_suspend, | 152 | .suspend = wiphy_suspend, |
150 | .resume = wiphy_resume, | 153 | .resume = wiphy_resume, |
154 | #endif | ||
151 | .ns_type = &net_ns_type_operations, | 155 | .ns_type = &net_ns_type_operations, |
152 | .namespace = wiphy_namespace, | 156 | .namespace = wiphy_namespace, |
153 | }; | 157 | }; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 5755bc14abbd..23fafeae8a10 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -1911,12 +1911,12 @@ TRACE_EVENT(cfg80211_send_rx_assoc, | |||
1911 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) | 1911 | NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG) |
1912 | ); | 1912 | ); |
1913 | 1913 | ||
1914 | DEFINE_EVENT(netdev_evt_only, __cfg80211_send_deauth, | 1914 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_deauth, |
1915 | TP_PROTO(struct net_device *netdev), | 1915 | TP_PROTO(struct net_device *netdev), |
1916 | TP_ARGS(netdev) | 1916 | TP_ARGS(netdev) |
1917 | ); | 1917 | ); |
1918 | 1918 | ||
1919 | DEFINE_EVENT(netdev_evt_only, __cfg80211_send_disassoc, | 1919 | DEFINE_EVENT(netdev_evt_only, cfg80211_send_disassoc, |
1920 | TP_PROTO(struct net_device *netdev), | 1920 | TP_PROTO(struct net_device *netdev), |
1921 | TP_ARGS(netdev) | 1921 | TP_ARGS(netdev) |
1922 | ); | 1922 | ); |
diff --git a/net/wireless/util.c b/net/wireless/util.c index f5ad4d94ba88..74458b7f61eb 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -33,6 +33,29 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | |||
33 | } | 33 | } |
34 | EXPORT_SYMBOL(ieee80211_get_response_rate); | 34 | EXPORT_SYMBOL(ieee80211_get_response_rate); |
35 | 35 | ||
36 | u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband) | ||
37 | { | ||
38 | struct ieee80211_rate *bitrates; | ||
39 | u32 mandatory_rates = 0; | ||
40 | enum ieee80211_rate_flags mandatory_flag; | ||
41 | int i; | ||
42 | |||
43 | if (WARN_ON(!sband)) | ||
44 | return 1; | ||
45 | |||
46 | if (sband->band == IEEE80211_BAND_2GHZ) | ||
47 | mandatory_flag = IEEE80211_RATE_MANDATORY_B; | ||
48 | else | ||
49 | mandatory_flag = IEEE80211_RATE_MANDATORY_A; | ||
50 | |||
51 | bitrates = sband->bitrates; | ||
52 | for (i = 0; i < sband->n_bitrates; i++) | ||
53 | if (bitrates[i].flags & mandatory_flag) | ||
54 | mandatory_rates |= BIT(i); | ||
55 | return mandatory_rates; | ||
56 | } | ||
57 | EXPORT_SYMBOL(ieee80211_mandatory_rates); | ||
58 | |||
36 | int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | 59 | int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) |
37 | { | 60 | { |
38 | /* see 802.11 17.3.8.3.2 and Annex J | 61 | /* see 802.11 17.3.8.3.2 and Annex J |
@@ -785,12 +808,8 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | |||
785 | ASSERT_RTNL(); | 808 | ASSERT_RTNL(); |
786 | ASSERT_RDEV_LOCK(rdev); | 809 | ASSERT_RDEV_LOCK(rdev); |
787 | 810 | ||
788 | mutex_lock(&rdev->devlist_mtx); | ||
789 | |||
790 | list_for_each_entry(wdev, &rdev->wdev_list, list) | 811 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
791 | cfg80211_process_wdev_events(wdev); | 812 | cfg80211_process_wdev_events(wdev); |
792 | |||
793 | mutex_unlock(&rdev->devlist_mtx); | ||
794 | } | 813 | } |
795 | 814 | ||
796 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | 815 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
@@ -822,10 +841,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
822 | return -EBUSY; | 841 | return -EBUSY; |
823 | 842 | ||
824 | if (ntype != otype && netif_running(dev)) { | 843 | if (ntype != otype && netif_running(dev)) { |
825 | mutex_lock(&rdev->devlist_mtx); | ||
826 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 844 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
827 | ntype); | 845 | ntype); |
828 | mutex_unlock(&rdev->devlist_mtx); | ||
829 | if (err) | 846 | if (err) |
830 | return err; | 847 | return err; |
831 | 848 | ||
@@ -841,8 +858,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
841 | break; | 858 | break; |
842 | case NL80211_IFTYPE_STATION: | 859 | case NL80211_IFTYPE_STATION: |
843 | case NL80211_IFTYPE_P2P_CLIENT: | 860 | case NL80211_IFTYPE_P2P_CLIENT: |
861 | wdev_lock(dev->ieee80211_ptr); | ||
844 | cfg80211_disconnect(rdev, dev, | 862 | cfg80211_disconnect(rdev, dev, |
845 | WLAN_REASON_DEAUTH_LEAVING, true); | 863 | WLAN_REASON_DEAUTH_LEAVING, true); |
864 | wdev_unlock(dev->ieee80211_ptr); | ||
846 | break; | 865 | break; |
847 | case NL80211_IFTYPE_MESH_POINT: | 866 | case NL80211_IFTYPE_MESH_POINT: |
848 | /* mesh should be handled? */ | 867 | /* mesh should be handled? */ |
@@ -1169,6 +1188,9 @@ bool ieee80211_operating_class_to_band(u8 operating_class, | |||
1169 | case 84: | 1188 | case 84: |
1170 | *band = IEEE80211_BAND_2GHZ; | 1189 | *band = IEEE80211_BAND_2GHZ; |
1171 | return true; | 1190 | return true; |
1191 | case 180: | ||
1192 | *band = IEEE80211_BAND_60GHZ; | ||
1193 | return true; | ||
1172 | } | 1194 | } |
1173 | 1195 | ||
1174 | return false; | 1196 | return false; |
@@ -1184,8 +1206,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
1184 | if (!beacon_int) | 1206 | if (!beacon_int) |
1185 | return -EINVAL; | 1207 | return -EINVAL; |
1186 | 1208 | ||
1187 | mutex_lock(&rdev->devlist_mtx); | ||
1188 | |||
1189 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 1209 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1190 | if (!wdev->beacon_interval) | 1210 | if (!wdev->beacon_interval) |
1191 | continue; | 1211 | continue; |
@@ -1195,8 +1215,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
1195 | } | 1215 | } |
1196 | } | 1216 | } |
1197 | 1217 | ||
1198 | mutex_unlock(&rdev->devlist_mtx); | ||
1199 | |||
1200 | return res; | 1218 | return res; |
1201 | } | 1219 | } |
1202 | 1220 | ||
@@ -1220,7 +1238,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
1220 | int i, j; | 1238 | int i, j; |
1221 | 1239 | ||
1222 | ASSERT_RTNL(); | 1240 | ASSERT_RTNL(); |
1223 | lockdep_assert_held(&rdev->devlist_mtx); | ||
1224 | 1241 | ||
1225 | if (WARN_ON(hweight32(radar_detect) > 1)) | 1242 | if (WARN_ON(hweight32(radar_detect) > 1)) |
1226 | return -EINVAL; | 1243 | return -EINVAL; |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index d997d0f0c54a..e7c6e862580d 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -72,7 +72,6 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
72 | struct cfg80211_registered_device *rdev; | 72 | struct cfg80211_registered_device *rdev; |
73 | struct vif_params vifparams; | 73 | struct vif_params vifparams; |
74 | enum nl80211_iftype type; | 74 | enum nl80211_iftype type; |
75 | int ret; | ||
76 | 75 | ||
77 | rdev = wiphy_to_dev(wdev->wiphy); | 76 | rdev = wiphy_to_dev(wdev->wiphy); |
78 | 77 | ||
@@ -98,11 +97,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
98 | 97 | ||
99 | memset(&vifparams, 0, sizeof(vifparams)); | 98 | memset(&vifparams, 0, sizeof(vifparams)); |
100 | 99 | ||
101 | cfg80211_lock_rdev(rdev); | 100 | return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); |
102 | ret = cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); | ||
103 | cfg80211_unlock_rdev(rdev); | ||
104 | |||
105 | return ret; | ||
106 | } | 101 | } |
107 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); | 102 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode); |
108 | 103 | ||
@@ -579,13 +574,10 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | |||
579 | { | 574 | { |
580 | int err; | 575 | int err; |
581 | 576 | ||
582 | /* devlist mutex needed for possible IBSS re-join */ | ||
583 | mutex_lock(&rdev->devlist_mtx); | ||
584 | wdev_lock(dev->ieee80211_ptr); | 577 | wdev_lock(dev->ieee80211_ptr); |
585 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, | 578 | err = __cfg80211_set_encryption(rdev, dev, pairwise, addr, |
586 | remove, tx_key, idx, params); | 579 | remove, tx_key, idx, params); |
587 | wdev_unlock(dev->ieee80211_ptr); | 580 | wdev_unlock(dev->ieee80211_ptr); |
588 | mutex_unlock(&rdev->devlist_mtx); | ||
589 | 581 | ||
590 | return err; | 582 | return err; |
591 | } | 583 | } |
@@ -787,7 +779,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
787 | struct cfg80211_chan_def chandef = { | 779 | struct cfg80211_chan_def chandef = { |
788 | .width = NL80211_CHAN_WIDTH_20_NOHT, | 780 | .width = NL80211_CHAN_WIDTH_20_NOHT, |
789 | }; | 781 | }; |
790 | int freq, err; | 782 | int freq; |
791 | 783 | ||
792 | switch (wdev->iftype) { | 784 | switch (wdev->iftype) { |
793 | case NL80211_IFTYPE_STATION: | 785 | case NL80211_IFTYPE_STATION: |
@@ -804,10 +796,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
804 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); | 796 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); |
805 | if (!chandef.chan) | 797 | if (!chandef.chan) |
806 | return -EINVAL; | 798 | return -EINVAL; |
807 | mutex_lock(&rdev->devlist_mtx); | 799 | return cfg80211_set_monitor_channel(rdev, &chandef); |
808 | err = cfg80211_set_monitor_channel(rdev, &chandef); | ||
809 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | return err; | ||
811 | case NL80211_IFTYPE_MESH_POINT: | 800 | case NL80211_IFTYPE_MESH_POINT: |
812 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); | 801 | freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); |
813 | if (freq < 0) | 802 | if (freq < 0) |
@@ -818,10 +807,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, | |||
818 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); | 807 | chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); |
819 | if (!chandef.chan) | 808 | if (!chandef.chan) |
820 | return -EINVAL; | 809 | return -EINVAL; |
821 | mutex_lock(&rdev->devlist_mtx); | 810 | return cfg80211_set_mesh_channel(rdev, wdev, &chandef); |
822 | err = cfg80211_set_mesh_channel(rdev, wdev, &chandef); | ||
823 | mutex_unlock(&rdev->devlist_mtx); | ||
824 | return err; | ||
825 | default: | 811 | default: |
826 | return -EOPNOTSUPP; | 812 | return -EOPNOTSUPP; |
827 | } | 813 | } |
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index e79cb5c0655a..a53f8404f451 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c | |||
@@ -54,8 +54,8 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | |||
54 | if (wdev->wext.prev_bssid_valid) | 54 | if (wdev->wext.prev_bssid_valid) |
55 | prev_bssid = wdev->wext.prev_bssid; | 55 | prev_bssid = wdev->wext.prev_bssid; |
56 | 56 | ||
57 | err = __cfg80211_connect(rdev, wdev->netdev, | 57 | err = cfg80211_connect(rdev, wdev->netdev, |
58 | &wdev->wext.connect, ck, prev_bssid); | 58 | &wdev->wext.connect, ck, prev_bssid); |
59 | if (err) | 59 | if (err) |
60 | kfree(ck); | 60 | kfree(ck); |
61 | 61 | ||
@@ -87,9 +87,6 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
87 | return -EINVAL; | 87 | return -EINVAL; |
88 | } | 88 | } |
89 | 89 | ||
90 | cfg80211_lock_rdev(rdev); | ||
91 | mutex_lock(&rdev->devlist_mtx); | ||
92 | mutex_lock(&rdev->sched_scan_mtx); | ||
93 | wdev_lock(wdev); | 90 | wdev_lock(wdev); |
94 | 91 | ||
95 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 92 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -103,8 +100,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
103 | /* if SSID set, we'll try right again, avoid event */ | 100 | /* if SSID set, we'll try right again, avoid event */ |
104 | if (wdev->wext.connect.ssid_len) | 101 | if (wdev->wext.connect.ssid_len) |
105 | event = false; | 102 | event = false; |
106 | err = __cfg80211_disconnect(rdev, dev, | 103 | err = cfg80211_disconnect(rdev, dev, |
107 | WLAN_REASON_DEAUTH_LEAVING, event); | 104 | WLAN_REASON_DEAUTH_LEAVING, event); |
108 | if (err) | 105 | if (err) |
109 | goto out; | 106 | goto out; |
110 | } | 107 | } |
@@ -136,9 +133,6 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, | |||
136 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 133 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
137 | out: | 134 | out: |
138 | wdev_unlock(wdev); | 135 | wdev_unlock(wdev); |
139 | mutex_unlock(&rdev->sched_scan_mtx); | ||
140 | mutex_unlock(&rdev->devlist_mtx); | ||
141 | cfg80211_unlock_rdev(rdev); | ||
142 | return err; | 136 | return err; |
143 | } | 137 | } |
144 | 138 | ||
@@ -190,9 +184,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
190 | if (len > 0 && ssid[len - 1] == '\0') | 184 | if (len > 0 && ssid[len - 1] == '\0') |
191 | len--; | 185 | len--; |
192 | 186 | ||
193 | cfg80211_lock_rdev(rdev); | ||
194 | mutex_lock(&rdev->devlist_mtx); | ||
195 | mutex_lock(&rdev->sched_scan_mtx); | ||
196 | wdev_lock(wdev); | 187 | wdev_lock(wdev); |
197 | 188 | ||
198 | err = 0; | 189 | err = 0; |
@@ -208,8 +199,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
208 | /* if SSID set now, we'll try to connect, avoid event */ | 199 | /* if SSID set now, we'll try to connect, avoid event */ |
209 | if (len) | 200 | if (len) |
210 | event = false; | 201 | event = false; |
211 | err = __cfg80211_disconnect(rdev, dev, | 202 | err = cfg80211_disconnect(rdev, dev, |
212 | WLAN_REASON_DEAUTH_LEAVING, event); | 203 | WLAN_REASON_DEAUTH_LEAVING, event); |
213 | if (err) | 204 | if (err) |
214 | goto out; | 205 | goto out; |
215 | } | 206 | } |
@@ -226,9 +217,6 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev, | |||
226 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 217 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
227 | out: | 218 | out: |
228 | wdev_unlock(wdev); | 219 | wdev_unlock(wdev); |
229 | mutex_unlock(&rdev->sched_scan_mtx); | ||
230 | mutex_unlock(&rdev->devlist_mtx); | ||
231 | cfg80211_unlock_rdev(rdev); | ||
232 | return err; | 220 | return err; |
233 | } | 221 | } |
234 | 222 | ||
@@ -287,9 +275,6 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
287 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) | 275 | if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) |
288 | bssid = NULL; | 276 | bssid = NULL; |
289 | 277 | ||
290 | cfg80211_lock_rdev(rdev); | ||
291 | mutex_lock(&rdev->devlist_mtx); | ||
292 | mutex_lock(&rdev->sched_scan_mtx); | ||
293 | wdev_lock(wdev); | 278 | wdev_lock(wdev); |
294 | 279 | ||
295 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 280 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
@@ -303,8 +288,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
303 | ether_addr_equal(bssid, wdev->wext.connect.bssid)) | 288 | ether_addr_equal(bssid, wdev->wext.connect.bssid)) |
304 | goto out; | 289 | goto out; |
305 | 290 | ||
306 | err = __cfg80211_disconnect(rdev, dev, | 291 | err = cfg80211_disconnect(rdev, dev, |
307 | WLAN_REASON_DEAUTH_LEAVING, false); | 292 | WLAN_REASON_DEAUTH_LEAVING, false); |
308 | if (err) | 293 | if (err) |
309 | goto out; | 294 | goto out; |
310 | } | 295 | } |
@@ -318,9 +303,6 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev, | |||
318 | err = cfg80211_mgd_wext_connect(rdev, wdev); | 303 | err = cfg80211_mgd_wext_connect(rdev, wdev); |
319 | out: | 304 | out: |
320 | wdev_unlock(wdev); | 305 | wdev_unlock(wdev); |
321 | mutex_unlock(&rdev->sched_scan_mtx); | ||
322 | mutex_unlock(&rdev->devlist_mtx); | ||
323 | cfg80211_unlock_rdev(rdev); | ||
324 | return err; | 306 | return err; |
325 | } | 307 | } |
326 | 308 | ||
@@ -383,8 +365,8 @@ int cfg80211_wext_siwgenie(struct net_device *dev, | |||
383 | wdev->wext.ie_len = ie_len; | 365 | wdev->wext.ie_len = ie_len; |
384 | 366 | ||
385 | if (wdev->sme_state != CFG80211_SME_IDLE) { | 367 | if (wdev->sme_state != CFG80211_SME_IDLE) { |
386 | err = __cfg80211_disconnect(rdev, dev, | 368 | err = cfg80211_disconnect(rdev, dev, |
387 | WLAN_REASON_DEAUTH_LEAVING, false); | 369 | WLAN_REASON_DEAUTH_LEAVING, false); |
388 | if (err) | 370 | if (err) |
389 | goto out; | 371 | goto out; |
390 | } | 372 | } |
@@ -420,8 +402,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev, | |||
420 | switch (mlme->cmd) { | 402 | switch (mlme->cmd) { |
421 | case IW_MLME_DEAUTH: | 403 | case IW_MLME_DEAUTH: |
422 | case IW_MLME_DISASSOC: | 404 | case IW_MLME_DISASSOC: |
423 | err = __cfg80211_disconnect(rdev, dev, mlme->reason_code, | 405 | err = cfg80211_disconnect(rdev, dev, mlme->reason_code, true); |
424 | true); | ||
425 | break; | 406 | break; |
426 | default: | 407 | default: |
427 | err = -EOPNOTSUPP; | 408 | err = -EOPNOTSUPP; |