diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-lib.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 2047 |
1 files changed, 2047 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c new file mode 100644 index 00000000000..3bee0f119bc --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -0,0 +1,2047 @@ | |||
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/etherdevice.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/sched.h> | ||
34 | |||
35 | #include "iwl-dev.h" | ||
36 | #include "iwl-core.h" | ||
37 | #include "iwl-io.h" | ||
38 | #include "iwl-helpers.h" | ||
39 | #include "iwl-agn-hw.h" | ||
40 | #include "iwl-agn.h" | ||
41 | #include "iwl-sta.h" | ||
42 | #include "iwl-trans.h" | ||
43 | |||
44 | static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) | ||
45 | { | ||
46 | return le32_to_cpup((__le32 *)&tx_resp->status + | ||
47 | tx_resp->frame_count) & MAX_SN; | ||
48 | } | ||
49 | |||
50 | static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status) | ||
51 | { | ||
52 | status &= TX_STATUS_MSK; | ||
53 | |||
54 | switch (status) { | ||
55 | case TX_STATUS_POSTPONE_DELAY: | ||
56 | priv->reply_tx_stats.pp_delay++; | ||
57 | break; | ||
58 | case TX_STATUS_POSTPONE_FEW_BYTES: | ||
59 | priv->reply_tx_stats.pp_few_bytes++; | ||
60 | break; | ||
61 | case TX_STATUS_POSTPONE_BT_PRIO: | ||
62 | priv->reply_tx_stats.pp_bt_prio++; | ||
63 | break; | ||
64 | case TX_STATUS_POSTPONE_QUIET_PERIOD: | ||
65 | priv->reply_tx_stats.pp_quiet_period++; | ||
66 | break; | ||
67 | case TX_STATUS_POSTPONE_CALC_TTAK: | ||
68 | priv->reply_tx_stats.pp_calc_ttak++; | ||
69 | break; | ||
70 | case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: | ||
71 | priv->reply_tx_stats.int_crossed_retry++; | ||
72 | break; | ||
73 | case TX_STATUS_FAIL_SHORT_LIMIT: | ||
74 | priv->reply_tx_stats.short_limit++; | ||
75 | break; | ||
76 | case TX_STATUS_FAIL_LONG_LIMIT: | ||
77 | priv->reply_tx_stats.long_limit++; | ||
78 | break; | ||
79 | case TX_STATUS_FAIL_FIFO_UNDERRUN: | ||
80 | priv->reply_tx_stats.fifo_underrun++; | ||
81 | break; | ||
82 | case TX_STATUS_FAIL_DRAIN_FLOW: | ||
83 | priv->reply_tx_stats.drain_flow++; | ||
84 | break; | ||
85 | case TX_STATUS_FAIL_RFKILL_FLUSH: | ||
86 | priv->reply_tx_stats.rfkill_flush++; | ||
87 | break; | ||
88 | case TX_STATUS_FAIL_LIFE_EXPIRE: | ||
89 | priv->reply_tx_stats.life_expire++; | ||
90 | break; | ||
91 | case TX_STATUS_FAIL_DEST_PS: | ||
92 | priv->reply_tx_stats.dest_ps++; | ||
93 | break; | ||
94 | case TX_STATUS_FAIL_HOST_ABORTED: | ||
95 | priv->reply_tx_stats.host_abort++; | ||
96 | break; | ||
97 | case TX_STATUS_FAIL_BT_RETRY: | ||
98 | priv->reply_tx_stats.bt_retry++; | ||
99 | break; | ||
100 | case TX_STATUS_FAIL_STA_INVALID: | ||
101 | priv->reply_tx_stats.sta_invalid++; | ||
102 | break; | ||
103 | case TX_STATUS_FAIL_FRAG_DROPPED: | ||
104 | priv->reply_tx_stats.frag_drop++; | ||
105 | break; | ||
106 | case TX_STATUS_FAIL_TID_DISABLE: | ||
107 | priv->reply_tx_stats.tid_disable++; | ||
108 | break; | ||
109 | case TX_STATUS_FAIL_FIFO_FLUSHED: | ||
110 | priv->reply_tx_stats.fifo_flush++; | ||
111 | break; | ||
112 | case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL: | ||
113 | priv->reply_tx_stats.insuff_cf_poll++; | ||
114 | break; | ||
115 | case TX_STATUS_FAIL_PASSIVE_NO_RX: | ||
116 | priv->reply_tx_stats.fail_hw_drop++; | ||
117 | break; | ||
118 | case TX_STATUS_FAIL_NO_BEACON_ON_RADAR: | ||
119 | priv->reply_tx_stats.sta_color_mismatch++; | ||
120 | break; | ||
121 | default: | ||
122 | priv->reply_tx_stats.unknown++; | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) | ||
128 | { | ||
129 | status &= AGG_TX_STATUS_MSK; | ||
130 | |||
131 | switch (status) { | ||
132 | case AGG_TX_STATE_UNDERRUN_MSK: | ||
133 | priv->reply_agg_tx_stats.underrun++; | ||
134 | break; | ||
135 | case AGG_TX_STATE_BT_PRIO_MSK: | ||
136 | priv->reply_agg_tx_stats.bt_prio++; | ||
137 | break; | ||
138 | case AGG_TX_STATE_FEW_BYTES_MSK: | ||
139 | priv->reply_agg_tx_stats.few_bytes++; | ||
140 | break; | ||
141 | case AGG_TX_STATE_ABORT_MSK: | ||
142 | priv->reply_agg_tx_stats.abort++; | ||
143 | break; | ||
144 | case AGG_TX_STATE_LAST_SENT_TTL_MSK: | ||
145 | priv->reply_agg_tx_stats.last_sent_ttl++; | ||
146 | break; | ||
147 | case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK: | ||
148 | priv->reply_agg_tx_stats.last_sent_try++; | ||
149 | break; | ||
150 | case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK: | ||
151 | priv->reply_agg_tx_stats.last_sent_bt_kill++; | ||
152 | break; | ||
153 | case AGG_TX_STATE_SCD_QUERY_MSK: | ||
154 | priv->reply_agg_tx_stats.scd_query++; | ||
155 | break; | ||
156 | case AGG_TX_STATE_TEST_BAD_CRC32_MSK: | ||
157 | priv->reply_agg_tx_stats.bad_crc32++; | ||
158 | break; | ||
159 | case AGG_TX_STATE_RESPONSE_MSK: | ||
160 | priv->reply_agg_tx_stats.response++; | ||
161 | break; | ||
162 | case AGG_TX_STATE_DUMP_TX_MSK: | ||
163 | priv->reply_agg_tx_stats.dump_tx++; | ||
164 | break; | ||
165 | case AGG_TX_STATE_DELAY_TX_MSK: | ||
166 | priv->reply_agg_tx_stats.delay_tx++; | ||
167 | break; | ||
168 | default: | ||
169 | priv->reply_agg_tx_stats.unknown++; | ||
170 | break; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | static void iwlagn_set_tx_status(struct iwl_priv *priv, | ||
175 | struct ieee80211_tx_info *info, | ||
176 | struct iwl_rxon_context *ctx, | ||
177 | struct iwlagn_tx_resp *tx_resp, | ||
178 | int txq_id, bool is_agg) | ||
179 | { | ||
180 | u16 status = le16_to_cpu(tx_resp->status.status); | ||
181 | |||
182 | info->status.rates[0].count = tx_resp->failure_frame + 1; | ||
183 | if (is_agg) | ||
184 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | ||
185 | info->flags |= iwl_tx_status_to_mac80211(status); | ||
186 | iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), | ||
187 | info); | ||
188 | if (!iwl_is_tx_success(status)) | ||
189 | iwlagn_count_tx_err_status(priv, status); | ||
190 | |||
191 | if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && | ||
192 | iwl_is_associated_ctx(ctx) && ctx->vif && | ||
193 | ctx->vif->type == NL80211_IFTYPE_STATION) { | ||
194 | ctx->last_tx_rejected = true; | ||
195 | iwl_stop_queue(priv, &priv->txq[txq_id]); | ||
196 | } | ||
197 | |||
198 | IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " | ||
199 | "0x%x retries %d\n", | ||
200 | txq_id, | ||
201 | iwl_get_tx_fail_reason(status), status, | ||
202 | le32_to_cpu(tx_resp->rate_n_flags), | ||
203 | tx_resp->failure_frame); | ||
204 | } | ||
205 | |||
206 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
207 | #define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x | ||
208 | |||
209 | const char *iwl_get_agg_tx_fail_reason(u16 status) | ||
210 | { | ||
211 | status &= AGG_TX_STATUS_MSK; | ||
212 | switch (status) { | ||
213 | case AGG_TX_STATE_TRANSMITTED: | ||
214 | return "SUCCESS"; | ||
215 | AGG_TX_STATE_FAIL(UNDERRUN_MSK); | ||
216 | AGG_TX_STATE_FAIL(BT_PRIO_MSK); | ||
217 | AGG_TX_STATE_FAIL(FEW_BYTES_MSK); | ||
218 | AGG_TX_STATE_FAIL(ABORT_MSK); | ||
219 | AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK); | ||
220 | AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK); | ||
221 | AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK); | ||
222 | AGG_TX_STATE_FAIL(SCD_QUERY_MSK); | ||
223 | AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK); | ||
224 | AGG_TX_STATE_FAIL(RESPONSE_MSK); | ||
225 | AGG_TX_STATE_FAIL(DUMP_TX_MSK); | ||
226 | AGG_TX_STATE_FAIL(DELAY_TX_MSK); | ||
227 | } | ||
228 | |||
229 | return "UNKNOWN"; | ||
230 | } | ||
231 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
232 | |||
233 | static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, | ||
234 | struct iwl_ht_agg *agg, | ||
235 | struct iwlagn_tx_resp *tx_resp, | ||
236 | int txq_id, u16 start_idx) | ||
237 | { | ||
238 | u16 status; | ||
239 | struct agg_tx_status *frame_status = &tx_resp->status; | ||
240 | struct ieee80211_hdr *hdr = NULL; | ||
241 | int i, sh, idx; | ||
242 | u16 seq; | ||
243 | |||
244 | if (agg->wait_for_ba) | ||
245 | IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n"); | ||
246 | |||
247 | agg->frame_count = tx_resp->frame_count; | ||
248 | agg->start_idx = start_idx; | ||
249 | agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); | ||
250 | agg->bitmap = 0; | ||
251 | |||
252 | /* # frames attempted by Tx command */ | ||
253 | if (agg->frame_count == 1) { | ||
254 | struct iwl_tx_info *txb; | ||
255 | |||
256 | /* Only one frame was attempted; no block-ack will arrive */ | ||
257 | idx = start_idx; | ||
258 | |||
259 | IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", | ||
260 | agg->frame_count, agg->start_idx, idx); | ||
261 | txb = &priv->txq[txq_id].txb[idx]; | ||
262 | iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), | ||
263 | txb->ctx, tx_resp, txq_id, true); | ||
264 | agg->wait_for_ba = 0; | ||
265 | } else { | ||
266 | /* Two or more frames were attempted; expect block-ack */ | ||
267 | u64 bitmap = 0; | ||
268 | |||
269 | /* | ||
270 | * Start is the lowest frame sent. It may not be the first | ||
271 | * frame in the batch; we figure this out dynamically during | ||
272 | * the following loop. | ||
273 | */ | ||
274 | int start = agg->start_idx; | ||
275 | |||
276 | /* Construct bit-map of pending frames within Tx window */ | ||
277 | for (i = 0; i < agg->frame_count; i++) { | ||
278 | u16 sc; | ||
279 | status = le16_to_cpu(frame_status[i].status); | ||
280 | seq = le16_to_cpu(frame_status[i].sequence); | ||
281 | idx = SEQ_TO_INDEX(seq); | ||
282 | txq_id = SEQ_TO_QUEUE(seq); | ||
283 | |||
284 | if (status & AGG_TX_STATUS_MSK) | ||
285 | iwlagn_count_agg_tx_err_status(priv, status); | ||
286 | |||
287 | if (status & (AGG_TX_STATE_FEW_BYTES_MSK | | ||
288 | AGG_TX_STATE_ABORT_MSK)) | ||
289 | continue; | ||
290 | |||
291 | IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n", | ||
292 | agg->frame_count, txq_id, idx); | ||
293 | IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " | ||
294 | "try-count (0x%08x)\n", | ||
295 | iwl_get_agg_tx_fail_reason(status), | ||
296 | status & AGG_TX_STATUS_MSK, | ||
297 | status & AGG_TX_TRY_MSK); | ||
298 | |||
299 | hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); | ||
300 | if (!hdr) { | ||
301 | IWL_ERR(priv, | ||
302 | "BUG_ON idx doesn't point to valid skb" | ||
303 | " idx=%d, txq_id=%d\n", idx, txq_id); | ||
304 | return -1; | ||
305 | } | ||
306 | |||
307 | sc = le16_to_cpu(hdr->seq_ctrl); | ||
308 | if (idx != (SEQ_TO_SN(sc) & 0xff)) { | ||
309 | IWL_ERR(priv, | ||
310 | "BUG_ON idx doesn't match seq control" | ||
311 | " idx=%d, seq_idx=%d, seq=%d\n", | ||
312 | idx, SEQ_TO_SN(sc), | ||
313 | hdr->seq_ctrl); | ||
314 | return -1; | ||
315 | } | ||
316 | |||
317 | IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n", | ||
318 | i, idx, SEQ_TO_SN(sc)); | ||
319 | |||
320 | /* | ||
321 | * sh -> how many frames ahead of the starting frame is | ||
322 | * the current one? | ||
323 | * | ||
324 | * Note that all frames sent in the batch must be in a | ||
325 | * 64-frame window, so this number should be in [0,63]. | ||
326 | * If outside of this window, then we've found a new | ||
327 | * "first" frame in the batch and need to change start. | ||
328 | */ | ||
329 | sh = idx - start; | ||
330 | |||
331 | /* | ||
332 | * If >= 64, out of window. start must be at the front | ||
333 | * of the circular buffer, idx must be near the end of | ||
334 | * the buffer, and idx is the new "first" frame. Shift | ||
335 | * the indices around. | ||
336 | */ | ||
337 | if (sh >= 64) { | ||
338 | /* Shift bitmap by start - idx, wrapped */ | ||
339 | sh = 0x100 - idx + start; | ||
340 | bitmap = bitmap << sh; | ||
341 | /* Now idx is the new start so sh = 0 */ | ||
342 | sh = 0; | ||
343 | start = idx; | ||
344 | /* | ||
345 | * If <= -64 then wraps the 256-pkt circular buffer | ||
346 | * (e.g., start = 255 and idx = 0, sh should be 1) | ||
347 | */ | ||
348 | } else if (sh <= -64) { | ||
349 | sh = 0x100 - start + idx; | ||
350 | /* | ||
351 | * If < 0 but > -64, out of window. idx is before start | ||
352 | * but not wrapped. Shift the indices around. | ||
353 | */ | ||
354 | } else if (sh < 0) { | ||
355 | /* Shift by how far start is ahead of idx */ | ||
356 | sh = start - idx; | ||
357 | bitmap = bitmap << sh; | ||
358 | /* Now idx is the new start so sh = 0 */ | ||
359 | start = idx; | ||
360 | sh = 0; | ||
361 | } | ||
362 | /* Sequence number start + sh was sent in this batch */ | ||
363 | bitmap |= 1ULL << sh; | ||
364 | IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n", | ||
365 | start, (unsigned long long)bitmap); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Store the bitmap and possibly the new start, if we wrapped | ||
370 | * the buffer above | ||
371 | */ | ||
372 | agg->bitmap = bitmap; | ||
373 | agg->start_idx = start; | ||
374 | IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n", | ||
375 | agg->frame_count, agg->start_idx, | ||
376 | (unsigned long long)agg->bitmap); | ||
377 | |||
378 | if (bitmap) | ||
379 | agg->wait_for_ba = 1; | ||
380 | } | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | void iwl_check_abort_status(struct iwl_priv *priv, | ||
385 | u8 frame_count, u32 status) | ||
386 | { | ||
387 | if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { | ||
388 | IWL_ERR(priv, "Tx flush command to flush out all frames\n"); | ||
389 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
390 | queue_work(priv->workqueue, &priv->tx_flush); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | ||
395 | { | ||
396 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
397 | u16 sequence = le16_to_cpu(pkt->hdr.sequence); | ||
398 | int txq_id = SEQ_TO_QUEUE(sequence); | ||
399 | int index = SEQ_TO_INDEX(sequence); | ||
400 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | ||
401 | struct ieee80211_tx_info *info; | ||
402 | struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; | ||
403 | struct ieee80211_hdr *hdr; | ||
404 | struct iwl_tx_info *txb; | ||
405 | u32 status = le16_to_cpu(tx_resp->status.status); | ||
406 | int tid; | ||
407 | int sta_id; | ||
408 | int freed; | ||
409 | unsigned long flags; | ||
410 | |||
411 | if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { | ||
412 | IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) " | ||
413 | "index %d is out of range [0-%d] %d %d\n", __func__, | ||
414 | txq_id, index, txq->q.n_bd, txq->q.write_ptr, | ||
415 | txq->q.read_ptr); | ||
416 | return; | ||
417 | } | ||
418 | |||
419 | txq->time_stamp = jiffies; | ||
420 | txb = &txq->txb[txq->q.read_ptr]; | ||
421 | info = IEEE80211_SKB_CB(txb->skb); | ||
422 | memset(&info->status, 0, sizeof(info->status)); | ||
423 | |||
424 | tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> | ||
425 | IWLAGN_TX_RES_TID_POS; | ||
426 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | ||
427 | IWLAGN_TX_RES_RA_POS; | ||
428 | |||
429 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
430 | |||
431 | hdr = (void *)txb->skb->data; | ||
432 | if (!ieee80211_is_data_qos(hdr->frame_control)) | ||
433 | priv->last_seq_ctl = tx_resp->seq_ctl; | ||
434 | |||
435 | if (txq->sched_retry) { | ||
436 | const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp); | ||
437 | struct iwl_ht_agg *agg; | ||
438 | |||
439 | agg = &priv->stations[sta_id].tid[tid].agg; | ||
440 | /* | ||
441 | * If the BT kill count is non-zero, we'll get this | ||
442 | * notification again. | ||
443 | */ | ||
444 | if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && | ||
445 | priv->cfg->bt_params && | ||
446 | priv->cfg->bt_params->advanced_bt_coexist) { | ||
447 | IWL_DEBUG_COEX(priv, "receive reply tx with bt_kill\n"); | ||
448 | } | ||
449 | iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); | ||
450 | |||
451 | /* check if BAR is needed */ | ||
452 | if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) | ||
453 | info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | ||
454 | |||
455 | if (txq->q.read_ptr != (scd_ssn & 0xff)) { | ||
456 | index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); | ||
457 | IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim " | ||
458 | "scd_ssn=%d idx=%d txq=%d swq=%d\n", | ||
459 | scd_ssn , index, txq_id, txq->swq_id); | ||
460 | |||
461 | freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); | ||
462 | iwl_free_tfds_in_queue(priv, sta_id, tid, freed); | ||
463 | |||
464 | if (priv->mac80211_registered && | ||
465 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && | ||
466 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) | ||
467 | iwl_wake_queue(priv, txq); | ||
468 | } | ||
469 | } else { | ||
470 | iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, | ||
471 | txq_id, false); | ||
472 | freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); | ||
473 | iwl_free_tfds_in_queue(priv, sta_id, tid, freed); | ||
474 | |||
475 | if (priv->mac80211_registered && | ||
476 | iwl_queue_space(&txq->q) > txq->q.low_mark && | ||
477 | status != TX_STATUS_FAIL_PASSIVE_NO_RX) | ||
478 | iwl_wake_queue(priv, txq); | ||
479 | } | ||
480 | |||
481 | iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); | ||
482 | |||
483 | iwl_check_abort_status(priv, tx_resp->frame_count, status); | ||
484 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
485 | } | ||
486 | |||
487 | int iwlagn_hw_valid_rtc_data_addr(u32 addr) | ||
488 | { | ||
489 | return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) && | ||
490 | (addr < IWLAGN_RTC_DATA_UPPER_BOUND); | ||
491 | } | ||
492 | |||
493 | int iwlagn_send_tx_power(struct iwl_priv *priv) | ||
494 | { | ||
495 | struct iwlagn_tx_power_dbm_cmd tx_power_cmd; | ||
496 | u8 tx_ant_cfg_cmd; | ||
497 | |||
498 | if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), | ||
499 | "TX Power requested while scanning!\n")) | ||
500 | return -EAGAIN; | ||
501 | |||
502 | /* half dBm need to multiply */ | ||
503 | tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); | ||
504 | |||
505 | if (priv->tx_power_lmt_in_half_dbm && | ||
506 | priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) { | ||
507 | /* | ||
508 | * For the newer devices which using enhanced/extend tx power | ||
509 | * table in EEPROM, the format is in half dBm. driver need to | ||
510 | * convert to dBm format before report to mac80211. | ||
511 | * By doing so, there is a possibility of 1/2 dBm resolution | ||
512 | * lost. driver will perform "round-up" operation before | ||
513 | * reporting, but it will cause 1/2 dBm tx power over the | ||
514 | * regulatory limit. Perform the checking here, if the | ||
515 | * "tx_power_user_lmt" is higher than EEPROM value (in | ||
516 | * half-dBm format), lower the tx power based on EEPROM | ||
517 | */ | ||
518 | tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm; | ||
519 | } | ||
520 | tx_power_cmd.flags = IWLAGN_TX_POWER_NO_CLOSED; | ||
521 | tx_power_cmd.srv_chan_lmt = IWLAGN_TX_POWER_AUTO; | ||
522 | |||
523 | if (IWL_UCODE_API(priv->ucode_ver) == 1) | ||
524 | tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1; | ||
525 | else | ||
526 | tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; | ||
527 | |||
528 | return trans_send_cmd_pdu(&priv->trans, tx_ant_cfg_cmd, CMD_SYNC, | ||
529 | sizeof(tx_power_cmd), &tx_power_cmd); | ||
530 | } | ||
531 | |||
532 | void iwlagn_temperature(struct iwl_priv *priv) | ||
533 | { | ||
534 | /* store temperature from correct statistics (in Celsius) */ | ||
535 | priv->temperature = le32_to_cpu(priv->statistics.common.temperature); | ||
536 | iwl_tt_handler(priv); | ||
537 | } | ||
538 | |||
539 | u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv) | ||
540 | { | ||
541 | struct iwl_eeprom_calib_hdr { | ||
542 | u8 version; | ||
543 | u8 pa_type; | ||
544 | u16 voltage; | ||
545 | } *hdr; | ||
546 | |||
547 | hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, | ||
548 | EEPROM_CALIB_ALL); | ||
549 | return hdr->version; | ||
550 | |||
551 | } | ||
552 | |||
553 | /* | ||
554 | * EEPROM | ||
555 | */ | ||
556 | static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) | ||
557 | { | ||
558 | u16 offset = 0; | ||
559 | |||
560 | if ((address & INDIRECT_ADDRESS) == 0) | ||
561 | return address; | ||
562 | |||
563 | switch (address & INDIRECT_TYPE_MSK) { | ||
564 | case INDIRECT_HOST: | ||
565 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST); | ||
566 | break; | ||
567 | case INDIRECT_GENERAL: | ||
568 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL); | ||
569 | break; | ||
570 | case INDIRECT_REGULATORY: | ||
571 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY); | ||
572 | break; | ||
573 | case INDIRECT_TXP_LIMIT: | ||
574 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT); | ||
575 | break; | ||
576 | case INDIRECT_TXP_LIMIT_SIZE: | ||
577 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE); | ||
578 | break; | ||
579 | case INDIRECT_CALIBRATION: | ||
580 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION); | ||
581 | break; | ||
582 | case INDIRECT_PROCESS_ADJST: | ||
583 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST); | ||
584 | break; | ||
585 | case INDIRECT_OTHERS: | ||
586 | offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS); | ||
587 | break; | ||
588 | default: | ||
589 | IWL_ERR(priv, "illegal indirect type: 0x%X\n", | ||
590 | address & INDIRECT_TYPE_MSK); | ||
591 | break; | ||
592 | } | ||
593 | |||
594 | /* translate the offset from words to byte */ | ||
595 | return (address & ADDRESS_MSK) + (offset << 1); | ||
596 | } | ||
597 | |||
598 | const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset) | ||
599 | { | ||
600 | u32 address = eeprom_indirect_address(priv, offset); | ||
601 | BUG_ON(address >= priv->cfg->base_params->eeprom_size); | ||
602 | return &priv->eeprom[address]; | ||
603 | } | ||
604 | |||
605 | struct iwl_mod_params iwlagn_mod_params = { | ||
606 | .amsdu_size_8K = 1, | ||
607 | .restart_fw = 1, | ||
608 | .plcp_check = true, | ||
609 | .bt_coex_active = true, | ||
610 | .no_sleep_autoadjust = true, | ||
611 | .power_level = IWL_POWER_INDEX_1, | ||
612 | /* the rest are 0 by default */ | ||
613 | }; | ||
614 | |||
615 | int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) | ||
616 | { | ||
617 | int idx = 0; | ||
618 | int band_offset = 0; | ||
619 | |||
620 | /* HT rate format: mac80211 wants an MCS number, which is just LSB */ | ||
621 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
622 | idx = (rate_n_flags & 0xff); | ||
623 | return idx; | ||
624 | /* Legacy rate format, search for match in table */ | ||
625 | } else { | ||
626 | if (band == IEEE80211_BAND_5GHZ) | ||
627 | band_offset = IWL_FIRST_OFDM_RATE; | ||
628 | for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) | ||
629 | if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) | ||
630 | return idx - band_offset; | ||
631 | } | ||
632 | |||
633 | return -1; | ||
634 | } | ||
635 | |||
636 | static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, | ||
637 | struct ieee80211_vif *vif, | ||
638 | enum ieee80211_band band, | ||
639 | struct iwl_scan_channel *scan_ch) | ||
640 | { | ||
641 | const struct ieee80211_supported_band *sband; | ||
642 | u16 passive_dwell = 0; | ||
643 | u16 active_dwell = 0; | ||
644 | int added = 0; | ||
645 | u16 channel = 0; | ||
646 | |||
647 | sband = iwl_get_hw_mode(priv, band); | ||
648 | if (!sband) { | ||
649 | IWL_ERR(priv, "invalid band\n"); | ||
650 | return added; | ||
651 | } | ||
652 | |||
653 | active_dwell = iwl_get_active_dwell_time(priv, band, 0); | ||
654 | passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); | ||
655 | |||
656 | if (passive_dwell <= active_dwell) | ||
657 | passive_dwell = active_dwell + 1; | ||
658 | |||
659 | channel = iwl_get_single_channel_number(priv, band); | ||
660 | if (channel) { | ||
661 | scan_ch->channel = cpu_to_le16(channel); | ||
662 | scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; | ||
663 | scan_ch->active_dwell = cpu_to_le16(active_dwell); | ||
664 | scan_ch->passive_dwell = cpu_to_le16(passive_dwell); | ||
665 | /* Set txpower levels to defaults */ | ||
666 | scan_ch->dsp_atten = 110; | ||
667 | if (band == IEEE80211_BAND_5GHZ) | ||
668 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | ||
669 | else | ||
670 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | ||
671 | added++; | ||
672 | } else | ||
673 | IWL_ERR(priv, "no valid channel found\n"); | ||
674 | return added; | ||
675 | } | ||
676 | |||
677 | static int iwl_get_channels_for_scan(struct iwl_priv *priv, | ||
678 | struct ieee80211_vif *vif, | ||
679 | enum ieee80211_band band, | ||
680 | u8 is_active, u8 n_probes, | ||
681 | struct iwl_scan_channel *scan_ch) | ||
682 | { | ||
683 | struct ieee80211_channel *chan; | ||
684 | const struct ieee80211_supported_band *sband; | ||
685 | const struct iwl_channel_info *ch_info; | ||
686 | u16 passive_dwell = 0; | ||
687 | u16 active_dwell = 0; | ||
688 | int added, i; | ||
689 | u16 channel; | ||
690 | |||
691 | sband = iwl_get_hw_mode(priv, band); | ||
692 | if (!sband) | ||
693 | return 0; | ||
694 | |||
695 | active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); | ||
696 | passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); | ||
697 | |||
698 | if (passive_dwell <= active_dwell) | ||
699 | passive_dwell = active_dwell + 1; | ||
700 | |||
701 | for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { | ||
702 | chan = priv->scan_request->channels[i]; | ||
703 | |||
704 | if (chan->band != band) | ||
705 | continue; | ||
706 | |||
707 | channel = chan->hw_value; | ||
708 | scan_ch->channel = cpu_to_le16(channel); | ||
709 | |||
710 | ch_info = iwl_get_channel_info(priv, band, channel); | ||
711 | if (!is_channel_valid(ch_info)) { | ||
712 | IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n", | ||
713 | channel); | ||
714 | continue; | ||
715 | } | ||
716 | |||
717 | if (!is_active || is_channel_passive(ch_info) || | ||
718 | (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) | ||
719 | scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; | ||
720 | else | ||
721 | scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; | ||
722 | |||
723 | if (n_probes) | ||
724 | scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); | ||
725 | |||
726 | scan_ch->active_dwell = cpu_to_le16(active_dwell); | ||
727 | scan_ch->passive_dwell = cpu_to_le16(passive_dwell); | ||
728 | |||
729 | /* Set txpower levels to defaults */ | ||
730 | scan_ch->dsp_atten = 110; | ||
731 | |||
732 | /* NOTE: if we were doing 6Mb OFDM for scans we'd use | ||
733 | * power level: | ||
734 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | ||
735 | */ | ||
736 | if (band == IEEE80211_BAND_5GHZ) | ||
737 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | ||
738 | else | ||
739 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | ||
740 | |||
741 | IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n", | ||
742 | channel, le32_to_cpu(scan_ch->type), | ||
743 | (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? | ||
744 | "ACTIVE" : "PASSIVE", | ||
745 | (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? | ||
746 | active_dwell : passive_dwell); | ||
747 | |||
748 | scan_ch++; | ||
749 | added++; | ||
750 | } | ||
751 | |||
752 | IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added); | ||
753 | return added; | ||
754 | } | ||
755 | |||
756 | static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen) | ||
757 | { | ||
758 | struct sk_buff *skb = priv->offchan_tx_skb; | ||
759 | |||
760 | if (skb->len < maxlen) | ||
761 | maxlen = skb->len; | ||
762 | |||
763 | memcpy(data, skb->data, maxlen); | ||
764 | |||
765 | return maxlen; | ||
766 | } | ||
767 | |||
768 | int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) | ||
769 | { | ||
770 | struct iwl_host_cmd cmd = { | ||
771 | .id = REPLY_SCAN_CMD, | ||
772 | .len = { sizeof(struct iwl_scan_cmd), }, | ||
773 | .flags = CMD_SYNC, | ||
774 | }; | ||
775 | struct iwl_scan_cmd *scan; | ||
776 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
777 | u32 rate_flags = 0; | ||
778 | u16 cmd_len; | ||
779 | u16 rx_chain = 0; | ||
780 | enum ieee80211_band band; | ||
781 | u8 n_probes = 0; | ||
782 | u8 rx_ant = priv->hw_params.valid_rx_ant; | ||
783 | u8 rate; | ||
784 | bool is_active = false; | ||
785 | int chan_mod; | ||
786 | u8 active_chains; | ||
787 | u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; | ||
788 | int ret; | ||
789 | |||
790 | lockdep_assert_held(&priv->mutex); | ||
791 | |||
792 | if (vif) | ||
793 | ctx = iwl_rxon_ctx_from_vif(vif); | ||
794 | |||
795 | if (!priv->scan_cmd) { | ||
796 | priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) + | ||
797 | IWL_MAX_SCAN_SIZE, GFP_KERNEL); | ||
798 | if (!priv->scan_cmd) { | ||
799 | IWL_DEBUG_SCAN(priv, | ||
800 | "fail to allocate memory for scan\n"); | ||
801 | return -ENOMEM; | ||
802 | } | ||
803 | } | ||
804 | scan = priv->scan_cmd; | ||
805 | memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); | ||
806 | |||
807 | scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; | ||
808 | scan->quiet_time = IWL_ACTIVE_QUIET_TIME; | ||
809 | |||
810 | if (priv->scan_type != IWL_SCAN_OFFCH_TX && | ||
811 | iwl_is_any_associated(priv)) { | ||
812 | u16 interval = 0; | ||
813 | u32 extra; | ||
814 | u32 suspend_time = 100; | ||
815 | u32 scan_suspend_time = 100; | ||
816 | |||
817 | IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); | ||
818 | switch (priv->scan_type) { | ||
819 | case IWL_SCAN_OFFCH_TX: | ||
820 | WARN_ON(1); | ||
821 | break; | ||
822 | case IWL_SCAN_RADIO_RESET: | ||
823 | interval = 0; | ||
824 | break; | ||
825 | case IWL_SCAN_NORMAL: | ||
826 | interval = vif->bss_conf.beacon_int; | ||
827 | break; | ||
828 | } | ||
829 | |||
830 | scan->suspend_time = 0; | ||
831 | scan->max_out_time = cpu_to_le32(200 * 1024); | ||
832 | if (!interval) | ||
833 | interval = suspend_time; | ||
834 | |||
835 | extra = (suspend_time / interval) << 22; | ||
836 | scan_suspend_time = (extra | | ||
837 | ((suspend_time % interval) * 1024)); | ||
838 | scan->suspend_time = cpu_to_le32(scan_suspend_time); | ||
839 | IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", | ||
840 | scan_suspend_time, interval); | ||
841 | } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) { | ||
842 | scan->suspend_time = 0; | ||
843 | scan->max_out_time = | ||
844 | cpu_to_le32(1024 * priv->offchan_tx_timeout); | ||
845 | } | ||
846 | |||
847 | switch (priv->scan_type) { | ||
848 | case IWL_SCAN_RADIO_RESET: | ||
849 | IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); | ||
850 | break; | ||
851 | case IWL_SCAN_NORMAL: | ||
852 | if (priv->scan_request->n_ssids) { | ||
853 | int i, p = 0; | ||
854 | IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); | ||
855 | for (i = 0; i < priv->scan_request->n_ssids; i++) { | ||
856 | /* always does wildcard anyway */ | ||
857 | if (!priv->scan_request->ssids[i].ssid_len) | ||
858 | continue; | ||
859 | scan->direct_scan[p].id = WLAN_EID_SSID; | ||
860 | scan->direct_scan[p].len = | ||
861 | priv->scan_request->ssids[i].ssid_len; | ||
862 | memcpy(scan->direct_scan[p].ssid, | ||
863 | priv->scan_request->ssids[i].ssid, | ||
864 | priv->scan_request->ssids[i].ssid_len); | ||
865 | n_probes++; | ||
866 | p++; | ||
867 | } | ||
868 | is_active = true; | ||
869 | } else | ||
870 | IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); | ||
871 | break; | ||
872 | case IWL_SCAN_OFFCH_TX: | ||
873 | IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n"); | ||
874 | break; | ||
875 | } | ||
876 | |||
877 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | ||
878 | scan->tx_cmd.sta_id = ctx->bcast_sta_id; | ||
879 | scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; | ||
880 | |||
881 | switch (priv->scan_band) { | ||
882 | case IEEE80211_BAND_2GHZ: | ||
883 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; | ||
884 | chan_mod = le32_to_cpu( | ||
885 | priv->contexts[IWL_RXON_CTX_BSS].active.flags & | ||
886 | RXON_FLG_CHANNEL_MODE_MSK) | ||
887 | >> RXON_FLG_CHANNEL_MODE_POS; | ||
888 | if (chan_mod == CHANNEL_MODE_PURE_40) { | ||
889 | rate = IWL_RATE_6M_PLCP; | ||
890 | } else { | ||
891 | rate = IWL_RATE_1M_PLCP; | ||
892 | rate_flags = RATE_MCS_CCK_MSK; | ||
893 | } | ||
894 | /* | ||
895 | * Internal scans are passive, so we can indiscriminately set | ||
896 | * the BT ignore flag on 2.4 GHz since it applies to TX only. | ||
897 | */ | ||
898 | if (priv->cfg->bt_params && | ||
899 | priv->cfg->bt_params->advanced_bt_coexist) | ||
900 | scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; | ||
901 | break; | ||
902 | case IEEE80211_BAND_5GHZ: | ||
903 | rate = IWL_RATE_6M_PLCP; | ||
904 | break; | ||
905 | default: | ||
906 | IWL_WARN(priv, "Invalid scan band\n"); | ||
907 | return -EIO; | ||
908 | } | ||
909 | |||
910 | /* | ||
911 | * If active scanning is requested but a certain channel is | ||
912 | * marked passive, we can do active scanning if we detect | ||
913 | * transmissions. | ||
914 | * | ||
915 | * There is an issue with some firmware versions that triggers | ||
916 | * a sysassert on a "good CRC threshold" of zero (== disabled), | ||
917 | * on a radar channel even though this means that we should NOT | ||
918 | * send probes. | ||
919 | * | ||
920 | * The "good CRC threshold" is the number of frames that we | ||
921 | * need to receive during our dwell time on a channel before | ||
922 | * sending out probes -- setting this to a huge value will | ||
923 | * mean we never reach it, but at the same time work around | ||
924 | * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER | ||
925 | * here instead of IWL_GOOD_CRC_TH_DISABLED. | ||
926 | * | ||
927 | * This was fixed in later versions along with some other | ||
928 | * scan changes, and the threshold behaves as a flag in those | ||
929 | * versions. | ||
930 | */ | ||
931 | if (priv->new_scan_threshold_behaviour) | ||
932 | scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : | ||
933 | IWL_GOOD_CRC_TH_DISABLED; | ||
934 | else | ||
935 | scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : | ||
936 | IWL_GOOD_CRC_TH_NEVER; | ||
937 | |||
938 | band = priv->scan_band; | ||
939 | |||
940 | if (priv->cfg->scan_rx_antennas[band]) | ||
941 | rx_ant = priv->cfg->scan_rx_antennas[band]; | ||
942 | |||
943 | if (band == IEEE80211_BAND_2GHZ && | ||
944 | priv->cfg->bt_params && | ||
945 | priv->cfg->bt_params->advanced_bt_coexist) { | ||
946 | /* transmit 2.4 GHz probes only on first antenna */ | ||
947 | scan_tx_antennas = first_antenna(scan_tx_antennas); | ||
948 | } | ||
949 | |||
950 | priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], | ||
951 | scan_tx_antennas); | ||
952 | rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); | ||
953 | scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); | ||
954 | |||
955 | /* In power save mode use one chain, otherwise use all chains */ | ||
956 | if (test_bit(STATUS_POWER_PMI, &priv->status)) { | ||
957 | /* rx_ant has been set to all valid chains previously */ | ||
958 | active_chains = rx_ant & | ||
959 | ((u8)(priv->chain_noise_data.active_chains)); | ||
960 | if (!active_chains) | ||
961 | active_chains = rx_ant; | ||
962 | |||
963 | IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", | ||
964 | priv->chain_noise_data.active_chains); | ||
965 | |||
966 | rx_ant = first_antenna(active_chains); | ||
967 | } | ||
968 | if (priv->cfg->bt_params && | ||
969 | priv->cfg->bt_params->advanced_bt_coexist && | ||
970 | priv->bt_full_concurrent) { | ||
971 | /* operated as 1x1 in full concurrency mode */ | ||
972 | rx_ant = first_antenna(rx_ant); | ||
973 | } | ||
974 | |||
975 | /* MIMO is not used here, but value is required */ | ||
976 | rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; | ||
977 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; | ||
978 | rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; | ||
979 | rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; | ||
980 | scan->rx_chain = cpu_to_le16(rx_chain); | ||
981 | switch (priv->scan_type) { | ||
982 | case IWL_SCAN_NORMAL: | ||
983 | cmd_len = iwl_fill_probe_req(priv, | ||
984 | (struct ieee80211_mgmt *)scan->data, | ||
985 | vif->addr, | ||
986 | priv->scan_request->ie, | ||
987 | priv->scan_request->ie_len, | ||
988 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | ||
989 | break; | ||
990 | case IWL_SCAN_RADIO_RESET: | ||
991 | /* use bcast addr, will not be transmitted but must be valid */ | ||
992 | cmd_len = iwl_fill_probe_req(priv, | ||
993 | (struct ieee80211_mgmt *)scan->data, | ||
994 | iwl_bcast_addr, NULL, 0, | ||
995 | IWL_MAX_SCAN_SIZE - sizeof(*scan)); | ||
996 | break; | ||
997 | case IWL_SCAN_OFFCH_TX: | ||
998 | cmd_len = iwl_fill_offch_tx(priv, scan->data, | ||
999 | IWL_MAX_SCAN_SIZE | ||
1000 | - sizeof(*scan) | ||
1001 | - sizeof(struct iwl_scan_channel)); | ||
1002 | scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX; | ||
1003 | break; | ||
1004 | default: | ||
1005 | BUG(); | ||
1006 | } | ||
1007 | scan->tx_cmd.len = cpu_to_le16(cmd_len); | ||
1008 | |||
1009 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | | ||
1010 | RXON_FILTER_BCON_AWARE_MSK); | ||
1011 | |||
1012 | switch (priv->scan_type) { | ||
1013 | case IWL_SCAN_RADIO_RESET: | ||
1014 | scan->channel_count = | ||
1015 | iwl_get_single_channel_for_scan(priv, vif, band, | ||
1016 | (void *)&scan->data[cmd_len]); | ||
1017 | break; | ||
1018 | case IWL_SCAN_NORMAL: | ||
1019 | scan->channel_count = | ||
1020 | iwl_get_channels_for_scan(priv, vif, band, | ||
1021 | is_active, n_probes, | ||
1022 | (void *)&scan->data[cmd_len]); | ||
1023 | break; | ||
1024 | case IWL_SCAN_OFFCH_TX: { | ||
1025 | struct iwl_scan_channel *scan_ch; | ||
1026 | |||
1027 | scan->channel_count = 1; | ||
1028 | |||
1029 | scan_ch = (void *)&scan->data[cmd_len]; | ||
1030 | scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; | ||
1031 | scan_ch->channel = | ||
1032 | cpu_to_le16(priv->offchan_tx_chan->hw_value); | ||
1033 | scan_ch->active_dwell = | ||
1034 | cpu_to_le16(priv->offchan_tx_timeout); | ||
1035 | scan_ch->passive_dwell = 0; | ||
1036 | |||
1037 | /* Set txpower levels to defaults */ | ||
1038 | scan_ch->dsp_atten = 110; | ||
1039 | |||
1040 | /* NOTE: if we were doing 6Mb OFDM for scans we'd use | ||
1041 | * power level: | ||
1042 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | ||
1043 | */ | ||
1044 | if (priv->offchan_tx_chan->band == IEEE80211_BAND_5GHZ) | ||
1045 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | ||
1046 | else | ||
1047 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | ||
1048 | } | ||
1049 | break; | ||
1050 | } | ||
1051 | |||
1052 | if (scan->channel_count == 0) { | ||
1053 | IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); | ||
1054 | return -EIO; | ||
1055 | } | ||
1056 | |||
1057 | cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) + | ||
1058 | scan->channel_count * sizeof(struct iwl_scan_channel); | ||
1059 | cmd.data[0] = scan; | ||
1060 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
1061 | scan->len = cpu_to_le16(cmd.len[0]); | ||
1062 | |||
1063 | /* set scan bit here for PAN params */ | ||
1064 | set_bit(STATUS_SCAN_HW, &priv->status); | ||
1065 | |||
1066 | ret = iwlagn_set_pan_params(priv); | ||
1067 | if (ret) | ||
1068 | return ret; | ||
1069 | |||
1070 | ret = trans_send_cmd(&priv->trans, &cmd); | ||
1071 | if (ret) { | ||
1072 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
1073 | iwlagn_set_pan_params(priv); | ||
1074 | } | ||
1075 | |||
1076 | return ret; | ||
1077 | } | ||
1078 | |||
1079 | int iwlagn_manage_ibss_station(struct iwl_priv *priv, | ||
1080 | struct ieee80211_vif *vif, bool add) | ||
1081 | { | ||
1082 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1083 | |||
1084 | if (add) | ||
1085 | return iwlagn_add_bssid_station(priv, vif_priv->ctx, | ||
1086 | vif->bss_conf.bssid, | ||
1087 | &vif_priv->ibss_bssid_sta_id); | ||
1088 | return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id, | ||
1089 | vif->bss_conf.bssid); | ||
1090 | } | ||
1091 | |||
1092 | void iwl_free_tfds_in_queue(struct iwl_priv *priv, | ||
1093 | int sta_id, int tid, int freed) | ||
1094 | { | ||
1095 | lockdep_assert_held(&priv->sta_lock); | ||
1096 | |||
1097 | if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed) | ||
1098 | priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; | ||
1099 | else { | ||
1100 | IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n", | ||
1101 | priv->stations[sta_id].tid[tid].tfds_in_queue, | ||
1102 | freed); | ||
1103 | priv->stations[sta_id].tid[tid].tfds_in_queue = 0; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | #define IWL_FLUSH_WAIT_MS 2000 | ||
1108 | |||
1109 | int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv) | ||
1110 | { | ||
1111 | struct iwl_tx_queue *txq; | ||
1112 | struct iwl_queue *q; | ||
1113 | int cnt; | ||
1114 | unsigned long now = jiffies; | ||
1115 | int ret = 0; | ||
1116 | |||
1117 | /* waiting for all the tx frames complete might take a while */ | ||
1118 | for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { | ||
1119 | if (cnt == priv->cmd_queue) | ||
1120 | continue; | ||
1121 | txq = &priv->txq[cnt]; | ||
1122 | q = &txq->q; | ||
1123 | while (q->read_ptr != q->write_ptr && !time_after(jiffies, | ||
1124 | now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) | ||
1125 | msleep(1); | ||
1126 | |||
1127 | if (q->read_ptr != q->write_ptr) { | ||
1128 | IWL_ERR(priv, "fail to flush all tx fifo queues\n"); | ||
1129 | ret = -ETIMEDOUT; | ||
1130 | break; | ||
1131 | } | ||
1132 | } | ||
1133 | return ret; | ||
1134 | } | ||
1135 | |||
1136 | #define IWL_TX_QUEUE_MSK 0xfffff | ||
1137 | |||
1138 | /** | ||
1139 | * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode | ||
1140 | * | ||
1141 | * pre-requirements: | ||
1142 | * 1. acquire mutex before calling | ||
1143 | * 2. make sure rf is on and not in exit state | ||
1144 | */ | ||
1145 | int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) | ||
1146 | { | ||
1147 | struct iwl_txfifo_flush_cmd flush_cmd; | ||
1148 | struct iwl_host_cmd cmd = { | ||
1149 | .id = REPLY_TXFIFO_FLUSH, | ||
1150 | .len = { sizeof(struct iwl_txfifo_flush_cmd), }, | ||
1151 | .flags = CMD_SYNC, | ||
1152 | .data = { &flush_cmd, }, | ||
1153 | }; | ||
1154 | |||
1155 | might_sleep(); | ||
1156 | |||
1157 | memset(&flush_cmd, 0, sizeof(flush_cmd)); | ||
1158 | if (flush_control & BIT(IWL_RXON_CTX_BSS)) | ||
1159 | flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK | | ||
1160 | IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | | ||
1161 | IWL_SCD_MGMT_MSK; | ||
1162 | if ((flush_control & BIT(IWL_RXON_CTX_PAN)) && | ||
1163 | (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) | ||
1164 | flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK | | ||
1165 | IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK | | ||
1166 | IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | | ||
1167 | IWL_PAN_SCD_MULTICAST_MSK; | ||
1168 | |||
1169 | if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) | ||
1170 | flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK; | ||
1171 | |||
1172 | IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n", | ||
1173 | flush_cmd.fifo_control); | ||
1174 | flush_cmd.flush_control = cpu_to_le16(flush_control); | ||
1175 | |||
1176 | return trans_send_cmd(&priv->trans, &cmd); | ||
1177 | } | ||
1178 | |||
1179 | void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) | ||
1180 | { | ||
1181 | mutex_lock(&priv->mutex); | ||
1182 | ieee80211_stop_queues(priv->hw); | ||
1183 | if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { | ||
1184 | IWL_ERR(priv, "flush request fail\n"); | ||
1185 | goto done; | ||
1186 | } | ||
1187 | IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n"); | ||
1188 | iwlagn_wait_tx_queue_empty(priv); | ||
1189 | done: | ||
1190 | ieee80211_wake_queues(priv->hw); | ||
1191 | mutex_unlock(&priv->mutex); | ||
1192 | } | ||
1193 | |||
1194 | /* | ||
1195 | * BT coex | ||
1196 | */ | ||
1197 | /* | ||
1198 | * Macros to access the lookup table. | ||
1199 | * | ||
1200 | * The lookup table has 7 inputs: bt3_prio, bt3_txrx, bt_rf_act, wifi_req, | ||
1201 | * wifi_prio, wifi_txrx and wifi_sh_ant_req. | ||
1202 | * | ||
1203 | * It has three outputs: WLAN_ACTIVE, WLAN_KILL and ANT_SWITCH | ||
1204 | * | ||
1205 | * The format is that "registers" 8 through 11 contain the WLAN_ACTIVE bits | ||
1206 | * one after another in 32-bit registers, and "registers" 0 through 7 contain | ||
1207 | * the WLAN_KILL and ANT_SWITCH bits interleaved (in that order). | ||
1208 | * | ||
1209 | * These macros encode that format. | ||
1210 | */ | ||
1211 | #define LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, wifi_req, wifi_prio, \ | ||
1212 | wifi_txrx, wifi_sh_ant_req) \ | ||
1213 | (bt3_prio | (bt3_txrx << 1) | (bt_rf_act << 2) | (wifi_req << 3) | \ | ||
1214 | (wifi_prio << 4) | (wifi_txrx << 5) | (wifi_sh_ant_req << 6)) | ||
1215 | |||
1216 | #define LUT_PTA_WLAN_ACTIVE_OP(lut, op, val) \ | ||
1217 | lut[8 + ((val) >> 5)] op (cpu_to_le32(BIT((val) & 0x1f))) | ||
1218 | #define LUT_TEST_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1219 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1220 | (!!(LUT_PTA_WLAN_ACTIVE_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1221 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1222 | wifi_sh_ant_req)))) | ||
1223 | #define LUT_SET_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1224 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1225 | LUT_PTA_WLAN_ACTIVE_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1226 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1227 | wifi_sh_ant_req)) | ||
1228 | #define LUT_CLEAR_PTA_WLAN_ACTIVE(lut, bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1229 | wifi_req, wifi_prio, wifi_txrx, \ | ||
1230 | wifi_sh_ant_req) \ | ||
1231 | LUT_PTA_WLAN_ACTIVE_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, \ | ||
1232 | bt_rf_act, wifi_req, wifi_prio, wifi_txrx, \ | ||
1233 | wifi_sh_ant_req)) | ||
1234 | |||
1235 | #define LUT_WLAN_KILL_OP(lut, op, val) \ | ||
1236 | lut[(val) >> 4] op (cpu_to_le32(BIT(((val) << 1) & 0x1e))) | ||
1237 | #define LUT_TEST_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1238 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1239 | (!!(LUT_WLAN_KILL_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1240 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)))) | ||
1241 | #define LUT_SET_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1242 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1243 | LUT_WLAN_KILL_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1244 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1245 | #define LUT_CLEAR_WLAN_KILL(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1246 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1247 | LUT_WLAN_KILL_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1248 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1249 | |||
1250 | #define LUT_ANT_SWITCH_OP(lut, op, val) \ | ||
1251 | lut[(val) >> 4] op (cpu_to_le32(BIT((((val) << 1) & 0x1e) + 1))) | ||
1252 | #define LUT_TEST_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1253 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1254 | (!!(LUT_ANT_SWITCH_OP(lut, &, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1255 | wifi_req, wifi_prio, wifi_txrx, \ | ||
1256 | wifi_sh_ant_req)))) | ||
1257 | #define LUT_SET_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1258 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1259 | LUT_ANT_SWITCH_OP(lut, |=, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1260 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1261 | #define LUT_CLEAR_ANT_SWITCH(lut, bt3_prio, bt3_txrx, bt_rf_act, wifi_req, \ | ||
1262 | wifi_prio, wifi_txrx, wifi_sh_ant_req) \ | ||
1263 | LUT_ANT_SWITCH_OP(lut, &= ~, LUT_VALUE(bt3_prio, bt3_txrx, bt_rf_act, \ | ||
1264 | wifi_req, wifi_prio, wifi_txrx, wifi_sh_ant_req)) | ||
1265 | |||
1266 | static const __le32 iwlagn_def_3w_lookup[12] = { | ||
1267 | cpu_to_le32(0xaaaaaaaa), | ||
1268 | cpu_to_le32(0xaaaaaaaa), | ||
1269 | cpu_to_le32(0xaeaaaaaa), | ||
1270 | cpu_to_le32(0xaaaaaaaa), | ||
1271 | cpu_to_le32(0xcc00ff28), | ||
1272 | cpu_to_le32(0x0000aaaa), | ||
1273 | cpu_to_le32(0xcc00aaaa), | ||
1274 | cpu_to_le32(0x0000aaaa), | ||
1275 | cpu_to_le32(0xc0004000), | ||
1276 | cpu_to_le32(0x00004000), | ||
1277 | cpu_to_le32(0xf0005000), | ||
1278 | cpu_to_le32(0xf0005000), | ||
1279 | }; | ||
1280 | |||
1281 | static const __le32 iwlagn_concurrent_lookup[12] = { | ||
1282 | cpu_to_le32(0xaaaaaaaa), | ||
1283 | cpu_to_le32(0xaaaaaaaa), | ||
1284 | cpu_to_le32(0xaaaaaaaa), | ||
1285 | cpu_to_le32(0xaaaaaaaa), | ||
1286 | cpu_to_le32(0xaaaaaaaa), | ||
1287 | cpu_to_le32(0xaaaaaaaa), | ||
1288 | cpu_to_le32(0xaaaaaaaa), | ||
1289 | cpu_to_le32(0xaaaaaaaa), | ||
1290 | cpu_to_le32(0x00000000), | ||
1291 | cpu_to_le32(0x00000000), | ||
1292 | cpu_to_le32(0x00000000), | ||
1293 | cpu_to_le32(0x00000000), | ||
1294 | }; | ||
1295 | |||
1296 | void iwlagn_send_advance_bt_config(struct iwl_priv *priv) | ||
1297 | { | ||
1298 | struct iwl_basic_bt_cmd basic = { | ||
1299 | .max_kill = IWLAGN_BT_MAX_KILL_DEFAULT, | ||
1300 | .bt3_timer_t7_value = IWLAGN_BT3_T7_DEFAULT, | ||
1301 | .bt3_prio_sample_time = IWLAGN_BT3_PRIO_SAMPLE_DEFAULT, | ||
1302 | .bt3_timer_t2_value = IWLAGN_BT3_T2_DEFAULT, | ||
1303 | }; | ||
1304 | struct iwl6000_bt_cmd bt_cmd_6000; | ||
1305 | struct iwl2000_bt_cmd bt_cmd_2000; | ||
1306 | int ret; | ||
1307 | |||
1308 | BUILD_BUG_ON(sizeof(iwlagn_def_3w_lookup) != | ||
1309 | sizeof(basic.bt3_lookup_table)); | ||
1310 | |||
1311 | if (priv->cfg->bt_params) { | ||
1312 | if (priv->cfg->bt_params->bt_session_2) { | ||
1313 | bt_cmd_2000.prio_boost = cpu_to_le32( | ||
1314 | priv->cfg->bt_params->bt_prio_boost); | ||
1315 | bt_cmd_2000.tx_prio_boost = 0; | ||
1316 | bt_cmd_2000.rx_prio_boost = 0; | ||
1317 | } else { | ||
1318 | bt_cmd_6000.prio_boost = | ||
1319 | priv->cfg->bt_params->bt_prio_boost; | ||
1320 | bt_cmd_6000.tx_prio_boost = 0; | ||
1321 | bt_cmd_6000.rx_prio_boost = 0; | ||
1322 | } | ||
1323 | } else { | ||
1324 | IWL_ERR(priv, "failed to construct BT Coex Config\n"); | ||
1325 | return; | ||
1326 | } | ||
1327 | |||
1328 | basic.kill_ack_mask = priv->kill_ack_mask; | ||
1329 | basic.kill_cts_mask = priv->kill_cts_mask; | ||
1330 | basic.valid = priv->bt_valid; | ||
1331 | |||
1332 | /* | ||
1333 | * Configure BT coex mode to "no coexistence" when the | ||
1334 | * user disabled BT coexistence, we have no interface | ||
1335 | * (might be in monitor mode), or the interface is in | ||
1336 | * IBSS mode (no proper uCode support for coex then). | ||
1337 | */ | ||
1338 | if (!iwlagn_mod_params.bt_coex_active || | ||
1339 | priv->iw_mode == NL80211_IFTYPE_ADHOC) { | ||
1340 | basic.flags = IWLAGN_BT_FLAG_COEX_MODE_DISABLED; | ||
1341 | } else { | ||
1342 | basic.flags = IWLAGN_BT_FLAG_COEX_MODE_3W << | ||
1343 | IWLAGN_BT_FLAG_COEX_MODE_SHIFT; | ||
1344 | |||
1345 | if (!priv->bt_enable_pspoll) | ||
1346 | basic.flags |= IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; | ||
1347 | else | ||
1348 | basic.flags &= ~IWLAGN_BT_FLAG_SYNC_2_BT_DISABLE; | ||
1349 | |||
1350 | if (priv->bt_ch_announce) | ||
1351 | basic.flags |= IWLAGN_BT_FLAG_CHANNEL_INHIBITION; | ||
1352 | IWL_DEBUG_COEX(priv, "BT coex flag: 0X%x\n", basic.flags); | ||
1353 | } | ||
1354 | priv->bt_enable_flag = basic.flags; | ||
1355 | if (priv->bt_full_concurrent) | ||
1356 | memcpy(basic.bt3_lookup_table, iwlagn_concurrent_lookup, | ||
1357 | sizeof(iwlagn_concurrent_lookup)); | ||
1358 | else | ||
1359 | memcpy(basic.bt3_lookup_table, iwlagn_def_3w_lookup, | ||
1360 | sizeof(iwlagn_def_3w_lookup)); | ||
1361 | |||
1362 | IWL_DEBUG_COEX(priv, "BT coex %s in %s mode\n", | ||
1363 | basic.flags ? "active" : "disabled", | ||
1364 | priv->bt_full_concurrent ? | ||
1365 | "full concurrency" : "3-wire"); | ||
1366 | |||
1367 | if (priv->cfg->bt_params->bt_session_2) { | ||
1368 | memcpy(&bt_cmd_2000.basic, &basic, | ||
1369 | sizeof(basic)); | ||
1370 | ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG, | ||
1371 | CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000); | ||
1372 | } else { | ||
1373 | memcpy(&bt_cmd_6000.basic, &basic, | ||
1374 | sizeof(basic)); | ||
1375 | ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG, | ||
1376 | CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000); | ||
1377 | } | ||
1378 | if (ret) | ||
1379 | IWL_ERR(priv, "failed to send BT Coex Config\n"); | ||
1380 | |||
1381 | } | ||
1382 | |||
1383 | void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena) | ||
1384 | { | ||
1385 | struct iwl_rxon_context *ctx, *found_ctx = NULL; | ||
1386 | bool found_ap = false; | ||
1387 | |||
1388 | lockdep_assert_held(&priv->mutex); | ||
1389 | |||
1390 | /* Check whether AP or GO mode is active. */ | ||
1391 | if (rssi_ena) { | ||
1392 | for_each_context(priv, ctx) { | ||
1393 | if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_AP && | ||
1394 | iwl_is_associated_ctx(ctx)) { | ||
1395 | found_ap = true; | ||
1396 | break; | ||
1397 | } | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | /* | ||
1402 | * If disable was received or If GO/AP mode, disable RSSI | ||
1403 | * measurements. | ||
1404 | */ | ||
1405 | if (!rssi_ena || found_ap) { | ||
1406 | if (priv->cur_rssi_ctx) { | ||
1407 | ctx = priv->cur_rssi_ctx; | ||
1408 | ieee80211_disable_rssi_reports(ctx->vif); | ||
1409 | priv->cur_rssi_ctx = NULL; | ||
1410 | } | ||
1411 | return; | ||
1412 | } | ||
1413 | |||
1414 | /* | ||
1415 | * If rssi measurements need to be enabled, consider all cases now. | ||
1416 | * Figure out how many contexts are active. | ||
1417 | */ | ||
1418 | for_each_context(priv, ctx) { | ||
1419 | if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION && | ||
1420 | iwl_is_associated_ctx(ctx)) { | ||
1421 | found_ctx = ctx; | ||
1422 | break; | ||
1423 | } | ||
1424 | } | ||
1425 | |||
1426 | /* | ||
1427 | * rssi monitor already enabled for the correct interface...nothing | ||
1428 | * to do. | ||
1429 | */ | ||
1430 | if (found_ctx == priv->cur_rssi_ctx) | ||
1431 | return; | ||
1432 | |||
1433 | /* | ||
1434 | * Figure out if rssi monitor is currently enabled, and needs | ||
1435 | * to be changed. If rssi monitor is already enabled, disable | ||
1436 | * it first else just enable rssi measurements on the | ||
1437 | * interface found above. | ||
1438 | */ | ||
1439 | if (priv->cur_rssi_ctx) { | ||
1440 | ctx = priv->cur_rssi_ctx; | ||
1441 | if (ctx->vif) | ||
1442 | ieee80211_disable_rssi_reports(ctx->vif); | ||
1443 | } | ||
1444 | |||
1445 | priv->cur_rssi_ctx = found_ctx; | ||
1446 | |||
1447 | if (!found_ctx) | ||
1448 | return; | ||
1449 | |||
1450 | ieee80211_enable_rssi_reports(found_ctx->vif, | ||
1451 | IWLAGN_BT_PSP_MIN_RSSI_THRESHOLD, | ||
1452 | IWLAGN_BT_PSP_MAX_RSSI_THRESHOLD); | ||
1453 | } | ||
1454 | |||
1455 | static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg) | ||
1456 | { | ||
1457 | return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >> | ||
1458 | BT_UART_MSG_FRAME3SCOESCO_POS; | ||
1459 | } | ||
1460 | |||
1461 | static void iwlagn_bt_traffic_change_work(struct work_struct *work) | ||
1462 | { | ||
1463 | struct iwl_priv *priv = | ||
1464 | container_of(work, struct iwl_priv, bt_traffic_change_work); | ||
1465 | struct iwl_rxon_context *ctx; | ||
1466 | int smps_request = -1; | ||
1467 | |||
1468 | if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { | ||
1469 | /* bt coex disabled */ | ||
1470 | return; | ||
1471 | } | ||
1472 | |||
1473 | /* | ||
1474 | * Note: bt_traffic_load can be overridden by scan complete and | ||
1475 | * coex profile notifications. Ignore that since only bad consequence | ||
1476 | * can be not matching debug print with actual state. | ||
1477 | */ | ||
1478 | IWL_DEBUG_COEX(priv, "BT traffic load changes: %d\n", | ||
1479 | priv->bt_traffic_load); | ||
1480 | |||
1481 | switch (priv->bt_traffic_load) { | ||
1482 | case IWL_BT_COEX_TRAFFIC_LOAD_NONE: | ||
1483 | if (priv->bt_status) | ||
1484 | smps_request = IEEE80211_SMPS_DYNAMIC; | ||
1485 | else | ||
1486 | smps_request = IEEE80211_SMPS_AUTOMATIC; | ||
1487 | break; | ||
1488 | case IWL_BT_COEX_TRAFFIC_LOAD_LOW: | ||
1489 | smps_request = IEEE80211_SMPS_DYNAMIC; | ||
1490 | break; | ||
1491 | case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: | ||
1492 | case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: | ||
1493 | smps_request = IEEE80211_SMPS_STATIC; | ||
1494 | break; | ||
1495 | default: | ||
1496 | IWL_ERR(priv, "Invalid BT traffic load: %d\n", | ||
1497 | priv->bt_traffic_load); | ||
1498 | break; | ||
1499 | } | ||
1500 | |||
1501 | mutex_lock(&priv->mutex); | ||
1502 | |||
1503 | /* | ||
1504 | * We can not send command to firmware while scanning. When the scan | ||
1505 | * complete we will schedule this work again. We do check with mutex | ||
1506 | * locked to prevent new scan request to arrive. We do not check | ||
1507 | * STATUS_SCANNING to avoid race when queue_work two times from | ||
1508 | * different notifications, but quit and not perform any work at all. | ||
1509 | */ | ||
1510 | if (test_bit(STATUS_SCAN_HW, &priv->status)) | ||
1511 | goto out; | ||
1512 | |||
1513 | iwl_update_chain_flags(priv); | ||
1514 | |||
1515 | if (smps_request != -1) { | ||
1516 | priv->current_ht_config.smps = smps_request; | ||
1517 | for_each_context(priv, ctx) { | ||
1518 | if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) | ||
1519 | ieee80211_request_smps(ctx->vif, smps_request); | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1523 | /* | ||
1524 | * Dynamic PS poll related functionality. Adjust RSSI measurements if | ||
1525 | * necessary. | ||
1526 | */ | ||
1527 | iwlagn_bt_coex_rssi_monitor(priv); | ||
1528 | out: | ||
1529 | mutex_unlock(&priv->mutex); | ||
1530 | } | ||
1531 | |||
1532 | /* | ||
1533 | * If BT sco traffic, and RSSI monitor is enabled, move measurements to the | ||
1534 | * correct interface or disable it if this is the last interface to be | ||
1535 | * removed. | ||
1536 | */ | ||
1537 | void iwlagn_bt_coex_rssi_monitor(struct iwl_priv *priv) | ||
1538 | { | ||
1539 | if (priv->bt_is_sco && | ||
1540 | priv->bt_traffic_load == IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS) | ||
1541 | iwlagn_bt_adjust_rssi_monitor(priv, true); | ||
1542 | else | ||
1543 | iwlagn_bt_adjust_rssi_monitor(priv, false); | ||
1544 | } | ||
1545 | |||
1546 | static void iwlagn_print_uartmsg(struct iwl_priv *priv, | ||
1547 | struct iwl_bt_uart_msg *uart_msg) | ||
1548 | { | ||
1549 | IWL_DEBUG_COEX(priv, "Message Type = 0x%X, SSN = 0x%X, " | ||
1550 | "Update Req = 0x%X", | ||
1551 | (BT_UART_MSG_FRAME1MSGTYPE_MSK & uart_msg->frame1) >> | ||
1552 | BT_UART_MSG_FRAME1MSGTYPE_POS, | ||
1553 | (BT_UART_MSG_FRAME1SSN_MSK & uart_msg->frame1) >> | ||
1554 | BT_UART_MSG_FRAME1SSN_POS, | ||
1555 | (BT_UART_MSG_FRAME1UPDATEREQ_MSK & uart_msg->frame1) >> | ||
1556 | BT_UART_MSG_FRAME1UPDATEREQ_POS); | ||
1557 | |||
1558 | IWL_DEBUG_COEX(priv, "Open connections = 0x%X, Traffic load = 0x%X, " | ||
1559 | "Chl_SeqN = 0x%X, In band = 0x%X", | ||
1560 | (BT_UART_MSG_FRAME2OPENCONNECTIONS_MSK & uart_msg->frame2) >> | ||
1561 | BT_UART_MSG_FRAME2OPENCONNECTIONS_POS, | ||
1562 | (BT_UART_MSG_FRAME2TRAFFICLOAD_MSK & uart_msg->frame2) >> | ||
1563 | BT_UART_MSG_FRAME2TRAFFICLOAD_POS, | ||
1564 | (BT_UART_MSG_FRAME2CHLSEQN_MSK & uart_msg->frame2) >> | ||
1565 | BT_UART_MSG_FRAME2CHLSEQN_POS, | ||
1566 | (BT_UART_MSG_FRAME2INBAND_MSK & uart_msg->frame2) >> | ||
1567 | BT_UART_MSG_FRAME2INBAND_POS); | ||
1568 | |||
1569 | IWL_DEBUG_COEX(priv, "SCO/eSCO = 0x%X, Sniff = 0x%X, A2DP = 0x%X, " | ||
1570 | "ACL = 0x%X, Master = 0x%X, OBEX = 0x%X", | ||
1571 | (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >> | ||
1572 | BT_UART_MSG_FRAME3SCOESCO_POS, | ||
1573 | (BT_UART_MSG_FRAME3SNIFF_MSK & uart_msg->frame3) >> | ||
1574 | BT_UART_MSG_FRAME3SNIFF_POS, | ||
1575 | (BT_UART_MSG_FRAME3A2DP_MSK & uart_msg->frame3) >> | ||
1576 | BT_UART_MSG_FRAME3A2DP_POS, | ||
1577 | (BT_UART_MSG_FRAME3ACL_MSK & uart_msg->frame3) >> | ||
1578 | BT_UART_MSG_FRAME3ACL_POS, | ||
1579 | (BT_UART_MSG_FRAME3MASTER_MSK & uart_msg->frame3) >> | ||
1580 | BT_UART_MSG_FRAME3MASTER_POS, | ||
1581 | (BT_UART_MSG_FRAME3OBEX_MSK & uart_msg->frame3) >> | ||
1582 | BT_UART_MSG_FRAME3OBEX_POS); | ||
1583 | |||
1584 | IWL_DEBUG_COEX(priv, "Idle duration = 0x%X", | ||
1585 | (BT_UART_MSG_FRAME4IDLEDURATION_MSK & uart_msg->frame4) >> | ||
1586 | BT_UART_MSG_FRAME4IDLEDURATION_POS); | ||
1587 | |||
1588 | IWL_DEBUG_COEX(priv, "Tx Activity = 0x%X, Rx Activity = 0x%X, " | ||
1589 | "eSCO Retransmissions = 0x%X", | ||
1590 | (BT_UART_MSG_FRAME5TXACTIVITY_MSK & uart_msg->frame5) >> | ||
1591 | BT_UART_MSG_FRAME5TXACTIVITY_POS, | ||
1592 | (BT_UART_MSG_FRAME5RXACTIVITY_MSK & uart_msg->frame5) >> | ||
1593 | BT_UART_MSG_FRAME5RXACTIVITY_POS, | ||
1594 | (BT_UART_MSG_FRAME5ESCORETRANSMIT_MSK & uart_msg->frame5) >> | ||
1595 | BT_UART_MSG_FRAME5ESCORETRANSMIT_POS); | ||
1596 | |||
1597 | IWL_DEBUG_COEX(priv, "Sniff Interval = 0x%X, Discoverable = 0x%X", | ||
1598 | (BT_UART_MSG_FRAME6SNIFFINTERVAL_MSK & uart_msg->frame6) >> | ||
1599 | BT_UART_MSG_FRAME6SNIFFINTERVAL_POS, | ||
1600 | (BT_UART_MSG_FRAME6DISCOVERABLE_MSK & uart_msg->frame6) >> | ||
1601 | BT_UART_MSG_FRAME6DISCOVERABLE_POS); | ||
1602 | |||
1603 | IWL_DEBUG_COEX(priv, "Sniff Activity = 0x%X, Page = " | ||
1604 | "0x%X, Inquiry = 0x%X, Connectable = 0x%X", | ||
1605 | (BT_UART_MSG_FRAME7SNIFFACTIVITY_MSK & uart_msg->frame7) >> | ||
1606 | BT_UART_MSG_FRAME7SNIFFACTIVITY_POS, | ||
1607 | (BT_UART_MSG_FRAME7PAGE_MSK & uart_msg->frame7) >> | ||
1608 | BT_UART_MSG_FRAME7PAGE_POS, | ||
1609 | (BT_UART_MSG_FRAME7INQUIRY_MSK & uart_msg->frame7) >> | ||
1610 | BT_UART_MSG_FRAME7INQUIRY_POS, | ||
1611 | (BT_UART_MSG_FRAME7CONNECTABLE_MSK & uart_msg->frame7) >> | ||
1612 | BT_UART_MSG_FRAME7CONNECTABLE_POS); | ||
1613 | } | ||
1614 | |||
1615 | static void iwlagn_set_kill_msk(struct iwl_priv *priv, | ||
1616 | struct iwl_bt_uart_msg *uart_msg) | ||
1617 | { | ||
1618 | u8 kill_msk; | ||
1619 | static const __le32 bt_kill_ack_msg[2] = { | ||
1620 | IWLAGN_BT_KILL_ACK_MASK_DEFAULT, | ||
1621 | IWLAGN_BT_KILL_ACK_CTS_MASK_SCO }; | ||
1622 | static const __le32 bt_kill_cts_msg[2] = { | ||
1623 | IWLAGN_BT_KILL_CTS_MASK_DEFAULT, | ||
1624 | IWLAGN_BT_KILL_ACK_CTS_MASK_SCO }; | ||
1625 | |||
1626 | kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) | ||
1627 | ? 1 : 0; | ||
1628 | if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] || | ||
1629 | priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) { | ||
1630 | priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK; | ||
1631 | priv->kill_ack_mask = bt_kill_ack_msg[kill_msk]; | ||
1632 | priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK; | ||
1633 | priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; | ||
1634 | |||
1635 | /* schedule to send runtime bt_config */ | ||
1636 | queue_work(priv->workqueue, &priv->bt_runtime_config); | ||
1637 | } | ||
1638 | } | ||
1639 | |||
1640 | void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, | ||
1641 | struct iwl_rx_mem_buffer *rxb) | ||
1642 | { | ||
1643 | unsigned long flags; | ||
1644 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1645 | struct iwl_bt_coex_profile_notif *coex = &pkt->u.bt_coex_profile_notif; | ||
1646 | struct iwl_bt_uart_msg *uart_msg = &coex->last_bt_uart_msg; | ||
1647 | |||
1648 | if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { | ||
1649 | /* bt coex disabled */ | ||
1650 | return; | ||
1651 | } | ||
1652 | |||
1653 | IWL_DEBUG_COEX(priv, "BT Coex notification:\n"); | ||
1654 | IWL_DEBUG_COEX(priv, " status: %d\n", coex->bt_status); | ||
1655 | IWL_DEBUG_COEX(priv, " traffic load: %d\n", coex->bt_traffic_load); | ||
1656 | IWL_DEBUG_COEX(priv, " CI compliance: %d\n", | ||
1657 | coex->bt_ci_compliance); | ||
1658 | iwlagn_print_uartmsg(priv, uart_msg); | ||
1659 | |||
1660 | priv->last_bt_traffic_load = priv->bt_traffic_load; | ||
1661 | priv->bt_is_sco = iwlagn_bt_traffic_is_sco(uart_msg); | ||
1662 | |||
1663 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { | ||
1664 | if (priv->bt_status != coex->bt_status || | ||
1665 | priv->last_bt_traffic_load != coex->bt_traffic_load) { | ||
1666 | if (coex->bt_status) { | ||
1667 | /* BT on */ | ||
1668 | if (!priv->bt_ch_announce) | ||
1669 | priv->bt_traffic_load = | ||
1670 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH; | ||
1671 | else | ||
1672 | priv->bt_traffic_load = | ||
1673 | coex->bt_traffic_load; | ||
1674 | } else { | ||
1675 | /* BT off */ | ||
1676 | priv->bt_traffic_load = | ||
1677 | IWL_BT_COEX_TRAFFIC_LOAD_NONE; | ||
1678 | } | ||
1679 | priv->bt_status = coex->bt_status; | ||
1680 | queue_work(priv->workqueue, | ||
1681 | &priv->bt_traffic_change_work); | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | iwlagn_set_kill_msk(priv, uart_msg); | ||
1686 | |||
1687 | /* FIXME: based on notification, adjust the prio_boost */ | ||
1688 | |||
1689 | spin_lock_irqsave(&priv->lock, flags); | ||
1690 | priv->bt_ci_compliance = coex->bt_ci_compliance; | ||
1691 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1692 | } | ||
1693 | |||
1694 | void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) | ||
1695 | { | ||
1696 | priv->rx_handlers[REPLY_BT_COEX_PROFILE_NOTIF] = | ||
1697 | iwlagn_bt_coex_profile_notif; | ||
1698 | } | ||
1699 | |||
1700 | void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv) | ||
1701 | { | ||
1702 | INIT_WORK(&priv->bt_traffic_change_work, | ||
1703 | iwlagn_bt_traffic_change_work); | ||
1704 | } | ||
1705 | |||
1706 | void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv) | ||
1707 | { | ||
1708 | cancel_work_sync(&priv->bt_traffic_change_work); | ||
1709 | } | ||
1710 | |||
1711 | static bool is_single_rx_stream(struct iwl_priv *priv) | ||
1712 | { | ||
1713 | return priv->current_ht_config.smps == IEEE80211_SMPS_STATIC || | ||
1714 | priv->current_ht_config.single_chain_sufficient; | ||
1715 | } | ||
1716 | |||
1717 | #define IWL_NUM_RX_CHAINS_MULTIPLE 3 | ||
1718 | #define IWL_NUM_RX_CHAINS_SINGLE 2 | ||
1719 | #define IWL_NUM_IDLE_CHAINS_DUAL 2 | ||
1720 | #define IWL_NUM_IDLE_CHAINS_SINGLE 1 | ||
1721 | |||
1722 | /* | ||
1723 | * Determine how many receiver/antenna chains to use. | ||
1724 | * | ||
1725 | * More provides better reception via diversity. Fewer saves power | ||
1726 | * at the expense of throughput, but only when not in powersave to | ||
1727 | * start with. | ||
1728 | * | ||
1729 | * MIMO (dual stream) requires at least 2, but works better with 3. | ||
1730 | * This does not determine *which* chains to use, just how many. | ||
1731 | */ | ||
1732 | static int iwl_get_active_rx_chain_count(struct iwl_priv *priv) | ||
1733 | { | ||
1734 | if (priv->cfg->bt_params && | ||
1735 | priv->cfg->bt_params->advanced_bt_coexist && | ||
1736 | (priv->bt_full_concurrent || | ||
1737 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | ||
1738 | /* | ||
1739 | * only use chain 'A' in bt high traffic load or | ||
1740 | * full concurrency mode | ||
1741 | */ | ||
1742 | return IWL_NUM_RX_CHAINS_SINGLE; | ||
1743 | } | ||
1744 | /* # of Rx chains to use when expecting MIMO. */ | ||
1745 | if (is_single_rx_stream(priv)) | ||
1746 | return IWL_NUM_RX_CHAINS_SINGLE; | ||
1747 | else | ||
1748 | return IWL_NUM_RX_CHAINS_MULTIPLE; | ||
1749 | } | ||
1750 | |||
1751 | /* | ||
1752 | * When we are in power saving mode, unless device support spatial | ||
1753 | * multiplexing power save, use the active count for rx chain count. | ||
1754 | */ | ||
1755 | static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) | ||
1756 | { | ||
1757 | /* # Rx chains when idling, depending on SMPS mode */ | ||
1758 | switch (priv->current_ht_config.smps) { | ||
1759 | case IEEE80211_SMPS_STATIC: | ||
1760 | case IEEE80211_SMPS_DYNAMIC: | ||
1761 | return IWL_NUM_IDLE_CHAINS_SINGLE; | ||
1762 | case IEEE80211_SMPS_OFF: | ||
1763 | return active_cnt; | ||
1764 | default: | ||
1765 | WARN(1, "invalid SMPS mode %d", | ||
1766 | priv->current_ht_config.smps); | ||
1767 | return active_cnt; | ||
1768 | } | ||
1769 | } | ||
1770 | |||
1771 | /* up to 4 chains */ | ||
1772 | static u8 iwl_count_chain_bitmap(u32 chain_bitmap) | ||
1773 | { | ||
1774 | u8 res; | ||
1775 | res = (chain_bitmap & BIT(0)) >> 0; | ||
1776 | res += (chain_bitmap & BIT(1)) >> 1; | ||
1777 | res += (chain_bitmap & BIT(2)) >> 2; | ||
1778 | res += (chain_bitmap & BIT(3)) >> 3; | ||
1779 | return res; | ||
1780 | } | ||
1781 | |||
1782 | /** | ||
1783 | * iwlagn_set_rxon_chain - Set up Rx chain usage in "staging" RXON image | ||
1784 | * | ||
1785 | * Selects how many and which Rx receivers/antennas/chains to use. | ||
1786 | * This should not be used for scan command ... it puts data in wrong place. | ||
1787 | */ | ||
1788 | void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
1789 | { | ||
1790 | bool is_single = is_single_rx_stream(priv); | ||
1791 | bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); | ||
1792 | u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; | ||
1793 | u32 active_chains; | ||
1794 | u16 rx_chain; | ||
1795 | |||
1796 | /* Tell uCode which antennas are actually connected. | ||
1797 | * Before first association, we assume all antennas are connected. | ||
1798 | * Just after first association, iwl_chain_noise_calibration() | ||
1799 | * checks which antennas actually *are* connected. */ | ||
1800 | if (priv->chain_noise_data.active_chains) | ||
1801 | active_chains = priv->chain_noise_data.active_chains; | ||
1802 | else | ||
1803 | active_chains = priv->hw_params.valid_rx_ant; | ||
1804 | |||
1805 | if (priv->cfg->bt_params && | ||
1806 | priv->cfg->bt_params->advanced_bt_coexist && | ||
1807 | (priv->bt_full_concurrent || | ||
1808 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH)) { | ||
1809 | /* | ||
1810 | * only use chain 'A' in bt high traffic load or | ||
1811 | * full concurrency mode | ||
1812 | */ | ||
1813 | active_chains = first_antenna(active_chains); | ||
1814 | } | ||
1815 | |||
1816 | rx_chain = active_chains << RXON_RX_CHAIN_VALID_POS; | ||
1817 | |||
1818 | /* How many receivers should we use? */ | ||
1819 | active_rx_cnt = iwl_get_active_rx_chain_count(priv); | ||
1820 | idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt); | ||
1821 | |||
1822 | |||
1823 | /* correct rx chain count according hw settings | ||
1824 | * and chain noise calibration | ||
1825 | */ | ||
1826 | valid_rx_cnt = iwl_count_chain_bitmap(active_chains); | ||
1827 | if (valid_rx_cnt < active_rx_cnt) | ||
1828 | active_rx_cnt = valid_rx_cnt; | ||
1829 | |||
1830 | if (valid_rx_cnt < idle_rx_cnt) | ||
1831 | idle_rx_cnt = valid_rx_cnt; | ||
1832 | |||
1833 | rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS; | ||
1834 | rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS; | ||
1835 | |||
1836 | ctx->staging.rx_chain = cpu_to_le16(rx_chain); | ||
1837 | |||
1838 | if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam) | ||
1839 | ctx->staging.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK; | ||
1840 | else | ||
1841 | ctx->staging.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK; | ||
1842 | |||
1843 | IWL_DEBUG_ASSOC(priv, "rx_chain=0x%X active=%d idle=%d\n", | ||
1844 | ctx->staging.rx_chain, | ||
1845 | active_rx_cnt, idle_rx_cnt); | ||
1846 | |||
1847 | WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 || | ||
1848 | active_rx_cnt < idle_rx_cnt); | ||
1849 | } | ||
1850 | |||
1851 | u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) | ||
1852 | { | ||
1853 | int i; | ||
1854 | u8 ind = ant; | ||
1855 | |||
1856 | if (priv->band == IEEE80211_BAND_2GHZ && | ||
1857 | priv->bt_traffic_load >= IWL_BT_COEX_TRAFFIC_LOAD_HIGH) | ||
1858 | return 0; | ||
1859 | |||
1860 | for (i = 0; i < RATE_ANT_NUM - 1; i++) { | ||
1861 | ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; | ||
1862 | if (valid & BIT(ind)) | ||
1863 | return ind; | ||
1864 | } | ||
1865 | return ant; | ||
1866 | } | ||
1867 | |||
1868 | static const char *get_csr_string(int cmd) | ||
1869 | { | ||
1870 | switch (cmd) { | ||
1871 | IWL_CMD(CSR_HW_IF_CONFIG_REG); | ||
1872 | IWL_CMD(CSR_INT_COALESCING); | ||
1873 | IWL_CMD(CSR_INT); | ||
1874 | IWL_CMD(CSR_INT_MASK); | ||
1875 | IWL_CMD(CSR_FH_INT_STATUS); | ||
1876 | IWL_CMD(CSR_GPIO_IN); | ||
1877 | IWL_CMD(CSR_RESET); | ||
1878 | IWL_CMD(CSR_GP_CNTRL); | ||
1879 | IWL_CMD(CSR_HW_REV); | ||
1880 | IWL_CMD(CSR_EEPROM_REG); | ||
1881 | IWL_CMD(CSR_EEPROM_GP); | ||
1882 | IWL_CMD(CSR_OTP_GP_REG); | ||
1883 | IWL_CMD(CSR_GIO_REG); | ||
1884 | IWL_CMD(CSR_GP_UCODE_REG); | ||
1885 | IWL_CMD(CSR_GP_DRIVER_REG); | ||
1886 | IWL_CMD(CSR_UCODE_DRV_GP1); | ||
1887 | IWL_CMD(CSR_UCODE_DRV_GP2); | ||
1888 | IWL_CMD(CSR_LED_REG); | ||
1889 | IWL_CMD(CSR_DRAM_INT_TBL_REG); | ||
1890 | IWL_CMD(CSR_GIO_CHICKEN_BITS); | ||
1891 | IWL_CMD(CSR_ANA_PLL_CFG); | ||
1892 | IWL_CMD(CSR_HW_REV_WA_REG); | ||
1893 | IWL_CMD(CSR_DBG_HPET_MEM_REG); | ||
1894 | default: | ||
1895 | return "UNKNOWN"; | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | void iwl_dump_csr(struct iwl_priv *priv) | ||
1900 | { | ||
1901 | int i; | ||
1902 | static const u32 csr_tbl[] = { | ||
1903 | CSR_HW_IF_CONFIG_REG, | ||
1904 | CSR_INT_COALESCING, | ||
1905 | CSR_INT, | ||
1906 | CSR_INT_MASK, | ||
1907 | CSR_FH_INT_STATUS, | ||
1908 | CSR_GPIO_IN, | ||
1909 | CSR_RESET, | ||
1910 | CSR_GP_CNTRL, | ||
1911 | CSR_HW_REV, | ||
1912 | CSR_EEPROM_REG, | ||
1913 | CSR_EEPROM_GP, | ||
1914 | CSR_OTP_GP_REG, | ||
1915 | CSR_GIO_REG, | ||
1916 | CSR_GP_UCODE_REG, | ||
1917 | CSR_GP_DRIVER_REG, | ||
1918 | CSR_UCODE_DRV_GP1, | ||
1919 | CSR_UCODE_DRV_GP2, | ||
1920 | CSR_LED_REG, | ||
1921 | CSR_DRAM_INT_TBL_REG, | ||
1922 | CSR_GIO_CHICKEN_BITS, | ||
1923 | CSR_ANA_PLL_CFG, | ||
1924 | CSR_HW_REV_WA_REG, | ||
1925 | CSR_DBG_HPET_MEM_REG | ||
1926 | }; | ||
1927 | IWL_ERR(priv, "CSR values:\n"); | ||
1928 | IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " | ||
1929 | "CSR_INT_PERIODIC_REG)\n"); | ||
1930 | for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { | ||
1931 | IWL_ERR(priv, " %25s: 0X%08x\n", | ||
1932 | get_csr_string(csr_tbl[i]), | ||
1933 | iwl_read32(priv, csr_tbl[i])); | ||
1934 | } | ||
1935 | } | ||
1936 | |||
1937 | static const char *get_fh_string(int cmd) | ||
1938 | { | ||
1939 | switch (cmd) { | ||
1940 | IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); | ||
1941 | IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); | ||
1942 | IWL_CMD(FH_RSCSR_CHNL0_WPTR); | ||
1943 | IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); | ||
1944 | IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); | ||
1945 | IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); | ||
1946 | IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); | ||
1947 | IWL_CMD(FH_TSSR_TX_STATUS_REG); | ||
1948 | IWL_CMD(FH_TSSR_TX_ERROR_REG); | ||
1949 | default: | ||
1950 | return "UNKNOWN"; | ||
1951 | } | ||
1952 | } | ||
1953 | |||
1954 | int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) | ||
1955 | { | ||
1956 | int i; | ||
1957 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1958 | int pos = 0; | ||
1959 | size_t bufsz = 0; | ||
1960 | #endif | ||
1961 | static const u32 fh_tbl[] = { | ||
1962 | FH_RSCSR_CHNL0_STTS_WPTR_REG, | ||
1963 | FH_RSCSR_CHNL0_RBDCB_BASE_REG, | ||
1964 | FH_RSCSR_CHNL0_WPTR, | ||
1965 | FH_MEM_RCSR_CHNL0_CONFIG_REG, | ||
1966 | FH_MEM_RSSR_SHARED_CTRL_REG, | ||
1967 | FH_MEM_RSSR_RX_STATUS_REG, | ||
1968 | FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, | ||
1969 | FH_TSSR_TX_STATUS_REG, | ||
1970 | FH_TSSR_TX_ERROR_REG | ||
1971 | }; | ||
1972 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1973 | if (display) { | ||
1974 | bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; | ||
1975 | *buf = kmalloc(bufsz, GFP_KERNEL); | ||
1976 | if (!*buf) | ||
1977 | return -ENOMEM; | ||
1978 | pos += scnprintf(*buf + pos, bufsz - pos, | ||
1979 | "FH register values:\n"); | ||
1980 | for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { | ||
1981 | pos += scnprintf(*buf + pos, bufsz - pos, | ||
1982 | " %34s: 0X%08x\n", | ||
1983 | get_fh_string(fh_tbl[i]), | ||
1984 | iwl_read_direct32(priv, fh_tbl[i])); | ||
1985 | } | ||
1986 | return pos; | ||
1987 | } | ||
1988 | #endif | ||
1989 | IWL_ERR(priv, "FH register values:\n"); | ||
1990 | for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { | ||
1991 | IWL_ERR(priv, " %34s: 0X%08x\n", | ||
1992 | get_fh_string(fh_tbl[i]), | ||
1993 | iwl_read_direct32(priv, fh_tbl[i])); | ||
1994 | } | ||
1995 | return 0; | ||
1996 | } | ||
1997 | |||
1998 | /* notification wait support */ | ||
1999 | void iwlagn_init_notification_wait(struct iwl_priv *priv, | ||
2000 | struct iwl_notification_wait *wait_entry, | ||
2001 | u8 cmd, | ||
2002 | void (*fn)(struct iwl_priv *priv, | ||
2003 | struct iwl_rx_packet *pkt, | ||
2004 | void *data), | ||
2005 | void *fn_data) | ||
2006 | { | ||
2007 | wait_entry->fn = fn; | ||
2008 | wait_entry->fn_data = fn_data; | ||
2009 | wait_entry->cmd = cmd; | ||
2010 | wait_entry->triggered = false; | ||
2011 | wait_entry->aborted = false; | ||
2012 | |||
2013 | spin_lock_bh(&priv->notif_wait_lock); | ||
2014 | list_add(&wait_entry->list, &priv->notif_waits); | ||
2015 | spin_unlock_bh(&priv->notif_wait_lock); | ||
2016 | } | ||
2017 | |||
2018 | int iwlagn_wait_notification(struct iwl_priv *priv, | ||
2019 | struct iwl_notification_wait *wait_entry, | ||
2020 | unsigned long timeout) | ||
2021 | { | ||
2022 | int ret; | ||
2023 | |||
2024 | ret = wait_event_timeout(priv->notif_waitq, | ||
2025 | wait_entry->triggered || wait_entry->aborted, | ||
2026 | timeout); | ||
2027 | |||
2028 | spin_lock_bh(&priv->notif_wait_lock); | ||
2029 | list_del(&wait_entry->list); | ||
2030 | spin_unlock_bh(&priv->notif_wait_lock); | ||
2031 | |||
2032 | if (wait_entry->aborted) | ||
2033 | return -EIO; | ||
2034 | |||
2035 | /* return value is always >= 0 */ | ||
2036 | if (ret <= 0) | ||
2037 | return -ETIMEDOUT; | ||
2038 | return 0; | ||
2039 | } | ||
2040 | |||
2041 | void iwlagn_remove_notification(struct iwl_priv *priv, | ||
2042 | struct iwl_notification_wait *wait_entry) | ||
2043 | { | ||
2044 | spin_lock_bh(&priv->notif_wait_lock); | ||
2045 | list_del(&wait_entry->list); | ||
2046 | spin_unlock_bh(&priv->notif_wait_lock); | ||
2047 | } | ||