blob: 8d2b139818ee52d17fd2d8826bbc11d649b5061b [file] [log] [blame]
Sujithf1dc5602008-10-29 10:16:30 +05301/*
2 * Copyright (c) 2008 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 "core.h"
18#include "hw.h"
19#include "reg.h"
20#include "phy.h"
21
22static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
23 struct ath9k_tx_queue_info *qi)
24{
25 struct ath_hal_5416 *ahp = AH5416(ah);
26
27 DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
Sujith04bd4632008-11-28 22:18:05 +053028 "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
29 ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask,
30 ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask,
31 ahp->ah_txUrnInterruptMask);
Sujithf1dc5602008-10-29 10:16:30 +053032
33 REG_WRITE(ah, AR_IMR_S0,
34 SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
35 | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
36 REG_WRITE(ah, AR_IMR_S1,
37 SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
38 | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
39 REG_RMW_FIELD(ah, AR_IMR_S2,
40 AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
41}
42
43void ath9k_hw_dmaRegDump(struct ath_hal *ah)
44{
45 u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
46 int qcuOffset = 0, dcuOffset = 0;
47 u32 *qcuBase = &val[0], *dcuBase = &val[4];
48 int i;
49
50 REG_WRITE(ah, AR_MACMISC,
51 ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
52 (AR_MACMISC_MISC_OBS_BUS_1 <<
53 AR_MACMISC_MISC_OBS_BUS_MSB_S)));
54
55 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
56
57 for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
58 if (i % 4 == 0)
59 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
60
61 val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
62 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
63 }
64
65 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
66 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
67 "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
68
69 for (i = 0; i < ATH9K_NUM_QUEUES;
70 i++, qcuOffset += 4, dcuOffset += 5) {
71 if (i == 8) {
72 qcuOffset = 0;
73 qcuBase++;
74 }
75
76 if (i == 6) {
77 dcuOffset = 0;
78 dcuBase++;
79 }
80
81 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
82 "%2d %2x %1x %2x %2x\n",
83 i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
84 (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
85 val[2] & (0x7 << (i * 3)) >> (i * 3),
86 (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
87 }
88
89 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
90 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
91 "qcu_stitch state: %2x qcu_fetch state: %2x\n",
92 (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
93 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
94 "qcu_complete state: %2x dcu_complete state: %2x\n",
95 (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
96 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
97 "dcu_arb state: %2x dcu_fp state: %2x\n",
98 (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
99 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
100 "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
101 (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
102 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
103 "txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
104 (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
105 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
106 "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
107 (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
108
109 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
110 REG_READ(ah, AR_OBS_BUS_1));
111 DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
112 "AR_CR 0x%x \n", REG_READ(ah, AR_CR));
113}
114
115u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
116{
117 return REG_READ(ah, AR_QTXDP(q));
118}
119
120bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp)
121{
122 REG_WRITE(ah, AR_QTXDP(q), txdp);
123
124 return true;
125}
126
127bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
128{
Sujith04bd4632008-11-28 22:18:05 +0530129 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530130
131 REG_WRITE(ah, AR_Q_TXE, 1 << q);
132
133 return true;
134}
135
136u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
137{
138 u32 npend;
139
140 npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
141 if (npend == 0) {
142
143 if (REG_READ(ah, AR_Q_TXE) & (1 << q))
144 npend = 1;
145 }
146
147 return npend;
148}
149
150bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
151{
152 struct ath_hal_5416 *ahp = AH5416(ah);
153 u32 txcfg, curLevel, newLevel;
154 enum ath9k_int omask;
155
156 if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
157 return false;
158
159 omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
160
161 txcfg = REG_READ(ah, AR_TXCFG);
162 curLevel = MS(txcfg, AR_FTRIG);
163 newLevel = curLevel;
164 if (bIncTrigLevel) {
165 if (curLevel < MAX_TX_FIFO_THRESHOLD)
166 newLevel++;
167 } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
168 newLevel--;
169 if (newLevel != curLevel)
170 REG_WRITE(ah, AR_TXCFG,
171 (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
172
173 ath9k_hw_set_interrupts(ah, omask);
174
175 ah->ah_txTrigLevel = newLevel;
176
177 return newLevel != curLevel;
178}
179
180bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
181{
182 u32 tsfLow, j, wait;
183
184 REG_WRITE(ah, AR_Q_TXD, 1 << q);
185
186 for (wait = 1000; wait != 0; wait--) {
187 if (ath9k_hw_numtxpending(ah, q) == 0)
188 break;
189 udelay(100);
190 }
191
192 if (ath9k_hw_numtxpending(ah, q)) {
193 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
194 "%s: Num of pending TX Frames %d on Q %d\n",
195 __func__, ath9k_hw_numtxpending(ah, q), q);
196
197 for (j = 0; j < 2; j++) {
198 tsfLow = REG_READ(ah, AR_TSF_L32);
199 REG_WRITE(ah, AR_QUIET2,
200 SM(10, AR_QUIET2_QUIET_DUR));
201 REG_WRITE(ah, AR_QUIET_PERIOD, 100);
202 REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
203 REG_SET_BIT(ah, AR_TIMER_MODE,
204 AR_QUIET_TIMER_EN);
205
206 if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
207 break;
208
209 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530210 "TSF have moved while trying to set "
211 "quiet time TSF: 0x%08x\n", tsfLow);
Sujithf1dc5602008-10-29 10:16:30 +0530212 }
213
214 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
215
216 udelay(200);
217 REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
218
219 wait = 1000;
220
221 while (ath9k_hw_numtxpending(ah, q)) {
222 if ((--wait) == 0) {
223 DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
Sujith04bd4632008-11-28 22:18:05 +0530224 "Failed to stop Tx DMA in 100 "
225 "msec after killing last frame\n");
Sujithf1dc5602008-10-29 10:16:30 +0530226 break;
227 }
228 udelay(100);
229 }
230
231 REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
232 }
233
234 REG_WRITE(ah, AR_Q_TXD, 0);
235
236 return wait != 0;
237}
238
239bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
240 u32 segLen, bool firstSeg,
241 bool lastSeg, const struct ath_desc *ds0)
242{
243 struct ar5416_desc *ads = AR5416DESC(ds);
244
245 if (firstSeg) {
246 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
247 } else if (lastSeg) {
248 ads->ds_ctl0 = 0;
249 ads->ds_ctl1 = segLen;
250 ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
251 ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
252 } else {
253 ads->ds_ctl0 = 0;
254 ads->ds_ctl1 = segLen | AR_TxMore;
255 ads->ds_ctl2 = 0;
256 ads->ds_ctl3 = 0;
257 }
258 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
259 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
260 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
261 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
262 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
263
264 return true;
265}
266
267void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
268{
269 struct ar5416_desc *ads = AR5416DESC(ds);
270
271 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
272 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
273 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
274 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
275 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
276}
277
278int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
279{
280 struct ar5416_desc *ads = AR5416DESC(ds);
281
282 if ((ads->ds_txstatus9 & AR_TxDone) == 0)
283 return -EINPROGRESS;
284
285 ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
286 ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
287 ds->ds_txstat.ts_status = 0;
288 ds->ds_txstat.ts_flags = 0;
289
290 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
291 ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
292 if (ads->ds_txstatus1 & AR_Filtered)
293 ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
Sujithdaa9deb2008-11-18 09:10:22 +0530294 if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
Sujithf1dc5602008-10-29 10:16:30 +0530295 ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
Sujithdaa9deb2008-11-18 09:10:22 +0530296 ath9k_hw_updatetxtriglevel(ah, true);
297 }
Sujithf1dc5602008-10-29 10:16:30 +0530298 if (ads->ds_txstatus9 & AR_TxOpExceeded)
299 ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
300 if (ads->ds_txstatus1 & AR_TxTimerExpired)
301 ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
302
303 if (ads->ds_txstatus1 & AR_DescCfgErr)
304 ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
305 if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
306 ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
307 ath9k_hw_updatetxtriglevel(ah, true);
308 }
309 if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
310 ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
311 ath9k_hw_updatetxtriglevel(ah, true);
312 }
313 if (ads->ds_txstatus0 & AR_TxBaStatus) {
314 ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
315 ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
316 ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
317 }
318
319 ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
320 switch (ds->ds_txstat.ts_rateindex) {
321 case 0:
322 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
323 break;
324 case 1:
325 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
326 break;
327 case 2:
328 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
329 break;
330 case 3:
331 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
332 break;
333 }
334
335 ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
336 ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
337 ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
338 ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
339 ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
340 ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
341 ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
342 ds->ds_txstat.evm0 = ads->AR_TxEVM0;
343 ds->ds_txstat.evm1 = ads->AR_TxEVM1;
344 ds->ds_txstat.evm2 = ads->AR_TxEVM2;
345 ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
346 ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
347 ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
348 ds->ds_txstat.ts_antenna = 1;
349
350 return 0;
351}
352
353void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
354 u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
355 u32 keyIx, enum ath9k_key_type keyType, u32 flags)
356{
357 struct ar5416_desc *ads = AR5416DESC(ds);
358 struct ath_hal_5416 *ahp = AH5416(ah);
359
360 txPower += ahp->ah_txPowerIndexOffset;
361 if (txPower > 63)
362 txPower = 63;
363
364 ads->ds_ctl0 = (pktLen & AR_FrameLen)
365 | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
366 | SM(txPower, AR_XmitPower)
367 | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
368 | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
369 | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
370 | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
371
372 ads->ds_ctl1 =
373 (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
374 | SM(type, AR_FrameType)
375 | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
376 | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
377 | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
378
379 ads->ds_ctl6 = SM(keyType, AR_EncrType);
380
381 if (AR_SREV_9285(ah)) {
382 ads->ds_ctl8 = 0;
383 ads->ds_ctl9 = 0;
384 ads->ds_ctl10 = 0;
385 ads->ds_ctl11 = 0;
386 }
387}
388
389void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
390 struct ath_desc *lastds,
391 u32 durUpdateEn, u32 rtsctsRate,
392 u32 rtsctsDuration,
393 struct ath9k_11n_rate_series series[],
394 u32 nseries, u32 flags)
395{
396 struct ar5416_desc *ads = AR5416DESC(ds);
397 struct ar5416_desc *last_ads = AR5416DESC(lastds);
398 u32 ds_ctl0;
399
400 (void) nseries;
401 (void) rtsctsDuration;
402
403 if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
404 ds_ctl0 = ads->ds_ctl0;
405
406 if (flags & ATH9K_TXDESC_RTSENA) {
407 ds_ctl0 &= ~AR_CTSEnable;
408 ds_ctl0 |= AR_RTSEnable;
409 } else {
410 ds_ctl0 &= ~AR_RTSEnable;
411 ds_ctl0 |= AR_CTSEnable;
412 }
413
414 ads->ds_ctl0 = ds_ctl0;
415 } else {
416 ads->ds_ctl0 =
417 (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
418 }
419
420 ads->ds_ctl2 = set11nTries(series, 0)
421 | set11nTries(series, 1)
422 | set11nTries(series, 2)
423 | set11nTries(series, 3)
424 | (durUpdateEn ? AR_DurUpdateEna : 0)
425 | SM(0, AR_BurstDur);
426
427 ads->ds_ctl3 = set11nRate(series, 0)
428 | set11nRate(series, 1)
429 | set11nRate(series, 2)
430 | set11nRate(series, 3);
431
432 ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
433 | set11nPktDurRTSCTS(series, 1);
434
435 ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
436 | set11nPktDurRTSCTS(series, 3);
437
438 ads->ds_ctl7 = set11nRateFlags(series, 0)
439 | set11nRateFlags(series, 1)
440 | set11nRateFlags(series, 2)
441 | set11nRateFlags(series, 3)
442 | SM(rtsctsRate, AR_RTSCTSRate);
443 last_ads->ds_ctl2 = ads->ds_ctl2;
444 last_ads->ds_ctl3 = ads->ds_ctl3;
445}
446
447void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
448 u32 aggrLen)
449{
450 struct ar5416_desc *ads = AR5416DESC(ds);
451
452 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
453 ads->ds_ctl6 &= ~AR_AggrLen;
454 ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
455}
456
457void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
458 u32 numDelims)
459{
460 struct ar5416_desc *ads = AR5416DESC(ds);
461 unsigned int ctl6;
462
463 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
464
465 ctl6 = ads->ds_ctl6;
466 ctl6 &= ~AR_PadDelim;
467 ctl6 |= SM(numDelims, AR_PadDelim);
468 ads->ds_ctl6 = ctl6;
469}
470
471void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
472{
473 struct ar5416_desc *ads = AR5416DESC(ds);
474
475 ads->ds_ctl1 |= AR_IsAggr;
476 ads->ds_ctl1 &= ~AR_MoreAggr;
477 ads->ds_ctl6 &= ~AR_PadDelim;
478}
479
480void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
481{
482 struct ar5416_desc *ads = AR5416DESC(ds);
483
484 ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
485}
486
487void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
488 u32 burstDuration)
489{
490 struct ar5416_desc *ads = AR5416DESC(ds);
491
492 ads->ds_ctl2 &= ~AR_BurstDur;
493 ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
494}
495
496void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
497 u32 vmf)
498{
499 struct ar5416_desc *ads = AR5416DESC(ds);
500
501 if (vmf)
502 ads->ds_ctl0 |= AR_VirtMoreFrag;
503 else
504 ads->ds_ctl0 &= ~AR_VirtMoreFrag;
505}
506
507void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
508{
509 struct ath_hal_5416 *ahp = AH5416(ah);
510
511 *txqs &= ahp->ah_intrTxqs;
512 ahp->ah_intrTxqs &= ~(*txqs);
513}
514
515bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
516 const struct ath9k_tx_queue_info *qinfo)
517{
518 u32 cw;
519 struct ath_hal_5416 *ahp = AH5416(ah);
520 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
521 struct ath9k_tx_queue_info *qi;
522
523 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530524 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530525 return false;
526 }
527
528 qi = &ahp->ah_txq[q];
529 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530530 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530531 return false;
532 }
533
Sujith04bd4632008-11-28 22:18:05 +0530534 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
Sujithf1dc5602008-10-29 10:16:30 +0530535
536 qi->tqi_ver = qinfo->tqi_ver;
537 qi->tqi_subtype = qinfo->tqi_subtype;
538 qi->tqi_qflags = qinfo->tqi_qflags;
539 qi->tqi_priority = qinfo->tqi_priority;
540 if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
541 qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
542 else
543 qi->tqi_aifs = INIT_AIFS;
544 if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
545 cw = min(qinfo->tqi_cwmin, 1024U);
546 qi->tqi_cwmin = 1;
547 while (qi->tqi_cwmin < cw)
548 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
549 } else
550 qi->tqi_cwmin = qinfo->tqi_cwmin;
551 if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
552 cw = min(qinfo->tqi_cwmax, 1024U);
553 qi->tqi_cwmax = 1;
554 while (qi->tqi_cwmax < cw)
555 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
556 } else
557 qi->tqi_cwmax = INIT_CWMAX;
558
559 if (qinfo->tqi_shretry != 0)
560 qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
561 else
562 qi->tqi_shretry = INIT_SH_RETRY;
563 if (qinfo->tqi_lgretry != 0)
564 qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
565 else
566 qi->tqi_lgretry = INIT_LG_RETRY;
567 qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
568 qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
569 qi->tqi_burstTime = qinfo->tqi_burstTime;
570 qi->tqi_readyTime = qinfo->tqi_readyTime;
571
572 switch (qinfo->tqi_subtype) {
573 case ATH9K_WME_UPSD:
574 if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
575 qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
576 break;
577 default:
578 break;
579 }
580
581 return true;
582}
583
584bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
585 struct ath9k_tx_queue_info *qinfo)
586{
587 struct ath_hal_5416 *ahp = AH5416(ah);
588 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
589 struct ath9k_tx_queue_info *qi;
590
591 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530592 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530593 return false;
594 }
595
596 qi = &ahp->ah_txq[q];
597 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530598 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530599 return false;
600 }
601
602 qinfo->tqi_qflags = qi->tqi_qflags;
603 qinfo->tqi_ver = qi->tqi_ver;
604 qinfo->tqi_subtype = qi->tqi_subtype;
605 qinfo->tqi_qflags = qi->tqi_qflags;
606 qinfo->tqi_priority = qi->tqi_priority;
607 qinfo->tqi_aifs = qi->tqi_aifs;
608 qinfo->tqi_cwmin = qi->tqi_cwmin;
609 qinfo->tqi_cwmax = qi->tqi_cwmax;
610 qinfo->tqi_shretry = qi->tqi_shretry;
611 qinfo->tqi_lgretry = qi->tqi_lgretry;
612 qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
613 qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
614 qinfo->tqi_burstTime = qi->tqi_burstTime;
615 qinfo->tqi_readyTime = qi->tqi_readyTime;
616
617 return true;
618}
619
620int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
621 const struct ath9k_tx_queue_info *qinfo)
622{
623 struct ath_hal_5416 *ahp = AH5416(ah);
624 struct ath9k_tx_queue_info *qi;
625 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
626 int q;
627
628 switch (type) {
629 case ATH9K_TX_QUEUE_BEACON:
630 q = pCap->total_queues - 1;
631 break;
632 case ATH9K_TX_QUEUE_CAB:
633 q = pCap->total_queues - 2;
634 break;
635 case ATH9K_TX_QUEUE_PSPOLL:
636 q = 1;
637 break;
638 case ATH9K_TX_QUEUE_UAPSD:
639 q = pCap->total_queues - 3;
640 break;
641 case ATH9K_TX_QUEUE_DATA:
642 for (q = 0; q < pCap->total_queues; q++)
643 if (ahp->ah_txq[q].tqi_type ==
644 ATH9K_TX_QUEUE_INACTIVE)
645 break;
646 if (q == pCap->total_queues) {
647 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530648 "no available tx queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530649 return -1;
650 }
651 break;
652 default:
Sujith04bd4632008-11-28 22:18:05 +0530653 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
Sujithf1dc5602008-10-29 10:16:30 +0530654 return -1;
655 }
656
Sujith04bd4632008-11-28 22:18:05 +0530657 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530658
659 qi = &ahp->ah_txq[q];
660 if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
661 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530662 "tx queue %u already active\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530663 return -1;
664 }
665 memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
666 qi->tqi_type = type;
667 if (qinfo == NULL) {
668 qi->tqi_qflags =
669 TXQ_FLAG_TXOKINT_ENABLE
670 | TXQ_FLAG_TXERRINT_ENABLE
671 | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
672 qi->tqi_aifs = INIT_AIFS;
673 qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
674 qi->tqi_cwmax = INIT_CWMAX;
675 qi->tqi_shretry = INIT_SH_RETRY;
676 qi->tqi_lgretry = INIT_LG_RETRY;
677 qi->tqi_physCompBuf = 0;
678 } else {
679 qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
680 (void) ath9k_hw_set_txq_props(ah, q, qinfo);
681 }
682
683 return q;
684}
685
686bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
687{
688 struct ath_hal_5416 *ahp = AH5416(ah);
689 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
690 struct ath9k_tx_queue_info *qi;
691
692 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530693 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530694 return false;
695 }
696 qi = &ahp->ah_txq[q];
697 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530698 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530699 return false;
700 }
701
Sujith04bd4632008-11-28 22:18:05 +0530702 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530703
704 qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
705 ahp->ah_txOkInterruptMask &= ~(1 << q);
706 ahp->ah_txErrInterruptMask &= ~(1 << q);
707 ahp->ah_txDescInterruptMask &= ~(1 << q);
708 ahp->ah_txEolInterruptMask &= ~(1 << q);
709 ahp->ah_txUrnInterruptMask &= ~(1 << q);
710 ath9k_hw_set_txq_interrupts(ah, qi);
711
712 return true;
713}
714
715bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
716{
717 struct ath_hal_5416 *ahp = AH5416(ah);
718 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
719 struct ath9k_channel *chan = ah->ah_curchan;
720 struct ath9k_tx_queue_info *qi;
721 u32 cwMin, chanCwMin, value;
722
723 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530724 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530725 return false;
726 }
727
728 qi = &ahp->ah_txq[q];
729 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530730 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530731 return true;
732 }
733
Sujith04bd4632008-11-28 22:18:05 +0530734 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530735
736 if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
737 if (chan && IS_CHAN_B(chan))
738 chanCwMin = INIT_CWMIN_11B;
739 else
740 chanCwMin = INIT_CWMIN;
741
742 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
743 } else
744 cwMin = qi->tqi_cwmin;
745
746 REG_WRITE(ah, AR_DLCL_IFS(q),
747 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
748 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
749 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
750
751 REG_WRITE(ah, AR_DRETRY_LIMIT(q),
752 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
753 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
754 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
755
756 REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
757 REG_WRITE(ah, AR_DMISC(q),
758 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
759
760 if (qi->tqi_cbrPeriod) {
761 REG_WRITE(ah, AR_QCBRCFG(q),
762 SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
763 SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
764 REG_WRITE(ah, AR_QMISC(q),
765 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
766 (qi->tqi_cbrOverflowLimit ?
767 AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
768 }
769 if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
770 REG_WRITE(ah, AR_QRDYTIMECFG(q),
771 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
772 AR_Q_RDYTIMECFG_EN);
773 }
774
775 REG_WRITE(ah, AR_DCHNTIME(q),
776 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
777 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
778
779 if (qi->tqi_burstTime
780 && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
781 REG_WRITE(ah, AR_QMISC(q),
782 REG_READ(ah, AR_QMISC(q)) |
783 AR_Q_MISC_RDYTIME_EXP_POLICY);
784
785 }
786
787 if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
788 REG_WRITE(ah, AR_DMISC(q),
789 REG_READ(ah, AR_DMISC(q)) |
790 AR_D_MISC_POST_FR_BKOFF_DIS);
791 }
792 if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
793 REG_WRITE(ah, AR_DMISC(q),
794 REG_READ(ah, AR_DMISC(q)) |
795 AR_D_MISC_FRAG_BKOFF_EN);
796 }
797 switch (qi->tqi_type) {
798 case ATH9K_TX_QUEUE_BEACON:
799 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
800 | AR_Q_MISC_FSP_DBA_GATED
801 | AR_Q_MISC_BEACON_USE
802 | AR_Q_MISC_CBR_INCR_DIS1);
803
804 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
805 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
806 AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
807 | AR_D_MISC_BEACON_USE
808 | AR_D_MISC_POST_FR_BKOFF_DIS);
809 break;
810 case ATH9K_TX_QUEUE_CAB:
811 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
812 | AR_Q_MISC_FSP_DBA_GATED
813 | AR_Q_MISC_CBR_INCR_DIS1
814 | AR_Q_MISC_CBR_INCR_DIS0);
815 value = (qi->tqi_readyTime -
816 (ah->ah_config.sw_beacon_response_time -
817 ah->ah_config.dma_beacon_response_time) -
818 ah->ah_config.additional_swba_backoff) * 1024;
819 REG_WRITE(ah, AR_QRDYTIMECFG(q),
820 value | AR_Q_RDYTIMECFG_EN);
821 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
822 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
823 AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
824 break;
825 case ATH9K_TX_QUEUE_PSPOLL:
826 REG_WRITE(ah, AR_QMISC(q),
827 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
828 break;
829 case ATH9K_TX_QUEUE_UAPSD:
830 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
831 AR_D_MISC_POST_FR_BKOFF_DIS);
832 break;
833 default:
834 break;
835 }
836
837 if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
838 REG_WRITE(ah, AR_DMISC(q),
839 REG_READ(ah, AR_DMISC(q)) |
840 SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
841 AR_D_MISC_ARB_LOCKOUT_CNTRL) |
842 AR_D_MISC_POST_FR_BKOFF_DIS);
843 }
844
845 if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
846 ahp->ah_txOkInterruptMask |= 1 << q;
847 else
848 ahp->ah_txOkInterruptMask &= ~(1 << q);
849 if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
850 ahp->ah_txErrInterruptMask |= 1 << q;
851 else
852 ahp->ah_txErrInterruptMask &= ~(1 << q);
853 if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
854 ahp->ah_txDescInterruptMask |= 1 << q;
855 else
856 ahp->ah_txDescInterruptMask &= ~(1 << q);
857 if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
858 ahp->ah_txEolInterruptMask |= 1 << q;
859 else
860 ahp->ah_txEolInterruptMask &= ~(1 << q);
861 if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
862 ahp->ah_txUrnInterruptMask |= 1 << q;
863 else
864 ahp->ah_txUrnInterruptMask &= ~(1 << q);
865 ath9k_hw_set_txq_interrupts(ah, qi);
866
867 return true;
868}
869
870int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
871 u32 pa, struct ath_desc *nds, u64 tsf)
872{
873 struct ar5416_desc ads;
874 struct ar5416_desc *adsp = AR5416DESC(ds);
875 u32 phyerr;
876
877 if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
878 return -EINPROGRESS;
879
880 ads.u.rx = adsp->u.rx;
881
882 ds->ds_rxstat.rs_status = 0;
883 ds->ds_rxstat.rs_flags = 0;
884
885 ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
886 ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
887
888 ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
889 ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
890 ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
891 ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
892 ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
893 ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
894 ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
895 if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
896 ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
897 else
898 ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
899
900 ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
901 ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
902
903 ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
904 ds->ds_rxstat.rs_moreaggr =
905 (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
906 ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
907 ds->ds_rxstat.rs_flags =
908 (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
909 ds->ds_rxstat.rs_flags |=
910 (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
911
912 if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
913 ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
914 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
915 ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
916 if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
917 ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
918
919 if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
920 if (ads.ds_rxstatus8 & AR_CRCErr)
921 ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
922 else if (ads.ds_rxstatus8 & AR_PHYErr) {
923 ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
924 phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
925 ds->ds_rxstat.rs_phyerr = phyerr;
926 } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
927 ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
928 else if (ads.ds_rxstatus8 & AR_MichaelErr)
929 ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
930 }
931
932 return 0;
933}
934
935bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
936 u32 size, u32 flags)
937{
938 struct ar5416_desc *ads = AR5416DESC(ds);
939 struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
940
941 ads->ds_ctl1 = size & AR_BufLen;
942 if (flags & ATH9K_RXDESC_INTREQ)
943 ads->ds_ctl1 |= AR_RxIntrReq;
944
945 ads->ds_rxstatus8 &= ~AR_RxDone;
946 if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
947 memset(&(ads->u), 0, sizeof(ads->u));
948
949 return true;
950}
951
952bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
953{
954 u32 reg;
955
956 if (set) {
957 REG_SET_BIT(ah, AR_DIAG_SW,
958 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
959
960 if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
961 REG_CLR_BIT(ah, AR_DIAG_SW,
962 (AR_DIAG_RX_DIS |
963 AR_DIAG_RX_ABORT));
964
965 reg = REG_READ(ah, AR_OBS_BUS_1);
966 DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
Sujith04bd4632008-11-28 22:18:05 +0530967 "rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
Sujithf1dc5602008-10-29 10:16:30 +0530968
969 return false;
970 }
971 } else {
972 REG_CLR_BIT(ah, AR_DIAG_SW,
973 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
974 }
975
976 return true;
977}
978
979void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
980{
981 REG_WRITE(ah, AR_RXDP, rxdp);
982}
983
984void ath9k_hw_rxena(struct ath_hal *ah)
985{
986 REG_WRITE(ah, AR_CR, AR_CR_RXE);
987}
988
989void ath9k_hw_startpcureceive(struct ath_hal *ah)
990{
991 REG_CLR_BIT(ah, AR_DIAG_SW,
992 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
993
994 ath9k_enable_mib_counters(ah);
995
996 ath9k_ani_reset(ah);
997}
998
999void ath9k_hw_stoppcurecv(struct ath_hal *ah)
1000{
1001 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
1002
1003 ath9k_hw_disable_mib_counters(ah);
1004}
1005
1006bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
1007{
1008 REG_WRITE(ah, AR_CR, AR_CR_RXD);
1009
1010 if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
1011 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +05301012 "dma failed to stop in 10ms\n"
Sujithf1dc5602008-10-29 10:16:30 +05301013 "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
Sujithf1dc5602008-10-29 10:16:30 +05301014 REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
1015 return false;
1016 } else {
1017 return true;
1018 }
1019}