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