blob: a6c204283ad56d415d90ecaa663961e3441b2230 [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
Sujithcbe61d82009-02-09 13:27:12 +053019static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053020 struct ath9k_tx_queue_info *qi)
21{
Sujithf1dc5602008-10-29 10:16:30 +053022 DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
Sujith04bd4632008-11-28 22:18:05 +053023 "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
Sujith2660b812009-02-09 13:27:26 +053024 ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
25 ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
26 ah->txurn_interrupt_mask);
Sujithf1dc5602008-10-29 10:16:30 +053027
28 REG_WRITE(ah, AR_IMR_S0,
Sujith2660b812009-02-09 13:27:26 +053029 SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
30 | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
Sujithf1dc5602008-10-29 10:16:30 +053031 REG_WRITE(ah, AR_IMR_S1,
Sujith2660b812009-02-09 13:27:26 +053032 SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
33 | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
Sujithf1dc5602008-10-29 10:16:30 +053034 REG_RMW_FIELD(ah, AR_IMR_S2,
Sujith2660b812009-02-09 13:27:26 +053035 AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask);
Sujithf1dc5602008-10-29 10:16:30 +053036}
37
Sujithcbe61d82009-02-09 13:27:12 +053038u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053039{
40 return REG_READ(ah, AR_QTXDP(q));
41}
42
Sujithcbe61d82009-02-09 13:27:12 +053043bool ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
Sujithf1dc5602008-10-29 10:16:30 +053044{
45 REG_WRITE(ah, AR_QTXDP(q), txdp);
46
47 return true;
48}
49
Sujithcbe61d82009-02-09 13:27:12 +053050bool ath9k_hw_txstart(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053051{
Sujith04bd4632008-11-28 22:18:05 +053052 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +053053
54 REG_WRITE(ah, AR_Q_TXE, 1 << q);
55
56 return true;
57}
58
Sujithcbe61d82009-02-09 13:27:12 +053059u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053060{
61 u32 npend;
62
63 npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
64 if (npend == 0) {
65
66 if (REG_READ(ah, AR_Q_TXE) & (1 << q))
67 npend = 1;
68 }
69
70 return npend;
71}
72
Sujithcbe61d82009-02-09 13:27:12 +053073bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
Sujithf1dc5602008-10-29 10:16:30 +053074{
Sujithf1dc5602008-10-29 10:16:30 +053075 u32 txcfg, curLevel, newLevel;
76 enum ath9k_int omask;
77
Sujith2660b812009-02-09 13:27:26 +053078 if (ah->tx_trig_level >= MAX_TX_FIFO_THRESHOLD)
Sujithf1dc5602008-10-29 10:16:30 +053079 return false;
80
Sujith2660b812009-02-09 13:27:26 +053081 omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
Sujithf1dc5602008-10-29 10:16:30 +053082
83 txcfg = REG_READ(ah, AR_TXCFG);
84 curLevel = MS(txcfg, AR_FTRIG);
85 newLevel = curLevel;
86 if (bIncTrigLevel) {
87 if (curLevel < MAX_TX_FIFO_THRESHOLD)
88 newLevel++;
89 } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
90 newLevel--;
91 if (newLevel != curLevel)
92 REG_WRITE(ah, AR_TXCFG,
93 (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
94
95 ath9k_hw_set_interrupts(ah, omask);
96
Sujith2660b812009-02-09 13:27:26 +053097 ah->tx_trig_level = newLevel;
Sujithf1dc5602008-10-29 10:16:30 +053098
99 return newLevel != curLevel;
100}
101
Sujithcbe61d82009-02-09 13:27:12 +0530102bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530103{
Sujith94ff91d2009-01-27 15:06:38 +0530104#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
105#define ATH9K_TIME_QUANTUM 100 /* usec */
106
Sujith2660b812009-02-09 13:27:26 +0530107 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujith94ff91d2009-01-27 15:06:38 +0530108 struct ath9k_tx_queue_info *qi;
Sujithf1dc5602008-10-29 10:16:30 +0530109 u32 tsfLow, j, wait;
Sujith94ff91d2009-01-27 15:06:38 +0530110 u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
111
112 if (q >= pCap->total_queues) {
113 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
114 return false;
115 }
116
Sujith2660b812009-02-09 13:27:26 +0530117 qi = &ah->txq[q];
Sujith94ff91d2009-01-27 15:06:38 +0530118 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
119 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
120 return false;
121 }
Sujithf1dc5602008-10-29 10:16:30 +0530122
123 REG_WRITE(ah, AR_Q_TXD, 1 << q);
124
Sujith94ff91d2009-01-27 15:06:38 +0530125 for (wait = wait_time; wait != 0; wait--) {
Sujithf1dc5602008-10-29 10:16:30 +0530126 if (ath9k_hw_numtxpending(ah, q) == 0)
127 break;
Sujith94ff91d2009-01-27 15:06:38 +0530128 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530129 }
130
131 if (ath9k_hw_numtxpending(ah, q)) {
132 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
133 "%s: Num of pending TX Frames %d on Q %d\n",
134 __func__, ath9k_hw_numtxpending(ah, q), q);
135
136 for (j = 0; j < 2; j++) {
137 tsfLow = REG_READ(ah, AR_TSF_L32);
138 REG_WRITE(ah, AR_QUIET2,
139 SM(10, AR_QUIET2_QUIET_DUR));
140 REG_WRITE(ah, AR_QUIET_PERIOD, 100);
141 REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
142 REG_SET_BIT(ah, AR_TIMER_MODE,
143 AR_QUIET_TIMER_EN);
144
145 if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
146 break;
147
148 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530149 "TSF have moved while trying to set "
150 "quiet time TSF: 0x%08x\n", tsfLow);
Sujithf1dc5602008-10-29 10:16:30 +0530151 }
152
153 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
154
155 udelay(200);
156 REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
157
Sujith94ff91d2009-01-27 15:06:38 +0530158 wait = wait_time;
Sujithf1dc5602008-10-29 10:16:30 +0530159 while (ath9k_hw_numtxpending(ah, q)) {
160 if ((--wait) == 0) {
161 DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
Sujith04bd4632008-11-28 22:18:05 +0530162 "Failed to stop Tx DMA in 100 "
163 "msec after killing last frame\n");
Sujithf1dc5602008-10-29 10:16:30 +0530164 break;
165 }
Sujith94ff91d2009-01-27 15:06:38 +0530166 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530167 }
168
169 REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
170 }
171
172 REG_WRITE(ah, AR_Q_TXD, 0);
Sujithf1dc5602008-10-29 10:16:30 +0530173 return wait != 0;
Sujith94ff91d2009-01-27 15:06:38 +0530174
175#undef ATH9K_TX_STOP_DMA_TIMEOUT
176#undef ATH9K_TIME_QUANTUM
Sujithf1dc5602008-10-29 10:16:30 +0530177}
178
Sujithcbe61d82009-02-09 13:27:12 +0530179bool ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530180 u32 segLen, bool firstSeg,
181 bool lastSeg, const struct ath_desc *ds0)
182{
183 struct ar5416_desc *ads = AR5416DESC(ds);
184
185 if (firstSeg) {
186 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
187 } else if (lastSeg) {
188 ads->ds_ctl0 = 0;
189 ads->ds_ctl1 = segLen;
190 ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
191 ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
192 } else {
193 ads->ds_ctl0 = 0;
194 ads->ds_ctl1 = segLen | AR_TxMore;
195 ads->ds_ctl2 = 0;
196 ads->ds_ctl3 = 0;
197 }
198 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
199 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
200 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
201 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
202 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
203
204 return true;
205}
206
Sujithcbe61d82009-02-09 13:27:12 +0530207void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530208{
209 struct ar5416_desc *ads = AR5416DESC(ds);
210
211 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
212 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
213 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
214 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
215 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
216}
217
Sujithcbe61d82009-02-09 13:27:12 +0530218int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530219{
220 struct ar5416_desc *ads = AR5416DESC(ds);
221
222 if ((ads->ds_txstatus9 & AR_TxDone) == 0)
223 return -EINPROGRESS;
224
225 ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
226 ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
227 ds->ds_txstat.ts_status = 0;
228 ds->ds_txstat.ts_flags = 0;
229
230 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
231 ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
232 if (ads->ds_txstatus1 & AR_Filtered)
233 ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
Sujithdaa9deb2008-11-18 09:10:22 +0530234 if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
Sujithf1dc5602008-10-29 10:16:30 +0530235 ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
Sujithdaa9deb2008-11-18 09:10:22 +0530236 ath9k_hw_updatetxtriglevel(ah, true);
237 }
Sujithf1dc5602008-10-29 10:16:30 +0530238 if (ads->ds_txstatus9 & AR_TxOpExceeded)
239 ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
240 if (ads->ds_txstatus1 & AR_TxTimerExpired)
241 ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
242
243 if (ads->ds_txstatus1 & AR_DescCfgErr)
244 ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
245 if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
246 ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
247 ath9k_hw_updatetxtriglevel(ah, true);
248 }
249 if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
250 ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
251 ath9k_hw_updatetxtriglevel(ah, true);
252 }
253 if (ads->ds_txstatus0 & AR_TxBaStatus) {
254 ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
255 ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
256 ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
257 }
258
259 ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
260 switch (ds->ds_txstat.ts_rateindex) {
261 case 0:
262 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
263 break;
264 case 1:
265 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
266 break;
267 case 2:
268 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
269 break;
270 case 3:
271 ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
272 break;
273 }
274
275 ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
276 ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
277 ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
278 ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
279 ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
280 ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
281 ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
282 ds->ds_txstat.evm0 = ads->AR_TxEVM0;
283 ds->ds_txstat.evm1 = ads->AR_TxEVM1;
284 ds->ds_txstat.evm2 = ads->AR_TxEVM2;
285 ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
286 ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
287 ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
288 ds->ds_txstat.ts_antenna = 1;
289
290 return 0;
291}
292
Sujithcbe61d82009-02-09 13:27:12 +0530293void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530294 u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
295 u32 keyIx, enum ath9k_key_type keyType, u32 flags)
296{
297 struct ar5416_desc *ads = AR5416DESC(ds);
Sujithf1dc5602008-10-29 10:16:30 +0530298
Sujith2660b812009-02-09 13:27:26 +0530299 txPower += ah->txpower_indexoffset;
Sujithf1dc5602008-10-29 10:16:30 +0530300 if (txPower > 63)
301 txPower = 63;
302
303 ads->ds_ctl0 = (pktLen & AR_FrameLen)
304 | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
305 | SM(txPower, AR_XmitPower)
306 | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
307 | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
308 | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
309 | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
310
311 ads->ds_ctl1 =
312 (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
313 | SM(type, AR_FrameType)
314 | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
315 | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
316 | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
317
318 ads->ds_ctl6 = SM(keyType, AR_EncrType);
319
320 if (AR_SREV_9285(ah)) {
321 ads->ds_ctl8 = 0;
322 ads->ds_ctl9 = 0;
323 ads->ds_ctl10 = 0;
324 ads->ds_ctl11 = 0;
325 }
326}
327
Sujithcbe61d82009-02-09 13:27:12 +0530328void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530329 struct ath_desc *lastds,
330 u32 durUpdateEn, u32 rtsctsRate,
331 u32 rtsctsDuration,
332 struct ath9k_11n_rate_series series[],
333 u32 nseries, u32 flags)
334{
335 struct ar5416_desc *ads = AR5416DESC(ds);
336 struct ar5416_desc *last_ads = AR5416DESC(lastds);
337 u32 ds_ctl0;
338
Sujithf1dc5602008-10-29 10:16:30 +0530339 if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
340 ds_ctl0 = ads->ds_ctl0;
341
342 if (flags & ATH9K_TXDESC_RTSENA) {
343 ds_ctl0 &= ~AR_CTSEnable;
344 ds_ctl0 |= AR_RTSEnable;
345 } else {
346 ds_ctl0 &= ~AR_RTSEnable;
347 ds_ctl0 |= AR_CTSEnable;
348 }
349
350 ads->ds_ctl0 = ds_ctl0;
351 } else {
352 ads->ds_ctl0 =
353 (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
354 }
355
356 ads->ds_ctl2 = set11nTries(series, 0)
357 | set11nTries(series, 1)
358 | set11nTries(series, 2)
359 | set11nTries(series, 3)
360 | (durUpdateEn ? AR_DurUpdateEna : 0)
361 | SM(0, AR_BurstDur);
362
363 ads->ds_ctl3 = set11nRate(series, 0)
364 | set11nRate(series, 1)
365 | set11nRate(series, 2)
366 | set11nRate(series, 3);
367
368 ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
369 | set11nPktDurRTSCTS(series, 1);
370
371 ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
372 | set11nPktDurRTSCTS(series, 3);
373
374 ads->ds_ctl7 = set11nRateFlags(series, 0)
375 | set11nRateFlags(series, 1)
376 | set11nRateFlags(series, 2)
377 | set11nRateFlags(series, 3)
378 | SM(rtsctsRate, AR_RTSCTSRate);
379 last_ads->ds_ctl2 = ads->ds_ctl2;
380 last_ads->ds_ctl3 = ads->ds_ctl3;
381}
382
Sujithcbe61d82009-02-09 13:27:12 +0530383void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530384 u32 aggrLen)
385{
386 struct ar5416_desc *ads = AR5416DESC(ds);
387
388 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
389 ads->ds_ctl6 &= ~AR_AggrLen;
390 ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
391}
392
Sujithcbe61d82009-02-09 13:27:12 +0530393void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530394 u32 numDelims)
395{
396 struct ar5416_desc *ads = AR5416DESC(ds);
397 unsigned int ctl6;
398
399 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
400
401 ctl6 = ads->ds_ctl6;
402 ctl6 &= ~AR_PadDelim;
403 ctl6 |= SM(numDelims, AR_PadDelim);
404 ads->ds_ctl6 = ctl6;
405}
406
Sujithcbe61d82009-02-09 13:27:12 +0530407void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530408{
409 struct ar5416_desc *ads = AR5416DESC(ds);
410
411 ads->ds_ctl1 |= AR_IsAggr;
412 ads->ds_ctl1 &= ~AR_MoreAggr;
413 ads->ds_ctl6 &= ~AR_PadDelim;
414}
415
Sujithcbe61d82009-02-09 13:27:12 +0530416void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530417{
418 struct ar5416_desc *ads = AR5416DESC(ds);
419
420 ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
421}
422
Sujithcbe61d82009-02-09 13:27:12 +0530423void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530424 u32 burstDuration)
425{
426 struct ar5416_desc *ads = AR5416DESC(ds);
427
428 ads->ds_ctl2 &= ~AR_BurstDur;
429 ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
430}
431
Sujithcbe61d82009-02-09 13:27:12 +0530432void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530433 u32 vmf)
434{
435 struct ar5416_desc *ads = AR5416DESC(ds);
436
437 if (vmf)
438 ads->ds_ctl0 |= AR_VirtMoreFrag;
439 else
440 ads->ds_ctl0 &= ~AR_VirtMoreFrag;
441}
442
Sujithcbe61d82009-02-09 13:27:12 +0530443void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
Sujithf1dc5602008-10-29 10:16:30 +0530444{
Sujith2660b812009-02-09 13:27:26 +0530445 *txqs &= ah->intr_txqs;
446 ah->intr_txqs &= ~(*txqs);
Sujithf1dc5602008-10-29 10:16:30 +0530447}
448
Sujithcbe61d82009-02-09 13:27:12 +0530449bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530450 const struct ath9k_tx_queue_info *qinfo)
451{
452 u32 cw;
Sujith2660b812009-02-09 13:27:26 +0530453 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530454 struct ath9k_tx_queue_info *qi;
455
456 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530457 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530458 return false;
459 }
460
Sujith2660b812009-02-09 13:27:26 +0530461 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530462 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530463 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530464 return false;
465 }
466
Sujith04bd4632008-11-28 22:18:05 +0530467 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi);
Sujithf1dc5602008-10-29 10:16:30 +0530468
469 qi->tqi_ver = qinfo->tqi_ver;
470 qi->tqi_subtype = qinfo->tqi_subtype;
471 qi->tqi_qflags = qinfo->tqi_qflags;
472 qi->tqi_priority = qinfo->tqi_priority;
473 if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
474 qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
475 else
476 qi->tqi_aifs = INIT_AIFS;
477 if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
478 cw = min(qinfo->tqi_cwmin, 1024U);
479 qi->tqi_cwmin = 1;
480 while (qi->tqi_cwmin < cw)
481 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
482 } else
483 qi->tqi_cwmin = qinfo->tqi_cwmin;
484 if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
485 cw = min(qinfo->tqi_cwmax, 1024U);
486 qi->tqi_cwmax = 1;
487 while (qi->tqi_cwmax < cw)
488 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
489 } else
490 qi->tqi_cwmax = INIT_CWMAX;
491
492 if (qinfo->tqi_shretry != 0)
493 qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
494 else
495 qi->tqi_shretry = INIT_SH_RETRY;
496 if (qinfo->tqi_lgretry != 0)
497 qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
498 else
499 qi->tqi_lgretry = INIT_LG_RETRY;
500 qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
501 qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
502 qi->tqi_burstTime = qinfo->tqi_burstTime;
503 qi->tqi_readyTime = qinfo->tqi_readyTime;
504
505 switch (qinfo->tqi_subtype) {
506 case ATH9K_WME_UPSD:
507 if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
508 qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
509 break;
510 default:
511 break;
512 }
513
514 return true;
515}
516
Sujithcbe61d82009-02-09 13:27:12 +0530517bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530518 struct ath9k_tx_queue_info *qinfo)
519{
Sujith2660b812009-02-09 13:27:26 +0530520 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530521 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
Sujith2660b812009-02-09 13:27:26 +0530528 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530529 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
534 qinfo->tqi_qflags = qi->tqi_qflags;
535 qinfo->tqi_ver = qi->tqi_ver;
536 qinfo->tqi_subtype = qi->tqi_subtype;
537 qinfo->tqi_qflags = qi->tqi_qflags;
538 qinfo->tqi_priority = qi->tqi_priority;
539 qinfo->tqi_aifs = qi->tqi_aifs;
540 qinfo->tqi_cwmin = qi->tqi_cwmin;
541 qinfo->tqi_cwmax = qi->tqi_cwmax;
542 qinfo->tqi_shretry = qi->tqi_shretry;
543 qinfo->tqi_lgretry = qi->tqi_lgretry;
544 qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
545 qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
546 qinfo->tqi_burstTime = qi->tqi_burstTime;
547 qinfo->tqi_readyTime = qi->tqi_readyTime;
548
549 return true;
550}
551
Sujithcbe61d82009-02-09 13:27:12 +0530552int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
Sujithf1dc5602008-10-29 10:16:30 +0530553 const struct ath9k_tx_queue_info *qinfo)
554{
Sujithf1dc5602008-10-29 10:16:30 +0530555 struct ath9k_tx_queue_info *qi;
Sujith2660b812009-02-09 13:27:26 +0530556 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530557 int q;
558
559 switch (type) {
560 case ATH9K_TX_QUEUE_BEACON:
561 q = pCap->total_queues - 1;
562 break;
563 case ATH9K_TX_QUEUE_CAB:
564 q = pCap->total_queues - 2;
565 break;
566 case ATH9K_TX_QUEUE_PSPOLL:
567 q = 1;
568 break;
569 case ATH9K_TX_QUEUE_UAPSD:
570 q = pCap->total_queues - 3;
571 break;
572 case ATH9K_TX_QUEUE_DATA:
573 for (q = 0; q < pCap->total_queues; q++)
Sujith2660b812009-02-09 13:27:26 +0530574 if (ah->txq[q].tqi_type ==
Sujithf1dc5602008-10-29 10:16:30 +0530575 ATH9K_TX_QUEUE_INACTIVE)
576 break;
577 if (q == pCap->total_queues) {
578 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530579 "no available tx queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530580 return -1;
581 }
582 break;
583 default:
Sujith04bd4632008-11-28 22:18:05 +0530584 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type);
Sujithf1dc5602008-10-29 10:16:30 +0530585 return -1;
586 }
587
Sujith04bd4632008-11-28 22:18:05 +0530588 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530589
Sujith2660b812009-02-09 13:27:26 +0530590 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530591 if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
592 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith04bd4632008-11-28 22:18:05 +0530593 "tx queue %u already active\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530594 return -1;
595 }
596 memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
597 qi->tqi_type = type;
598 if (qinfo == NULL) {
599 qi->tqi_qflags =
600 TXQ_FLAG_TXOKINT_ENABLE
601 | TXQ_FLAG_TXERRINT_ENABLE
602 | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
603 qi->tqi_aifs = INIT_AIFS;
604 qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
605 qi->tqi_cwmax = INIT_CWMAX;
606 qi->tqi_shretry = INIT_SH_RETRY;
607 qi->tqi_lgretry = INIT_LG_RETRY;
608 qi->tqi_physCompBuf = 0;
609 } else {
610 qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
611 (void) ath9k_hw_set_txq_props(ah, q, qinfo);
612 }
613
614 return q;
615}
616
Sujithcbe61d82009-02-09 13:27:12 +0530617bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530618{
Sujith2660b812009-02-09 13:27:26 +0530619 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530620 struct ath9k_tx_queue_info *qi;
621
622 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530623 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530624 return false;
625 }
Sujith2660b812009-02-09 13:27:26 +0530626 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530627 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530628 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530629 return false;
630 }
631
Sujith04bd4632008-11-28 22:18:05 +0530632 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530633
634 qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
Sujith2660b812009-02-09 13:27:26 +0530635 ah->txok_interrupt_mask &= ~(1 << q);
636 ah->txerr_interrupt_mask &= ~(1 << q);
637 ah->txdesc_interrupt_mask &= ~(1 << q);
638 ah->txeol_interrupt_mask &= ~(1 << q);
639 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530640 ath9k_hw_set_txq_interrupts(ah, qi);
641
642 return true;
643}
644
Sujithcbe61d82009-02-09 13:27:12 +0530645bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530646{
Sujith2660b812009-02-09 13:27:26 +0530647 struct ath9k_hw_capabilities *pCap = &ah->caps;
648 struct ath9k_channel *chan = ah->curchan;
Sujithf1dc5602008-10-29 10:16:30 +0530649 struct ath9k_tx_queue_info *qi;
650 u32 cwMin, chanCwMin, value;
651
652 if (q >= pCap->total_queues) {
Sujith04bd4632008-11-28 22:18:05 +0530653 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530654 return false;
655 }
656
Sujith2660b812009-02-09 13:27:26 +0530657 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530658 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Sujith04bd4632008-11-28 22:18:05 +0530659 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530660 return true;
661 }
662
Sujith04bd4632008-11-28 22:18:05 +0530663 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530664
665 if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
666 if (chan && IS_CHAN_B(chan))
667 chanCwMin = INIT_CWMIN_11B;
668 else
669 chanCwMin = INIT_CWMIN;
670
671 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
672 } else
673 cwMin = qi->tqi_cwmin;
674
675 REG_WRITE(ah, AR_DLCL_IFS(q),
676 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
677 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
678 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
679
680 REG_WRITE(ah, AR_DRETRY_LIMIT(q),
681 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
682 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
683 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
684
685 REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
686 REG_WRITE(ah, AR_DMISC(q),
687 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
688
689 if (qi->tqi_cbrPeriod) {
690 REG_WRITE(ah, AR_QCBRCFG(q),
691 SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
692 SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
693 REG_WRITE(ah, AR_QMISC(q),
694 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
695 (qi->tqi_cbrOverflowLimit ?
696 AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
697 }
698 if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
699 REG_WRITE(ah, AR_QRDYTIMECFG(q),
700 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
701 AR_Q_RDYTIMECFG_EN);
702 }
703
704 REG_WRITE(ah, AR_DCHNTIME(q),
705 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
706 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
707
708 if (qi->tqi_burstTime
709 && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
710 REG_WRITE(ah, AR_QMISC(q),
711 REG_READ(ah, AR_QMISC(q)) |
712 AR_Q_MISC_RDYTIME_EXP_POLICY);
713
714 }
715
716 if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
717 REG_WRITE(ah, AR_DMISC(q),
718 REG_READ(ah, AR_DMISC(q)) |
719 AR_D_MISC_POST_FR_BKOFF_DIS);
720 }
721 if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
722 REG_WRITE(ah, AR_DMISC(q),
723 REG_READ(ah, AR_DMISC(q)) |
724 AR_D_MISC_FRAG_BKOFF_EN);
725 }
726 switch (qi->tqi_type) {
727 case ATH9K_TX_QUEUE_BEACON:
728 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
729 | AR_Q_MISC_FSP_DBA_GATED
730 | AR_Q_MISC_BEACON_USE
731 | AR_Q_MISC_CBR_INCR_DIS1);
732
733 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
734 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
735 AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
736 | AR_D_MISC_BEACON_USE
737 | AR_D_MISC_POST_FR_BKOFF_DIS);
738 break;
739 case ATH9K_TX_QUEUE_CAB:
740 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
741 | AR_Q_MISC_FSP_DBA_GATED
742 | AR_Q_MISC_CBR_INCR_DIS1
743 | AR_Q_MISC_CBR_INCR_DIS0);
744 value = (qi->tqi_readyTime -
Sujith2660b812009-02-09 13:27:26 +0530745 (ah->config.sw_beacon_response_time -
746 ah->config.dma_beacon_response_time) -
747 ah->config.additional_swba_backoff) * 1024;
Sujithf1dc5602008-10-29 10:16:30 +0530748 REG_WRITE(ah, AR_QRDYTIMECFG(q),
749 value | AR_Q_RDYTIMECFG_EN);
750 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
751 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
752 AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
753 break;
754 case ATH9K_TX_QUEUE_PSPOLL:
755 REG_WRITE(ah, AR_QMISC(q),
756 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
757 break;
758 case ATH9K_TX_QUEUE_UAPSD:
759 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
760 AR_D_MISC_POST_FR_BKOFF_DIS);
761 break;
762 default:
763 break;
764 }
765
766 if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
767 REG_WRITE(ah, AR_DMISC(q),
768 REG_READ(ah, AR_DMISC(q)) |
769 SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
770 AR_D_MISC_ARB_LOCKOUT_CNTRL) |
771 AR_D_MISC_POST_FR_BKOFF_DIS);
772 }
773
774 if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530775 ah->txok_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530776 else
Sujith2660b812009-02-09 13:27:26 +0530777 ah->txok_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530778 if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530779 ah->txerr_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530780 else
Sujith2660b812009-02-09 13:27:26 +0530781 ah->txerr_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530782 if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530783 ah->txdesc_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530784 else
Sujith2660b812009-02-09 13:27:26 +0530785 ah->txdesc_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530786 if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530787 ah->txeol_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530788 else
Sujith2660b812009-02-09 13:27:26 +0530789 ah->txeol_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530790 if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530791 ah->txurn_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530792 else
Sujith2660b812009-02-09 13:27:26 +0530793 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530794 ath9k_hw_set_txq_interrupts(ah, qi);
795
796 return true;
797}
798
Sujithcbe61d82009-02-09 13:27:12 +0530799int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530800 u32 pa, struct ath_desc *nds, u64 tsf)
801{
802 struct ar5416_desc ads;
803 struct ar5416_desc *adsp = AR5416DESC(ds);
804 u32 phyerr;
805
806 if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
807 return -EINPROGRESS;
808
809 ads.u.rx = adsp->u.rx;
810
811 ds->ds_rxstat.rs_status = 0;
812 ds->ds_rxstat.rs_flags = 0;
813
814 ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
815 ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
816
817 ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
818 ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
819 ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
820 ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
821 ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
822 ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
823 ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
824 if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
825 ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
826 else
827 ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
828
829 ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
830 ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
831
832 ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
833 ds->ds_rxstat.rs_moreaggr =
834 (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
835 ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
836 ds->ds_rxstat.rs_flags =
837 (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
838 ds->ds_rxstat.rs_flags |=
839 (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
840
841 if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
842 ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
843 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
844 ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
845 if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
846 ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
847
848 if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
849 if (ads.ds_rxstatus8 & AR_CRCErr)
850 ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
851 else if (ads.ds_rxstatus8 & AR_PHYErr) {
852 ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
853 phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
854 ds->ds_rxstat.rs_phyerr = phyerr;
855 } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
856 ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
857 else if (ads.ds_rxstatus8 & AR_MichaelErr)
858 ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
859 }
860
861 return 0;
862}
863
Sujithcbe61d82009-02-09 13:27:12 +0530864bool ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530865 u32 size, u32 flags)
866{
867 struct ar5416_desc *ads = AR5416DESC(ds);
Sujith2660b812009-02-09 13:27:26 +0530868 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530869
870 ads->ds_ctl1 = size & AR_BufLen;
871 if (flags & ATH9K_RXDESC_INTREQ)
872 ads->ds_ctl1 |= AR_RxIntrReq;
873
874 ads->ds_rxstatus8 &= ~AR_RxDone;
875 if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
876 memset(&(ads->u), 0, sizeof(ads->u));
877
878 return true;
879}
880
Sujithcbe61d82009-02-09 13:27:12 +0530881bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
Sujithf1dc5602008-10-29 10:16:30 +0530882{
883 u32 reg;
884
885 if (set) {
886 REG_SET_BIT(ah, AR_DIAG_SW,
887 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
888
Sujith0caa7b12009-02-16 13:23:20 +0530889 if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
890 0, AH_WAIT_TIMEOUT)) {
Sujithf1dc5602008-10-29 10:16:30 +0530891 REG_CLR_BIT(ah, AR_DIAG_SW,
892 (AR_DIAG_RX_DIS |
893 AR_DIAG_RX_ABORT));
894
895 reg = REG_READ(ah, AR_OBS_BUS_1);
896 DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
Sujith04bd4632008-11-28 22:18:05 +0530897 "rx failed to go idle in 10 ms RXSM=0x%x\n", reg);
Sujithf1dc5602008-10-29 10:16:30 +0530898
899 return false;
900 }
901 } else {
902 REG_CLR_BIT(ah, AR_DIAG_SW,
903 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
904 }
905
906 return true;
907}
908
Sujithcbe61d82009-02-09 13:27:12 +0530909void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
Sujithf1dc5602008-10-29 10:16:30 +0530910{
911 REG_WRITE(ah, AR_RXDP, rxdp);
912}
913
Sujithcbe61d82009-02-09 13:27:12 +0530914void ath9k_hw_rxena(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530915{
916 REG_WRITE(ah, AR_CR, AR_CR_RXE);
917}
918
Sujithcbe61d82009-02-09 13:27:12 +0530919void ath9k_hw_startpcureceive(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530920{
Sujithf1dc5602008-10-29 10:16:30 +0530921 ath9k_enable_mib_counters(ah);
922
923 ath9k_ani_reset(ah);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530924
Senthil Balasubramanian8aa15e12008-12-08 19:43:50 +0530925 REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
Sujithf1dc5602008-10-29 10:16:30 +0530926}
927
Sujithcbe61d82009-02-09 13:27:12 +0530928void ath9k_hw_stoppcurecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530929{
930 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
931
932 ath9k_hw_disable_mib_counters(ah);
933}
934
Sujithcbe61d82009-02-09 13:27:12 +0530935bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530936{
Sujith0caa7b12009-02-16 13:23:20 +0530937#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
938#define AH_RX_TIME_QUANTUM 100 /* usec */
939
940 int i;
941
Sujithf1dc5602008-10-29 10:16:30 +0530942 REG_WRITE(ah, AR_CR, AR_CR_RXD);
943
Sujith0caa7b12009-02-16 13:23:20 +0530944 /* Wait for rx enable bit to go low */
945 for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
946 if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
947 break;
948 udelay(AH_TIME_QUANTUM);
949 }
950
951 if (i == 0) {
Sujithf1dc5602008-10-29 10:16:30 +0530952 DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
Sujith0caa7b12009-02-16 13:23:20 +0530953 "dma failed to stop in %d ms "
954 "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
955 AH_RX_STOP_DMA_TIMEOUT / 1000,
956 REG_READ(ah, AR_CR),
957 REG_READ(ah, AR_DIAG_SW));
Sujithf1dc5602008-10-29 10:16:30 +0530958 return false;
959 } else {
960 return true;
961 }
Sujith0caa7b12009-02-16 13:23:20 +0530962
963#undef AH_RX_TIME_QUANTUM
964#undef AH_RX_STOP_DMA_TIMEOUT
Sujithf1dc5602008-10-29 10:16:30 +0530965}