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