diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-legacy.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-legacy.c | 662 |
1 files changed, 0 insertions, 662 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c deleted file mode 100644 index bb1a742a98a0..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ /dev/null | |||
@@ -1,662 +0,0 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * GPL LICENSE SUMMARY | ||
4 | * | ||
5 | * Copyright(c) 2008 - 2010 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 <net/mac80211.h> | ||
31 | |||
32 | #include "iwl-dev.h" | ||
33 | #include "iwl-core.h" | ||
34 | #include "iwl-helpers.h" | ||
35 | #include "iwl-legacy.h" | ||
36 | |||
37 | static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
38 | { | ||
39 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
40 | return; | ||
41 | |||
42 | if (!ctx->is_active) | ||
43 | return; | ||
44 | |||
45 | ctx->qos_data.def_qos_parm.qos_flags = 0; | ||
46 | |||
47 | if (ctx->qos_data.qos_active) | ||
48 | ctx->qos_data.def_qos_parm.qos_flags |= | ||
49 | QOS_PARAM_FLG_UPDATE_EDCA_MSK; | ||
50 | |||
51 | if (ctx->ht.enabled) | ||
52 | ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; | ||
53 | |||
54 | IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", | ||
55 | ctx->qos_data.qos_active, | ||
56 | ctx->qos_data.def_qos_parm.qos_flags); | ||
57 | |||
58 | iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, | ||
59 | sizeof(struct iwl_qosparam_cmd), | ||
60 | &ctx->qos_data.def_qos_parm, NULL); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * iwl_legacy_mac_config - mac80211 config callback | ||
65 | */ | ||
66 | int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) | ||
67 | { | ||
68 | struct iwl_priv *priv = hw->priv; | ||
69 | const struct iwl_channel_info *ch_info; | ||
70 | struct ieee80211_conf *conf = &hw->conf; | ||
71 | struct ieee80211_channel *channel = conf->channel; | ||
72 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; | ||
73 | struct iwl_rxon_context *ctx; | ||
74 | unsigned long flags = 0; | ||
75 | int ret = 0; | ||
76 | u16 ch; | ||
77 | int scan_active = 0; | ||
78 | bool ht_changed[NUM_IWL_RXON_CTX] = {}; | ||
79 | |||
80 | if (WARN_ON(!priv->cfg->ops->legacy)) | ||
81 | return -EOPNOTSUPP; | ||
82 | |||
83 | mutex_lock(&priv->mutex); | ||
84 | |||
85 | IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", | ||
86 | channel->hw_value, changed); | ||
87 | |||
88 | if (unlikely(!priv->cfg->mod_params->disable_hw_scan && | ||
89 | test_bit(STATUS_SCANNING, &priv->status))) { | ||
90 | scan_active = 1; | ||
91 | IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); | ||
92 | } | ||
93 | |||
94 | if (changed & (IEEE80211_CONF_CHANGE_SMPS | | ||
95 | IEEE80211_CONF_CHANGE_CHANNEL)) { | ||
96 | /* mac80211 uses static for non-HT which is what we want */ | ||
97 | priv->current_ht_config.smps = conf->smps_mode; | ||
98 | |||
99 | /* | ||
100 | * Recalculate chain counts. | ||
101 | * | ||
102 | * If monitor mode is enabled then mac80211 will | ||
103 | * set up the SM PS mode to OFF if an HT channel is | ||
104 | * configured. | ||
105 | */ | ||
106 | if (priv->cfg->ops->hcmd->set_rxon_chain) | ||
107 | for_each_context(priv, ctx) | ||
108 | priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); | ||
109 | } | ||
110 | |||
111 | /* during scanning mac80211 will delay channel setting until | ||
112 | * scan finish with changed = 0 | ||
113 | */ | ||
114 | if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { | ||
115 | if (scan_active) | ||
116 | goto set_ch_out; | ||
117 | |||
118 | ch = channel->hw_value; | ||
119 | ch_info = iwl_get_channel_info(priv, channel->band, ch); | ||
120 | if (!is_channel_valid(ch_info)) { | ||
121 | IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); | ||
122 | ret = -EINVAL; | ||
123 | goto set_ch_out; | ||
124 | } | ||
125 | |||
126 | spin_lock_irqsave(&priv->lock, flags); | ||
127 | |||
128 | for_each_context(priv, ctx) { | ||
129 | /* Configure HT40 channels */ | ||
130 | if (ctx->ht.enabled != conf_is_ht(conf)) { | ||
131 | ctx->ht.enabled = conf_is_ht(conf); | ||
132 | ht_changed[ctx->ctxid] = true; | ||
133 | } | ||
134 | if (ctx->ht.enabled) { | ||
135 | if (conf_is_ht40_minus(conf)) { | ||
136 | ctx->ht.extension_chan_offset = | ||
137 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
138 | ctx->ht.is_40mhz = true; | ||
139 | } else if (conf_is_ht40_plus(conf)) { | ||
140 | ctx->ht.extension_chan_offset = | ||
141 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE; | ||
142 | ctx->ht.is_40mhz = true; | ||
143 | } else { | ||
144 | ctx->ht.extension_chan_offset = | ||
145 | IEEE80211_HT_PARAM_CHA_SEC_NONE; | ||
146 | ctx->ht.is_40mhz = false; | ||
147 | } | ||
148 | } else | ||
149 | ctx->ht.is_40mhz = false; | ||
150 | |||
151 | /* | ||
152 | * Default to no protection. Protection mode will | ||
153 | * later be set from BSS config in iwl_ht_conf | ||
154 | */ | ||
155 | ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | ||
156 | |||
157 | /* if we are switching from ht to 2.4 clear flags | ||
158 | * from any ht related info since 2.4 does not | ||
159 | * support ht */ | ||
160 | if ((le16_to_cpu(ctx->staging.channel) != ch)) | ||
161 | ctx->staging.flags = 0; | ||
162 | |||
163 | iwl_set_rxon_channel(priv, channel, ctx); | ||
164 | iwl_set_rxon_ht(priv, ht_conf); | ||
165 | |||
166 | iwl_set_flags_for_band(priv, ctx, channel->band, | ||
167 | ctx->vif); | ||
168 | } | ||
169 | |||
170 | spin_unlock_irqrestore(&priv->lock, flags); | ||
171 | |||
172 | if (priv->cfg->ops->legacy->update_bcast_stations) | ||
173 | ret = priv->cfg->ops->legacy->update_bcast_stations(priv); | ||
174 | |||
175 | set_ch_out: | ||
176 | /* The list of supported rates and rate mask can be different | ||
177 | * for each band; since the band may have changed, reset | ||
178 | * the rate mask to what mac80211 lists */ | ||
179 | iwl_set_rate(priv); | ||
180 | } | ||
181 | |||
182 | if (changed & (IEEE80211_CONF_CHANGE_PS | | ||
183 | IEEE80211_CONF_CHANGE_IDLE)) { | ||
184 | ret = iwl_power_update_mode(priv, false); | ||
185 | if (ret) | ||
186 | IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); | ||
187 | } | ||
188 | |||
189 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | ||
190 | IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", | ||
191 | priv->tx_power_user_lmt, conf->power_level); | ||
192 | |||
193 | iwl_set_tx_power(priv, conf->power_level, false); | ||
194 | } | ||
195 | |||
196 | if (!iwl_is_ready(priv)) { | ||
197 | IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); | ||
198 | goto out; | ||
199 | } | ||
200 | |||
201 | if (scan_active) | ||
202 | goto out; | ||
203 | |||
204 | for_each_context(priv, ctx) { | ||
205 | if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) | ||
206 | iwlcore_commit_rxon(priv, ctx); | ||
207 | else | ||
208 | IWL_DEBUG_INFO(priv, | ||
209 | "Not re-sending same RXON configuration.\n"); | ||
210 | if (ht_changed[ctx->ctxid]) | ||
211 | iwl_update_qos(priv, ctx); | ||
212 | } | ||
213 | |||
214 | out: | ||
215 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
216 | mutex_unlock(&priv->mutex); | ||
217 | return ret; | ||
218 | } | ||
219 | EXPORT_SYMBOL(iwl_legacy_mac_config); | ||
220 | |||
221 | void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) | ||
222 | { | ||
223 | struct iwl_priv *priv = hw->priv; | ||
224 | unsigned long flags; | ||
225 | /* IBSS can only be the IWL_RXON_CTX_BSS context */ | ||
226 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
227 | |||
228 | if (WARN_ON(!priv->cfg->ops->legacy)) | ||
229 | return; | ||
230 | |||
231 | mutex_lock(&priv->mutex); | ||
232 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
233 | |||
234 | spin_lock_irqsave(&priv->lock, flags); | ||
235 | memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); | ||
236 | spin_unlock_irqrestore(&priv->lock, flags); | ||
237 | |||
238 | spin_lock_irqsave(&priv->lock, flags); | ||
239 | |||
240 | /* new association get rid of ibss beacon skb */ | ||
241 | if (priv->beacon_skb) | ||
242 | dev_kfree_skb(priv->beacon_skb); | ||
243 | |||
244 | priv->beacon_skb = NULL; | ||
245 | |||
246 | priv->timestamp = 0; | ||
247 | |||
248 | spin_unlock_irqrestore(&priv->lock, flags); | ||
249 | |||
250 | iwl_scan_cancel_timeout(priv, 100); | ||
251 | if (!iwl_is_ready_rf(priv)) { | ||
252 | IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); | ||
253 | mutex_unlock(&priv->mutex); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | /* we are restarting association process | ||
258 | * clear RXON_FILTER_ASSOC_MSK bit | ||
259 | */ | ||
260 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | ||
261 | iwlcore_commit_rxon(priv, ctx); | ||
262 | |||
263 | iwl_set_rate(priv); | ||
264 | |||
265 | mutex_unlock(&priv->mutex); | ||
266 | |||
267 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
268 | } | ||
269 | EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf); | ||
270 | |||
271 | static void iwl_ht_conf(struct iwl_priv *priv, | ||
272 | struct ieee80211_vif *vif) | ||
273 | { | ||
274 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; | ||
275 | struct ieee80211_sta *sta; | ||
276 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
277 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
278 | |||
279 | IWL_DEBUG_ASSOC(priv, "enter:\n"); | ||
280 | |||
281 | if (!ctx->ht.enabled) | ||
282 | return; | ||
283 | |||
284 | ctx->ht.protection = | ||
285 | bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; | ||
286 | ctx->ht.non_gf_sta_present = | ||
287 | !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | ||
288 | |||
289 | ht_conf->single_chain_sufficient = false; | ||
290 | |||
291 | switch (vif->type) { | ||
292 | case NL80211_IFTYPE_STATION: | ||
293 | rcu_read_lock(); | ||
294 | sta = ieee80211_find_sta(vif, bss_conf->bssid); | ||
295 | if (sta) { | ||
296 | struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; | ||
297 | int maxstreams; | ||
298 | |||
299 | maxstreams = (ht_cap->mcs.tx_params & | ||
300 | IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | ||
301 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; | ||
302 | maxstreams += 1; | ||
303 | |||
304 | if ((ht_cap->mcs.rx_mask[1] == 0) && | ||
305 | (ht_cap->mcs.rx_mask[2] == 0)) | ||
306 | ht_conf->single_chain_sufficient = true; | ||
307 | if (maxstreams <= 1) | ||
308 | ht_conf->single_chain_sufficient = true; | ||
309 | } else { | ||
310 | /* | ||
311 | * If at all, this can only happen through a race | ||
312 | * when the AP disconnects us while we're still | ||
313 | * setting up the connection, in that case mac80211 | ||
314 | * will soon tell us about that. | ||
315 | */ | ||
316 | ht_conf->single_chain_sufficient = true; | ||
317 | } | ||
318 | rcu_read_unlock(); | ||
319 | break; | ||
320 | case NL80211_IFTYPE_ADHOC: | ||
321 | ht_conf->single_chain_sufficient = true; | ||
322 | break; | ||
323 | default: | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | IWL_DEBUG_ASSOC(priv, "leave\n"); | ||
328 | } | ||
329 | |||
330 | static inline void iwl_set_no_assoc(struct iwl_priv *priv, | ||
331 | struct ieee80211_vif *vif) | ||
332 | { | ||
333 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
334 | |||
335 | iwl_led_disassociate(priv); | ||
336 | /* | ||
337 | * inform the ucode that there is no longer an | ||
338 | * association and that no more packets should be | ||
339 | * sent | ||
340 | */ | ||
341 | ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | ||
342 | ctx->staging.assoc_id = 0; | ||
343 | iwlcore_commit_rxon(priv, ctx); | ||
344 | } | ||
345 | |||
346 | static void iwlcore_beacon_update(struct ieee80211_hw *hw, | ||
347 | struct ieee80211_vif *vif) | ||
348 | { | ||
349 | struct iwl_priv *priv = hw->priv; | ||
350 | unsigned long flags; | ||
351 | __le64 timestamp; | ||
352 | struct sk_buff *skb = ieee80211_beacon_get(hw, vif); | ||
353 | |||
354 | if (!skb) | ||
355 | return; | ||
356 | |||
357 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
358 | |||
359 | lockdep_assert_held(&priv->mutex); | ||
360 | |||
361 | if (!priv->beacon_ctx) { | ||
362 | IWL_ERR(priv, "update beacon but no beacon context!\n"); | ||
363 | dev_kfree_skb(skb); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | spin_lock_irqsave(&priv->lock, flags); | ||
368 | |||
369 | if (priv->beacon_skb) | ||
370 | dev_kfree_skb(priv->beacon_skb); | ||
371 | |||
372 | priv->beacon_skb = skb; | ||
373 | |||
374 | timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | ||
375 | priv->timestamp = le64_to_cpu(timestamp); | ||
376 | |||
377 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
378 | spin_unlock_irqrestore(&priv->lock, flags); | ||
379 | |||
380 | if (!iwl_is_ready_rf(priv)) { | ||
381 | IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | priv->cfg->ops->legacy->post_associate(priv); | ||
386 | } | ||
387 | |||
388 | void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, | ||
389 | struct ieee80211_vif *vif, | ||
390 | struct ieee80211_bss_conf *bss_conf, | ||
391 | u32 changes) | ||
392 | { | ||
393 | struct iwl_priv *priv = hw->priv; | ||
394 | struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); | ||
395 | int ret; | ||
396 | |||
397 | if (WARN_ON(!priv->cfg->ops->legacy)) | ||
398 | return; | ||
399 | |||
400 | IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); | ||
401 | |||
402 | if (!iwl_is_alive(priv)) | ||
403 | return; | ||
404 | |||
405 | mutex_lock(&priv->mutex); | ||
406 | |||
407 | if (changes & BSS_CHANGED_QOS) { | ||
408 | unsigned long flags; | ||
409 | |||
410 | spin_lock_irqsave(&priv->lock, flags); | ||
411 | ctx->qos_data.qos_active = bss_conf->qos; | ||
412 | iwl_update_qos(priv, ctx); | ||
413 | spin_unlock_irqrestore(&priv->lock, flags); | ||
414 | } | ||
415 | |||
416 | if (changes & BSS_CHANGED_BEACON_ENABLED) { | ||
417 | /* | ||
418 | * the add_interface code must make sure we only ever | ||
419 | * have a single interface that could be beaconing at | ||
420 | * any time. | ||
421 | */ | ||
422 | if (vif->bss_conf.enable_beacon) | ||
423 | priv->beacon_ctx = ctx; | ||
424 | else | ||
425 | priv->beacon_ctx = NULL; | ||
426 | } | ||
427 | |||
428 | if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) { | ||
429 | dev_kfree_skb(priv->beacon_skb); | ||
430 | priv->beacon_skb = ieee80211_beacon_get(hw, vif); | ||
431 | } | ||
432 | |||
433 | if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP) | ||
434 | iwl_send_rxon_timing(priv, ctx); | ||
435 | |||
436 | if (changes & BSS_CHANGED_BSSID) { | ||
437 | IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); | ||
438 | |||
439 | /* | ||
440 | * If there is currently a HW scan going on in the | ||
441 | * background then we need to cancel it else the RXON | ||
442 | * below/in post_associate will fail. | ||
443 | */ | ||
444 | if (iwl_scan_cancel_timeout(priv, 100)) { | ||
445 | IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); | ||
446 | IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); | ||
447 | mutex_unlock(&priv->mutex); | ||
448 | return; | ||
449 | } | ||
450 | |||
451 | /* mac80211 only sets assoc when in STATION mode */ | ||
452 | if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { | ||
453 | memcpy(ctx->staging.bssid_addr, | ||
454 | bss_conf->bssid, ETH_ALEN); | ||
455 | |||
456 | /* currently needed in a few places */ | ||
457 | memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); | ||
458 | } else { | ||
459 | ctx->staging.filter_flags &= | ||
460 | ~RXON_FILTER_ASSOC_MSK; | ||
461 | } | ||
462 | |||
463 | } | ||
464 | |||
465 | /* | ||
466 | * This needs to be after setting the BSSID in case | ||
467 | * mac80211 decides to do both changes at once because | ||
468 | * it will invoke post_associate. | ||
469 | */ | ||
470 | if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON) | ||
471 | iwlcore_beacon_update(hw, vif); | ||
472 | |||
473 | if (changes & BSS_CHANGED_ERP_PREAMBLE) { | ||
474 | IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", | ||
475 | bss_conf->use_short_preamble); | ||
476 | if (bss_conf->use_short_preamble) | ||
477 | ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; | ||
478 | else | ||
479 | ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; | ||
480 | } | ||
481 | |||
482 | if (changes & BSS_CHANGED_ERP_CTS_PROT) { | ||
483 | IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); | ||
484 | if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) | ||
485 | ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; | ||
486 | else | ||
487 | ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; | ||
488 | if (bss_conf->use_cts_prot) | ||
489 | ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; | ||
490 | else | ||
491 | ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; | ||
492 | } | ||
493 | |||
494 | if (changes & BSS_CHANGED_BASIC_RATES) { | ||
495 | /* XXX use this information | ||
496 | * | ||
497 | * To do that, remove code from iwl_set_rate() and put something | ||
498 | * like this here: | ||
499 | * | ||
500 | if (A-band) | ||
501 | ctx->staging.ofdm_basic_rates = | ||
502 | bss_conf->basic_rates; | ||
503 | else | ||
504 | ctx->staging.ofdm_basic_rates = | ||
505 | bss_conf->basic_rates >> 4; | ||
506 | ctx->staging.cck_basic_rates = | ||
507 | bss_conf->basic_rates & 0xF; | ||
508 | */ | ||
509 | } | ||
510 | |||
511 | if (changes & BSS_CHANGED_HT) { | ||
512 | iwl_ht_conf(priv, vif); | ||
513 | |||
514 | if (priv->cfg->ops->hcmd->set_rxon_chain) | ||
515 | priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); | ||
516 | } | ||
517 | |||
518 | if (changes & BSS_CHANGED_ASSOC) { | ||
519 | IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); | ||
520 | if (bss_conf->assoc) { | ||
521 | priv->timestamp = bss_conf->timestamp; | ||
522 | |||
523 | iwl_led_associate(priv); | ||
524 | |||
525 | if (!iwl_is_rfkill(priv)) | ||
526 | priv->cfg->ops->legacy->post_associate(priv); | ||
527 | } else | ||
528 | iwl_set_no_assoc(priv, vif); | ||
529 | } | ||
530 | |||
531 | if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) { | ||
532 | IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n", | ||
533 | changes); | ||
534 | ret = iwl_send_rxon_assoc(priv, ctx); | ||
535 | if (!ret) { | ||
536 | /* Sync active_rxon with latest change. */ | ||
537 | memcpy((void *)&ctx->active, | ||
538 | &ctx->staging, | ||
539 | sizeof(struct iwl_rxon_cmd)); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | if (changes & BSS_CHANGED_BEACON_ENABLED) { | ||
544 | if (vif->bss_conf.enable_beacon) { | ||
545 | memcpy(ctx->staging.bssid_addr, | ||
546 | bss_conf->bssid, ETH_ALEN); | ||
547 | memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); | ||
548 | iwl_led_associate(priv); | ||
549 | priv->cfg->ops->legacy->config_ap(priv); | ||
550 | } else | ||
551 | iwl_set_no_assoc(priv, vif); | ||
552 | } | ||
553 | |||
554 | if (changes & BSS_CHANGED_IBSS) { | ||
555 | ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif, | ||
556 | bss_conf->ibss_joined); | ||
557 | if (ret) | ||
558 | IWL_ERR(priv, "failed to %s IBSS station %pM\n", | ||
559 | bss_conf->ibss_joined ? "add" : "remove", | ||
560 | bss_conf->bssid); | ||
561 | } | ||
562 | |||
563 | mutex_unlock(&priv->mutex); | ||
564 | |||
565 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
566 | } | ||
567 | EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed); | ||
568 | |||
569 | irqreturn_t iwl_isr_legacy(int irq, void *data) | ||
570 | { | ||
571 | struct iwl_priv *priv = data; | ||
572 | u32 inta, inta_mask; | ||
573 | u32 inta_fh; | ||
574 | unsigned long flags; | ||
575 | if (!priv) | ||
576 | return IRQ_NONE; | ||
577 | |||
578 | spin_lock_irqsave(&priv->lock, flags); | ||
579 | |||
580 | /* Disable (but don't clear!) interrupts here to avoid | ||
581 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
582 | * If we have something to service, the tasklet will re-enable ints. | ||
583 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
584 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
585 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
586 | |||
587 | /* Discover which interrupts are active/pending */ | ||
588 | inta = iwl_read32(priv, CSR_INT); | ||
589 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
590 | |||
591 | /* Ignore interrupt if there's nothing in NIC to service. | ||
592 | * This may be due to IRQ shared with another device, | ||
593 | * or due to sporadic interrupts thrown from our NIC. */ | ||
594 | if (!inta && !inta_fh) { | ||
595 | IWL_DEBUG_ISR(priv, | ||
596 | "Ignore interrupt, inta == 0, inta_fh == 0\n"); | ||
597 | goto none; | ||
598 | } | ||
599 | |||
600 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
601 | /* Hardware disappeared. It might have already raised | ||
602 | * an interrupt */ | ||
603 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
604 | goto unplugged; | ||
605 | } | ||
606 | |||
607 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | ||
608 | inta, inta_mask, inta_fh); | ||
609 | |||
610 | inta &= ~CSR_INT_BIT_SCD; | ||
611 | |||
612 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
613 | if (likely(inta || inta_fh)) | ||
614 | tasklet_schedule(&priv->irq_tasklet); | ||
615 | |||
616 | unplugged: | ||
617 | spin_unlock_irqrestore(&priv->lock, flags); | ||
618 | return IRQ_HANDLED; | ||
619 | |||
620 | none: | ||
621 | /* re-enable interrupts here since we don't have anything to service. */ | ||
622 | /* only Re-enable if disabled by irq */ | ||
623 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
624 | iwl_enable_interrupts(priv); | ||
625 | spin_unlock_irqrestore(&priv->lock, flags); | ||
626 | return IRQ_NONE; | ||
627 | } | ||
628 | EXPORT_SYMBOL(iwl_isr_legacy); | ||
629 | |||
630 | /* | ||
631 | * iwl_legacy_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this | ||
632 | * function. | ||
633 | */ | ||
634 | void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv, | ||
635 | struct ieee80211_tx_info *info, | ||
636 | __le16 fc, __le32 *tx_flags) | ||
637 | { | ||
638 | if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { | ||
639 | *tx_flags |= TX_CMD_FLG_RTS_MSK; | ||
640 | *tx_flags &= ~TX_CMD_FLG_CTS_MSK; | ||
641 | *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; | ||
642 | |||
643 | if (!ieee80211_is_mgmt(fc)) | ||
644 | return; | ||
645 | |||
646 | switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { | ||
647 | case cpu_to_le16(IEEE80211_STYPE_AUTH): | ||
648 | case cpu_to_le16(IEEE80211_STYPE_DEAUTH): | ||
649 | case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): | ||
650 | case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): | ||
651 | *tx_flags &= ~TX_CMD_FLG_RTS_MSK; | ||
652 | *tx_flags |= TX_CMD_FLG_CTS_MSK; | ||
653 | break; | ||
654 | } | ||
655 | } else if (info->control.rates[0].flags & | ||
656 | IEEE80211_TX_RC_USE_CTS_PROTECT) { | ||
657 | *tx_flags &= ~TX_CMD_FLG_RTS_MSK; | ||
658 | *tx_flags |= TX_CMD_FLG_CTS_MSK; | ||
659 | *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; | ||
660 | } | ||
661 | } | ||
662 | EXPORT_SYMBOL(iwl_legacy_tx_cmd_protection); | ||