Commit | Line | Data |
---|---|---|
be663ab6 WYG |
1 | /****************************************************************************** |
2 | * | |
3 | * GPL LICENSE SUMMARY | |
4 | * | |
5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of version 2 of the GNU General Public License as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | |
19 | * USA | |
20 | * | |
21 | * The full GNU General Public License is included in this distribution | |
22 | * in the file called LICENSE.GPL. | |
23 | * | |
24 | * Contact Information: | |
25 | * Intel Linux Wireless <ilw@linux.intel.com> | |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
27 | *****************************************************************************/ | |
28 | ||
29 | #include <linux/kernel.h> | |
30 | #include <linux/module.h> | |
31 | #include <linux/etherdevice.h> | |
32 | #include <linux/sched.h> | |
33 | #include <linux/slab.h> | |
34 | #include <net/mac80211.h> | |
35 | ||
36 | #include "iwl-eeprom.h" | |
37 | #include "iwl-dev.h" | |
38 | #include "iwl-debug.h" | |
39 | #include "iwl-core.h" | |
40 | #include "iwl-io.h" | |
41 | #include "iwl-power.h" | |
42 | #include "iwl-sta.h" | |
43 | #include "iwl-helpers.h" | |
44 | ||
45 | ||
46 | MODULE_DESCRIPTION("iwl-legacy: common functions for 3945 and 4965"); | |
47 | MODULE_VERSION(IWLWIFI_VERSION); | |
48 | MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); | |
49 | MODULE_LICENSE("GPL"); | |
50 | ||
51 | /* | |
52 | * set bt_coex_active to true, uCode will do kill/defer | |
53 | * every time the priority line is asserted (BT is sending signals on the | |
54 | * priority line in the PCIx). | |
55 | * set bt_coex_active to false, uCode will ignore the BT activity and | |
56 | * perform the normal operation | |
57 | * | |
58 | * User might experience transmit issue on some platform due to WiFi/BT | |
59 | * co-exist problem. The possible behaviors are: | |
60 | * Able to scan and finding all the available AP | |
61 | * Not able to associate with any AP | |
62 | * On those platforms, WiFi communication can be restored by set | |
63 | * "bt_coex_active" module parameter to "false" | |
64 | * | |
65 | * default: bt_coex_active = true (BT_COEX_ENABLE) | |
66 | */ | |
ef33417d | 67 | static bool bt_coex_active = true; |
be663ab6 WYG |
68 | module_param(bt_coex_active, bool, S_IRUGO); |
69 | MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); | |
70 | ||
d2ddf621 SG |
71 | u32 il_debug_level; |
72 | EXPORT_SYMBOL(il_debug_level); | |
be663ab6 | 73 | |
d2ddf621 SG |
74 | const u8 il_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
75 | EXPORT_SYMBOL(il_bcast_addr); | |
be663ab6 WYG |
76 | |
77 | ||
46bc8d4b | 78 | /* This function both allocates and initializes hw and il. */ |
e2ebc833 | 79 | struct ieee80211_hw *il_alloc_all(struct il_cfg *cfg) |
be663ab6 | 80 | { |
46bc8d4b | 81 | struct il_priv *il; |
be663ab6 | 82 | /* mac80211 allocates memory for this device instance, including |
46bc8d4b | 83 | * space for this driver's ilate structure */ |
be663ab6 WYG |
84 | struct ieee80211_hw *hw; |
85 | ||
e2ebc833 | 86 | hw = ieee80211_alloc_hw(sizeof(struct il_priv), |
be663ab6 WYG |
87 | cfg->ops->ieee80211_ops); |
88 | if (hw == NULL) { | |
89 | pr_err("%s: Can not allocate network device\n", | |
90 | cfg->name); | |
91 | goto out; | |
92 | } | |
93 | ||
46bc8d4b SG |
94 | il = hw->priv; |
95 | il->hw = hw; | |
be663ab6 WYG |
96 | |
97 | out: | |
98 | return hw; | |
99 | } | |
e2ebc833 | 100 | EXPORT_SYMBOL(il_alloc_all); |
be663ab6 WYG |
101 | |
102 | #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ | |
103 | #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ | |
46bc8d4b | 104 | static void il_init_ht_hw_capab(const struct il_priv *il, |
be663ab6 WYG |
105 | struct ieee80211_sta_ht_cap *ht_info, |
106 | enum ieee80211_band band) | |
107 | { | |
108 | u16 max_bit_rate = 0; | |
46bc8d4b SG |
109 | u8 rx_chains_num = il->hw_params.rx_chains_num; |
110 | u8 tx_chains_num = il->hw_params.tx_chains_num; | |
be663ab6 WYG |
111 | |
112 | ht_info->cap = 0; | |
113 | memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); | |
114 | ||
115 | ht_info->ht_supported = true; | |
116 | ||
117 | ht_info->cap |= IEEE80211_HT_CAP_SGI_20; | |
118 | max_bit_rate = MAX_BIT_RATE_20_MHZ; | |
46bc8d4b | 119 | if (il->hw_params.ht40_channel & BIT(band)) { |
be663ab6 WYG |
120 | ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
121 | ht_info->cap |= IEEE80211_HT_CAP_SGI_40; | |
122 | ht_info->mcs.rx_mask[4] = 0x01; | |
123 | max_bit_rate = MAX_BIT_RATE_40_MHZ; | |
124 | } | |
125 | ||
46bc8d4b | 126 | if (il->cfg->mod_params->amsdu_size_8K) |
be663ab6 WYG |
127 | ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; |
128 | ||
129 | ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; | |
130 | ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; | |
131 | ||
132 | ht_info->mcs.rx_mask[0] = 0xFF; | |
133 | if (rx_chains_num >= 2) | |
134 | ht_info->mcs.rx_mask[1] = 0xFF; | |
135 | if (rx_chains_num >= 3) | |
136 | ht_info->mcs.rx_mask[2] = 0xFF; | |
137 | ||
138 | /* Highest supported Rx data rate */ | |
139 | max_bit_rate *= rx_chains_num; | |
140 | WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); | |
141 | ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); | |
142 | ||
143 | /* Tx MCS capabilities */ | |
144 | ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | |
145 | if (tx_chains_num != rx_chains_num) { | |
146 | ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; | |
147 | ht_info->mcs.tx_params |= ((tx_chains_num - 1) << | |
148 | IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); | |
149 | } | |
150 | } | |
151 | ||
152 | /** | |
e2ebc833 | 153 | * il_init_geos - Initialize mac80211's geo/channel info based from eeprom |
be663ab6 | 154 | */ |
46bc8d4b | 155 | int il_init_geos(struct il_priv *il) |
be663ab6 | 156 | { |
e2ebc833 | 157 | struct il_channel_info *ch; |
be663ab6 WYG |
158 | struct ieee80211_supported_band *sband; |
159 | struct ieee80211_channel *channels; | |
160 | struct ieee80211_channel *geo_ch; | |
161 | struct ieee80211_rate *rates; | |
162 | int i = 0; | |
332704a5 | 163 | s8 max_tx_power = 0; |
be663ab6 | 164 | |
46bc8d4b SG |
165 | if (il->bands[IEEE80211_BAND_2GHZ].n_bitrates || |
166 | il->bands[IEEE80211_BAND_5GHZ].n_bitrates) { | |
58de00a4 | 167 | D_INFO("Geography modes already initialized.\n"); |
46bc8d4b | 168 | set_bit(STATUS_GEO_CONFIGURED, &il->status); |
be663ab6 WYG |
169 | return 0; |
170 | } | |
171 | ||
172 | channels = kzalloc(sizeof(struct ieee80211_channel) * | |
46bc8d4b | 173 | il->channel_count, GFP_KERNEL); |
be663ab6 WYG |
174 | if (!channels) |
175 | return -ENOMEM; | |
176 | ||
e2ebc833 | 177 | rates = kzalloc((sizeof(struct ieee80211_rate) * IL_RATE_COUNT_LEGACY), |
be663ab6 WYG |
178 | GFP_KERNEL); |
179 | if (!rates) { | |
180 | kfree(channels); | |
181 | return -ENOMEM; | |
182 | } | |
183 | ||
184 | /* 5.2GHz channels start after the 2.4GHz channels */ | |
46bc8d4b | 185 | sband = &il->bands[IEEE80211_BAND_5GHZ]; |
d2ddf621 | 186 | sband->channels = &channels[ARRAY_SIZE(il_eeprom_band_1)]; |
be663ab6 | 187 | /* just OFDM */ |
e2ebc833 SG |
188 | sband->bitrates = &rates[IL_FIRST_OFDM_RATE]; |
189 | sband->n_bitrates = IL_RATE_COUNT_LEGACY - IL_FIRST_OFDM_RATE; | |
be663ab6 | 190 | |
46bc8d4b SG |
191 | if (il->cfg->sku & IL_SKU_N) |
192 | il_init_ht_hw_capab(il, &sband->ht_cap, | |
be663ab6 WYG |
193 | IEEE80211_BAND_5GHZ); |
194 | ||
46bc8d4b | 195 | sband = &il->bands[IEEE80211_BAND_2GHZ]; |
be663ab6 WYG |
196 | sband->channels = channels; |
197 | /* OFDM & CCK */ | |
198 | sband->bitrates = rates; | |
e2ebc833 | 199 | sband->n_bitrates = IL_RATE_COUNT_LEGACY; |
be663ab6 | 200 | |
46bc8d4b SG |
201 | if (il->cfg->sku & IL_SKU_N) |
202 | il_init_ht_hw_capab(il, &sband->ht_cap, | |
be663ab6 WYG |
203 | IEEE80211_BAND_2GHZ); |
204 | ||
46bc8d4b SG |
205 | il->ieee_channels = channels; |
206 | il->ieee_rates = rates; | |
be663ab6 | 207 | |
46bc8d4b SG |
208 | for (i = 0; i < il->channel_count; i++) { |
209 | ch = &il->channel_info[i]; | |
be663ab6 | 210 | |
e2ebc833 | 211 | if (!il_is_channel_valid(ch)) |
be663ab6 WYG |
212 | continue; |
213 | ||
46bc8d4b | 214 | sband = &il->bands[ch->band]; |
be663ab6 WYG |
215 | |
216 | geo_ch = &sband->channels[sband->n_channels++]; | |
217 | ||
218 | geo_ch->center_freq = | |
219 | ieee80211_channel_to_frequency(ch->channel, ch->band); | |
220 | geo_ch->max_power = ch->max_power_avg; | |
221 | geo_ch->max_antenna_gain = 0xff; | |
222 | geo_ch->hw_value = ch->channel; | |
223 | ||
e2ebc833 | 224 | if (il_is_channel_valid(ch)) { |
be663ab6 WYG |
225 | if (!(ch->flags & EEPROM_CHANNEL_IBSS)) |
226 | geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; | |
227 | ||
228 | if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) | |
229 | geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; | |
230 | ||
231 | if (ch->flags & EEPROM_CHANNEL_RADAR) | |
232 | geo_ch->flags |= IEEE80211_CHAN_RADAR; | |
233 | ||
234 | geo_ch->flags |= ch->ht40_extension_channel; | |
235 | ||
332704a5 SG |
236 | if (ch->max_power_avg > max_tx_power) |
237 | max_tx_power = ch->max_power_avg; | |
be663ab6 WYG |
238 | } else { |
239 | geo_ch->flags |= IEEE80211_CHAN_DISABLED; | |
240 | } | |
241 | ||
58de00a4 | 242 | D_INFO("Channel %d Freq=%d[%sGHz] %s flag=0x%X\n", |
be663ab6 | 243 | ch->channel, geo_ch->center_freq, |
e2ebc833 | 244 | il_is_channel_a_band(ch) ? "5.2" : "2.4", |
be663ab6 WYG |
245 | geo_ch->flags & IEEE80211_CHAN_DISABLED ? |
246 | "restricted" : "valid", | |
247 | geo_ch->flags); | |
248 | } | |
249 | ||
46bc8d4b SG |
250 | il->tx_power_device_lmt = max_tx_power; |
251 | il->tx_power_user_lmt = max_tx_power; | |
252 | il->tx_power_next = max_tx_power; | |
332704a5 | 253 | |
232913b5 SG |
254 | if (il->bands[IEEE80211_BAND_5GHZ].n_channels == 0 && |
255 | (il->cfg->sku & IL_SKU_A)) { | |
9406f797 | 256 | IL_INFO("Incorrectly detected BG card as ABG. " |
be663ab6 | 257 | "Please send your PCI ID 0x%04X:0x%04X to maintainer.\n", |
46bc8d4b SG |
258 | il->pci_dev->device, |
259 | il->pci_dev->subsystem_device); | |
260 | il->cfg->sku &= ~IL_SKU_A; | |
be663ab6 WYG |
261 | } |
262 | ||
9406f797 | 263 | IL_INFO("Tunable channels: %d 802.11bg, %d 802.11a channels\n", |
46bc8d4b SG |
264 | il->bands[IEEE80211_BAND_2GHZ].n_channels, |
265 | il->bands[IEEE80211_BAND_5GHZ].n_channels); | |
be663ab6 | 266 | |
46bc8d4b | 267 | set_bit(STATUS_GEO_CONFIGURED, &il->status); |
be663ab6 WYG |
268 | |
269 | return 0; | |
270 | } | |
e2ebc833 | 271 | EXPORT_SYMBOL(il_init_geos); |
be663ab6 WYG |
272 | |
273 | /* | |
e2ebc833 | 274 | * il_free_geos - undo allocations in il_init_geos |
be663ab6 | 275 | */ |
46bc8d4b | 276 | void il_free_geos(struct il_priv *il) |
be663ab6 | 277 | { |
46bc8d4b SG |
278 | kfree(il->ieee_channels); |
279 | kfree(il->ieee_rates); | |
280 | clear_bit(STATUS_GEO_CONFIGURED, &il->status); | |
be663ab6 | 281 | } |
e2ebc833 | 282 | EXPORT_SYMBOL(il_free_geos); |
be663ab6 | 283 | |
46bc8d4b | 284 | static bool il_is_channel_extension(struct il_priv *il, |
be663ab6 WYG |
285 | enum ieee80211_band band, |
286 | u16 channel, u8 extension_chan_offset) | |
287 | { | |
e2ebc833 | 288 | const struct il_channel_info *ch_info; |
be663ab6 | 289 | |
46bc8d4b | 290 | ch_info = il_get_channel_info(il, band, channel); |
e2ebc833 | 291 | if (!il_is_channel_valid(ch_info)) |
be663ab6 WYG |
292 | return false; |
293 | ||
294 | if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) | |
295 | return !(ch_info->ht40_extension_channel & | |
296 | IEEE80211_CHAN_NO_HT40PLUS); | |
297 | else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) | |
298 | return !(ch_info->ht40_extension_channel & | |
299 | IEEE80211_CHAN_NO_HT40MINUS); | |
300 | ||
301 | return false; | |
302 | } | |
303 | ||
46bc8d4b | 304 | bool il_is_ht40_tx_allowed(struct il_priv *il, |
e2ebc833 | 305 | struct il_rxon_context *ctx, |
be663ab6 WYG |
306 | struct ieee80211_sta_ht_cap *ht_cap) |
307 | { | |
308 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | |
309 | return false; | |
310 | ||
311 | /* | |
312 | * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
313 | * the bit will not set if it is pure 40MHz case | |
314 | */ | |
315 | if (ht_cap && !ht_cap->ht_supported) | |
316 | return false; | |
317 | ||
d3175167 | 318 | #ifdef CONFIG_IWLEGACY_DEBUGFS |
46bc8d4b | 319 | if (il->disable_ht40) |
be663ab6 WYG |
320 | return false; |
321 | #endif | |
322 | ||
46bc8d4b | 323 | return il_is_channel_extension(il, il->band, |
be663ab6 WYG |
324 | le16_to_cpu(ctx->staging.channel), |
325 | ctx->ht.extension_chan_offset); | |
326 | } | |
e2ebc833 | 327 | EXPORT_SYMBOL(il_is_ht40_tx_allowed); |
be663ab6 | 328 | |
e2ebc833 | 329 | static u16 il_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val) |
be663ab6 WYG |
330 | { |
331 | u16 new_val; | |
332 | u16 beacon_factor; | |
333 | ||
334 | /* | |
335 | * If mac80211 hasn't given us a beacon interval, program | |
336 | * the default into the device. | |
337 | */ | |
338 | if (!beacon_val) | |
339 | return DEFAULT_BEACON_INTERVAL; | |
340 | ||
341 | /* | |
342 | * If the beacon interval we obtained from the peer | |
343 | * is too large, we'll have to wake up more often | |
344 | * (and in IBSS case, we'll beacon too much) | |
345 | * | |
346 | * For example, if max_beacon_val is 4096, and the | |
347 | * requested beacon interval is 7000, we'll have to | |
348 | * use 3500 to be able to wake up on the beacons. | |
349 | * | |
350 | * This could badly influence beacon detection stats. | |
351 | */ | |
352 | ||
353 | beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val; | |
354 | new_val = beacon_val / beacon_factor; | |
355 | ||
356 | if (!new_val) | |
357 | new_val = max_beacon_val; | |
358 | ||
359 | return new_val; | |
360 | } | |
361 | ||
362 | int | |
46bc8d4b | 363 | il_send_rxon_timing(struct il_priv *il, struct il_rxon_context *ctx) |
be663ab6 WYG |
364 | { |
365 | u64 tsf; | |
366 | s32 interval_tm, rem; | |
367 | struct ieee80211_conf *conf = NULL; | |
368 | u16 beacon_int; | |
369 | struct ieee80211_vif *vif = ctx->vif; | |
370 | ||
46bc8d4b | 371 | conf = il_ieee80211_get_hw_conf(il->hw); |
be663ab6 | 372 | |
46bc8d4b | 373 | lockdep_assert_held(&il->mutex); |
be663ab6 | 374 | |
e2ebc833 | 375 | memset(&ctx->timing, 0, sizeof(struct il_rxon_time_cmd)); |
be663ab6 | 376 | |
46bc8d4b | 377 | ctx->timing.timestamp = cpu_to_le64(il->timestamp); |
be663ab6 WYG |
378 | ctx->timing.listen_interval = cpu_to_le16(conf->listen_interval); |
379 | ||
380 | beacon_int = vif ? vif->bss_conf.beacon_int : 0; | |
381 | ||
382 | /* | |
6ce1dc45 | 383 | * TODO: For IBSS we need to get atim_win from mac80211, |
be663ab6 WYG |
384 | * for now just always use 0 |
385 | */ | |
6ce1dc45 | 386 | ctx->timing.atim_win = 0; |
be663ab6 | 387 | |
e2ebc833 | 388 | beacon_int = il_adjust_beacon_interval(beacon_int, |
46bc8d4b | 389 | il->hw_params.max_beacon_itrvl * TIME_UNIT); |
be663ab6 WYG |
390 | ctx->timing.beacon_interval = cpu_to_le16(beacon_int); |
391 | ||
46bc8d4b | 392 | tsf = il->timestamp; /* tsf is modifed by do_div: copy it */ |
be663ab6 WYG |
393 | interval_tm = beacon_int * TIME_UNIT; |
394 | rem = do_div(tsf, interval_tm); | |
395 | ctx->timing.beacon_init_val = cpu_to_le32(interval_tm - rem); | |
396 | ||
397 | ctx->timing.dtim_period = vif ? (vif->bss_conf.dtim_period ?: 1) : 1; | |
398 | ||
58de00a4 | 399 | D_ASSOC( |
be663ab6 WYG |
400 | "beacon interval %d beacon timer %d beacon tim %d\n", |
401 | le16_to_cpu(ctx->timing.beacon_interval), | |
402 | le32_to_cpu(ctx->timing.beacon_init_val), | |
6ce1dc45 | 403 | le16_to_cpu(ctx->timing.atim_win)); |
be663ab6 | 404 | |
46bc8d4b | 405 | return il_send_cmd_pdu(il, ctx->rxon_timing_cmd, |
be663ab6 WYG |
406 | sizeof(ctx->timing), &ctx->timing); |
407 | } | |
e2ebc833 | 408 | EXPORT_SYMBOL(il_send_rxon_timing); |
be663ab6 WYG |
409 | |
410 | void | |
46bc8d4b | 411 | il_set_rxon_hwcrypto(struct il_priv *il, |
e2ebc833 | 412 | struct il_rxon_context *ctx, |
be663ab6 WYG |
413 | int hw_decrypt) |
414 | { | |
e2ebc833 | 415 | struct il_rxon_cmd *rxon = &ctx->staging; |
be663ab6 WYG |
416 | |
417 | if (hw_decrypt) | |
418 | rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; | |
419 | else | |
420 | rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK; | |
421 | ||
422 | } | |
e2ebc833 | 423 | EXPORT_SYMBOL(il_set_rxon_hwcrypto); |
be663ab6 WYG |
424 | |
425 | /* validate RXON structure is valid */ | |
426 | int | |
46bc8d4b | 427 | il_check_rxon_cmd(struct il_priv *il, struct il_rxon_context *ctx) |
be663ab6 | 428 | { |
e2ebc833 | 429 | struct il_rxon_cmd *rxon = &ctx->staging; |
be663ab6 WYG |
430 | bool error = false; |
431 | ||
432 | if (rxon->flags & RXON_FLG_BAND_24G_MSK) { | |
433 | if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { | |
9406f797 | 434 | IL_WARN("check 2.4G: wrong narrow\n"); |
be663ab6 WYG |
435 | error = true; |
436 | } | |
437 | if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { | |
9406f797 | 438 | IL_WARN("check 2.4G: wrong radar\n"); |
be663ab6 WYG |
439 | error = true; |
440 | } | |
441 | } else { | |
442 | if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { | |
9406f797 | 443 | IL_WARN("check 5.2G: not short slot!\n"); |
be663ab6 WYG |
444 | error = true; |
445 | } | |
446 | if (rxon->flags & RXON_FLG_CCK_MSK) { | |
9406f797 | 447 | IL_WARN("check 5.2G: CCK!\n"); |
be663ab6 WYG |
448 | error = true; |
449 | } | |
450 | } | |
451 | if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { | |
9406f797 | 452 | IL_WARN("mac/bssid mcast!\n"); |
be663ab6 WYG |
453 | error = true; |
454 | } | |
455 | ||
456 | /* make sure basic rates 6Mbps and 1Mbps are supported */ | |
e2ebc833 SG |
457 | if ((rxon->ofdm_basic_rates & IL_RATE_6M_MASK) == 0 && |
458 | (rxon->cck_basic_rates & IL_RATE_1M_MASK) == 0) { | |
9406f797 | 459 | IL_WARN("neither 1 nor 6 are basic\n"); |
be663ab6 WYG |
460 | error = true; |
461 | } | |
462 | ||
463 | if (le16_to_cpu(rxon->assoc_id) > 2007) { | |
9406f797 | 464 | IL_WARN("aid > 2007\n"); |
be663ab6 WYG |
465 | error = true; |
466 | } | |
467 | ||
468 | if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) | |
469 | == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { | |
9406f797 | 470 | IL_WARN("CCK and short slot\n"); |
be663ab6 WYG |
471 | error = true; |
472 | } | |
473 | ||
474 | if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) | |
475 | == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { | |
9406f797 | 476 | IL_WARN("CCK and auto detect"); |
be663ab6 WYG |
477 | error = true; |
478 | } | |
479 | ||
480 | if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | | |
481 | RXON_FLG_TGG_PROTECT_MSK)) == | |
482 | RXON_FLG_TGG_PROTECT_MSK) { | |
9406f797 | 483 | IL_WARN("TGg but no auto-detect\n"); |
be663ab6 WYG |
484 | error = true; |
485 | } | |
486 | ||
487 | if (error) | |
9406f797 | 488 | IL_WARN("Tuning to channel %d\n", |
be663ab6 WYG |
489 | le16_to_cpu(rxon->channel)); |
490 | ||
491 | if (error) { | |
9406f797 | 492 | IL_ERR("Invalid RXON\n"); |
be663ab6 WYG |
493 | return -EINVAL; |
494 | } | |
495 | return 0; | |
496 | } | |
e2ebc833 | 497 | EXPORT_SYMBOL(il_check_rxon_cmd); |
be663ab6 WYG |
498 | |
499 | /** | |
e2ebc833 | 500 | * il_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed |
46bc8d4b | 501 | * @il: staging_rxon is compared to active_rxon |
be663ab6 WYG |
502 | * |
503 | * If the RXON structure is changing enough to require a new tune, | |
504 | * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that | |
505 | * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required. | |
506 | */ | |
46bc8d4b | 507 | int il_full_rxon_required(struct il_priv *il, |
e2ebc833 | 508 | struct il_rxon_context *ctx) |
be663ab6 | 509 | { |
e2ebc833 SG |
510 | const struct il_rxon_cmd *staging = &ctx->staging; |
511 | const struct il_rxon_cmd *active = &ctx->active; | |
be663ab6 WYG |
512 | |
513 | #define CHK(cond) \ | |
514 | if ((cond)) { \ | |
58de00a4 | 515 | D_INFO("need full RXON - " #cond "\n"); \ |
be663ab6 WYG |
516 | return 1; \ |
517 | } | |
518 | ||
519 | #define CHK_NEQ(c1, c2) \ | |
520 | if ((c1) != (c2)) { \ | |
58de00a4 | 521 | D_INFO("need full RXON - " \ |
be663ab6 WYG |
522 | #c1 " != " #c2 " - %d != %d\n", \ |
523 | (c1), (c2)); \ | |
524 | return 1; \ | |
525 | } | |
526 | ||
527 | /* These items are only settable from the full RXON command */ | |
e2ebc833 | 528 | CHK(!il_is_associated_ctx(ctx)); |
be663ab6 WYG |
529 | CHK(compare_ether_addr(staging->bssid_addr, active->bssid_addr)); |
530 | CHK(compare_ether_addr(staging->node_addr, active->node_addr)); | |
531 | CHK(compare_ether_addr(staging->wlap_bssid_addr, | |
532 | active->wlap_bssid_addr)); | |
533 | CHK_NEQ(staging->dev_type, active->dev_type); | |
534 | CHK_NEQ(staging->channel, active->channel); | |
535 | CHK_NEQ(staging->air_propagation, active->air_propagation); | |
536 | CHK_NEQ(staging->ofdm_ht_single_stream_basic_rates, | |
537 | active->ofdm_ht_single_stream_basic_rates); | |
538 | CHK_NEQ(staging->ofdm_ht_dual_stream_basic_rates, | |
539 | active->ofdm_ht_dual_stream_basic_rates); | |
540 | CHK_NEQ(staging->assoc_id, active->assoc_id); | |
541 | ||
542 | /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can | |
543 | * be updated with the RXON_ASSOC command -- however only some | |
544 | * flag transitions are allowed using RXON_ASSOC */ | |
545 | ||
546 | /* Check if we are not switching bands */ | |
547 | CHK_NEQ(staging->flags & RXON_FLG_BAND_24G_MSK, | |
548 | active->flags & RXON_FLG_BAND_24G_MSK); | |
549 | ||
550 | /* Check if we are switching association toggle */ | |
551 | CHK_NEQ(staging->filter_flags & RXON_FILTER_ASSOC_MSK, | |
552 | active->filter_flags & RXON_FILTER_ASSOC_MSK); | |
553 | ||
554 | #undef CHK | |
555 | #undef CHK_NEQ | |
556 | ||
557 | return 0; | |
558 | } | |
e2ebc833 | 559 | EXPORT_SYMBOL(il_full_rxon_required); |
be663ab6 | 560 | |
46bc8d4b | 561 | u8 il_get_lowest_plcp(struct il_priv *il, |
e2ebc833 | 562 | struct il_rxon_context *ctx) |
be663ab6 WYG |
563 | { |
564 | /* | |
565 | * Assign the lowest rate -- should really get this from | |
566 | * the beacon skb from mac80211. | |
567 | */ | |
568 | if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) | |
e2ebc833 | 569 | return IL_RATE_1M_PLCP; |
be663ab6 | 570 | else |
e2ebc833 | 571 | return IL_RATE_6M_PLCP; |
be663ab6 | 572 | } |
e2ebc833 | 573 | EXPORT_SYMBOL(il_get_lowest_plcp); |
be663ab6 | 574 | |
46bc8d4b | 575 | static void _il_set_rxon_ht(struct il_priv *il, |
e2ebc833 SG |
576 | struct il_ht_config *ht_conf, |
577 | struct il_rxon_context *ctx) | |
be663ab6 | 578 | { |
e2ebc833 | 579 | struct il_rxon_cmd *rxon = &ctx->staging; |
be663ab6 WYG |
580 | |
581 | if (!ctx->ht.enabled) { | |
582 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | |
583 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | |
584 | RXON_FLG_HT40_PROT_MSK | | |
585 | RXON_FLG_HT_PROT_MSK); | |
586 | return; | |
587 | } | |
588 | ||
589 | rxon->flags |= cpu_to_le32(ctx->ht.protection << | |
590 | RXON_FLG_HT_OPERATING_MODE_POS); | |
591 | ||
592 | /* Set up channel bandwidth: | |
593 | * 20 MHz only, 20/40 mixed or pure 40 if ht40 ok */ | |
594 | /* clear the HT channel mode before set the mode */ | |
595 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | | |
596 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | |
46bc8d4b | 597 | if (il_is_ht40_tx_allowed(il, ctx, NULL)) { |
be663ab6 WYG |
598 | /* pure ht40 */ |
599 | if (ctx->ht.protection == | |
600 | IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) { | |
601 | rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; | |
602 | /* Note: control channel is opposite of extension channel */ | |
603 | switch (ctx->ht.extension_chan_offset) { | |
604 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | |
605 | rxon->flags &= | |
606 | ~RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | |
607 | break; | |
608 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | |
609 | rxon->flags |= | |
610 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | |
611 | break; | |
612 | } | |
613 | } else { | |
614 | /* Note: control channel is opposite of extension channel */ | |
615 | switch (ctx->ht.extension_chan_offset) { | |
616 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | |
617 | rxon->flags &= | |
618 | ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | |
619 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | |
620 | break; | |
621 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | |
622 | rxon->flags |= | |
623 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | |
624 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | |
625 | break; | |
626 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | |
627 | default: | |
628 | /* channel location only valid if in Mixed mode */ | |
9406f797 | 629 | IL_ERR( |
be663ab6 WYG |
630 | "invalid extension channel offset\n"); |
631 | break; | |
632 | } | |
633 | } | |
634 | } else { | |
635 | rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; | |
636 | } | |
637 | ||
46bc8d4b SG |
638 | if (il->cfg->ops->hcmd->set_rxon_chain) |
639 | il->cfg->ops->hcmd->set_rxon_chain(il, ctx); | |
be663ab6 | 640 | |
58de00a4 | 641 | D_ASSOC("rxon flags 0x%X operation mode :0x%X " |
be663ab6 WYG |
642 | "extension channel offset 0x%x\n", |
643 | le32_to_cpu(rxon->flags), ctx->ht.protection, | |
644 | ctx->ht.extension_chan_offset); | |
645 | } | |
646 | ||
46bc8d4b | 647 | void il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf) |
be663ab6 | 648 | { |
e2ebc833 | 649 | struct il_rxon_context *ctx; |
be663ab6 | 650 | |
46bc8d4b SG |
651 | for_each_context(il, ctx) |
652 | _il_set_rxon_ht(il, ht_conf, ctx); | |
be663ab6 | 653 | } |
e2ebc833 | 654 | EXPORT_SYMBOL(il_set_rxon_ht); |
be663ab6 WYG |
655 | |
656 | /* Return valid, unused, channel for a passive scan to reset the RF */ | |
46bc8d4b | 657 | u8 il_get_single_channel_number(struct il_priv *il, |
be663ab6 WYG |
658 | enum ieee80211_band band) |
659 | { | |
e2ebc833 | 660 | const struct il_channel_info *ch_info; |
be663ab6 WYG |
661 | int i; |
662 | u8 channel = 0; | |
663 | u8 min, max; | |
e2ebc833 | 664 | struct il_rxon_context *ctx; |
be663ab6 WYG |
665 | |
666 | if (band == IEEE80211_BAND_5GHZ) { | |
667 | min = 14; | |
46bc8d4b | 668 | max = il->channel_count; |
be663ab6 WYG |
669 | } else { |
670 | min = 0; | |
671 | max = 14; | |
672 | } | |
673 | ||
674 | for (i = min; i < max; i++) { | |
675 | bool busy = false; | |
676 | ||
46bc8d4b SG |
677 | for_each_context(il, ctx) { |
678 | busy = il->channel_info[i].channel == | |
be663ab6 WYG |
679 | le16_to_cpu(ctx->staging.channel); |
680 | if (busy) | |
681 | break; | |
682 | } | |
683 | ||
684 | if (busy) | |
685 | continue; | |
686 | ||
46bc8d4b SG |
687 | channel = il->channel_info[i].channel; |
688 | ch_info = il_get_channel_info(il, band, channel); | |
e2ebc833 | 689 | if (il_is_channel_valid(ch_info)) |
be663ab6 WYG |
690 | break; |
691 | } | |
692 | ||
693 | return channel; | |
694 | } | |
e2ebc833 | 695 | EXPORT_SYMBOL(il_get_single_channel_number); |
be663ab6 WYG |
696 | |
697 | /** | |
e2ebc833 | 698 | * il_set_rxon_channel - Set the band and channel values in staging RXON |
be663ab6 WYG |
699 | * @ch: requested channel as a pointer to struct ieee80211_channel |
700 | ||
701 | * NOTE: Does not commit to the hardware; it sets appropriate bit fields | |
702 | * in the staging RXON flag structure based on the ch->band | |
703 | */ | |
704 | int | |
46bc8d4b | 705 | il_set_rxon_channel(struct il_priv *il, struct ieee80211_channel *ch, |
e2ebc833 | 706 | struct il_rxon_context *ctx) |
be663ab6 WYG |
707 | { |
708 | enum ieee80211_band band = ch->band; | |
709 | u16 channel = ch->hw_value; | |
710 | ||
232913b5 | 711 | if (le16_to_cpu(ctx->staging.channel) == channel && il->band == band) |
be663ab6 WYG |
712 | return 0; |
713 | ||
714 | ctx->staging.channel = cpu_to_le16(channel); | |
715 | if (band == IEEE80211_BAND_5GHZ) | |
716 | ctx->staging.flags &= ~RXON_FLG_BAND_24G_MSK; | |
717 | else | |
718 | ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; | |
719 | ||
46bc8d4b | 720 | il->band = band; |
be663ab6 | 721 | |
58de00a4 | 722 | D_INFO("Staging channel set to %d [%d]\n", channel, band); |
be663ab6 WYG |
723 | |
724 | return 0; | |
725 | } | |
e2ebc833 | 726 | EXPORT_SYMBOL(il_set_rxon_channel); |
be663ab6 | 727 | |
46bc8d4b | 728 | void il_set_flags_for_band(struct il_priv *il, |
e2ebc833 | 729 | struct il_rxon_context *ctx, |
be663ab6 WYG |
730 | enum ieee80211_band band, |
731 | struct ieee80211_vif *vif) | |
732 | { | |
733 | if (band == IEEE80211_BAND_5GHZ) { | |
734 | ctx->staging.flags &= | |
735 | ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | |
736 | | RXON_FLG_CCK_MSK); | |
737 | ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; | |
738 | } else { | |
e2ebc833 | 739 | /* Copied from il_post_associate() */ |
be663ab6 WYG |
740 | if (vif && vif->bss_conf.use_short_slot) |
741 | ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; | |
742 | else | |
743 | ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; | |
744 | ||
745 | ctx->staging.flags |= RXON_FLG_BAND_24G_MSK; | |
746 | ctx->staging.flags |= RXON_FLG_AUTO_DETECT_MSK; | |
747 | ctx->staging.flags &= ~RXON_FLG_CCK_MSK; | |
748 | } | |
749 | } | |
e2ebc833 | 750 | EXPORT_SYMBOL(il_set_flags_for_band); |
be663ab6 WYG |
751 | |
752 | /* | |
753 | * initialize rxon structure with default values from eeprom | |
754 | */ | |
46bc8d4b | 755 | void il_connection_init_rx_config(struct il_priv *il, |
e2ebc833 | 756 | struct il_rxon_context *ctx) |
be663ab6 | 757 | { |
e2ebc833 | 758 | const struct il_channel_info *ch_info; |
be663ab6 WYG |
759 | |
760 | memset(&ctx->staging, 0, sizeof(ctx->staging)); | |
761 | ||
762 | if (!ctx->vif) { | |
763 | ctx->staging.dev_type = ctx->unused_devtype; | |
764 | } else | |
765 | switch (ctx->vif->type) { | |
766 | ||
767 | case NL80211_IFTYPE_STATION: | |
768 | ctx->staging.dev_type = ctx->station_devtype; | |
769 | ctx->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK; | |
770 | break; | |
771 | ||
772 | case NL80211_IFTYPE_ADHOC: | |
773 | ctx->staging.dev_type = ctx->ibss_devtype; | |
774 | ctx->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK; | |
775 | ctx->staging.filter_flags = RXON_FILTER_BCON_AWARE_MSK | | |
776 | RXON_FILTER_ACCEPT_GRP_MSK; | |
777 | break; | |
778 | ||
779 | default: | |
9406f797 | 780 | IL_ERR("Unsupported interface type %d\n", |
be663ab6 WYG |
781 | ctx->vif->type); |
782 | break; | |
783 | } | |
784 | ||
785 | #if 0 | |
786 | /* TODO: Figure out when short_preamble would be set and cache from | |
787 | * that */ | |
46bc8d4b | 788 | if (!hw_to_local(il->hw)->short_preamble) |
be663ab6 WYG |
789 | ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; |
790 | else | |
791 | ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | |
792 | #endif | |
793 | ||
46bc8d4b | 794 | ch_info = il_get_channel_info(il, il->band, |
be663ab6 WYG |
795 | le16_to_cpu(ctx->active.channel)); |
796 | ||
797 | if (!ch_info) | |
46bc8d4b | 798 | ch_info = &il->channel_info[0]; |
be663ab6 WYG |
799 | |
800 | ctx->staging.channel = cpu_to_le16(ch_info->channel); | |
46bc8d4b | 801 | il->band = ch_info->band; |
be663ab6 | 802 | |
46bc8d4b | 803 | il_set_flags_for_band(il, ctx, il->band, ctx->vif); |
be663ab6 WYG |
804 | |
805 | ctx->staging.ofdm_basic_rates = | |
e2ebc833 | 806 | (IL_OFDM_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF; |
be663ab6 | 807 | ctx->staging.cck_basic_rates = |
e2ebc833 | 808 | (IL_CCK_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF; |
be663ab6 WYG |
809 | |
810 | /* clear both MIX and PURE40 mode flag */ | |
811 | ctx->staging.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | | |
812 | RXON_FLG_CHANNEL_MODE_PURE_40); | |
813 | if (ctx->vif) | |
814 | memcpy(ctx->staging.node_addr, ctx->vif->addr, ETH_ALEN); | |
815 | ||
816 | ctx->staging.ofdm_ht_single_stream_basic_rates = 0xff; | |
817 | ctx->staging.ofdm_ht_dual_stream_basic_rates = 0xff; | |
818 | } | |
e2ebc833 | 819 | EXPORT_SYMBOL(il_connection_init_rx_config); |
be663ab6 | 820 | |
46bc8d4b | 821 | void il_set_rate(struct il_priv *il) |
be663ab6 WYG |
822 | { |
823 | const struct ieee80211_supported_band *hw = NULL; | |
824 | struct ieee80211_rate *rate; | |
e2ebc833 | 825 | struct il_rxon_context *ctx; |
be663ab6 WYG |
826 | int i; |
827 | ||
46bc8d4b | 828 | hw = il_get_hw_mode(il, il->band); |
be663ab6 | 829 | if (!hw) { |
9406f797 | 830 | IL_ERR("Failed to set rate: unable to get hw mode\n"); |
be663ab6 WYG |
831 | return; |
832 | } | |
833 | ||
46bc8d4b | 834 | il->active_rate = 0; |
be663ab6 WYG |
835 | |
836 | for (i = 0; i < hw->n_bitrates; i++) { | |
837 | rate = &(hw->bitrates[i]); | |
e2ebc833 | 838 | if (rate->hw_value < IL_RATE_COUNT_LEGACY) |
46bc8d4b | 839 | il->active_rate |= (1 << rate->hw_value); |
be663ab6 WYG |
840 | } |
841 | ||
58de00a4 | 842 | D_RATE("Set active_rate = %0x\n", il->active_rate); |
be663ab6 | 843 | |
46bc8d4b | 844 | for_each_context(il, ctx) { |
be663ab6 | 845 | ctx->staging.cck_basic_rates = |
e2ebc833 | 846 | (IL_CCK_BASIC_RATES_MASK >> IL_FIRST_CCK_RATE) & 0xF; |
be663ab6 WYG |
847 | |
848 | ctx->staging.ofdm_basic_rates = | |
e2ebc833 | 849 | (IL_OFDM_BASIC_RATES_MASK >> IL_FIRST_OFDM_RATE) & 0xFF; |
be663ab6 WYG |
850 | } |
851 | } | |
e2ebc833 | 852 | EXPORT_SYMBOL(il_set_rate); |
be663ab6 | 853 | |
46bc8d4b | 854 | void il_chswitch_done(struct il_priv *il, bool is_success) |
be663ab6 | 855 | { |
7c2cde2e | 856 | struct il_rxon_context *ctx = &il->ctx; |
be663ab6 | 857 | |
46bc8d4b | 858 | if (test_bit(STATUS_EXIT_PENDING, &il->status)) |
be663ab6 WYG |
859 | return; |
860 | ||
46bc8d4b | 861 | if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &il->status)) |
be663ab6 | 862 | ieee80211_chswitch_done(ctx->vif, is_success); |
be663ab6 | 863 | } |
e2ebc833 | 864 | EXPORT_SYMBOL(il_chswitch_done); |
be663ab6 | 865 | |
b73bb5f1 | 866 | void il_rx_csa(struct il_priv *il, struct il_rx_buf *rxb) |
be663ab6 | 867 | { |
dcae1c64 | 868 | struct il_rx_pkt *pkt = rxb_addr(rxb); |
e2ebc833 | 869 | struct il_csa_notification *csa = &(pkt->u.csa_notif); |
be663ab6 | 870 | |
7c2cde2e | 871 | struct il_rxon_context *ctx = &il->ctx; |
e2ebc833 | 872 | struct il_rxon_cmd *rxon = (void *)&ctx->active; |
be663ab6 | 873 | |
46bc8d4b | 874 | if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &il->status)) |
51e65257 SG |
875 | return; |
876 | ||
46bc8d4b | 877 | if (!le32_to_cpu(csa->status) && csa->channel == il->switch_channel) { |
51e65257 SG |
878 | rxon->channel = csa->channel; |
879 | ctx->staging.channel = csa->channel; | |
58de00a4 | 880 | D_11H("CSA notif: channel %d\n", |
be663ab6 | 881 | le16_to_cpu(csa->channel)); |
46bc8d4b | 882 | il_chswitch_done(il, true); |
51e65257 | 883 | } else { |
9406f797 | 884 | IL_ERR("CSA notif (fail) : channel %d\n", |
51e65257 | 885 | le16_to_cpu(csa->channel)); |
46bc8d4b | 886 | il_chswitch_done(il, false); |
be663ab6 WYG |
887 | } |
888 | } | |
e2ebc833 | 889 | EXPORT_SYMBOL(il_rx_csa); |
be663ab6 | 890 | |
d3175167 | 891 | #ifdef CONFIG_IWLEGACY_DEBUG |
46bc8d4b | 892 | void il_print_rx_config_cmd(struct il_priv *il, |
e2ebc833 | 893 | struct il_rxon_context *ctx) |
be663ab6 | 894 | { |
e2ebc833 | 895 | struct il_rxon_cmd *rxon = &ctx->staging; |
be663ab6 | 896 | |
58de00a4 | 897 | D_RADIO("RX CONFIG:\n"); |
46bc8d4b | 898 | il_print_hex_dump(il, IL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); |
58de00a4 | 899 | D_RADIO("u16 channel: 0x%x\n", |
be663ab6 | 900 | le16_to_cpu(rxon->channel)); |
58de00a4 SG |
901 | D_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags)); |
902 | D_RADIO("u32 filter_flags: 0x%08x\n", | |
be663ab6 | 903 | le32_to_cpu(rxon->filter_flags)); |
58de00a4 SG |
904 | D_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type); |
905 | D_RADIO("u8 ofdm_basic_rates: 0x%02x\n", | |
be663ab6 | 906 | rxon->ofdm_basic_rates); |
58de00a4 | 907 | D_RADIO("u8 cck_basic_rates: 0x%02x\n", |
be663ab6 | 908 | rxon->cck_basic_rates); |
58de00a4 SG |
909 | D_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); |
910 | D_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); | |
911 | D_RADIO("u16 assoc_id: 0x%x\n", | |
be663ab6 WYG |
912 | le16_to_cpu(rxon->assoc_id)); |
913 | } | |
e2ebc833 | 914 | EXPORT_SYMBOL(il_print_rx_config_cmd); |
be663ab6 WYG |
915 | #endif |
916 | /** | |
e2ebc833 | 917 | * il_irq_handle_error - called for HW or SW error interrupt from card |
be663ab6 | 918 | */ |
46bc8d4b | 919 | void il_irq_handle_error(struct il_priv *il) |
be663ab6 | 920 | { |
e2ebc833 | 921 | /* Set the FW error flag -- cleared on il_down */ |
46bc8d4b | 922 | set_bit(STATUS_FW_ERROR, &il->status); |
be663ab6 WYG |
923 | |
924 | /* Cancel currently queued command. */ | |
46bc8d4b | 925 | clear_bit(STATUS_HCMD_ACTIVE, &il->status); |
be663ab6 | 926 | |
9406f797 | 927 | IL_ERR("Loaded firmware version: %s\n", |
46bc8d4b | 928 | il->hw->wiphy->fw_version); |
be663ab6 | 929 | |
46bc8d4b SG |
930 | il->cfg->ops->lib->dump_nic_error_log(il); |
931 | if (il->cfg->ops->lib->dump_fh) | |
932 | il->cfg->ops->lib->dump_fh(il, NULL, false); | |
d3175167 | 933 | #ifdef CONFIG_IWLEGACY_DEBUG |
46bc8d4b SG |
934 | if (il_get_debug_level(il) & IL_DL_FW_ERRORS) |
935 | il_print_rx_config_cmd(il, | |
7c2cde2e | 936 | &il->ctx); |
be663ab6 WYG |
937 | #endif |
938 | ||
46bc8d4b | 939 | wake_up(&il->wait_command_queue); |
be663ab6 WYG |
940 | |
941 | /* Keep the restart process from trying to send host | |
942 | * commands by clearing the INIT status bit */ | |
46bc8d4b | 943 | clear_bit(STATUS_READY, &il->status); |
be663ab6 | 944 | |
46bc8d4b | 945 | if (!test_bit(STATUS_EXIT_PENDING, &il->status)) { |
58de00a4 | 946 | IL_DBG(IL_DL_FW_ERRORS, |
be663ab6 WYG |
947 | "Restarting adapter due to uCode error.\n"); |
948 | ||
46bc8d4b SG |
949 | if (il->cfg->mod_params->restart_fw) |
950 | queue_work(il->workqueue, &il->restart); | |
be663ab6 WYG |
951 | } |
952 | } | |
e2ebc833 | 953 | EXPORT_SYMBOL(il_irq_handle_error); |
be663ab6 | 954 | |
46bc8d4b | 955 | static int il_apm_stop_master(struct il_priv *il) |
be663ab6 WYG |
956 | { |
957 | int ret = 0; | |
958 | ||
959 | /* stop device's busmaster DMA activity */ | |
46bc8d4b | 960 | il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); |
be663ab6 | 961 | |
142b343f | 962 | ret = _il_poll_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, |
be663ab6 WYG |
963 | CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); |
964 | if (ret) | |
9406f797 | 965 | IL_WARN("Master Disable Timed Out, 100 usec\n"); |
be663ab6 | 966 | |
58de00a4 | 967 | D_INFO("stop master\n"); |
be663ab6 WYG |
968 | |
969 | return ret; | |
970 | } | |
971 | ||
46bc8d4b | 972 | void il_apm_stop(struct il_priv *il) |
be663ab6 | 973 | { |
58de00a4 | 974 | D_INFO("Stop card, put in low power state\n"); |
be663ab6 WYG |
975 | |
976 | /* Stop device's DMA activity */ | |
46bc8d4b | 977 | il_apm_stop_master(il); |
be663ab6 WYG |
978 | |
979 | /* Reset the entire device */ | |
46bc8d4b | 980 | il_set_bit(il, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); |
be663ab6 WYG |
981 | |
982 | udelay(10); | |
983 | ||
984 | /* | |
985 | * Clear "initialization complete" bit to move adapter from | |
986 | * D0A* (powered-up Active) --> D0U* (Uninitialized) state. | |
987 | */ | |
46bc8d4b | 988 | il_clear_bit(il, CSR_GP_CNTRL, |
be663ab6 WYG |
989 | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
990 | } | |
e2ebc833 | 991 | EXPORT_SYMBOL(il_apm_stop); |
be663ab6 WYG |
992 | |
993 | ||
994 | /* | |
995 | * Start up NIC's basic functionality after it has been reset | |
e2ebc833 | 996 | * (e.g. after platform boot, or shutdown via il_apm_stop()) |
be663ab6 WYG |
997 | * NOTE: This does not load uCode nor start the embedded processor |
998 | */ | |
46bc8d4b | 999 | int il_apm_init(struct il_priv *il) |
be663ab6 WYG |
1000 | { |
1001 | int ret = 0; | |
1002 | u16 lctl; | |
1003 | ||
58de00a4 | 1004 | D_INFO("Init card's basic functions\n"); |
be663ab6 WYG |
1005 | |
1006 | /* | |
1007 | * Use "set_bit" below rather than "write", to preserve any hardware | |
1008 | * bits already set by default after reset. | |
1009 | */ | |
1010 | ||
1011 | /* Disable L0S exit timer (platform NMI Work/Around) */ | |
46bc8d4b | 1012 | il_set_bit(il, CSR_GIO_CHICKEN_BITS, |
be663ab6 WYG |
1013 | CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); |
1014 | ||
1015 | /* | |
1016 | * Disable L0s without affecting L1; | |
1017 | * don't wait for ICH L0s (ICH bug W/A) | |
1018 | */ | |
46bc8d4b | 1019 | il_set_bit(il, CSR_GIO_CHICKEN_BITS, |
be663ab6 WYG |
1020 | CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); |
1021 | ||
1022 | /* Set FH wait threshold to maximum (HW error during stress W/A) */ | |
46bc8d4b | 1023 | il_set_bit(il, CSR_DBG_HPET_MEM_REG, |
be663ab6 WYG |
1024 | CSR_DBG_HPET_MEM_REG_VAL); |
1025 | ||
1026 | /* | |
1027 | * Enable HAP INTA (interrupt from management bus) to | |
1028 | * wake device's PCI Express link L1a -> L0s | |
25985edc | 1029 | * NOTE: This is no-op for 3945 (non-existent bit) |
be663ab6 | 1030 | */ |
46bc8d4b | 1031 | il_set_bit(il, CSR_HW_IF_CONFIG_REG, |
be663ab6 WYG |
1032 | CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); |
1033 | ||
1034 | /* | |
1035 | * HW bug W/A for instability in PCIe bus L0->L0S->L1 transition. | |
1036 | * Check if BIOS (or OS) enabled L1-ASPM on this device. | |
1037 | * If so (likely), disable L0S, so device moves directly L0->L1; | |
1038 | * costs negligible amount of power savings. | |
1039 | * If not (unlikely), enable L0S, so there is at least some | |
1040 | * power savings, even without L1. | |
1041 | */ | |
46bc8d4b SG |
1042 | if (il->cfg->base_params->set_l0s) { |
1043 | lctl = il_pcie_link_ctl(il); | |
be663ab6 WYG |
1044 | if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == |
1045 | PCI_CFG_LINK_CTRL_VAL_L1_EN) { | |
1046 | /* L1-ASPM enabled; disable(!) L0S */ | |
46bc8d4b | 1047 | il_set_bit(il, CSR_GIO_REG, |
be663ab6 | 1048 | CSR_GIO_REG_VAL_L0S_ENABLED); |
58de00a4 | 1049 | D_POWER("L1 Enabled; Disabling L0S\n"); |
be663ab6 WYG |
1050 | } else { |
1051 | /* L1-ASPM disabled; enable(!) L0S */ | |
46bc8d4b | 1052 | il_clear_bit(il, CSR_GIO_REG, |
be663ab6 | 1053 | CSR_GIO_REG_VAL_L0S_ENABLED); |
58de00a4 | 1054 | D_POWER("L1 Disabled; Enabling L0S\n"); |
be663ab6 WYG |
1055 | } |
1056 | } | |
1057 | ||
1058 | /* Configure analog phase-lock-loop before activating to D0A */ | |
46bc8d4b SG |
1059 | if (il->cfg->base_params->pll_cfg_val) |
1060 | il_set_bit(il, CSR_ANA_PLL_CFG, | |
1061 | il->cfg->base_params->pll_cfg_val); | |
be663ab6 WYG |
1062 | |
1063 | /* | |
1064 | * Set "initialization complete" bit to move adapter from | |
1065 | * D0U* --> D0A* (powered-up active) state. | |
1066 | */ | |
46bc8d4b | 1067 | il_set_bit(il, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
be663ab6 WYG |
1068 | |
1069 | /* | |
1070 | * Wait for clock stabilization; once stabilized, access to | |
db54eb57 | 1071 | * device-internal resources is supported, e.g. il_wr_prph() |
be663ab6 WYG |
1072 | * and accesses to uCode SRAM. |
1073 | */ | |
142b343f | 1074 | ret = _il_poll_bit(il, CSR_GP_CNTRL, |
be663ab6 WYG |
1075 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, |
1076 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); | |
1077 | if (ret < 0) { | |
58de00a4 | 1078 | D_INFO("Failed to init the card\n"); |
be663ab6 WYG |
1079 | goto out; |
1080 | } | |
1081 | ||
1082 | /* | |
1083 | * Enable DMA and BSM (if used) clocks, wait for them to stabilize. | |
1084 | * BSM (Boostrap State Machine) is only in 3945 and 4965. | |
1085 | * | |
1086 | * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits | |
1087 | * do not disable clocks. This preserves any hardware bits already | |
1088 | * set by default in "CLK_CTRL_REG" after reset. | |
1089 | */ | |
46bc8d4b | 1090 | if (il->cfg->base_params->use_bsm) |
db54eb57 | 1091 | il_wr_prph(il, APMG_CLK_EN_REG, |
be663ab6 WYG |
1092 | APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); |
1093 | else | |
db54eb57 | 1094 | il_wr_prph(il, APMG_CLK_EN_REG, |
be663ab6 WYG |
1095 | APMG_CLK_VAL_DMA_CLK_RQT); |
1096 | udelay(20); | |
1097 | ||
1098 | /* Disable L1-Active */ | |
46bc8d4b | 1099 | il_set_bits_prph(il, APMG_PCIDEV_STT_REG, |
be663ab6 WYG |
1100 | APMG_PCIDEV_STT_VAL_L1_ACT_DIS); |
1101 | ||
1102 | out: | |
1103 | return ret; | |
1104 | } | |
e2ebc833 | 1105 | EXPORT_SYMBOL(il_apm_init); |
be663ab6 WYG |
1106 | |
1107 | ||
46bc8d4b | 1108 | int il_set_tx_power(struct il_priv *il, s8 tx_power, bool force) |
be663ab6 WYG |
1109 | { |
1110 | int ret; | |
1111 | s8 prev_tx_power; | |
43f12d47 | 1112 | bool defer; |
7c2cde2e | 1113 | struct il_rxon_context *ctx = &il->ctx; |
be663ab6 | 1114 | |
46bc8d4b | 1115 | lockdep_assert_held(&il->mutex); |
be663ab6 | 1116 | |
46bc8d4b | 1117 | if (il->tx_power_user_lmt == tx_power && !force) |
be663ab6 WYG |
1118 | return 0; |
1119 | ||
46bc8d4b | 1120 | if (!il->cfg->ops->lib->send_tx_power) |
be663ab6 WYG |
1121 | return -EOPNOTSUPP; |
1122 | ||
332704a5 SG |
1123 | /* 0 dBm mean 1 milliwatt */ |
1124 | if (tx_power < 0) { | |
9406f797 | 1125 | IL_WARN( |
332704a5 SG |
1126 | "Requested user TXPOWER %d below 1 mW.\n", |
1127 | tx_power); | |
be663ab6 WYG |
1128 | return -EINVAL; |
1129 | } | |
1130 | ||
46bc8d4b | 1131 | if (tx_power > il->tx_power_device_lmt) { |
9406f797 | 1132 | IL_WARN( |
be663ab6 | 1133 | "Requested user TXPOWER %d above upper limit %d.\n", |
46bc8d4b | 1134 | tx_power, il->tx_power_device_lmt); |
be663ab6 WYG |
1135 | return -EINVAL; |
1136 | } | |
1137 | ||
46bc8d4b | 1138 | if (!il_is_ready_rf(il)) |
be663ab6 WYG |
1139 | return -EIO; |
1140 | ||
43f12d47 SG |
1141 | /* scan complete and commit_rxon use tx_power_next value, |
1142 | * it always need to be updated for newest request */ | |
46bc8d4b | 1143 | il->tx_power_next = tx_power; |
43f12d47 SG |
1144 | |
1145 | /* do not set tx power when scanning or channel changing */ | |
46bc8d4b | 1146 | defer = test_bit(STATUS_SCANNING, &il->status) || |
43f12d47 SG |
1147 | memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); |
1148 | if (defer && !force) { | |
58de00a4 | 1149 | D_INFO("Deferring tx power set\n"); |
be663ab6 WYG |
1150 | return 0; |
1151 | } | |
1152 | ||
46bc8d4b SG |
1153 | prev_tx_power = il->tx_power_user_lmt; |
1154 | il->tx_power_user_lmt = tx_power; | |
be663ab6 | 1155 | |
46bc8d4b | 1156 | ret = il->cfg->ops->lib->send_tx_power(il); |
be663ab6 WYG |
1157 | |
1158 | /* if fail to set tx_power, restore the orig. tx power */ | |
1159 | if (ret) { | |
46bc8d4b SG |
1160 | il->tx_power_user_lmt = prev_tx_power; |
1161 | il->tx_power_next = prev_tx_power; | |
be663ab6 WYG |
1162 | } |
1163 | return ret; | |
1164 | } | |
e2ebc833 | 1165 | EXPORT_SYMBOL(il_set_tx_power); |
be663ab6 | 1166 | |
46bc8d4b | 1167 | void il_send_bt_config(struct il_priv *il) |
be663ab6 | 1168 | { |
e2ebc833 | 1169 | struct il_bt_cmd bt_cmd = { |
be663ab6 WYG |
1170 | .lead_time = BT_LEAD_TIME_DEF, |
1171 | .max_kill = BT_MAX_KILL_DEF, | |
1172 | .kill_ack_mask = 0, | |
1173 | .kill_cts_mask = 0, | |
1174 | }; | |
1175 | ||
1176 | if (!bt_coex_active) | |
1177 | bt_cmd.flags = BT_COEX_DISABLE; | |
1178 | else | |
1179 | bt_cmd.flags = BT_COEX_ENABLE; | |
1180 | ||
58de00a4 | 1181 | D_INFO("BT coex %s\n", |
be663ab6 WYG |
1182 | (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); |
1183 | ||
46bc8d4b | 1184 | if (il_send_cmd_pdu(il, REPLY_BT_CONFIG, |
e2ebc833 | 1185 | sizeof(struct il_bt_cmd), &bt_cmd)) |
9406f797 | 1186 | IL_ERR("failed to send BT Coex Config\n"); |
be663ab6 | 1187 | } |
e2ebc833 | 1188 | EXPORT_SYMBOL(il_send_bt_config); |
be663ab6 | 1189 | |
ebf0d90d | 1190 | int il_send_stats_request(struct il_priv *il, u8 flags, bool clear) |
be663ab6 | 1191 | { |
ebf0d90d | 1192 | struct il_stats_cmd stats_cmd = { |
be663ab6 | 1193 | .configuration_flags = |
e2ebc833 | 1194 | clear ? IL_STATS_CONF_CLEAR_STATS : 0, |
be663ab6 WYG |
1195 | }; |
1196 | ||
1197 | if (flags & CMD_ASYNC) | |
46bc8d4b | 1198 | return il_send_cmd_pdu_async(il, REPLY_STATISTICS_CMD, |
ebf0d90d SG |
1199 | sizeof(struct il_stats_cmd), |
1200 | &stats_cmd, NULL); | |
be663ab6 | 1201 | else |
46bc8d4b | 1202 | return il_send_cmd_pdu(il, REPLY_STATISTICS_CMD, |
ebf0d90d SG |
1203 | sizeof(struct il_stats_cmd), |
1204 | &stats_cmd); | |
be663ab6 | 1205 | } |
ebf0d90d | 1206 | EXPORT_SYMBOL(il_send_stats_request); |
be663ab6 | 1207 | |
46bc8d4b | 1208 | void il_rx_pm_sleep_notif(struct il_priv *il, |
b73bb5f1 | 1209 | struct il_rx_buf *rxb) |
be663ab6 | 1210 | { |
d3175167 | 1211 | #ifdef CONFIG_IWLEGACY_DEBUG |
dcae1c64 | 1212 | struct il_rx_pkt *pkt = rxb_addr(rxb); |
e2ebc833 | 1213 | struct il_sleep_notification *sleep = &(pkt->u.sleep_notif); |
58de00a4 | 1214 | D_RX("sleep mode: %d, src: %d\n", |
be663ab6 WYG |
1215 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); |
1216 | #endif | |
1217 | } | |
e2ebc833 | 1218 | EXPORT_SYMBOL(il_rx_pm_sleep_notif); |
be663ab6 | 1219 | |
ebf0d90d | 1220 | void il_rx_pm_debug_stats_notif(struct il_priv *il, |
b73bb5f1 | 1221 | struct il_rx_buf *rxb) |
be663ab6 | 1222 | { |
dcae1c64 | 1223 | struct il_rx_pkt *pkt = rxb_addr(rxb); |
be663ab6 | 1224 | u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; |
58de00a4 | 1225 | D_RADIO("Dumping %d bytes of unhandled " |
be663ab6 | 1226 | "notification for %s:\n", len, |
e2ebc833 | 1227 | il_get_cmd_string(pkt->hdr.cmd)); |
46bc8d4b | 1228 | il_print_hex_dump(il, IL_DL_RADIO, pkt->u.raw, len); |
be663ab6 | 1229 | } |
ebf0d90d | 1230 | EXPORT_SYMBOL(il_rx_pm_debug_stats_notif); |
be663ab6 | 1231 | |
46bc8d4b | 1232 | void il_rx_reply_error(struct il_priv *il, |
b73bb5f1 | 1233 | struct il_rx_buf *rxb) |
be663ab6 | 1234 | { |
dcae1c64 | 1235 | struct il_rx_pkt *pkt = rxb_addr(rxb); |
be663ab6 | 1236 | |
9406f797 | 1237 | IL_ERR("Error Reply type 0x%08X cmd %s (0x%02X) " |
be663ab6 WYG |
1238 | "seq 0x%04X ser 0x%08X\n", |
1239 | le32_to_cpu(pkt->u.err_resp.error_type), | |
e2ebc833 | 1240 | il_get_cmd_string(pkt->u.err_resp.cmd_id), |
be663ab6 WYG |
1241 | pkt->u.err_resp.cmd_id, |
1242 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | |
1243 | le32_to_cpu(pkt->u.err_resp.error_info)); | |
1244 | } | |
e2ebc833 | 1245 | EXPORT_SYMBOL(il_rx_reply_error); |
be663ab6 | 1246 | |
46bc8d4b | 1247 | void il_clear_isr_stats(struct il_priv *il) |
be663ab6 | 1248 | { |
46bc8d4b | 1249 | memset(&il->isr_stats, 0, sizeof(il->isr_stats)); |
be663ab6 WYG |
1250 | } |
1251 | ||
e2ebc833 | 1252 | int il_mac_conf_tx(struct ieee80211_hw *hw, |
8a3a3c85 | 1253 | struct ieee80211_vif *vif, u16 queue, |
be663ab6 WYG |
1254 | const struct ieee80211_tx_queue_params *params) |
1255 | { | |
46bc8d4b | 1256 | struct il_priv *il = hw->priv; |
e2ebc833 | 1257 | struct il_rxon_context *ctx; |
be663ab6 WYG |
1258 | unsigned long flags; |
1259 | int q; | |
1260 | ||
58de00a4 | 1261 | D_MAC80211("enter\n"); |
be663ab6 | 1262 | |
46bc8d4b | 1263 | if (!il_is_ready_rf(il)) { |
58de00a4 | 1264 | D_MAC80211("leave - RF not ready\n"); |
be663ab6 WYG |
1265 | return -EIO; |
1266 | } | |
1267 | ||
1268 | if (queue >= AC_NUM) { | |
58de00a4 | 1269 | D_MAC80211("leave - queue >= AC_NUM %d\n", queue); |
be663ab6 WYG |
1270 | return 0; |
1271 | } | |
1272 | ||
1273 | q = AC_NUM - 1 - queue; | |
1274 | ||
46bc8d4b | 1275 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 | 1276 | |
46bc8d4b | 1277 | for_each_context(il, ctx) { |
be663ab6 WYG |
1278 | ctx->qos_data.def_qos_parm.ac[q].cw_min = |
1279 | cpu_to_le16(params->cw_min); | |
1280 | ctx->qos_data.def_qos_parm.ac[q].cw_max = | |
1281 | cpu_to_le16(params->cw_max); | |
1282 | ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; | |
1283 | ctx->qos_data.def_qos_parm.ac[q].edca_txop = | |
1284 | cpu_to_le16((params->txop * 32)); | |
1285 | ||
1286 | ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; | |
1287 | } | |
1288 | ||
46bc8d4b | 1289 | spin_unlock_irqrestore(&il->lock, flags); |
be663ab6 | 1290 | |
58de00a4 | 1291 | D_MAC80211("leave\n"); |
be663ab6 WYG |
1292 | return 0; |
1293 | } | |
e2ebc833 | 1294 | EXPORT_SYMBOL(il_mac_conf_tx); |
be663ab6 | 1295 | |
e2ebc833 | 1296 | int il_mac_tx_last_beacon(struct ieee80211_hw *hw) |
be663ab6 | 1297 | { |
46bc8d4b | 1298 | struct il_priv *il = hw->priv; |
be663ab6 | 1299 | |
46bc8d4b | 1300 | return il->ibss_manager == IL_IBSS_MANAGER; |
be663ab6 | 1301 | } |
e2ebc833 | 1302 | EXPORT_SYMBOL_GPL(il_mac_tx_last_beacon); |
be663ab6 WYG |
1303 | |
1304 | static int | |
46bc8d4b | 1305 | il_set_mode(struct il_priv *il, struct il_rxon_context *ctx) |
be663ab6 | 1306 | { |
46bc8d4b | 1307 | il_connection_init_rx_config(il, ctx); |
be663ab6 | 1308 | |
46bc8d4b SG |
1309 | if (il->cfg->ops->hcmd->set_rxon_chain) |
1310 | il->cfg->ops->hcmd->set_rxon_chain(il, ctx); | |
be663ab6 | 1311 | |
46bc8d4b | 1312 | return il_commit_rxon(il, ctx); |
be663ab6 WYG |
1313 | } |
1314 | ||
46bc8d4b | 1315 | static int il_setup_interface(struct il_priv *il, |
e2ebc833 | 1316 | struct il_rxon_context *ctx) |
be663ab6 WYG |
1317 | { |
1318 | struct ieee80211_vif *vif = ctx->vif; | |
1319 | int err; | |
1320 | ||
46bc8d4b | 1321 | lockdep_assert_held(&il->mutex); |
be663ab6 WYG |
1322 | |
1323 | /* | |
1324 | * This variable will be correct only when there's just | |
1325 | * a single context, but all code using it is for hardware | |
1326 | * that supports only one context. | |
1327 | */ | |
46bc8d4b | 1328 | il->iw_mode = vif->type; |
be663ab6 WYG |
1329 | |
1330 | ctx->is_active = true; | |
1331 | ||
46bc8d4b | 1332 | err = il_set_mode(il, ctx); |
be663ab6 WYG |
1333 | if (err) { |
1334 | if (!ctx->always_active) | |
1335 | ctx->is_active = false; | |
1336 | return err; | |
1337 | } | |
1338 | ||
1339 | return 0; | |
1340 | } | |
1341 | ||
1342 | int | |
e2ebc833 | 1343 | il_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
be663ab6 | 1344 | { |
46bc8d4b | 1345 | struct il_priv *il = hw->priv; |
e2ebc833 SG |
1346 | struct il_vif_priv *vif_priv = (void *)vif->drv_priv; |
1347 | struct il_rxon_context *tmp, *ctx = NULL; | |
be663ab6 WYG |
1348 | int err; |
1349 | ||
58de00a4 | 1350 | D_MAC80211("enter: type %d, addr %pM\n", |
be663ab6 WYG |
1351 | vif->type, vif->addr); |
1352 | ||
46bc8d4b | 1353 | mutex_lock(&il->mutex); |
be663ab6 | 1354 | |
46bc8d4b | 1355 | if (!il_is_ready_rf(il)) { |
9406f797 | 1356 | IL_WARN("Try to add interface when device not ready\n"); |
be663ab6 WYG |
1357 | err = -EINVAL; |
1358 | goto out; | |
1359 | } | |
1360 | ||
46bc8d4b | 1361 | for_each_context(il, tmp) { |
be663ab6 WYG |
1362 | u32 possible_modes = |
1363 | tmp->interface_modes | tmp->exclusive_interface_modes; | |
1364 | ||
1365 | if (tmp->vif) { | |
1366 | /* check if this busy context is exclusive */ | |
1367 | if (tmp->exclusive_interface_modes & | |
1368 | BIT(tmp->vif->type)) { | |
1369 | err = -EINVAL; | |
1370 | goto out; | |
1371 | } | |
1372 | continue; | |
1373 | } | |
1374 | ||
1375 | if (!(possible_modes & BIT(vif->type))) | |
1376 | continue; | |
1377 | ||
1378 | /* have maybe usable context w/o interface */ | |
1379 | ctx = tmp; | |
1380 | break; | |
1381 | } | |
1382 | ||
1383 | if (!ctx) { | |
1384 | err = -EOPNOTSUPP; | |
1385 | goto out; | |
1386 | } | |
1387 | ||
1388 | vif_priv->ctx = ctx; | |
1389 | ctx->vif = vif; | |
1390 | ||
46bc8d4b | 1391 | err = il_setup_interface(il, ctx); |
be663ab6 WYG |
1392 | if (!err) |
1393 | goto out; | |
1394 | ||
1395 | ctx->vif = NULL; | |
46bc8d4b | 1396 | il->iw_mode = NL80211_IFTYPE_STATION; |
be663ab6 | 1397 | out: |
46bc8d4b | 1398 | mutex_unlock(&il->mutex); |
be663ab6 | 1399 | |
58de00a4 | 1400 | D_MAC80211("leave\n"); |
be663ab6 WYG |
1401 | return err; |
1402 | } | |
e2ebc833 | 1403 | EXPORT_SYMBOL(il_mac_add_interface); |
be663ab6 | 1404 | |
46bc8d4b | 1405 | static void il_teardown_interface(struct il_priv *il, |
be663ab6 WYG |
1406 | struct ieee80211_vif *vif, |
1407 | bool mode_change) | |
1408 | { | |
e2ebc833 | 1409 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
be663ab6 | 1410 | |
46bc8d4b | 1411 | lockdep_assert_held(&il->mutex); |
be663ab6 | 1412 | |
46bc8d4b SG |
1413 | if (il->scan_vif == vif) { |
1414 | il_scan_cancel_timeout(il, 200); | |
1415 | il_force_scan_end(il); | |
be663ab6 WYG |
1416 | } |
1417 | ||
1418 | if (!mode_change) { | |
46bc8d4b | 1419 | il_set_mode(il, ctx); |
be663ab6 WYG |
1420 | if (!ctx->always_active) |
1421 | ctx->is_active = false; | |
1422 | } | |
1423 | } | |
1424 | ||
e2ebc833 | 1425 | void il_mac_remove_interface(struct ieee80211_hw *hw, |
be663ab6 WYG |
1426 | struct ieee80211_vif *vif) |
1427 | { | |
46bc8d4b | 1428 | struct il_priv *il = hw->priv; |
e2ebc833 | 1429 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
be663ab6 | 1430 | |
58de00a4 | 1431 | D_MAC80211("enter\n"); |
be663ab6 | 1432 | |
46bc8d4b | 1433 | mutex_lock(&il->mutex); |
be663ab6 WYG |
1434 | |
1435 | WARN_ON(ctx->vif != vif); | |
1436 | ctx->vif = NULL; | |
1437 | ||
46bc8d4b | 1438 | il_teardown_interface(il, vif, false); |
be663ab6 | 1439 | |
46bc8d4b SG |
1440 | memset(il->bssid, 0, ETH_ALEN); |
1441 | mutex_unlock(&il->mutex); | |
be663ab6 | 1442 | |
58de00a4 | 1443 | D_MAC80211("leave\n"); |
be663ab6 WYG |
1444 | |
1445 | } | |
e2ebc833 | 1446 | EXPORT_SYMBOL(il_mac_remove_interface); |
be663ab6 | 1447 | |
46bc8d4b | 1448 | int il_alloc_txq_mem(struct il_priv *il) |
be663ab6 | 1449 | { |
46bc8d4b SG |
1450 | if (!il->txq) |
1451 | il->txq = kzalloc( | |
e2ebc833 | 1452 | sizeof(struct il_tx_queue) * |
46bc8d4b | 1453 | il->cfg->base_params->num_of_queues, |
be663ab6 | 1454 | GFP_KERNEL); |
46bc8d4b | 1455 | if (!il->txq) { |
9406f797 | 1456 | IL_ERR("Not enough memory for txq\n"); |
be663ab6 WYG |
1457 | return -ENOMEM; |
1458 | } | |
1459 | return 0; | |
1460 | } | |
e2ebc833 | 1461 | EXPORT_SYMBOL(il_alloc_txq_mem); |
be663ab6 | 1462 | |
46bc8d4b | 1463 | void il_txq_mem(struct il_priv *il) |
be663ab6 | 1464 | { |
46bc8d4b SG |
1465 | kfree(il->txq); |
1466 | il->txq = NULL; | |
be663ab6 | 1467 | } |
e2ebc833 | 1468 | EXPORT_SYMBOL(il_txq_mem); |
be663ab6 | 1469 | |
d3175167 | 1470 | #ifdef CONFIG_IWLEGACY_DEBUGFS |
be663ab6 | 1471 | |
e2ebc833 | 1472 | #define IL_TRAFFIC_DUMP_SIZE (IL_TRAFFIC_ENTRY_SIZE * IL_TRAFFIC_ENTRIES) |
be663ab6 | 1473 | |
46bc8d4b | 1474 | void il_reset_traffic_log(struct il_priv *il) |
be663ab6 | 1475 | { |
46bc8d4b SG |
1476 | il->tx_traffic_idx = 0; |
1477 | il->rx_traffic_idx = 0; | |
1478 | if (il->tx_traffic) | |
1479 | memset(il->tx_traffic, 0, IL_TRAFFIC_DUMP_SIZE); | |
1480 | if (il->rx_traffic) | |
1481 | memset(il->rx_traffic, 0, IL_TRAFFIC_DUMP_SIZE); | |
be663ab6 WYG |
1482 | } |
1483 | ||
46bc8d4b | 1484 | int il_alloc_traffic_mem(struct il_priv *il) |
be663ab6 | 1485 | { |
e2ebc833 | 1486 | u32 traffic_size = IL_TRAFFIC_DUMP_SIZE; |
be663ab6 | 1487 | |
d2ddf621 | 1488 | if (il_debug_level & IL_DL_TX) { |
46bc8d4b SG |
1489 | if (!il->tx_traffic) { |
1490 | il->tx_traffic = | |
be663ab6 | 1491 | kzalloc(traffic_size, GFP_KERNEL); |
46bc8d4b | 1492 | if (!il->tx_traffic) |
be663ab6 WYG |
1493 | return -ENOMEM; |
1494 | } | |
1495 | } | |
d2ddf621 | 1496 | if (il_debug_level & IL_DL_RX) { |
46bc8d4b SG |
1497 | if (!il->rx_traffic) { |
1498 | il->rx_traffic = | |
be663ab6 | 1499 | kzalloc(traffic_size, GFP_KERNEL); |
46bc8d4b | 1500 | if (!il->rx_traffic) |
be663ab6 WYG |
1501 | return -ENOMEM; |
1502 | } | |
1503 | } | |
46bc8d4b | 1504 | il_reset_traffic_log(il); |
be663ab6 WYG |
1505 | return 0; |
1506 | } | |
e2ebc833 | 1507 | EXPORT_SYMBOL(il_alloc_traffic_mem); |
be663ab6 | 1508 | |
46bc8d4b | 1509 | void il_free_traffic_mem(struct il_priv *il) |
be663ab6 | 1510 | { |
46bc8d4b SG |
1511 | kfree(il->tx_traffic); |
1512 | il->tx_traffic = NULL; | |
be663ab6 | 1513 | |
46bc8d4b SG |
1514 | kfree(il->rx_traffic); |
1515 | il->rx_traffic = NULL; | |
be663ab6 | 1516 | } |
e2ebc833 | 1517 | EXPORT_SYMBOL(il_free_traffic_mem); |
be663ab6 | 1518 | |
46bc8d4b | 1519 | void il_dbg_log_tx_data_frame(struct il_priv *il, |
be663ab6 WYG |
1520 | u16 length, struct ieee80211_hdr *header) |
1521 | { | |
1522 | __le16 fc; | |
1523 | u16 len; | |
1524 | ||
d2ddf621 | 1525 | if (likely(!(il_debug_level & IL_DL_TX))) |
be663ab6 WYG |
1526 | return; |
1527 | ||
46bc8d4b | 1528 | if (!il->tx_traffic) |
be663ab6 WYG |
1529 | return; |
1530 | ||
1531 | fc = header->frame_control; | |
1532 | if (ieee80211_is_data(fc)) { | |
e2ebc833 SG |
1533 | len = (length > IL_TRAFFIC_ENTRY_SIZE) |
1534 | ? IL_TRAFFIC_ENTRY_SIZE : length; | |
46bc8d4b SG |
1535 | memcpy((il->tx_traffic + |
1536 | (il->tx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), | |
be663ab6 | 1537 | header, len); |
46bc8d4b SG |
1538 | il->tx_traffic_idx = |
1539 | (il->tx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES; | |
be663ab6 WYG |
1540 | } |
1541 | } | |
e2ebc833 | 1542 | EXPORT_SYMBOL(il_dbg_log_tx_data_frame); |
be663ab6 | 1543 | |
46bc8d4b | 1544 | void il_dbg_log_rx_data_frame(struct il_priv *il, |
be663ab6 WYG |
1545 | u16 length, struct ieee80211_hdr *header) |
1546 | { | |
1547 | __le16 fc; | |
1548 | u16 len; | |
1549 | ||
d2ddf621 | 1550 | if (likely(!(il_debug_level & IL_DL_RX))) |
be663ab6 WYG |
1551 | return; |
1552 | ||
46bc8d4b | 1553 | if (!il->rx_traffic) |
be663ab6 WYG |
1554 | return; |
1555 | ||
1556 | fc = header->frame_control; | |
1557 | if (ieee80211_is_data(fc)) { | |
e2ebc833 SG |
1558 | len = (length > IL_TRAFFIC_ENTRY_SIZE) |
1559 | ? IL_TRAFFIC_ENTRY_SIZE : length; | |
46bc8d4b SG |
1560 | memcpy((il->rx_traffic + |
1561 | (il->rx_traffic_idx * IL_TRAFFIC_ENTRY_SIZE)), | |
be663ab6 | 1562 | header, len); |
46bc8d4b SG |
1563 | il->rx_traffic_idx = |
1564 | (il->rx_traffic_idx + 1) % IL_TRAFFIC_ENTRIES; | |
be663ab6 WYG |
1565 | } |
1566 | } | |
e2ebc833 | 1567 | EXPORT_SYMBOL(il_dbg_log_rx_data_frame); |
be663ab6 | 1568 | |
e2ebc833 | 1569 | const char *il_get_mgmt_string(int cmd) |
be663ab6 WYG |
1570 | { |
1571 | switch (cmd) { | |
e2ebc833 SG |
1572 | IL_CMD(MANAGEMENT_ASSOC_REQ); |
1573 | IL_CMD(MANAGEMENT_ASSOC_RESP); | |
1574 | IL_CMD(MANAGEMENT_REASSOC_REQ); | |
1575 | IL_CMD(MANAGEMENT_REASSOC_RESP); | |
1576 | IL_CMD(MANAGEMENT_PROBE_REQ); | |
1577 | IL_CMD(MANAGEMENT_PROBE_RESP); | |
1578 | IL_CMD(MANAGEMENT_BEACON); | |
1579 | IL_CMD(MANAGEMENT_ATIM); | |
1580 | IL_CMD(MANAGEMENT_DISASSOC); | |
1581 | IL_CMD(MANAGEMENT_AUTH); | |
1582 | IL_CMD(MANAGEMENT_DEAUTH); | |
1583 | IL_CMD(MANAGEMENT_ACTION); | |
be663ab6 WYG |
1584 | default: |
1585 | return "UNKNOWN"; | |
1586 | ||
1587 | } | |
1588 | } | |
1589 | ||
e2ebc833 | 1590 | const char *il_get_ctrl_string(int cmd) |
be663ab6 WYG |
1591 | { |
1592 | switch (cmd) { | |
e2ebc833 SG |
1593 | IL_CMD(CONTROL_BACK_REQ); |
1594 | IL_CMD(CONTROL_BACK); | |
1595 | IL_CMD(CONTROL_PSPOLL); | |
1596 | IL_CMD(CONTROL_RTS); | |
1597 | IL_CMD(CONTROL_CTS); | |
1598 | IL_CMD(CONTROL_ACK); | |
1599 | IL_CMD(CONTROL_CFEND); | |
1600 | IL_CMD(CONTROL_CFENDACK); | |
be663ab6 WYG |
1601 | default: |
1602 | return "UNKNOWN"; | |
1603 | ||
1604 | } | |
1605 | } | |
1606 | ||
46bc8d4b | 1607 | void il_clear_traffic_stats(struct il_priv *il) |
be663ab6 | 1608 | { |
46bc8d4b SG |
1609 | memset(&il->tx_stats, 0, sizeof(struct traffic_stats)); |
1610 | memset(&il->rx_stats, 0, sizeof(struct traffic_stats)); | |
be663ab6 WYG |
1611 | } |
1612 | ||
1613 | /* | |
d3175167 | 1614 | * if CONFIG_IWLEGACY_DEBUGFS defined, |
e2ebc833 | 1615 | * il_update_stats function will |
be663ab6 | 1616 | * record all the MGMT, CTRL and DATA pkt for both TX and Rx pass |
ebf0d90d | 1617 | * Use debugFs to display the rx/rx_stats |
d3175167 | 1618 | * if CONFIG_IWLEGACY_DEBUGFS not being defined, then no MGMT and CTRL |
be663ab6 | 1619 | * information will be recorded, but DATA pkt still will be recorded |
e2ebc833 | 1620 | * for the reason of il_led.c need to control the led blinking based on |
be663ab6 WYG |
1621 | * number of tx and rx data. |
1622 | * | |
1623 | */ | |
1624 | void | |
46bc8d4b | 1625 | il_update_stats(struct il_priv *il, bool is_tx, __le16 fc, u16 len) |
be663ab6 WYG |
1626 | { |
1627 | struct traffic_stats *stats; | |
1628 | ||
1629 | if (is_tx) | |
46bc8d4b | 1630 | stats = &il->tx_stats; |
be663ab6 | 1631 | else |
46bc8d4b | 1632 | stats = &il->rx_stats; |
be663ab6 WYG |
1633 | |
1634 | if (ieee80211_is_mgmt(fc)) { | |
1635 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | |
1636 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): | |
1637 | stats->mgmt[MANAGEMENT_ASSOC_REQ]++; | |
1638 | break; | |
1639 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): | |
1640 | stats->mgmt[MANAGEMENT_ASSOC_RESP]++; | |
1641 | break; | |
1642 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): | |
1643 | stats->mgmt[MANAGEMENT_REASSOC_REQ]++; | |
1644 | break; | |
1645 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): | |
1646 | stats->mgmt[MANAGEMENT_REASSOC_RESP]++; | |
1647 | break; | |
1648 | case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): | |
1649 | stats->mgmt[MANAGEMENT_PROBE_REQ]++; | |
1650 | break; | |
1651 | case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): | |
1652 | stats->mgmt[MANAGEMENT_PROBE_RESP]++; | |
1653 | break; | |
1654 | case cpu_to_le16(IEEE80211_STYPE_BEACON): | |
1655 | stats->mgmt[MANAGEMENT_BEACON]++; | |
1656 | break; | |
1657 | case cpu_to_le16(IEEE80211_STYPE_ATIM): | |
1658 | stats->mgmt[MANAGEMENT_ATIM]++; | |
1659 | break; | |
1660 | case cpu_to_le16(IEEE80211_STYPE_DISASSOC): | |
1661 | stats->mgmt[MANAGEMENT_DISASSOC]++; | |
1662 | break; | |
1663 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | |
1664 | stats->mgmt[MANAGEMENT_AUTH]++; | |
1665 | break; | |
1666 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | |
1667 | stats->mgmt[MANAGEMENT_DEAUTH]++; | |
1668 | break; | |
1669 | case cpu_to_le16(IEEE80211_STYPE_ACTION): | |
1670 | stats->mgmt[MANAGEMENT_ACTION]++; | |
1671 | break; | |
1672 | } | |
1673 | } else if (ieee80211_is_ctl(fc)) { | |
1674 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | |
1675 | case cpu_to_le16(IEEE80211_STYPE_BACK_REQ): | |
1676 | stats->ctrl[CONTROL_BACK_REQ]++; | |
1677 | break; | |
1678 | case cpu_to_le16(IEEE80211_STYPE_BACK): | |
1679 | stats->ctrl[CONTROL_BACK]++; | |
1680 | break; | |
1681 | case cpu_to_le16(IEEE80211_STYPE_PSPOLL): | |
1682 | stats->ctrl[CONTROL_PSPOLL]++; | |
1683 | break; | |
1684 | case cpu_to_le16(IEEE80211_STYPE_RTS): | |
1685 | stats->ctrl[CONTROL_RTS]++; | |
1686 | break; | |
1687 | case cpu_to_le16(IEEE80211_STYPE_CTS): | |
1688 | stats->ctrl[CONTROL_CTS]++; | |
1689 | break; | |
1690 | case cpu_to_le16(IEEE80211_STYPE_ACK): | |
1691 | stats->ctrl[CONTROL_ACK]++; | |
1692 | break; | |
1693 | case cpu_to_le16(IEEE80211_STYPE_CFEND): | |
1694 | stats->ctrl[CONTROL_CFEND]++; | |
1695 | break; | |
1696 | case cpu_to_le16(IEEE80211_STYPE_CFENDACK): | |
1697 | stats->ctrl[CONTROL_CFENDACK]++; | |
1698 | break; | |
1699 | } | |
1700 | } else { | |
1701 | /* data */ | |
1702 | stats->data_cnt++; | |
1703 | stats->data_bytes += len; | |
1704 | } | |
1705 | } | |
e2ebc833 | 1706 | EXPORT_SYMBOL(il_update_stats); |
be663ab6 WYG |
1707 | #endif |
1708 | ||
46bc8d4b | 1709 | int il_force_reset(struct il_priv *il, bool external) |
be663ab6 | 1710 | { |
e2ebc833 | 1711 | struct il_force_reset *force_reset; |
be663ab6 | 1712 | |
46bc8d4b | 1713 | if (test_bit(STATUS_EXIT_PENDING, &il->status)) |
be663ab6 WYG |
1714 | return -EINVAL; |
1715 | ||
46bc8d4b | 1716 | force_reset = &il->force_reset; |
be663ab6 WYG |
1717 | force_reset->reset_request_count++; |
1718 | if (!external) { | |
1719 | if (force_reset->last_force_reset_jiffies && | |
1720 | time_after(force_reset->last_force_reset_jiffies + | |
1721 | force_reset->reset_duration, jiffies)) { | |
58de00a4 | 1722 | D_INFO("force reset rejected\n"); |
be663ab6 WYG |
1723 | force_reset->reset_reject_count++; |
1724 | return -EAGAIN; | |
1725 | } | |
1726 | } | |
1727 | force_reset->reset_success_count++; | |
1728 | force_reset->last_force_reset_jiffies = jiffies; | |
dd6d2a8a SG |
1729 | |
1730 | /* | |
1731 | * if the request is from external(ex: debugfs), | |
1732 | * then always perform the request in regardless the module | |
1733 | * parameter setting | |
1734 | * if the request is from internal (uCode error or driver | |
1735 | * detect failure), then fw_restart module parameter | |
1736 | * need to be check before performing firmware reload | |
1737 | */ | |
1738 | ||
46bc8d4b | 1739 | if (!external && !il->cfg->mod_params->restart_fw) { |
58de00a4 | 1740 | D_INFO("Cancel firmware reload based on " |
dd6d2a8a SG |
1741 | "module parameter setting\n"); |
1742 | return 0; | |
be663ab6 | 1743 | } |
dd6d2a8a | 1744 | |
9406f797 | 1745 | IL_ERR("On demand firmware reload\n"); |
dd6d2a8a | 1746 | |
e2ebc833 | 1747 | /* Set the FW error flag -- cleared on il_down */ |
46bc8d4b SG |
1748 | set_bit(STATUS_FW_ERROR, &il->status); |
1749 | wake_up(&il->wait_command_queue); | |
dd6d2a8a SG |
1750 | /* |
1751 | * Keep the restart process from trying to send host | |
1752 | * commands by clearing the INIT status bit | |
1753 | */ | |
46bc8d4b SG |
1754 | clear_bit(STATUS_READY, &il->status); |
1755 | queue_work(il->workqueue, &il->restart); | |
dd6d2a8a | 1756 | |
be663ab6 WYG |
1757 | return 0; |
1758 | } | |
1759 | ||
1760 | int | |
e2ebc833 | 1761 | il_mac_change_interface(struct ieee80211_hw *hw, |
be663ab6 WYG |
1762 | struct ieee80211_vif *vif, |
1763 | enum nl80211_iftype newtype, bool newp2p) | |
1764 | { | |
46bc8d4b | 1765 | struct il_priv *il = hw->priv; |
e2ebc833 SG |
1766 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
1767 | struct il_rxon_context *tmp; | |
be663ab6 WYG |
1768 | u32 interface_modes; |
1769 | int err; | |
1770 | ||
1771 | newtype = ieee80211_iftype_p2p(newtype, newp2p); | |
1772 | ||
46bc8d4b | 1773 | mutex_lock(&il->mutex); |
be663ab6 | 1774 | |
46bc8d4b | 1775 | if (!ctx->vif || !il_is_ready_rf(il)) { |
ffd8c746 JB |
1776 | /* |
1777 | * Huh? But wait ... this can maybe happen when | |
1778 | * we're in the middle of a firmware restart! | |
1779 | */ | |
1780 | err = -EBUSY; | |
1781 | goto out; | |
1782 | } | |
1783 | ||
be663ab6 WYG |
1784 | interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; |
1785 | ||
1786 | if (!(interface_modes & BIT(newtype))) { | |
1787 | err = -EBUSY; | |
1788 | goto out; | |
1789 | } | |
1790 | ||
1791 | if (ctx->exclusive_interface_modes & BIT(newtype)) { | |
46bc8d4b | 1792 | for_each_context(il, tmp) { |
be663ab6 WYG |
1793 | if (ctx == tmp) |
1794 | continue; | |
1795 | ||
1796 | if (!tmp->vif) | |
1797 | continue; | |
1798 | ||
1799 | /* | |
1800 | * The current mode switch would be exclusive, but | |
1801 | * another context is active ... refuse the switch. | |
1802 | */ | |
1803 | err = -EBUSY; | |
1804 | goto out; | |
1805 | } | |
1806 | } | |
1807 | ||
1808 | /* success */ | |
46bc8d4b | 1809 | il_teardown_interface(il, vif, true); |
be663ab6 | 1810 | vif->type = newtype; |
ffd8c746 | 1811 | vif->p2p = newp2p; |
46bc8d4b | 1812 | err = il_setup_interface(il, ctx); |
be663ab6 WYG |
1813 | WARN_ON(err); |
1814 | /* | |
1815 | * We've switched internally, but submitting to the | |
1816 | * device may have failed for some reason. Mask this | |
1817 | * error, because otherwise mac80211 will not switch | |
1818 | * (and set the interface type back) and we'll be | |
1819 | * out of sync with it. | |
1820 | */ | |
1821 | err = 0; | |
1822 | ||
1823 | out: | |
46bc8d4b | 1824 | mutex_unlock(&il->mutex); |
be663ab6 WYG |
1825 | return err; |
1826 | } | |
e2ebc833 | 1827 | EXPORT_SYMBOL(il_mac_change_interface); |
be663ab6 WYG |
1828 | |
1829 | /* | |
1830 | * On every watchdog tick we check (latest) time stamp. If it does not | |
1831 | * change during timeout period and queue is not empty we reset firmware. | |
1832 | */ | |
46bc8d4b | 1833 | static int il_check_stuck_queue(struct il_priv *il, int cnt) |
be663ab6 | 1834 | { |
46bc8d4b | 1835 | struct il_tx_queue *txq = &il->txq[cnt]; |
e2ebc833 | 1836 | struct il_queue *q = &txq->q; |
be663ab6 WYG |
1837 | unsigned long timeout; |
1838 | int ret; | |
1839 | ||
1840 | if (q->read_ptr == q->write_ptr) { | |
1841 | txq->time_stamp = jiffies; | |
1842 | return 0; | |
1843 | } | |
1844 | ||
1845 | timeout = txq->time_stamp + | |
46bc8d4b | 1846 | msecs_to_jiffies(il->cfg->base_params->wd_timeout); |
be663ab6 WYG |
1847 | |
1848 | if (time_after(jiffies, timeout)) { | |
9406f797 | 1849 | IL_ERR("Queue %d stuck for %u ms.\n", |
46bc8d4b SG |
1850 | q->id, il->cfg->base_params->wd_timeout); |
1851 | ret = il_force_reset(il, false); | |
be663ab6 WYG |
1852 | return (ret == -EAGAIN) ? 0 : 1; |
1853 | } | |
1854 | ||
1855 | return 0; | |
1856 | } | |
1857 | ||
1858 | /* | |
1859 | * Making watchdog tick be a quarter of timeout assure we will | |
1860 | * discover the queue hung between timeout and 1.25*timeout | |
1861 | */ | |
e2ebc833 | 1862 | #define IL_WD_TICK(timeout) ((timeout) / 4) |
be663ab6 WYG |
1863 | |
1864 | /* | |
1865 | * Watchdog timer callback, we check each tx queue for stuck, if if hung | |
1866 | * we reset the firmware. If everything is fine just rearm the timer. | |
1867 | */ | |
e2ebc833 | 1868 | void il_bg_watchdog(unsigned long data) |
be663ab6 | 1869 | { |
46bc8d4b | 1870 | struct il_priv *il = (struct il_priv *)data; |
be663ab6 WYG |
1871 | int cnt; |
1872 | unsigned long timeout; | |
1873 | ||
46bc8d4b | 1874 | if (test_bit(STATUS_EXIT_PENDING, &il->status)) |
be663ab6 WYG |
1875 | return; |
1876 | ||
46bc8d4b | 1877 | timeout = il->cfg->base_params->wd_timeout; |
be663ab6 WYG |
1878 | if (timeout == 0) |
1879 | return; | |
1880 | ||
1881 | /* monitor and check for stuck cmd queue */ | |
46bc8d4b | 1882 | if (il_check_stuck_queue(il, il->cmd_queue)) |
be663ab6 WYG |
1883 | return; |
1884 | ||
1885 | /* monitor and check for other stuck queues */ | |
46bc8d4b SG |
1886 | if (il_is_any_associated(il)) { |
1887 | for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { | |
be663ab6 | 1888 | /* skip as we already checked the command queue */ |
46bc8d4b | 1889 | if (cnt == il->cmd_queue) |
be663ab6 | 1890 | continue; |
46bc8d4b | 1891 | if (il_check_stuck_queue(il, cnt)) |
be663ab6 WYG |
1892 | return; |
1893 | } | |
1894 | } | |
1895 | ||
46bc8d4b | 1896 | mod_timer(&il->watchdog, jiffies + |
e2ebc833 | 1897 | msecs_to_jiffies(IL_WD_TICK(timeout))); |
be663ab6 | 1898 | } |
e2ebc833 | 1899 | EXPORT_SYMBOL(il_bg_watchdog); |
be663ab6 | 1900 | |
46bc8d4b | 1901 | void il_setup_watchdog(struct il_priv *il) |
be663ab6 | 1902 | { |
46bc8d4b | 1903 | unsigned int timeout = il->cfg->base_params->wd_timeout; |
be663ab6 WYG |
1904 | |
1905 | if (timeout) | |
46bc8d4b | 1906 | mod_timer(&il->watchdog, |
e2ebc833 | 1907 | jiffies + msecs_to_jiffies(IL_WD_TICK(timeout))); |
be663ab6 | 1908 | else |
46bc8d4b | 1909 | del_timer(&il->watchdog); |
be663ab6 | 1910 | } |
e2ebc833 | 1911 | EXPORT_SYMBOL(il_setup_watchdog); |
be663ab6 WYG |
1912 | |
1913 | /* | |
1914 | * extended beacon time format | |
1915 | * time in usec will be changed into a 32-bit value in extended:internal format | |
1916 | * the extended part is the beacon counts | |
1917 | * the internal part is the time in usec within one beacon interval | |
1918 | */ | |
1919 | u32 | |
46bc8d4b | 1920 | il_usecs_to_beacons(struct il_priv *il, |
be663ab6 WYG |
1921 | u32 usec, u32 beacon_interval) |
1922 | { | |
1923 | u32 quot; | |
1924 | u32 rem; | |
1925 | u32 interval = beacon_interval * TIME_UNIT; | |
1926 | ||
1927 | if (!interval || !usec) | |
1928 | return 0; | |
1929 | ||
1930 | quot = (usec / interval) & | |
46bc8d4b SG |
1931 | (il_beacon_time_mask_high(il, |
1932 | il->hw_params.beacon_time_tsf_bits) >> | |
1933 | il->hw_params.beacon_time_tsf_bits); | |
1934 | rem = (usec % interval) & il_beacon_time_mask_low(il, | |
1935 | il->hw_params.beacon_time_tsf_bits); | |
be663ab6 | 1936 | |
46bc8d4b | 1937 | return (quot << il->hw_params.beacon_time_tsf_bits) + rem; |
be663ab6 | 1938 | } |
e2ebc833 | 1939 | EXPORT_SYMBOL(il_usecs_to_beacons); |
be663ab6 WYG |
1940 | |
1941 | /* base is usually what we get from ucode with each received frame, | |
1942 | * the same as HW timer counter counting down | |
1943 | */ | |
46bc8d4b | 1944 | __le32 il_add_beacon_time(struct il_priv *il, u32 base, |
be663ab6 WYG |
1945 | u32 addon, u32 beacon_interval) |
1946 | { | |
46bc8d4b SG |
1947 | u32 base_low = base & il_beacon_time_mask_low(il, |
1948 | il->hw_params.beacon_time_tsf_bits); | |
1949 | u32 addon_low = addon & il_beacon_time_mask_low(il, | |
1950 | il->hw_params.beacon_time_tsf_bits); | |
be663ab6 | 1951 | u32 interval = beacon_interval * TIME_UNIT; |
46bc8d4b SG |
1952 | u32 res = (base & il_beacon_time_mask_high(il, |
1953 | il->hw_params.beacon_time_tsf_bits)) + | |
1954 | (addon & il_beacon_time_mask_high(il, | |
1955 | il->hw_params.beacon_time_tsf_bits)); | |
be663ab6 WYG |
1956 | |
1957 | if (base_low > addon_low) | |
1958 | res += base_low - addon_low; | |
1959 | else if (base_low < addon_low) { | |
1960 | res += interval + base_low - addon_low; | |
46bc8d4b | 1961 | res += (1 << il->hw_params.beacon_time_tsf_bits); |
be663ab6 | 1962 | } else |
46bc8d4b | 1963 | res += (1 << il->hw_params.beacon_time_tsf_bits); |
be663ab6 WYG |
1964 | |
1965 | return cpu_to_le32(res); | |
1966 | } | |
e2ebc833 | 1967 | EXPORT_SYMBOL(il_add_beacon_time); |
be663ab6 WYG |
1968 | |
1969 | #ifdef CONFIG_PM | |
1970 | ||
e2ebc833 | 1971 | int il_pci_suspend(struct device *device) |
be663ab6 WYG |
1972 | { |
1973 | struct pci_dev *pdev = to_pci_dev(device); | |
46bc8d4b | 1974 | struct il_priv *il = pci_get_drvdata(pdev); |
be663ab6 WYG |
1975 | |
1976 | /* | |
1977 | * This function is called when system goes into suspend state | |
e2ebc833 SG |
1978 | * mac80211 will call il_mac_stop() from the mac80211 suspend function |
1979 | * first but since il_mac_stop() has no knowledge of who the caller is, | |
be663ab6 WYG |
1980 | * it will not call apm_ops.stop() to stop the DMA operation. |
1981 | * Calling apm_ops.stop here to make sure we stop the DMA. | |
1982 | */ | |
46bc8d4b | 1983 | il_apm_stop(il); |
be663ab6 WYG |
1984 | |
1985 | return 0; | |
1986 | } | |
e2ebc833 | 1987 | EXPORT_SYMBOL(il_pci_suspend); |
be663ab6 | 1988 | |
e2ebc833 | 1989 | int il_pci_resume(struct device *device) |
be663ab6 WYG |
1990 | { |
1991 | struct pci_dev *pdev = to_pci_dev(device); | |
46bc8d4b | 1992 | struct il_priv *il = pci_get_drvdata(pdev); |
be663ab6 WYG |
1993 | bool hw_rfkill = false; |
1994 | ||
1995 | /* | |
1996 | * We disable the RETRY_TIMEOUT register (0x41) to keep | |
1997 | * PCI Tx retries from interfering with C3 CPU state. | |
1998 | */ | |
1999 | pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); | |
2000 | ||
46bc8d4b | 2001 | il_enable_interrupts(il); |
be663ab6 | 2002 | |
841b2cca | 2003 | if (!(_il_rd(il, CSR_GP_CNTRL) & |
be663ab6 WYG |
2004 | CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) |
2005 | hw_rfkill = true; | |
2006 | ||
2007 | if (hw_rfkill) | |
46bc8d4b | 2008 | set_bit(STATUS_RF_KILL_HW, &il->status); |
be663ab6 | 2009 | else |
46bc8d4b | 2010 | clear_bit(STATUS_RF_KILL_HW, &il->status); |
be663ab6 | 2011 | |
46bc8d4b | 2012 | wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rfkill); |
be663ab6 WYG |
2013 | |
2014 | return 0; | |
2015 | } | |
e2ebc833 | 2016 | EXPORT_SYMBOL(il_pci_resume); |
be663ab6 | 2017 | |
e2ebc833 SG |
2018 | const struct dev_pm_ops il_pm_ops = { |
2019 | .suspend = il_pci_suspend, | |
2020 | .resume = il_pci_resume, | |
2021 | .freeze = il_pci_suspend, | |
2022 | .thaw = il_pci_resume, | |
2023 | .poweroff = il_pci_suspend, | |
2024 | .restore = il_pci_resume, | |
be663ab6 | 2025 | }; |
e2ebc833 | 2026 | EXPORT_SYMBOL(il_pm_ops); |
be663ab6 WYG |
2027 | |
2028 | #endif /* CONFIG_PM */ | |
2029 | ||
2030 | static void | |
46bc8d4b | 2031 | il_update_qos(struct il_priv *il, struct il_rxon_context *ctx) |
be663ab6 | 2032 | { |
46bc8d4b | 2033 | if (test_bit(STATUS_EXIT_PENDING, &il->status)) |
be663ab6 WYG |
2034 | return; |
2035 | ||
2036 | if (!ctx->is_active) | |
2037 | return; | |
2038 | ||
2039 | ctx->qos_data.def_qos_parm.qos_flags = 0; | |
2040 | ||
2041 | if (ctx->qos_data.qos_active) | |
2042 | ctx->qos_data.def_qos_parm.qos_flags |= | |
2043 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; | |
2044 | ||
2045 | if (ctx->ht.enabled) | |
2046 | ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; | |
2047 | ||
58de00a4 | 2048 | D_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n", |
be663ab6 WYG |
2049 | ctx->qos_data.qos_active, |
2050 | ctx->qos_data.def_qos_parm.qos_flags); | |
2051 | ||
46bc8d4b | 2052 | il_send_cmd_pdu_async(il, ctx->qos_cmd, |
e2ebc833 | 2053 | sizeof(struct il_qosparam_cmd), |
be663ab6 WYG |
2054 | &ctx->qos_data.def_qos_parm, NULL); |
2055 | } | |
2056 | ||
2057 | /** | |
e2ebc833 | 2058 | * il_mac_config - mac80211 config callback |
be663ab6 | 2059 | */ |
e2ebc833 | 2060 | int il_mac_config(struct ieee80211_hw *hw, u32 changed) |
be663ab6 | 2061 | { |
46bc8d4b | 2062 | struct il_priv *il = hw->priv; |
e2ebc833 | 2063 | const struct il_channel_info *ch_info; |
be663ab6 WYG |
2064 | struct ieee80211_conf *conf = &hw->conf; |
2065 | struct ieee80211_channel *channel = conf->channel; | |
46bc8d4b | 2066 | struct il_ht_config *ht_conf = &il->current_ht_config; |
e2ebc833 | 2067 | struct il_rxon_context *ctx; |
be663ab6 WYG |
2068 | unsigned long flags = 0; |
2069 | int ret = 0; | |
2070 | u16 ch; | |
2071 | int scan_active = 0; | |
7c2cde2e | 2072 | bool ht_changed = false; |
be663ab6 | 2073 | |
46bc8d4b | 2074 | if (WARN_ON(!il->cfg->ops->legacy)) |
be663ab6 WYG |
2075 | return -EOPNOTSUPP; |
2076 | ||
46bc8d4b | 2077 | mutex_lock(&il->mutex); |
be663ab6 | 2078 | |
58de00a4 | 2079 | D_MAC80211("enter to channel %d changed 0x%X\n", |
be663ab6 WYG |
2080 | channel->hw_value, changed); |
2081 | ||
46bc8d4b | 2082 | if (unlikely(test_bit(STATUS_SCANNING, &il->status))) { |
be663ab6 | 2083 | scan_active = 1; |
58de00a4 | 2084 | D_MAC80211("scan active\n"); |
be663ab6 WYG |
2085 | } |
2086 | ||
2087 | if (changed & (IEEE80211_CONF_CHANGE_SMPS | | |
2088 | IEEE80211_CONF_CHANGE_CHANNEL)) { | |
2089 | /* mac80211 uses static for non-HT which is what we want */ | |
46bc8d4b | 2090 | il->current_ht_config.smps = conf->smps_mode; |
be663ab6 WYG |
2091 | |
2092 | /* | |
2093 | * Recalculate chain counts. | |
2094 | * | |
2095 | * If monitor mode is enabled then mac80211 will | |
2096 | * set up the SM PS mode to OFF if an HT channel is | |
2097 | * configured. | |
2098 | */ | |
46bc8d4b SG |
2099 | if (il->cfg->ops->hcmd->set_rxon_chain) |
2100 | for_each_context(il, ctx) | |
2101 | il->cfg->ops->hcmd->set_rxon_chain(il, ctx); | |
be663ab6 WYG |
2102 | } |
2103 | ||
2104 | /* during scanning mac80211 will delay channel setting until | |
2105 | * scan finish with changed = 0 | |
2106 | */ | |
2107 | if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { | |
2108 | if (scan_active) | |
2109 | goto set_ch_out; | |
2110 | ||
2111 | ch = channel->hw_value; | |
46bc8d4b | 2112 | ch_info = il_get_channel_info(il, channel->band, ch); |
e2ebc833 | 2113 | if (!il_is_channel_valid(ch_info)) { |
58de00a4 | 2114 | D_MAC80211("leave - invalid channel\n"); |
be663ab6 WYG |
2115 | ret = -EINVAL; |
2116 | goto set_ch_out; | |
2117 | } | |
2118 | ||
46bc8d4b | 2119 | if (il->iw_mode == NL80211_IFTYPE_ADHOC && |
e2ebc833 | 2120 | !il_is_channel_ibss(ch_info)) { |
58de00a4 | 2121 | D_MAC80211("leave - not IBSS channel\n"); |
eb85de3f SG |
2122 | ret = -EINVAL; |
2123 | goto set_ch_out; | |
2124 | } | |
2125 | ||
46bc8d4b | 2126 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 | 2127 | |
46bc8d4b | 2128 | for_each_context(il, ctx) { |
be663ab6 WYG |
2129 | /* Configure HT40 channels */ |
2130 | if (ctx->ht.enabled != conf_is_ht(conf)) { | |
2131 | ctx->ht.enabled = conf_is_ht(conf); | |
7c2cde2e | 2132 | ht_changed = true; |
be663ab6 WYG |
2133 | } |
2134 | if (ctx->ht.enabled) { | |
2135 | if (conf_is_ht40_minus(conf)) { | |
2136 | ctx->ht.extension_chan_offset = | |
2137 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | |
2138 | ctx->ht.is_40mhz = true; | |
2139 | } else if (conf_is_ht40_plus(conf)) { | |
2140 | ctx->ht.extension_chan_offset = | |
2141 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | |
2142 | ctx->ht.is_40mhz = true; | |
2143 | } else { | |
2144 | ctx->ht.extension_chan_offset = | |
2145 | IEEE80211_HT_PARAM_CHA_SEC_NONE; | |
2146 | ctx->ht.is_40mhz = false; | |
2147 | } | |
2148 | } else | |
2149 | ctx->ht.is_40mhz = false; | |
2150 | ||
2151 | /* | |
2152 | * Default to no protection. Protection mode will | |
e2ebc833 | 2153 | * later be set from BSS config in il_ht_conf |
be663ab6 WYG |
2154 | */ |
2155 | ctx->ht.protection = | |
2156 | IEEE80211_HT_OP_MODE_PROTECTION_NONE; | |
2157 | ||
2158 | /* if we are switching from ht to 2.4 clear flags | |
2159 | * from any ht related info since 2.4 does not | |
2160 | * support ht */ | |
2161 | if ((le16_to_cpu(ctx->staging.channel) != ch)) | |
2162 | ctx->staging.flags = 0; | |
2163 | ||
46bc8d4b SG |
2164 | il_set_rxon_channel(il, channel, ctx); |
2165 | il_set_rxon_ht(il, ht_conf); | |
be663ab6 | 2166 | |
46bc8d4b | 2167 | il_set_flags_for_band(il, ctx, channel->band, |
be663ab6 WYG |
2168 | ctx->vif); |
2169 | } | |
2170 | ||
46bc8d4b | 2171 | spin_unlock_irqrestore(&il->lock, flags); |
be663ab6 | 2172 | |
46bc8d4b | 2173 | if (il->cfg->ops->legacy->update_bcast_stations) |
be663ab6 | 2174 | ret = |
46bc8d4b | 2175 | il->cfg->ops->legacy->update_bcast_stations(il); |
be663ab6 WYG |
2176 | |
2177 | set_ch_out: | |
2178 | /* The list of supported rates and rate mask can be different | |
2179 | * for each band; since the band may have changed, reset | |
2180 | * the rate mask to what mac80211 lists */ | |
46bc8d4b | 2181 | il_set_rate(il); |
be663ab6 WYG |
2182 | } |
2183 | ||
2184 | if (changed & (IEEE80211_CONF_CHANGE_PS | | |
2185 | IEEE80211_CONF_CHANGE_IDLE)) { | |
46bc8d4b | 2186 | ret = il_power_update_mode(il, false); |
be663ab6 | 2187 | if (ret) |
58de00a4 | 2188 | D_MAC80211("Error setting sleep level\n"); |
be663ab6 WYG |
2189 | } |
2190 | ||
2191 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | |
58de00a4 | 2192 | D_MAC80211("TX Power old=%d new=%d\n", |
46bc8d4b | 2193 | il->tx_power_user_lmt, conf->power_level); |
be663ab6 | 2194 | |
46bc8d4b | 2195 | il_set_tx_power(il, conf->power_level, false); |
be663ab6 WYG |
2196 | } |
2197 | ||
46bc8d4b | 2198 | if (!il_is_ready(il)) { |
58de00a4 | 2199 | D_MAC80211("leave - not ready\n"); |
be663ab6 WYG |
2200 | goto out; |
2201 | } | |
2202 | ||
2203 | if (scan_active) | |
2204 | goto out; | |
2205 | ||
46bc8d4b | 2206 | for_each_context(il, ctx) { |
be663ab6 | 2207 | if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) |
46bc8d4b | 2208 | il_commit_rxon(il, ctx); |
be663ab6 | 2209 | else |
58de00a4 | 2210 | D_INFO( |
be663ab6 | 2211 | "Not re-sending same RXON configuration.\n"); |
7c2cde2e | 2212 | if (ht_changed) |
46bc8d4b | 2213 | il_update_qos(il, ctx); |
be663ab6 WYG |
2214 | } |
2215 | ||
2216 | out: | |
58de00a4 | 2217 | D_MAC80211("leave\n"); |
46bc8d4b | 2218 | mutex_unlock(&il->mutex); |
be663ab6 WYG |
2219 | return ret; |
2220 | } | |
e2ebc833 | 2221 | EXPORT_SYMBOL(il_mac_config); |
be663ab6 | 2222 | |
e2ebc833 | 2223 | void il_mac_reset_tsf(struct ieee80211_hw *hw, |
37a41b4a | 2224 | struct ieee80211_vif *vif) |
be663ab6 | 2225 | { |
46bc8d4b | 2226 | struct il_priv *il = hw->priv; |
be663ab6 | 2227 | unsigned long flags; |
7c2cde2e | 2228 | struct il_rxon_context *ctx = &il->ctx; |
be663ab6 | 2229 | |
46bc8d4b | 2230 | if (WARN_ON(!il->cfg->ops->legacy)) |
be663ab6 WYG |
2231 | return; |
2232 | ||
46bc8d4b | 2233 | mutex_lock(&il->mutex); |
58de00a4 | 2234 | D_MAC80211("enter\n"); |
be663ab6 | 2235 | |
46bc8d4b SG |
2236 | spin_lock_irqsave(&il->lock, flags); |
2237 | memset(&il->current_ht_config, 0, sizeof(struct il_ht_config)); | |
2238 | spin_unlock_irqrestore(&il->lock, flags); | |
be663ab6 | 2239 | |
46bc8d4b | 2240 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 WYG |
2241 | |
2242 | /* new association get rid of ibss beacon skb */ | |
46bc8d4b SG |
2243 | if (il->beacon_skb) |
2244 | dev_kfree_skb(il->beacon_skb); | |
be663ab6 | 2245 | |
46bc8d4b | 2246 | il->beacon_skb = NULL; |
be663ab6 | 2247 | |
46bc8d4b | 2248 | il->timestamp = 0; |
be663ab6 | 2249 | |
46bc8d4b | 2250 | spin_unlock_irqrestore(&il->lock, flags); |
be663ab6 | 2251 | |
46bc8d4b SG |
2252 | il_scan_cancel_timeout(il, 100); |
2253 | if (!il_is_ready_rf(il)) { | |
58de00a4 | 2254 | D_MAC80211("leave - not ready\n"); |
46bc8d4b | 2255 | mutex_unlock(&il->mutex); |
be663ab6 WYG |
2256 | return; |
2257 | } | |
2258 | ||
2259 | /* we are restarting association process | |
2260 | * clear RXON_FILTER_ASSOC_MSK bit | |
2261 | */ | |
2262 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | |
46bc8d4b | 2263 | il_commit_rxon(il, ctx); |
be663ab6 | 2264 | |
46bc8d4b | 2265 | il_set_rate(il); |
be663ab6 | 2266 | |
46bc8d4b | 2267 | mutex_unlock(&il->mutex); |
be663ab6 | 2268 | |
58de00a4 | 2269 | D_MAC80211("leave\n"); |
be663ab6 | 2270 | } |
e2ebc833 | 2271 | EXPORT_SYMBOL(il_mac_reset_tsf); |
be663ab6 | 2272 | |
46bc8d4b | 2273 | static void il_ht_conf(struct il_priv *il, |
be663ab6 WYG |
2274 | struct ieee80211_vif *vif) |
2275 | { | |
46bc8d4b | 2276 | struct il_ht_config *ht_conf = &il->current_ht_config; |
be663ab6 WYG |
2277 | struct ieee80211_sta *sta; |
2278 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | |
e2ebc833 | 2279 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
be663ab6 | 2280 | |
58de00a4 | 2281 | D_ASSOC("enter:\n"); |
be663ab6 WYG |
2282 | |
2283 | if (!ctx->ht.enabled) | |
2284 | return; | |
2285 | ||
2286 | ctx->ht.protection = | |
2287 | bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; | |
2288 | ctx->ht.non_gf_sta_present = | |
2289 | !!(bss_conf->ht_operation_mode & | |
2290 | IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | |
2291 | ||
2292 | ht_conf->single_chain_sufficient = false; | |
2293 | ||
2294 | switch (vif->type) { | |
2295 | case NL80211_IFTYPE_STATION: | |
2296 | rcu_read_lock(); | |
2297 | sta = ieee80211_find_sta(vif, bss_conf->bssid); | |
2298 | if (sta) { | |
2299 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | |
2300 | int maxstreams; | |
2301 | ||
2302 | maxstreams = (ht_cap->mcs.tx_params & | |
2303 | IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | |
2304 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | |
2305 | maxstreams += 1; | |
2306 | ||
232913b5 SG |
2307 | if (ht_cap->mcs.rx_mask[1] == 0 && |
2308 | ht_cap->mcs.rx_mask[2] == 0) | |
be663ab6 WYG |
2309 | ht_conf->single_chain_sufficient = true; |
2310 | if (maxstreams <= 1) | |
2311 | ht_conf->single_chain_sufficient = true; | |
2312 | } else { | |
2313 | /* | |
2314 | * If at all, this can only happen through a race | |
2315 | * when the AP disconnects us while we're still | |
2316 | * setting up the connection, in that case mac80211 | |
2317 | * will soon tell us about that. | |
2318 | */ | |
2319 | ht_conf->single_chain_sufficient = true; | |
2320 | } | |
2321 | rcu_read_unlock(); | |
2322 | break; | |
2323 | case NL80211_IFTYPE_ADHOC: | |
2324 | ht_conf->single_chain_sufficient = true; | |
2325 | break; | |
2326 | default: | |
2327 | break; | |
2328 | } | |
2329 | ||
58de00a4 | 2330 | D_ASSOC("leave\n"); |
be663ab6 WYG |
2331 | } |
2332 | ||
46bc8d4b | 2333 | static inline void il_set_no_assoc(struct il_priv *il, |
be663ab6 WYG |
2334 | struct ieee80211_vif *vif) |
2335 | { | |
e2ebc833 | 2336 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
be663ab6 WYG |
2337 | |
2338 | /* | |
2339 | * inform the ucode that there is no longer an | |
2340 | * association and that no more packets should be | |
2341 | * sent | |
2342 | */ | |
2343 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | |
2344 | ctx->staging.assoc_id = 0; | |
46bc8d4b | 2345 | il_commit_rxon(il, ctx); |
be663ab6 WYG |
2346 | } |
2347 | ||
e2ebc833 | 2348 | static void il_beacon_update(struct ieee80211_hw *hw, |
be663ab6 WYG |
2349 | struct ieee80211_vif *vif) |
2350 | { | |
46bc8d4b | 2351 | struct il_priv *il = hw->priv; |
be663ab6 WYG |
2352 | unsigned long flags; |
2353 | __le64 timestamp; | |
2354 | struct sk_buff *skb = ieee80211_beacon_get(hw, vif); | |
2355 | ||
2356 | if (!skb) | |
2357 | return; | |
2358 | ||
58de00a4 | 2359 | D_MAC80211("enter\n"); |
be663ab6 | 2360 | |
46bc8d4b | 2361 | lockdep_assert_held(&il->mutex); |
be663ab6 | 2362 | |
46bc8d4b | 2363 | if (!il->beacon_ctx) { |
9406f797 | 2364 | IL_ERR("update beacon but no beacon context!\n"); |
be663ab6 WYG |
2365 | dev_kfree_skb(skb); |
2366 | return; | |
2367 | } | |
2368 | ||
46bc8d4b | 2369 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 | 2370 | |
46bc8d4b SG |
2371 | if (il->beacon_skb) |
2372 | dev_kfree_skb(il->beacon_skb); | |
be663ab6 | 2373 | |
46bc8d4b | 2374 | il->beacon_skb = skb; |
be663ab6 WYG |
2375 | |
2376 | timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | |
46bc8d4b | 2377 | il->timestamp = le64_to_cpu(timestamp); |
be663ab6 | 2378 | |
58de00a4 | 2379 | D_MAC80211("leave\n"); |
46bc8d4b | 2380 | spin_unlock_irqrestore(&il->lock, flags); |
be663ab6 | 2381 | |
46bc8d4b | 2382 | if (!il_is_ready_rf(il)) { |
58de00a4 | 2383 | D_MAC80211("leave - RF not ready\n"); |
be663ab6 WYG |
2384 | return; |
2385 | } | |
2386 | ||
46bc8d4b | 2387 | il->cfg->ops->legacy->post_associate(il); |
be663ab6 WYG |
2388 | } |
2389 | ||
e2ebc833 | 2390 | void il_mac_bss_info_changed(struct ieee80211_hw *hw, |
be663ab6 WYG |
2391 | struct ieee80211_vif *vif, |
2392 | struct ieee80211_bss_conf *bss_conf, | |
2393 | u32 changes) | |
2394 | { | |
46bc8d4b | 2395 | struct il_priv *il = hw->priv; |
e2ebc833 | 2396 | struct il_rxon_context *ctx = il_rxon_ctx_from_vif(vif); |
be663ab6 WYG |
2397 | int ret; |
2398 | ||
46bc8d4b | 2399 | if (WARN_ON(!il->cfg->ops->legacy)) |
be663ab6 WYG |
2400 | return; |
2401 | ||
58de00a4 | 2402 | D_MAC80211("changes = 0x%X\n", changes); |
be663ab6 | 2403 | |
46bc8d4b | 2404 | mutex_lock(&il->mutex); |
be663ab6 | 2405 | |
46bc8d4b SG |
2406 | if (!il_is_alive(il)) { |
2407 | mutex_unlock(&il->mutex); | |
28a6e577 SG |
2408 | return; |
2409 | } | |
2410 | ||
be663ab6 WYG |
2411 | if (changes & BSS_CHANGED_QOS) { |
2412 | unsigned long flags; | |
2413 | ||
46bc8d4b | 2414 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 | 2415 | ctx->qos_data.qos_active = bss_conf->qos; |
46bc8d4b SG |
2416 | il_update_qos(il, ctx); |
2417 | spin_unlock_irqrestore(&il->lock, flags); | |
be663ab6 WYG |
2418 | } |
2419 | ||
2420 | if (changes & BSS_CHANGED_BEACON_ENABLED) { | |
2421 | /* | |
2422 | * the add_interface code must make sure we only ever | |
2423 | * have a single interface that could be beaconing at | |
2424 | * any time. | |
2425 | */ | |
2426 | if (vif->bss_conf.enable_beacon) | |
46bc8d4b | 2427 | il->beacon_ctx = ctx; |
be663ab6 | 2428 | else |
46bc8d4b | 2429 | il->beacon_ctx = NULL; |
be663ab6 WYG |
2430 | } |
2431 | ||
2432 | if (changes & BSS_CHANGED_BSSID) { | |
58de00a4 | 2433 | D_MAC80211("BSSID %pM\n", bss_conf->bssid); |
be663ab6 WYG |
2434 | |
2435 | /* | |
2436 | * If there is currently a HW scan going on in the | |
2437 | * background then we need to cancel it else the RXON | |
2438 | * below/in post_associate will fail. | |
2439 | */ | |
46bc8d4b | 2440 | if (il_scan_cancel_timeout(il, 100)) { |
9406f797 | 2441 | IL_WARN( |
be663ab6 | 2442 | "Aborted scan still in progress after 100ms\n"); |
58de00a4 | 2443 | D_MAC80211( |
be663ab6 | 2444 | "leaving - scan abort failed.\n"); |
46bc8d4b | 2445 | mutex_unlock(&il->mutex); |
be663ab6 WYG |
2446 | return; |
2447 | } | |
2448 | ||
2449 | /* mac80211 only sets assoc when in STATION mode */ | |
2450 | if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { | |
2451 | memcpy(ctx->staging.bssid_addr, | |
2452 | bss_conf->bssid, ETH_ALEN); | |
2453 | ||
2454 | /* currently needed in a few places */ | |
46bc8d4b | 2455 | memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); |
be663ab6 WYG |
2456 | } else { |
2457 | ctx->staging.filter_flags &= | |
2458 | ~RXON_FILTER_ASSOC_MSK; | |
2459 | } | |
2460 | ||
2461 | } | |
2462 | ||
2463 | /* | |
2464 | * This needs to be after setting the BSSID in case | |
2465 | * mac80211 decides to do both changes at once because | |
2466 | * it will invoke post_associate. | |
2467 | */ | |
232913b5 | 2468 | if (vif->type == NL80211_IFTYPE_ADHOC && (changes & BSS_CHANGED_BEACON)) |
e2ebc833 | 2469 | il_beacon_update(hw, vif); |
be663ab6 WYG |
2470 | |
2471 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { | |
58de00a4 | 2472 | D_MAC80211("ERP_PREAMBLE %d\n", |
be663ab6 WYG |
2473 | bss_conf->use_short_preamble); |
2474 | if (bss_conf->use_short_preamble) | |
2475 | ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | |
2476 | else | |
2477 | ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; | |
2478 | } | |
2479 | ||
2480 | if (changes & BSS_CHANGED_ERP_CTS_PROT) { | |
58de00a4 | 2481 | D_MAC80211( |
be663ab6 | 2482 | "ERP_CTS %d\n", bss_conf->use_cts_prot); |
232913b5 | 2483 | if (bss_conf->use_cts_prot && il->band != IEEE80211_BAND_5GHZ) |
be663ab6 WYG |
2484 | ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; |
2485 | else | |
2486 | ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; | |
2487 | if (bss_conf->use_cts_prot) | |
2488 | ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; | |
2489 | else | |
2490 | ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; | |
2491 | } | |
2492 | ||
2493 | if (changes & BSS_CHANGED_BASIC_RATES) { | |
2494 | /* XXX use this information | |
2495 | * | |
e2ebc833 | 2496 | * To do that, remove code from il_set_rate() and put something |
be663ab6 WYG |
2497 | * like this here: |
2498 | * | |
2499 | if (A-band) | |
2500 | ctx->staging.ofdm_basic_rates = | |
2501 | bss_conf->basic_rates; | |
2502 | else | |
2503 | ctx->staging.ofdm_basic_rates = | |
2504 | bss_conf->basic_rates >> 4; | |
2505 | ctx->staging.cck_basic_rates = | |
2506 | bss_conf->basic_rates & 0xF; | |
2507 | */ | |
2508 | } | |
2509 | ||
2510 | if (changes & BSS_CHANGED_HT) { | |
46bc8d4b | 2511 | il_ht_conf(il, vif); |
be663ab6 | 2512 | |
46bc8d4b SG |
2513 | if (il->cfg->ops->hcmd->set_rxon_chain) |
2514 | il->cfg->ops->hcmd->set_rxon_chain(il, ctx); | |
be663ab6 WYG |
2515 | } |
2516 | ||
2517 | if (changes & BSS_CHANGED_ASSOC) { | |
58de00a4 | 2518 | D_MAC80211("ASSOC %d\n", bss_conf->assoc); |
be663ab6 | 2519 | if (bss_conf->assoc) { |
46bc8d4b | 2520 | il->timestamp = bss_conf->timestamp; |
be663ab6 | 2521 | |
46bc8d4b SG |
2522 | if (!il_is_rfkill(il)) |
2523 | il->cfg->ops->legacy->post_associate(il); | |
be663ab6 | 2524 | } else |
46bc8d4b | 2525 | il_set_no_assoc(il, vif); |
be663ab6 WYG |
2526 | } |
2527 | ||
e2ebc833 | 2528 | if (changes && il_is_associated_ctx(ctx) && bss_conf->aid) { |
58de00a4 | 2529 | D_MAC80211("Changes (%#x) while associated\n", |
be663ab6 | 2530 | changes); |
46bc8d4b | 2531 | ret = il_send_rxon_assoc(il, ctx); |
be663ab6 WYG |
2532 | if (!ret) { |
2533 | /* Sync active_rxon with latest change. */ | |
2534 | memcpy((void *)&ctx->active, | |
2535 | &ctx->staging, | |
e2ebc833 | 2536 | sizeof(struct il_rxon_cmd)); |
be663ab6 WYG |
2537 | } |
2538 | } | |
2539 | ||
2540 | if (changes & BSS_CHANGED_BEACON_ENABLED) { | |
2541 | if (vif->bss_conf.enable_beacon) { | |
2542 | memcpy(ctx->staging.bssid_addr, | |
2543 | bss_conf->bssid, ETH_ALEN); | |
46bc8d4b SG |
2544 | memcpy(il->bssid, bss_conf->bssid, ETH_ALEN); |
2545 | il->cfg->ops->legacy->config_ap(il); | |
be663ab6 | 2546 | } else |
46bc8d4b | 2547 | il_set_no_assoc(il, vif); |
be663ab6 WYG |
2548 | } |
2549 | ||
2550 | if (changes & BSS_CHANGED_IBSS) { | |
46bc8d4b | 2551 | ret = il->cfg->ops->legacy->manage_ibss_station(il, vif, |
be663ab6 WYG |
2552 | bss_conf->ibss_joined); |
2553 | if (ret) | |
9406f797 | 2554 | IL_ERR("failed to %s IBSS station %pM\n", |
be663ab6 WYG |
2555 | bss_conf->ibss_joined ? "add" : "remove", |
2556 | bss_conf->bssid); | |
2557 | } | |
2558 | ||
46bc8d4b | 2559 | mutex_unlock(&il->mutex); |
be663ab6 | 2560 | |
58de00a4 | 2561 | D_MAC80211("leave\n"); |
be663ab6 | 2562 | } |
e2ebc833 | 2563 | EXPORT_SYMBOL(il_mac_bss_info_changed); |
be663ab6 | 2564 | |
e2ebc833 | 2565 | irqreturn_t il_isr(int irq, void *data) |
be663ab6 | 2566 | { |
46bc8d4b | 2567 | struct il_priv *il = data; |
be663ab6 WYG |
2568 | u32 inta, inta_mask; |
2569 | u32 inta_fh; | |
2570 | unsigned long flags; | |
46bc8d4b | 2571 | if (!il) |
be663ab6 WYG |
2572 | return IRQ_NONE; |
2573 | ||
46bc8d4b | 2574 | spin_lock_irqsave(&il->lock, flags); |
be663ab6 WYG |
2575 | |
2576 | /* Disable (but don't clear!) interrupts here to avoid | |
2577 | * back-to-back ISRs and sporadic interrupts from our NIC. | |
2578 | * If we have something to service, the tasklet will re-enable ints. | |
2579 | * If we *don't* have something, we'll re-enable before leaving here. */ | |
841b2cca SG |
2580 | inta_mask = _il_rd(il, CSR_INT_MASK); /* just for debug */ |
2581 | _il_wr(il, CSR_INT_MASK, 0x00000000); | |
be663ab6 WYG |
2582 | |
2583 | /* Discover which interrupts are active/pending */ | |
841b2cca SG |
2584 | inta = _il_rd(il, CSR_INT); |
2585 | inta_fh = _il_rd(il, CSR_FH_INT_STATUS); | |
be663ab6 WYG |
2586 | |
2587 | /* Ignore interrupt if there's nothing in NIC to service. | |
2588 | * This may be due to IRQ shared with another device, | |
2589 | * or due to sporadic interrupts thrown from our NIC. */ | |
2590 | if (!inta && !inta_fh) { | |
58de00a4 | 2591 | D_ISR( |
be663ab6 WYG |
2592 | "Ignore interrupt, inta == 0, inta_fh == 0\n"); |
2593 | goto none; | |
2594 | } | |
2595 | ||
232913b5 | 2596 | if (inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0) { |
be663ab6 WYG |
2597 | /* Hardware disappeared. It might have already raised |
2598 | * an interrupt */ | |
9406f797 | 2599 | IL_WARN("HARDWARE GONE?? INTA == 0x%08x\n", inta); |
be663ab6 WYG |
2600 | goto unplugged; |
2601 | } | |
2602 | ||
58de00a4 | 2603 | D_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", |
be663ab6 WYG |
2604 | inta, inta_mask, inta_fh); |
2605 | ||
2606 | inta &= ~CSR_INT_BIT_SCD; | |
2607 | ||
e2ebc833 | 2608 | /* il_irq_tasklet() will service interrupts and re-enable them */ |
be663ab6 | 2609 | if (likely(inta || inta_fh)) |
46bc8d4b | 2610 | tasklet_schedule(&il->irq_tasklet); |
be663ab6 WYG |
2611 | |
2612 | unplugged: | |
46bc8d4b | 2613 | spin_unlock_irqrestore(&il->lock, flags); |
be663ab6 WYG |
2614 | return IRQ_HANDLED; |
2615 | ||
2616 | none: | |
2617 | /* re-enable interrupts here since we don't have anything to service. */ | |
93fd74e3 | 2618 | /* only Re-enable if disabled by irq */ |
46bc8d4b SG |
2619 | if (test_bit(STATUS_INT_ENABLED, &il->status)) |
2620 | il_enable_interrupts(il); | |
2621 | spin_unlock_irqrestore(&il->lock, flags); | |
be663ab6 WYG |
2622 | return IRQ_NONE; |
2623 | } | |
e2ebc833 | 2624 | EXPORT_SYMBOL(il_isr); |
be663ab6 WYG |
2625 | |
2626 | /* | |
e2ebc833 | 2627 | * il_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this |
be663ab6 WYG |
2628 | * function. |
2629 | */ | |
46bc8d4b | 2630 | void il_tx_cmd_protection(struct il_priv *il, |
be663ab6 WYG |
2631 | struct ieee80211_tx_info *info, |
2632 | __le16 fc, __le32 *tx_flags) | |
2633 | { | |
2634 | if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { | |
2635 | *tx_flags |= TX_CMD_FLG_RTS_MSK; | |
2636 | *tx_flags &= ~TX_CMD_FLG_CTS_MSK; | |
2637 | *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; | |
2638 | ||
2639 | if (!ieee80211_is_mgmt(fc)) | |
2640 | return; | |
2641 | ||
2642 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | |
2643 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | |
2644 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | |
2645 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): | |
2646 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): | |
2647 | *tx_flags &= ~TX_CMD_FLG_RTS_MSK; | |
2648 | *tx_flags |= TX_CMD_FLG_CTS_MSK; | |
2649 | break; | |
2650 | } | |
2651 | } else if (info->control.rates[0].flags & | |
2652 | IEEE80211_TX_RC_USE_CTS_PROTECT) { | |
2653 | *tx_flags &= ~TX_CMD_FLG_RTS_MSK; | |
2654 | *tx_flags |= TX_CMD_FLG_CTS_MSK; | |
2655 | *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; | |
2656 | } | |
2657 | } | |
e2ebc833 | 2658 | EXPORT_SYMBOL(il_tx_cmd_protection); |