Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2008-2011 Atheros Communications Inc.
3 : : *
4 : : * Permission to use, copy, modify, and/or distribute this software for any
5 : : * purpose with or without fee is hereby granted, provided that the above
6 : : * copyright notice and this permission notice appear in all copies.
7 : : *
8 : : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 : : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 : : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 : : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 : : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 : : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 : : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 : : */
16 : :
17 : : #include "hw.h"
18 : : #include "hw-ops.h"
19 : : #include <linux/export.h>
20 : :
21 : : static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
22 : : struct ath9k_tx_queue_info *qi)
23 : : {
24 : : ath_dbg(ath9k_hw_common(ah), INTERRUPT,
25 : : "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
26 : : ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
27 : : ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
28 : : ah->txurn_interrupt_mask);
29 : :
30 : : ENABLE_REGWRITE_BUFFER(ah);
31 : :
32 : : REG_WRITE(ah, AR_IMR_S0,
33 : : SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
34 : : | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
35 : : REG_WRITE(ah, AR_IMR_S1,
36 : : SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
37 : : | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
38 : :
39 : : ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
40 : : ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
41 : : REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
42 : :
43 : : REGWRITE_BUFFER_FLUSH(ah);
44 : : }
45 : :
46 : 0 : u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
47 : : {
48 : 0 : return REG_READ(ah, AR_QTXDP(q));
49 : : }
50 : : EXPORT_SYMBOL(ath9k_hw_gettxbuf);
51 : :
52 : 0 : void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
53 : : {
54 : 0 : REG_WRITE(ah, AR_QTXDP(q), txdp);
55 : 0 : }
56 : : EXPORT_SYMBOL(ath9k_hw_puttxbuf);
57 : :
58 : 0 : void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
59 : : {
60 [ # # ]: 0 : ath_dbg(ath9k_hw_common(ah), QUEUE, "Enable TXE on queue: %u\n", q);
61 : 0 : REG_WRITE(ah, AR_Q_TXE, 1 << q);
62 : 0 : }
63 : : EXPORT_SYMBOL(ath9k_hw_txstart);
64 : :
65 : 5854 : u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
66 : : {
67 : 5854 : u32 npend;
68 : :
69 : 5854 : npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
70 [ + + ]: 5854 : if (npend == 0) {
71 : :
72 [ + + ]: 1339 : if (REG_READ(ah, AR_Q_TXE) & (1 << q))
73 : 799 : npend = 1;
74 : : }
75 : :
76 : 5854 : return npend;
77 : : }
78 : : EXPORT_SYMBOL(ath9k_hw_numtxpending);
79 : :
80 : : /**
81 : : * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
82 : : *
83 : : * @ah: atheros hardware struct
84 : : * @bIncTrigLevel: whether or not the frame trigger level should be updated
85 : : *
86 : : * The frame trigger level specifies the minimum number of bytes,
87 : : * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
88 : : * before the PCU will initiate sending the frame on the air. This can
89 : : * mean we initiate transmit before a full frame is on the PCU TX FIFO.
90 : : * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
91 : : * first)
92 : : *
93 : : * Caution must be taken to ensure to set the frame trigger level based
94 : : * on the DMA request size. For example if the DMA request size is set to
95 : : * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
96 : : * there need to be enough space in the tx FIFO for the requested transfer
97 : : * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
98 : : * the threshold to a value beyond 6, then the transmit will hang.
99 : : *
100 : : * Current dual stream devices have a PCU TX FIFO size of 8 KB.
101 : : * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
102 : : * there is a hardware issue which forces us to use 2 KB instead so the
103 : : * frame trigger level must not exceed 2 KB for these chipsets.
104 : : */
105 : 0 : bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
106 : : {
107 : 0 : u32 txcfg, curLevel, newLevel;
108 : :
109 [ # # ]: 0 : if (ah->tx_trig_level >= ah->config.max_txtrig_level)
110 : : return false;
111 : :
112 : 0 : ath9k_hw_disable_interrupts(ah);
113 : :
114 : 0 : txcfg = REG_READ(ah, AR_TXCFG);
115 : 0 : curLevel = MS(txcfg, AR_FTRIG);
116 : 0 : newLevel = curLevel;
117 [ # # ]: 0 : if (bIncTrigLevel) {
118 [ # # ]: 0 : if (curLevel < ah->config.max_txtrig_level)
119 : 0 : newLevel++;
120 [ # # ]: 0 : } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
121 : 0 : newLevel--;
122 [ # # ]: 0 : if (newLevel != curLevel)
123 : 0 : REG_WRITE(ah, AR_TXCFG,
124 : : (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
125 : :
126 : 0 : ath9k_hw_enable_interrupts(ah);
127 : :
128 : 0 : ah->tx_trig_level = newLevel;
129 : :
130 : 0 : return newLevel != curLevel;
131 : : }
132 : : EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
133 : :
134 : 54 : void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
135 : : {
136 : 54 : int maxdelay = 1000;
137 : 54 : int i, q;
138 : :
139 [ + - ]: 54 : if (ah->curchan) {
140 [ + - ]: 54 : if (IS_CHAN_HALF_RATE(ah->curchan))
141 : : maxdelay *= 2;
142 [ - + ]: 54 : else if (IS_CHAN_QUARTER_RATE(ah->curchan))
143 : 0 : maxdelay *= 4;
144 : : }
145 : :
146 : 54 : REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
147 : :
148 : 54 : REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
149 : 54 : REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
150 : 54 : REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
151 : :
152 [ + + ]: 648 : for (q = 0; q < AR_NUM_QCU; q++) {
153 [ + - ]: 5853 : for (i = 0; i < maxdelay; i++) {
154 [ + + ]: 5853 : if (i)
155 : 5313 : udelay(5);
156 : :
157 [ + + ]: 5853 : if (!ath9k_hw_numtxpending(ah, q))
158 : : break;
159 : : }
160 : : }
161 : :
162 : 54 : REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
163 : 54 : REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
164 : 54 : REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
165 : :
166 : 54 : REG_WRITE(ah, AR_Q_TXD, 0);
167 : 54 : }
168 : : EXPORT_SYMBOL(ath9k_hw_abort_tx_dma);
169 : :
170 : 0 : bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q)
171 : : {
172 : : #define ATH9K_TX_STOP_DMA_TIMEOUT 1000 /* usec */
173 : : #define ATH9K_TIME_QUANTUM 100 /* usec */
174 : 0 : int wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
175 : 0 : int wait;
176 : :
177 : 0 : REG_WRITE(ah, AR_Q_TXD, 1 << q);
178 : :
179 [ # # ]: 0 : for (wait = wait_time; wait != 0; wait--) {
180 [ # # ]: 0 : if (wait != wait_time)
181 : 0 : udelay(ATH9K_TIME_QUANTUM);
182 : :
183 [ # # ]: 0 : if (ath9k_hw_numtxpending(ah, q) == 0)
184 : : break;
185 : : }
186 : :
187 : 0 : REG_WRITE(ah, AR_Q_TXD, 0);
188 : :
189 : 0 : return wait != 0;
190 : :
191 : : #undef ATH9K_TX_STOP_DMA_TIMEOUT
192 : : #undef ATH9K_TIME_QUANTUM
193 : : }
194 : : EXPORT_SYMBOL(ath9k_hw_stop_dma_queue);
195 : :
196 : 72 : bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
197 : : const struct ath9k_tx_queue_info *qinfo)
198 : : {
199 : 72 : u32 cw;
200 [ - + ]: 72 : struct ath_common *common = ath9k_hw_common(ah);
201 : 72 : struct ath9k_tx_queue_info *qi;
202 : :
203 : 72 : qi = &ah->txq[q];
204 [ - + ]: 72 : if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
205 [ # # ]: 0 : ath_dbg(common, QUEUE,
206 : : "Set TXQ properties, inactive queue: %u\n", q);
207 : 0 : return false;
208 : : }
209 : :
210 [ - + ]: 72 : ath_dbg(common, QUEUE, "Set queue properties for: %u\n", q);
211 : :
212 : 72 : qi->tqi_ver = qinfo->tqi_ver;
213 : 72 : qi->tqi_subtype = qinfo->tqi_subtype;
214 : 72 : qi->tqi_qflags = qinfo->tqi_qflags;
215 : 72 : qi->tqi_priority = qinfo->tqi_priority;
216 [ + + ]: 72 : if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
217 : 36 : qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
218 : : else
219 : 36 : qi->tqi_aifs = INIT_AIFS;
220 [ + + ]: 72 : if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
221 : 30 : cw = min(qinfo->tqi_cwmin, 1024U);
222 : 30 : qi->tqi_cwmin = 1;
223 [ + + ]: 102 : while (qi->tqi_cwmin < cw)
224 : 72 : qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
225 : : } else
226 : 42 : qi->tqi_cwmin = qinfo->tqi_cwmin;
227 [ + + ]: 72 : if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
228 : 36 : cw = min(qinfo->tqi_cwmax, 1024U);
229 : 36 : qi->tqi_cwmax = 1;
230 [ + + ]: 306 : while (qi->tqi_cwmax < cw)
231 : 270 : qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
232 : : } else
233 : 36 : qi->tqi_cwmax = INIT_CWMAX;
234 : :
235 [ + + ]: 72 : if (qinfo->tqi_shretry != 0)
236 : 30 : qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
237 : : else
238 : 42 : qi->tqi_shretry = INIT_SH_RETRY;
239 [ + + ]: 72 : if (qinfo->tqi_lgretry != 0)
240 : 30 : qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
241 : : else
242 : 42 : qi->tqi_lgretry = INIT_LG_RETRY;
243 : 72 : qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
244 : 72 : qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
245 : 72 : qi->tqi_burstTime = qinfo->tqi_burstTime;
246 : 72 : qi->tqi_readyTime = qinfo->tqi_readyTime;
247 : :
248 [ - + ]: 72 : switch (qinfo->tqi_subtype) {
249 : 0 : case ATH9K_WME_UPSD:
250 [ # # ]: 0 : if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
251 : 0 : qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
252 : : break;
253 : : default:
254 : : break;
255 : : }
256 : :
257 : : return true;
258 : : }
259 : : EXPORT_SYMBOL(ath9k_hw_set_txq_props);
260 : :
261 : 36 : bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
262 : : struct ath9k_tx_queue_info *qinfo)
263 : : {
264 [ - + ]: 36 : struct ath_common *common = ath9k_hw_common(ah);
265 : 36 : struct ath9k_tx_queue_info *qi;
266 : :
267 : 36 : qi = &ah->txq[q];
268 [ - + ]: 36 : if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
269 [ # # ]: 0 : ath_dbg(common, QUEUE,
270 : : "Get TXQ properties, inactive queue: %u\n", q);
271 : 0 : return false;
272 : : }
273 : :
274 : 36 : qinfo->tqi_qflags = qi->tqi_qflags;
275 : 36 : qinfo->tqi_ver = qi->tqi_ver;
276 : 36 : qinfo->tqi_subtype = qi->tqi_subtype;
277 : 36 : qinfo->tqi_qflags = qi->tqi_qflags;
278 : 36 : qinfo->tqi_priority = qi->tqi_priority;
279 : 36 : qinfo->tqi_aifs = qi->tqi_aifs;
280 : 36 : qinfo->tqi_cwmin = qi->tqi_cwmin;
281 : 36 : qinfo->tqi_cwmax = qi->tqi_cwmax;
282 : 36 : qinfo->tqi_shretry = qi->tqi_shretry;
283 : 36 : qinfo->tqi_lgretry = qi->tqi_lgretry;
284 : 36 : qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
285 : 36 : qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
286 : 36 : qinfo->tqi_burstTime = qi->tqi_burstTime;
287 : 36 : qinfo->tqi_readyTime = qi->tqi_readyTime;
288 : :
289 : 36 : return true;
290 : : }
291 : : EXPORT_SYMBOL(ath9k_hw_get_txq_props);
292 : :
293 : 42 : int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
294 : : const struct ath9k_tx_queue_info *qinfo)
295 : : {
296 [ + - + + : 42 : struct ath_common *common = ath9k_hw_common(ah);
- + ]
297 : 42 : struct ath9k_tx_queue_info *qi;
298 : 42 : int q;
299 : :
300 [ + - + + : 42 : switch (type) {
- + ]
301 : : case ATH9K_TX_QUEUE_BEACON:
302 : : q = ATH9K_NUM_TX_QUEUES - 1;
303 : : break;
304 : 6 : case ATH9K_TX_QUEUE_CAB:
305 : 6 : q = ATH9K_NUM_TX_QUEUES - 2;
306 : 6 : break;
307 : 0 : case ATH9K_TX_QUEUE_PSPOLL:
308 : 0 : q = 1;
309 : 0 : break;
310 : 6 : case ATH9K_TX_QUEUE_UAPSD:
311 : 6 : q = ATH9K_NUM_TX_QUEUES - 3;
312 : 6 : break;
313 : 24 : case ATH9K_TX_QUEUE_DATA:
314 : 24 : q = qinfo->tqi_subtype;
315 : 24 : break;
316 : 0 : default:
317 : 0 : ath_err(common, "Invalid TX queue type: %u\n", type);
318 : 0 : return -1;
319 : : }
320 : :
321 [ - + ]: 42 : ath_dbg(common, QUEUE, "Setup TX queue: %u\n", q);
322 : :
323 : 42 : qi = &ah->txq[q];
324 [ - + ]: 42 : if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
325 : 0 : ath_err(common, "TX queue: %u already active\n", q);
326 : 0 : return -1;
327 : : }
328 : 42 : memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
329 : 42 : qi->tqi_type = type;
330 : 42 : qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
331 : 42 : (void) ath9k_hw_set_txq_props(ah, q, qinfo);
332 : :
333 : 42 : return q;
334 : : }
335 : : EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
336 : :
337 : 450 : static void ath9k_hw_clear_queue_interrupts(struct ath_hw *ah, u32 q)
338 : : {
339 : 450 : ah->txok_interrupt_mask &= ~(1 << q);
340 : 450 : ah->txerr_interrupt_mask &= ~(1 << q);
341 : 450 : ah->txdesc_interrupt_mask &= ~(1 << q);
342 : 450 : ah->txeol_interrupt_mask &= ~(1 << q);
343 : 450 : ah->txurn_interrupt_mask &= ~(1 << q);
344 : : }
345 : :
346 : 0 : bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
347 : : {
348 [ # # ]: 0 : struct ath_common *common = ath9k_hw_common(ah);
349 : 0 : struct ath9k_tx_queue_info *qi;
350 : :
351 : 0 : qi = &ah->txq[q];
352 [ # # ]: 0 : if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
353 [ # # ]: 0 : ath_dbg(common, QUEUE, "Release TXQ, inactive queue: %u\n", q);
354 : 0 : return false;
355 : : }
356 : :
357 [ # # ]: 0 : ath_dbg(common, QUEUE, "Release TX queue: %u\n", q);
358 : :
359 : 0 : qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
360 : 0 : ath9k_hw_clear_queue_interrupts(ah, q);
361 : 0 : ath9k_hw_set_txq_interrupts(ah, qi);
362 : :
363 : 0 : return true;
364 : : }
365 : : EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
366 : :
367 : 630 : bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
368 : : {
369 [ + + ]: 630 : struct ath_common *common = ath9k_hw_common(ah);
370 : 630 : struct ath9k_tx_queue_info *qi;
371 : 630 : u32 cwMin, chanCwMin, value;
372 : :
373 : 630 : qi = &ah->txq[q];
374 [ + + ]: 630 : if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
375 [ - + ]: 180 : ath_dbg(common, QUEUE, "Reset TXQ, inactive queue: %u\n", q);
376 : 180 : return true;
377 : : }
378 : :
379 [ - + ]: 450 : ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q);
380 : :
381 [ + + ]: 450 : if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
382 : : chanCwMin = INIT_CWMIN;
383 : :
384 [ + + ]: 680 : for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
385 : : } else
386 : : cwMin = qi->tqi_cwmin;
387 : :
388 [ - + ]: 450 : ENABLE_REGWRITE_BUFFER(ah);
389 : :
390 : 450 : REG_WRITE(ah, AR_DLCL_IFS(q),
391 : : SM(cwMin, AR_D_LCL_IFS_CWMIN) |
392 : : SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
393 : : SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
394 : :
395 : 450 : REG_WRITE(ah, AR_DRETRY_LIMIT(q),
396 : : SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
397 : : SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
398 : : SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
399 : :
400 : 450 : REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
401 : :
402 [ - + - - ]: 450 : if (AR_SREV_9340(ah) && !AR_SREV_9340_13_OR_LATER(ah))
403 : 0 : REG_WRITE(ah, AR_DMISC(q),
404 : : AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
405 : : else
406 : 450 : REG_WRITE(ah, AR_DMISC(q),
407 : : AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
408 : :
409 [ - + ]: 450 : if (qi->tqi_cbrPeriod) {
410 : 0 : REG_WRITE(ah, AR_QCBRCFG(q),
411 : : SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
412 : : SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
413 [ # # ]: 0 : REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
414 : : (qi->tqi_cbrOverflowLimit ?
415 : : AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
416 : : }
417 [ - + - - ]: 450 : if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
418 : 0 : REG_WRITE(ah, AR_QRDYTIMECFG(q),
419 : : SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
420 : : AR_Q_RDYTIMECFG_EN);
421 : : }
422 : :
423 [ + - ]: 900 : REG_WRITE(ah, AR_DCHNTIME(q),
424 : : SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
425 : : (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
426 : :
427 [ - + ]: 450 : if (qi->tqi_burstTime
428 [ # # ]: 0 : && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
429 : 0 : REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
430 : :
431 [ - + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
432 : 0 : REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
433 : :
434 [ - + ]: 450 : REGWRITE_BUFFER_FLUSH(ah);
435 : :
436 [ - + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
437 : 0 : REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
438 : :
439 [ + + - + : 450 : switch (qi->tqi_type) {
+ ]
440 : 60 : case ATH9K_TX_QUEUE_BEACON:
441 [ - + ]: 60 : ENABLE_REGWRITE_BUFFER(ah);
442 : :
443 : 60 : REG_SET_BIT(ah, AR_QMISC(q),
444 : : AR_Q_MISC_FSP_DBA_GATED
445 : : | AR_Q_MISC_BEACON_USE
446 : : | AR_Q_MISC_CBR_INCR_DIS1);
447 : :
448 : 60 : REG_SET_BIT(ah, AR_DMISC(q),
449 : : (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
450 : : AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
451 : : | AR_D_MISC_BEACON_USE
452 : : | AR_D_MISC_POST_FR_BKOFF_DIS);
453 : :
454 [ - + ]: 60 : REGWRITE_BUFFER_FLUSH(ah);
455 : :
456 : : /*
457 : : * cwmin and cwmax should be 0 for beacon queue
458 : : * but not for IBSS as we would create an imbalance
459 : : * on beaconing fairness for participating nodes.
460 : : */
461 [ + + ]: 60 : if (AR_SREV_9300_20_OR_LATER(ah) &&
462 [ + - ]: 40 : ah->opmode != NL80211_IFTYPE_ADHOC) {
463 : 40 : REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
464 : : | SM(0, AR_D_LCL_IFS_CWMAX)
465 : : | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
466 : : }
467 : : break;
468 : 66 : case ATH9K_TX_QUEUE_CAB:
469 [ - + ]: 66 : ENABLE_REGWRITE_BUFFER(ah);
470 : :
471 : 66 : REG_SET_BIT(ah, AR_QMISC(q),
472 : : AR_Q_MISC_FSP_DBA_GATED
473 : : | AR_Q_MISC_CBR_INCR_DIS1
474 : : | AR_Q_MISC_CBR_INCR_DIS0);
475 : 66 : value = (qi->tqi_readyTime -
476 : 66 : (ah->config.sw_beacon_response_time -
477 : 66 : ah->config.dma_beacon_response_time)) * 1024;
478 : 66 : REG_WRITE(ah, AR_QRDYTIMECFG(q),
479 : : value | AR_Q_RDYTIMECFG_EN);
480 : 66 : REG_SET_BIT(ah, AR_DMISC(q),
481 : : (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
482 : : AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
483 : :
484 [ - + ]: 66 : REGWRITE_BUFFER_FLUSH(ah);
485 : :
486 : : break;
487 : 0 : case ATH9K_TX_QUEUE_PSPOLL:
488 : 0 : REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1);
489 : 0 : break;
490 : 60 : case ATH9K_TX_QUEUE_UAPSD:
491 : 60 : REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
492 : 60 : break;
493 : : default:
494 : : break;
495 : : }
496 : :
497 [ - + ]: 450 : if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
498 : 0 : REG_SET_BIT(ah, AR_DMISC(q),
499 : : SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
500 : : AR_D_MISC_ARB_LOCKOUT_CNTRL) |
501 : : AR_D_MISC_POST_FR_BKOFF_DIS);
502 : : }
503 : :
504 [ + + ]: 450 : if (AR_SREV_9300_20_OR_LATER(ah))
505 : 300 : REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
506 : :
507 : 450 : ath9k_hw_clear_queue_interrupts(ah, q);
508 [ + + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_TXINT_ENABLE) {
509 : 300 : ah->txok_interrupt_mask |= 1 << q;
510 : 300 : ah->txerr_interrupt_mask |= 1 << q;
511 : : }
512 [ + + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
513 : 130 : ah->txdesc_interrupt_mask |= 1 << q;
514 [ + + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
515 : 110 : ah->txeol_interrupt_mask |= 1 << q;
516 [ - + ]: 450 : if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
517 : 0 : ah->txurn_interrupt_mask |= 1 << q;
518 : 450 : ath9k_hw_set_txq_interrupts(ah, qi);
519 : :
520 : 450 : return true;
521 : : }
522 : : EXPORT_SYMBOL(ath9k_hw_resettxqueue);
523 : :
524 : 260 : int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
525 : : struct ath_rx_status *rs)
526 : : {
527 : 260 : struct ar5416_desc ads;
528 : 260 : struct ar5416_desc *adsp = AR5416DESC(ds);
529 : 260 : u32 phyerr;
530 : :
531 [ + + ]: 260 : if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
532 : : return -EINPROGRESS;
533 : :
534 : 188 : ads.u.rx = adsp->u.rx;
535 : :
536 : 188 : rs->rs_status = 0;
537 : 188 : rs->rs_flags = 0;
538 : 188 : rs->enc_flags = 0;
539 : 188 : rs->bw = RATE_INFO_BW_20;
540 : :
541 : 188 : rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
542 : 188 : rs->rs_tstamp = ads.AR_RcvTimestamp;
543 : :
544 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
545 : 104 : rs->rs_rssi = ATH9K_RSSI_BAD;
546 : 104 : rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
547 : 104 : rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
548 : 104 : rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
549 : 104 : rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
550 : 104 : rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
551 : 104 : rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
552 : : } else {
553 : 84 : rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
554 : 84 : rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
555 : : AR_RxRSSIAnt00);
556 : 84 : rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
557 : : AR_RxRSSIAnt01);
558 : 84 : rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
559 : : AR_RxRSSIAnt02);
560 : 84 : rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
561 : : AR_RxRSSIAnt10);
562 : 84 : rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
563 : : AR_RxRSSIAnt11);
564 : 84 : rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
565 : : AR_RxRSSIAnt12);
566 : : }
567 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
568 : 36 : rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
569 : : else
570 : 152 : rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
571 : :
572 : 188 : rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate);
573 : 188 : rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
574 : :
575 : 188 : rs->rs_firstaggr = (ads.ds_rxstatus8 & AR_RxFirstAggr) ? 1 : 0;
576 : 188 : rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
577 : 188 : rs->rs_moreaggr = (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
578 : 188 : rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
579 : :
580 : : /* directly mapped flags for ieee80211_rx_status */
581 : 188 : rs->enc_flags |=
582 : 188 : (ads.ds_rxstatus3 & AR_GI) ? RX_ENC_FLAG_SHORT_GI : 0;
583 [ + + ]: 188 : rs->bw = (ads.ds_rxstatus3 & AR_2040) ? RATE_INFO_BW_40 :
584 : : RATE_INFO_BW_20;
585 [ - + ]: 188 : if (AR_SREV_9280_20_OR_LATER(ah))
586 : 0 : rs->enc_flags |=
587 : : (ads.ds_rxstatus3 & AR_STBC) ?
588 : : /* we can only Nss=1 STBC */
589 : 0 : (1 << RX_ENC_FLAG_STBC_SHIFT) : 0;
590 : :
591 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
592 : 68 : rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
593 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
594 : 104 : rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
595 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
596 : 28 : rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
597 : :
598 [ + + ]: 188 : if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
599 : : /*
600 : : * Treat these errors as mutually exclusive to avoid spurious
601 : : * extra error reports from the hardware. If a CRC error is
602 : : * reported, then decryption and MIC errors are irrelevant,
603 : : * the frame is going to be dropped either way
604 : : */
605 [ + + ]: 128 : if (ads.ds_rxstatus8 & AR_PHYErr) {
606 : 36 : rs->rs_status |= ATH9K_RXERR_PHY;
607 : 36 : phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
608 : 36 : rs->rs_phyerr = phyerr;
609 [ + + ]: 92 : } else if (ads.ds_rxstatus8 & AR_CRCErr)
610 : 20 : rs->rs_status |= ATH9K_RXERR_CRC;
611 [ + + ]: 72 : else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
612 : 10 : rs->rs_status |= ATH9K_RXERR_DECRYPT;
613 [ + + ]: 62 : else if (ads.ds_rxstatus8 & AR_MichaelErr)
614 : 2 : rs->rs_status |= ATH9K_RXERR_MIC;
615 : : } else {
616 [ + + ]: 60 : if (ads.ds_rxstatus8 &
617 : : (AR_CRCErr | AR_PHYErr | AR_DecryptCRCErr | AR_MichaelErr))
618 : 58 : rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
619 : :
620 : : /* Only up to MCS16 supported, everything above is invalid */
621 [ + + ]: 60 : if (rs->rs_rate >= 0x90)
622 : 8 : rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
623 : : }
624 : :
625 [ + + ]: 188 : if (ads.ds_rxstatus8 & AR_KeyMiss)
626 : 46 : rs->rs_status |= ATH9K_RXERR_KEYMISS;
627 : :
628 : : return 0;
629 : : }
630 : : EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
631 : :
632 : : /*
633 : : * This can stop or re-enables RX.
634 : : *
635 : : * If bool is set this will kill any frame which is currently being
636 : : * transferred between the MAC and baseband and also prevent any new
637 : : * frames from getting started.
638 : : */
639 : 33 : bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
640 : : {
641 : 33 : u32 reg;
642 : :
643 [ + + ]: 33 : if (set) {
644 : 31 : REG_SET_BIT(ah, AR_DIAG_SW,
645 : : (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
646 : :
647 [ - + ]: 31 : if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
648 : : 0, AH_WAIT_TIMEOUT)) {
649 : 0 : REG_CLR_BIT(ah, AR_DIAG_SW,
650 : : (AR_DIAG_RX_DIS |
651 : : AR_DIAG_RX_ABORT));
652 : :
653 : 0 : reg = REG_READ(ah, AR_OBS_BUS_1);
654 : 0 : ath_err(ath9k_hw_common(ah),
655 : : "RX failed to go idle in 10 ms RXSM=0x%x\n",
656 : : reg);
657 : :
658 : 0 : return false;
659 : : }
660 : : } else {
661 : 2 : REG_CLR_BIT(ah, AR_DIAG_SW,
662 : : (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
663 : : }
664 : :
665 : : return true;
666 : : }
667 : : EXPORT_SYMBOL(ath9k_hw_setrxabort);
668 : :
669 : 40 : void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
670 : : {
671 : 40 : REG_WRITE(ah, AR_RXDP, rxdp);
672 : 40 : }
673 : : EXPORT_SYMBOL(ath9k_hw_putrxbuf);
674 : :
675 : 60 : void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning)
676 : : {
677 : 60 : ath9k_enable_mib_counters(ah);
678 : :
679 : 60 : ath9k_ani_reset(ah, is_scanning);
680 : :
681 : 60 : REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
682 : 60 : }
683 : : EXPORT_SYMBOL(ath9k_hw_startpcureceive);
684 : :
685 : 54 : void ath9k_hw_abortpcurecv(struct ath_hw *ah)
686 : : {
687 : 54 : REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
688 : :
689 : 54 : ath9k_hw_disable_mib_counters(ah);
690 : 54 : }
691 : : EXPORT_SYMBOL(ath9k_hw_abortpcurecv);
692 : :
693 : 85 : bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
694 : : {
695 : : #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
696 : 85 : struct ath_common *common = ath9k_hw_common(ah);
697 : 85 : u32 mac_status, last_mac_status = 0;
698 : 85 : int i;
699 : :
700 : : /* Enable access to the DMA observation bus */
701 : 85 : REG_WRITE(ah, AR_MACMISC,
702 : : ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
703 : : (AR_MACMISC_MISC_OBS_BUS_1 <<
704 : : AR_MACMISC_MISC_OBS_BUS_MSB_S)));
705 : :
706 : 85 : REG_WRITE(ah, AR_CR, AR_CR_RXD);
707 : :
708 : : /* Wait for rx enable bit to go low */
709 [ + - ]: 226 : for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
710 [ + + + + ]: 179 : if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
711 : : break;
712 : :
713 [ + + ]: 56 : if (!AR_SREV_9300_20_OR_LATER(ah)) {
714 : 10 : mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0;
715 [ - + - - ]: 10 : if (mac_status == 0x1c0 && mac_status == last_mac_status) {
716 : 0 : *reset = true;
717 : 0 : break;
718 : : }
719 : :
720 : : last_mac_status = mac_status;
721 : : }
722 : :
723 : 56 : udelay(AH_TIME_QUANTUM);
724 : : }
725 : :
726 [ - + ]: 85 : if (i == 0) {
727 : 0 : ath_err(common,
728 : : "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
729 : : AH_RX_STOP_DMA_TIMEOUT / 1000,
730 : : REG_READ(ah, AR_CR),
731 : : REG_READ(ah, AR_DIAG_SW),
732 : : REG_READ(ah, AR_DMADBG_7));
733 : 0 : return false;
734 : : } else {
735 : : return true;
736 : : }
737 : :
738 : : #undef AH_RX_STOP_DMA_TIMEOUT
739 : : }
740 : : EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
741 : :
742 : 6 : int ath9k_hw_beaconq_setup(struct ath_hw *ah)
743 : : {
744 : 6 : struct ath9k_tx_queue_info qi;
745 : :
746 : 6 : memset(&qi, 0, sizeof(qi));
747 : 6 : qi.tqi_aifs = 1;
748 : 6 : qi.tqi_cwmin = 0;
749 : 6 : qi.tqi_cwmax = 0;
750 : :
751 [ + + ]: 6 : if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
752 : 4 : qi.tqi_qflags = TXQ_FLAG_TXINT_ENABLE;
753 : :
754 : 6 : return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
755 : : }
756 : : EXPORT_SYMBOL(ath9k_hw_beaconq_setup);
757 : :
758 : 181 : bool ath9k_hw_intrpend(struct ath_hw *ah)
759 : : {
760 : 181 : u32 host_isr;
761 : :
762 [ + - ]: 181 : if (AR_SREV_9100(ah))
763 : : return true;
764 : :
765 [ + - ]: 362 : host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
766 : :
767 [ + + ]: 181 : if (((host_isr & AR_INTR_MAC_IRQ) ||
768 [ - + ]: 29 : (host_isr & AR_INTR_ASYNC_MASK_MCI)) &&
769 : : (host_isr != AR_INTR_SPURIOUS))
770 : : return true;
771 : :
772 [ + - ]: 304 : host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
773 [ + + ]: 152 : if ((host_isr & AR_INTR_SYNC_DEFAULT)
774 [ + - ]: 107 : && (host_isr != AR_INTR_SPURIOUS))
775 : 107 : return true;
776 : :
777 : : return false;
778 : : }
779 : : EXPORT_SYMBOL(ath9k_hw_intrpend);
780 : :
781 : 223 : void ath9k_hw_kill_interrupts(struct ath_hw *ah)
782 : : {
783 [ - + ]: 223 : struct ath_common *common = ath9k_hw_common(ah);
784 : :
785 [ - + ]: 223 : ath_dbg(common, INTERRUPT, "disable IER\n");
786 : 223 : REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
787 : 223 : (void) REG_READ(ah, AR_IER);
788 [ + - ]: 223 : if (!AR_SREV_9100(ah)) {
789 [ + - ]: 446 : REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
790 [ + - ]: 446 : (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
791 : :
792 [ + - ]: 446 : REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
793 [ + - ]: 446 : (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
794 : : }
795 : 223 : }
796 : : EXPORT_SYMBOL(ath9k_hw_kill_interrupts);
797 : :
798 : 120 : void ath9k_hw_disable_interrupts(struct ath_hw *ah)
799 : : {
800 [ - + ]: 120 : if (!(ah->imask & ATH9K_INT_GLOBAL))
801 : 0 : atomic_set(&ah->intr_ref_cnt, -1);
802 : : else
803 : 120 : atomic_dec(&ah->intr_ref_cnt);
804 : :
805 : 120 : ath9k_hw_kill_interrupts(ah);
806 : 120 : }
807 : : EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
808 : :
809 : 67 : static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
810 : : {
811 [ + - ]: 67 : struct ath_common *common = ath9k_hw_common(ah);
812 : 67 : u32 sync_default = AR_INTR_SYNC_DEFAULT;
813 : 67 : u32 async_mask;
814 : :
815 [ + - + - : 67 : if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ + + + ]
816 : : AR_SREV_9561(ah))
817 : 21 : sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
818 : :
819 : 67 : async_mask = AR_INTR_MAC_IRQ;
820 : :
821 [ - + ]: 67 : if (ah->imask & ATH9K_INT_MCI)
822 : 0 : async_mask |= AR_INTR_ASYNC_MASK_MCI;
823 : :
824 [ - + ]: 67 : ath_dbg(common, INTERRUPT, "enable IER\n");
825 : 67 : REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
826 [ + - ]: 67 : if (!AR_SREV_9100(ah)) {
827 [ + - ]: 134 : REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, async_mask);
828 [ + - ]: 134 : REG_WRITE(ah, AR_INTR_ASYNC_MASK, async_mask);
829 : :
830 [ + - ]: 134 : REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
831 [ + - ]: 134 : REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
832 : : }
833 [ - + ]: 67 : ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
834 : : REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
835 : :
836 [ - + ]: 67 : if (ah->msi_enabled) {
837 : 0 : u32 _msi_reg = 0;
838 : 0 : u32 i = 0;
839 : 0 : u32 msi_pend_addr_mask = AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64;
840 : :
841 [ # # ]: 0 : ath_dbg(ath9k_hw_common(ah), INTERRUPT,
842 : : "Enabling MSI, msi_mask=0x%X\n", ah->msi_mask);
843 : :
844 [ # # ]: 0 : REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, ah->msi_mask);
845 [ # # ]: 0 : REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, ah->msi_mask);
846 [ # # # # : 0 : ath_dbg(ath9k_hw_common(ah), INTERRUPT,
# # ]
847 : : "AR_INTR_PRIO_ASYNC_ENABLE=0x%X, AR_INTR_PRIO_ASYNC_MASK=0x%X\n",
848 : : REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE),
849 : : REG_READ(ah, AR_INTR_PRIO_ASYNC_MASK));
850 : :
851 [ # # ]: 0 : if (ah->msi_reg == 0)
852 [ # # # # ]: 0 : ah->msi_reg = REG_READ(ah, AR_PCIE_MSI);
853 : :
854 [ # # # # : 0 : ath_dbg(ath9k_hw_common(ah), INTERRUPT,
# # ]
855 : : "AR_PCIE_MSI=0x%X, ah->msi_reg = 0x%X\n",
856 : : AR_PCIE_MSI, ah->msi_reg);
857 : :
858 : : i = 0;
859 : 0 : do {
860 [ # # # # ]: 0 : REG_WRITE(ah, AR_PCIE_MSI,
861 : : (ah->msi_reg | AR_PCIE_MSI_ENABLE)
862 : : & msi_pend_addr_mask);
863 [ # # # # ]: 0 : _msi_reg = REG_READ(ah, AR_PCIE_MSI);
864 : 0 : i++;
865 [ # # # # ]: 0 : } while ((_msi_reg & AR_PCIE_MSI_ENABLE) == 0 && i < 200);
866 : :
867 [ # # ]: 0 : if (i >= 200)
868 : 0 : ath_err(ath9k_hw_common(ah),
869 : : "%s: _msi_reg = 0x%X\n",
870 : : __func__, _msi_reg);
871 : : }
872 : 67 : }
873 : :
874 : 1 : void ath9k_hw_resume_interrupts(struct ath_hw *ah)
875 : : {
876 [ + - ]: 1 : struct ath_common *common = ath9k_hw_common(ah);
877 : :
878 [ + - ]: 1 : if (!(ah->imask & ATH9K_INT_GLOBAL))
879 : : return;
880 : :
881 [ - + ]: 1 : if (atomic_read(&ah->intr_ref_cnt) != 0) {
882 [ # # ]: 0 : ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
883 : : atomic_read(&ah->intr_ref_cnt));
884 : 0 : return;
885 : : }
886 : :
887 : 1 : __ath9k_hw_enable_interrupts(ah);
888 : : }
889 : : EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
890 : :
891 : 126 : void ath9k_hw_enable_interrupts(struct ath_hw *ah)
892 : : {
893 [ + - ]: 126 : struct ath_common *common = ath9k_hw_common(ah);
894 : :
895 [ + - ]: 126 : if (!(ah->imask & ATH9K_INT_GLOBAL))
896 : : return;
897 : :
898 [ + + ]: 126 : if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
899 [ - + ]: 60 : ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
900 : : atomic_read(&ah->intr_ref_cnt));
901 : 60 : return;
902 : : }
903 : :
904 : 66 : __ath9k_hw_enable_interrupts(ah);
905 : : }
906 : : EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
907 : :
908 : 194 : void ath9k_hw_set_interrupts(struct ath_hw *ah)
909 : : {
910 : 194 : enum ath9k_int ints = ah->imask;
911 : 194 : u32 mask, mask2;
912 : 194 : struct ath9k_hw_capabilities *pCap = &ah->caps;
913 [ - + ]: 194 : struct ath_common *common = ath9k_hw_common(ah);
914 : :
915 [ - + ]: 194 : if (!(ints & ATH9K_INT_GLOBAL))
916 : 0 : ath9k_hw_disable_interrupts(ah);
917 : :
918 [ - + ]: 194 : if (ah->msi_enabled) {
919 [ # # ]: 0 : ath_dbg(common, INTERRUPT, "Clearing AR_INTR_PRIO_ASYNC_ENABLE\n");
920 : :
921 [ # # ]: 0 : REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
922 [ # # ]: 0 : REG_READ(ah, AR_INTR_PRIO_ASYNC_ENABLE);
923 : : }
924 : :
925 [ - + ]: 194 : ath_dbg(common, INTERRUPT, "New interrupt mask 0x%x\n", ints);
926 : :
927 : 194 : mask = ints & ATH9K_INT_COMMON;
928 : 194 : mask2 = 0;
929 : :
930 : 194 : ah->msi_mask = 0;
931 [ + - ]: 194 : if (ints & ATH9K_INT_TX) {
932 : 194 : ah->msi_mask |= AR_INTR_PRIO_TX;
933 [ - + ]: 194 : if (ah->config.tx_intr_mitigation)
934 : 0 : mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
935 : : else {
936 [ + + ]: 194 : if (ah->txok_interrupt_mask)
937 : 130 : mask |= AR_IMR_TXOK;
938 [ + + ]: 194 : if (ah->txdesc_interrupt_mask)
939 : 64 : mask |= AR_IMR_TXDESC;
940 : : }
941 [ + + ]: 194 : if (ah->txerr_interrupt_mask)
942 : 130 : mask |= AR_IMR_TXERR;
943 [ + + ]: 194 : if (ah->txeol_interrupt_mask)
944 : 64 : mask |= AR_IMR_TXEOL;
945 : : }
946 [ + - ]: 194 : if (ints & ATH9K_INT_RX) {
947 : 194 : ah->msi_mask |= AR_INTR_PRIO_RXLP | AR_INTR_PRIO_RXHP;
948 [ + + ]: 194 : if (AR_SREV_9300_20_OR_LATER(ah)) {
949 : 130 : mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP;
950 [ + - ]: 130 : if (ah->config.rx_intr_mitigation) {
951 : 130 : mask &= ~AR_IMR_RXOK_LP;
952 : 130 : mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
953 : : } else {
954 : 0 : mask |= AR_IMR_RXOK_LP;
955 : : }
956 : : } else {
957 [ + - ]: 64 : if (ah->config.rx_intr_mitigation)
958 : 64 : mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
959 : : else
960 : 0 : mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
961 : : }
962 [ + + ]: 194 : if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
963 : 64 : mask |= AR_IMR_GENTMR;
964 : : }
965 : :
966 [ - + ]: 194 : if (ints & ATH9K_INT_GENTIMER)
967 : 0 : mask |= AR_IMR_GENTMR;
968 : :
969 [ + + ]: 194 : if (ints & (ATH9K_INT_BMISC)) {
970 : 161 : mask |= AR_IMR_BCNMISC;
971 [ - + ]: 161 : if (ints & ATH9K_INT_TIM)
972 : 0 : mask2 |= AR_IMR_S2_TIM;
973 [ - + ]: 161 : if (ints & ATH9K_INT_DTIM)
974 : 0 : mask2 |= AR_IMR_S2_DTIM;
975 [ - + ]: 161 : if (ints & ATH9K_INT_DTIMSYNC)
976 : 0 : mask2 |= AR_IMR_S2_DTIMSYNC;
977 [ - + ]: 161 : if (ints & ATH9K_INT_CABEND)
978 : 0 : mask2 |= AR_IMR_S2_CABEND;
979 [ + - ]: 161 : if (ints & ATH9K_INT_TSFOOR)
980 : 161 : mask2 |= AR_IMR_S2_TSFOOR;
981 : : }
982 : :
983 [ + - ]: 194 : if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
984 : 194 : mask |= AR_IMR_BCNMISC;
985 [ + + ]: 194 : if (ints & ATH9K_INT_GTT)
986 : 130 : mask2 |= AR_IMR_S2_GTT;
987 [ + - ]: 194 : if (ints & ATH9K_INT_CST)
988 : 194 : mask2 |= AR_IMR_S2_CST;
989 : : }
990 : :
991 [ + + ]: 194 : if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
992 [ + - ]: 130 : if (ints & ATH9K_INT_BB_WATCHDOG) {
993 : 130 : mask |= AR_IMR_BCNMISC;
994 : 130 : mask2 |= AR_IMR_S2_BB_WATCHDOG;
995 : : }
996 : : }
997 : :
998 [ - + ]: 194 : ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask);
999 : 194 : REG_WRITE(ah, AR_IMR, mask);
1000 : 194 : ah->imrs2_reg &= ~(AR_IMR_S2_TIM |
1001 : : AR_IMR_S2_DTIM |
1002 : : AR_IMR_S2_DTIMSYNC |
1003 : : AR_IMR_S2_CABEND |
1004 : : AR_IMR_S2_CABTO |
1005 : : AR_IMR_S2_TSFOOR |
1006 : : AR_IMR_S2_GTT |
1007 : : AR_IMR_S2_CST);
1008 : :
1009 [ + + ]: 194 : if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
1010 [ + - ]: 130 : if (ints & ATH9K_INT_BB_WATCHDOG)
1011 : 130 : ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG;
1012 : : }
1013 : :
1014 : 194 : ah->imrs2_reg |= mask2;
1015 : 194 : REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
1016 : :
1017 [ + + ]: 194 : if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
1018 [ - + ]: 64 : if (ints & ATH9K_INT_TIM_TIMER)
1019 : 0 : REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
1020 : : else
1021 : 64 : REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
1022 : : }
1023 : :
1024 : 194 : return;
1025 : : }
1026 : : EXPORT_SYMBOL(ath9k_hw_set_interrupts);
1027 : :
1028 : : #define ATH9K_HW_MAX_DCU 10
1029 : : #define ATH9K_HW_SLICE_PER_DCU 16
1030 : : #define ATH9K_HW_BIT_IN_SLICE 16
1031 : 0 : void ath9k_hw_set_tx_filter(struct ath_hw *ah, u8 destidx, bool set)
1032 : : {
1033 : 0 : int dcu_idx;
1034 : 0 : u32 filter;
1035 : :
1036 [ # # ]: 0 : for (dcu_idx = 0; dcu_idx < 10; dcu_idx++) {
1037 : 0 : filter = SM(set, AR_D_TXBLK_WRITE_COMMAND);
1038 : 0 : filter |= SM(dcu_idx, AR_D_TXBLK_WRITE_DCU);
1039 : 0 : filter |= SM((destidx / ATH9K_HW_SLICE_PER_DCU),
1040 : : AR_D_TXBLK_WRITE_SLICE);
1041 : 0 : filter |= BIT(destidx % ATH9K_HW_BIT_IN_SLICE);
1042 [ # # ]: 0 : ath_dbg(ath9k_hw_common(ah), PS,
1043 : : "DCU%d staid %d set %d txfilter %08x\n",
1044 : : dcu_idx, destidx, set, filter);
1045 : 0 : REG_WRITE(ah, AR_D_TXBLK_BASE, filter);
1046 : : }
1047 : 0 : }
1048 : : EXPORT_SYMBOL(ath9k_hw_set_tx_filter);
|