blob: ae9d54c9c79a97324dc315cc4e8509d37930f8c8 [file] [log] [blame]
Sujithf1dc5602008-10-29 10:16:30 +05301/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 Atheros Communications Inc.
Sujithf1dc5602008-10-29 10:16:30 +05303 *
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
Luis R. Rodriguez990b70a2009-09-13 23:55:05 -070017#include "hw.h"
Sujithf1dc5602008-10-29 10:16:30 +053018
Vasanthakumar Thiagarajancee1f622010-04-15 17:38:26 -040019static void ar9002_hw_rx_enable(struct ath_hw *ah)
20{
21 REG_WRITE(ah, AR_CR, AR_CR_RXE);
22}
23
24void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
25{
26 struct ath_hw_ops *ops = ath9k_hw_ops(ah);
27
28 ops->rx_enable = ar9002_hw_rx_enable;
29}
Sujithcbe61d82009-02-09 13:27:12 +053030static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053031 struct ath9k_tx_queue_info *qi)
32{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070033 ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
34 "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
35 ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
36 ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
37 ah->txurn_interrupt_mask);
Sujithf1dc5602008-10-29 10:16:30 +053038
39 REG_WRITE(ah, AR_IMR_S0,
Sujith2660b812009-02-09 13:27:26 +053040 SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
41 | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
Sujithf1dc5602008-10-29 10:16:30 +053042 REG_WRITE(ah, AR_IMR_S1,
Sujith2660b812009-02-09 13:27:26 +053043 SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
44 | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
Pavel Roskin74bad5c2010-02-23 18:15:27 -050045
46 ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
47 ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
48 REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
Sujithf1dc5602008-10-29 10:16:30 +053049}
50
Sujithcbe61d82009-02-09 13:27:12 +053051u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053052{
53 return REG_READ(ah, AR_QTXDP(q));
54}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040055EXPORT_SYMBOL(ath9k_hw_gettxbuf);
Sujithf1dc5602008-10-29 10:16:30 +053056
Sujith54e4cec2009-08-07 09:45:09 +053057void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
Sujithf1dc5602008-10-29 10:16:30 +053058{
59 REG_WRITE(ah, AR_QTXDP(q), txdp);
Sujithf1dc5602008-10-29 10:16:30 +053060}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040061EXPORT_SYMBOL(ath9k_hw_puttxbuf);
Sujithf1dc5602008-10-29 10:16:30 +053062
Sujith54e4cec2009-08-07 09:45:09 +053063void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053064{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070065 ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
66 "Enable TXE on queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +053067 REG_WRITE(ah, AR_Q_TXE, 1 << q);
Sujithf1dc5602008-10-29 10:16:30 +053068}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040069EXPORT_SYMBOL(ath9k_hw_txstart);
Sujithf1dc5602008-10-29 10:16:30 +053070
Sujithcbe61d82009-02-09 13:27:12 +053071u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053072{
73 u32 npend;
74
75 npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
76 if (npend == 0) {
77
78 if (REG_READ(ah, AR_Q_TXE) & (1 << q))
79 npend = 1;
80 }
81
82 return npend;
83}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040084EXPORT_SYMBOL(ath9k_hw_numtxpending);
Sujithf1dc5602008-10-29 10:16:30 +053085
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -050086/**
87 * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
88 *
89 * @ah: atheros hardware struct
90 * @bIncTrigLevel: whether or not the frame trigger level should be updated
91 *
92 * The frame trigger level specifies the minimum number of bytes,
93 * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
94 * before the PCU will initiate sending the frame on the air. This can
95 * mean we initiate transmit before a full frame is on the PCU TX FIFO.
96 * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
97 * first)
98 *
99 * Caution must be taken to ensure to set the frame trigger level based
100 * on the DMA request size. For example if the DMA request size is set to
101 * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
102 * there need to be enough space in the tx FIFO for the requested transfer
103 * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
104 * the threshold to a value beyond 6, then the transmit will hang.
105 *
106 * Current dual stream devices have a PCU TX FIFO size of 8 KB.
107 * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
108 * there is a hardware issue which forces us to use 2 KB instead so the
109 * frame trigger level must not exceed 2 KB for these chipsets.
110 */
Sujithcbe61d82009-02-09 13:27:12 +0530111bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
Sujithf1dc5602008-10-29 10:16:30 +0530112{
Sujithf1dc5602008-10-29 10:16:30 +0530113 u32 txcfg, curLevel, newLevel;
114 enum ath9k_int omask;
115
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -0500116 if (ah->tx_trig_level >= ah->config.max_txtrig_level)
Sujithf1dc5602008-10-29 10:16:30 +0530117 return false;
118
Pavel Roskin152d5302010-03-31 18:05:37 -0400119 omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
Sujithf1dc5602008-10-29 10:16:30 +0530120
121 txcfg = REG_READ(ah, AR_TXCFG);
122 curLevel = MS(txcfg, AR_FTRIG);
123 newLevel = curLevel;
124 if (bIncTrigLevel) {
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -0500125 if (curLevel < ah->config.max_txtrig_level)
Sujithf1dc5602008-10-29 10:16:30 +0530126 newLevel++;
127 } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
128 newLevel--;
129 if (newLevel != curLevel)
130 REG_WRITE(ah, AR_TXCFG,
131 (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
132
133 ath9k_hw_set_interrupts(ah, omask);
134
Sujith2660b812009-02-09 13:27:26 +0530135 ah->tx_trig_level = newLevel;
Sujithf1dc5602008-10-29 10:16:30 +0530136
137 return newLevel != curLevel;
138}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400139EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
Sujithf1dc5602008-10-29 10:16:30 +0530140
Sujithcbe61d82009-02-09 13:27:12 +0530141bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530142{
Sujith94ff91d2009-01-27 15:06:38 +0530143#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
144#define ATH9K_TIME_QUANTUM 100 /* usec */
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700145 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530146 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujith94ff91d2009-01-27 15:06:38 +0530147 struct ath9k_tx_queue_info *qi;
Sujithf1dc5602008-10-29 10:16:30 +0530148 u32 tsfLow, j, wait;
Sujith94ff91d2009-01-27 15:06:38 +0530149 u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
150
151 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700152 ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
153 "invalid queue: %u\n", q);
Sujith94ff91d2009-01-27 15:06:38 +0530154 return false;
155 }
156
Sujith2660b812009-02-09 13:27:26 +0530157 qi = &ah->txq[q];
Sujith94ff91d2009-01-27 15:06:38 +0530158 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700159 ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
160 "inactive queue: %u\n", q);
Sujith94ff91d2009-01-27 15:06:38 +0530161 return false;
162 }
Sujithf1dc5602008-10-29 10:16:30 +0530163
164 REG_WRITE(ah, AR_Q_TXD, 1 << q);
165
Sujith94ff91d2009-01-27 15:06:38 +0530166 for (wait = wait_time; wait != 0; wait--) {
Sujithf1dc5602008-10-29 10:16:30 +0530167 if (ath9k_hw_numtxpending(ah, q) == 0)
168 break;
Sujith94ff91d2009-01-27 15:06:38 +0530169 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530170 }
171
172 if (ath9k_hw_numtxpending(ah, q)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700173 ath_print(common, ATH_DBG_QUEUE,
174 "%s: Num of pending TX Frames %d on Q %d\n",
175 __func__, ath9k_hw_numtxpending(ah, q), q);
Sujithf1dc5602008-10-29 10:16:30 +0530176
177 for (j = 0; j < 2; j++) {
178 tsfLow = REG_READ(ah, AR_TSF_L32);
179 REG_WRITE(ah, AR_QUIET2,
180 SM(10, AR_QUIET2_QUIET_DUR));
181 REG_WRITE(ah, AR_QUIET_PERIOD, 100);
182 REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
183 REG_SET_BIT(ah, AR_TIMER_MODE,
184 AR_QUIET_TIMER_EN);
185
186 if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
187 break;
188
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700189 ath_print(common, ATH_DBG_QUEUE,
190 "TSF has moved while trying to set "
191 "quiet time TSF: 0x%08x\n", tsfLow);
Sujithf1dc5602008-10-29 10:16:30 +0530192 }
193
194 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
195
196 udelay(200);
197 REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
198
Sujith94ff91d2009-01-27 15:06:38 +0530199 wait = wait_time;
Sujithf1dc5602008-10-29 10:16:30 +0530200 while (ath9k_hw_numtxpending(ah, q)) {
201 if ((--wait) == 0) {
Sujithe8009e92009-12-14 14:57:08 +0530202 ath_print(common, ATH_DBG_FATAL,
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700203 "Failed to stop TX DMA in 100 "
204 "msec after killing last frame\n");
Sujithf1dc5602008-10-29 10:16:30 +0530205 break;
206 }
Sujith94ff91d2009-01-27 15:06:38 +0530207 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530208 }
209
210 REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
211 }
212
213 REG_WRITE(ah, AR_Q_TXD, 0);
Sujithf1dc5602008-10-29 10:16:30 +0530214 return wait != 0;
Sujith94ff91d2009-01-27 15:06:38 +0530215
216#undef ATH9K_TX_STOP_DMA_TIMEOUT
217#undef ATH9K_TIME_QUANTUM
Sujithf1dc5602008-10-29 10:16:30 +0530218}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400219EXPORT_SYMBOL(ath9k_hw_stoptxdma);
Sujithf1dc5602008-10-29 10:16:30 +0530220
Sujith54e4cec2009-08-07 09:45:09 +0530221void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530222 u32 segLen, bool firstSeg,
223 bool lastSeg, const struct ath_desc *ds0)
224{
225 struct ar5416_desc *ads = AR5416DESC(ds);
226
227 if (firstSeg) {
228 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
229 } else if (lastSeg) {
230 ads->ds_ctl0 = 0;
231 ads->ds_ctl1 = segLen;
232 ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
233 ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
234 } else {
235 ads->ds_ctl0 = 0;
236 ads->ds_ctl1 = segLen | AR_TxMore;
237 ads->ds_ctl2 = 0;
238 ads->ds_ctl3 = 0;
239 }
240 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
241 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
242 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
243 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
244 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530245}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400246EXPORT_SYMBOL(ath9k_hw_filltxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530247
Sujithcbe61d82009-02-09 13:27:12 +0530248void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530249{
250 struct ar5416_desc *ads = AR5416DESC(ds);
251
252 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
253 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
254 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
255 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
256 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
257}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400258EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530259
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700260int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds,
261 struct ath_tx_status *ts)
Sujithf1dc5602008-10-29 10:16:30 +0530262{
263 struct ar5416_desc *ads = AR5416DESC(ds);
264
265 if ((ads->ds_txstatus9 & AR_TxDone) == 0)
266 return -EINPROGRESS;
267
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700268 ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
269 ts->ts_tstamp = ads->AR_SendTimestamp;
270 ts->ts_status = 0;
271 ts->ts_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530272
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500273 if (ads->ds_txstatus1 & AR_FrmXmitOK)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700274 ts->ts_status |= ATH9K_TX_ACKED;
Sujithf1dc5602008-10-29 10:16:30 +0530275 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700276 ts->ts_status |= ATH9K_TXERR_XRETRY;
Sujithf1dc5602008-10-29 10:16:30 +0530277 if (ads->ds_txstatus1 & AR_Filtered)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700278 ts->ts_status |= ATH9K_TXERR_FILT;
Sujithdaa9deb2008-11-18 09:10:22 +0530279 if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700280 ts->ts_status |= ATH9K_TXERR_FIFO;
Sujithdaa9deb2008-11-18 09:10:22 +0530281 ath9k_hw_updatetxtriglevel(ah, true);
282 }
Sujithf1dc5602008-10-29 10:16:30 +0530283 if (ads->ds_txstatus9 & AR_TxOpExceeded)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700284 ts->ts_status |= ATH9K_TXERR_XTXOP;
Sujithf1dc5602008-10-29 10:16:30 +0530285 if (ads->ds_txstatus1 & AR_TxTimerExpired)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700286 ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
Sujithf1dc5602008-10-29 10:16:30 +0530287
288 if (ads->ds_txstatus1 & AR_DescCfgErr)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700289 ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
Sujithf1dc5602008-10-29 10:16:30 +0530290 if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700291 ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530292 ath9k_hw_updatetxtriglevel(ah, true);
293 }
294 if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700295 ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530296 ath9k_hw_updatetxtriglevel(ah, true);
297 }
298 if (ads->ds_txstatus0 & AR_TxBaStatus) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700299 ts->ts_flags |= ATH9K_TX_BA;
300 ts->ba_low = ads->AR_BaBitmapLow;
301 ts->ba_high = ads->AR_BaBitmapHigh;
Sujithf1dc5602008-10-29 10:16:30 +0530302 }
303
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700304 ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
305 switch (ts->ts_rateindex) {
Sujithf1dc5602008-10-29 10:16:30 +0530306 case 0:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700307 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
Sujithf1dc5602008-10-29 10:16:30 +0530308 break;
309 case 1:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700310 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
Sujithf1dc5602008-10-29 10:16:30 +0530311 break;
312 case 2:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700313 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
Sujithf1dc5602008-10-29 10:16:30 +0530314 break;
315 case 3:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700316 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
Sujithf1dc5602008-10-29 10:16:30 +0530317 break;
318 }
319
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700320 ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
321 ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
322 ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
323 ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
324 ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
325 ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
326 ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
327 ts->evm0 = ads->AR_TxEVM0;
328 ts->evm1 = ads->AR_TxEVM1;
329 ts->evm2 = ads->AR_TxEVM2;
330 ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
331 ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
332 ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
333 ts->ts_antenna = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530334
335 return 0;
336}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400337EXPORT_SYMBOL(ath9k_hw_txprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530338
Sujithcbe61d82009-02-09 13:27:12 +0530339void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530340 u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
341 u32 keyIx, enum ath9k_key_type keyType, u32 flags)
342{
343 struct ar5416_desc *ads = AR5416DESC(ds);
Sujithf1dc5602008-10-29 10:16:30 +0530344
Sujith2660b812009-02-09 13:27:26 +0530345 txPower += ah->txpower_indexoffset;
Sujithf1dc5602008-10-29 10:16:30 +0530346 if (txPower > 63)
347 txPower = 63;
348
349 ads->ds_ctl0 = (pktLen & AR_FrameLen)
350 | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
351 | SM(txPower, AR_XmitPower)
352 | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
353 | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
354 | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
355 | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
356
357 ads->ds_ctl1 =
358 (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
359 | SM(type, AR_FrameType)
360 | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
361 | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
362 | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
363
364 ads->ds_ctl6 = SM(keyType, AR_EncrType);
365
Sujithe492d7c2010-03-17 14:25:17 +0530366 if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
Sujithf1dc5602008-10-29 10:16:30 +0530367 ads->ds_ctl8 = 0;
368 ads->ds_ctl9 = 0;
369 ads->ds_ctl10 = 0;
370 ads->ds_ctl11 = 0;
371 }
372}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400373EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530374
Sujithcbe61d82009-02-09 13:27:12 +0530375void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530376 struct ath_desc *lastds,
377 u32 durUpdateEn, u32 rtsctsRate,
378 u32 rtsctsDuration,
379 struct ath9k_11n_rate_series series[],
380 u32 nseries, u32 flags)
381{
382 struct ar5416_desc *ads = AR5416DESC(ds);
383 struct ar5416_desc *last_ads = AR5416DESC(lastds);
384 u32 ds_ctl0;
385
Sujithf1dc5602008-10-29 10:16:30 +0530386 if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
387 ds_ctl0 = ads->ds_ctl0;
388
389 if (flags & ATH9K_TXDESC_RTSENA) {
390 ds_ctl0 &= ~AR_CTSEnable;
391 ds_ctl0 |= AR_RTSEnable;
392 } else {
393 ds_ctl0 &= ~AR_RTSEnable;
394 ds_ctl0 |= AR_CTSEnable;
395 }
396
397 ads->ds_ctl0 = ds_ctl0;
398 } else {
399 ads->ds_ctl0 =
400 (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
401 }
402
403 ads->ds_ctl2 = set11nTries(series, 0)
404 | set11nTries(series, 1)
405 | set11nTries(series, 2)
406 | set11nTries(series, 3)
407 | (durUpdateEn ? AR_DurUpdateEna : 0)
408 | SM(0, AR_BurstDur);
409
410 ads->ds_ctl3 = set11nRate(series, 0)
411 | set11nRate(series, 1)
412 | set11nRate(series, 2)
413 | set11nRate(series, 3);
414
415 ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
416 | set11nPktDurRTSCTS(series, 1);
417
418 ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
419 | set11nPktDurRTSCTS(series, 3);
420
421 ads->ds_ctl7 = set11nRateFlags(series, 0)
422 | set11nRateFlags(series, 1)
423 | set11nRateFlags(series, 2)
424 | set11nRateFlags(series, 3)
425 | SM(rtsctsRate, AR_RTSCTSRate);
426 last_ads->ds_ctl2 = ads->ds_ctl2;
427 last_ads->ds_ctl3 = ads->ds_ctl3;
428}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400429EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
Sujithf1dc5602008-10-29 10:16:30 +0530430
Sujithcbe61d82009-02-09 13:27:12 +0530431void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530432 u32 aggrLen)
433{
434 struct ar5416_desc *ads = AR5416DESC(ds);
435
436 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
437 ads->ds_ctl6 &= ~AR_AggrLen;
438 ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
439}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400440EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
Sujithf1dc5602008-10-29 10:16:30 +0530441
Sujithcbe61d82009-02-09 13:27:12 +0530442void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530443 u32 numDelims)
444{
445 struct ar5416_desc *ads = AR5416DESC(ds);
446 unsigned int ctl6;
447
448 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
449
450 ctl6 = ads->ds_ctl6;
451 ctl6 &= ~AR_PadDelim;
452 ctl6 |= SM(numDelims, AR_PadDelim);
453 ads->ds_ctl6 = ctl6;
454}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400455EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
Sujithf1dc5602008-10-29 10:16:30 +0530456
Sujithcbe61d82009-02-09 13:27:12 +0530457void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530458{
459 struct ar5416_desc *ads = AR5416DESC(ds);
460
461 ads->ds_ctl1 |= AR_IsAggr;
462 ads->ds_ctl1 &= ~AR_MoreAggr;
463 ads->ds_ctl6 &= ~AR_PadDelim;
464}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400465EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
Sujithf1dc5602008-10-29 10:16:30 +0530466
Sujithcbe61d82009-02-09 13:27:12 +0530467void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530468{
469 struct ar5416_desc *ads = AR5416DESC(ds);
470
471 ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
472}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400473EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
Sujithf1dc5602008-10-29 10:16:30 +0530474
Sujithcbe61d82009-02-09 13:27:12 +0530475void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530476 u32 burstDuration)
477{
478 struct ar5416_desc *ads = AR5416DESC(ds);
479
480 ads->ds_ctl2 &= ~AR_BurstDur;
481 ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
482}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400483EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
Sujithf1dc5602008-10-29 10:16:30 +0530484
Sujithcbe61d82009-02-09 13:27:12 +0530485void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530486 u32 vmf)
487{
488 struct ar5416_desc *ads = AR5416DESC(ds);
489
490 if (vmf)
491 ads->ds_ctl0 |= AR_VirtMoreFrag;
492 else
493 ads->ds_ctl0 &= ~AR_VirtMoreFrag;
494}
495
Sujithcbe61d82009-02-09 13:27:12 +0530496void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
Sujithf1dc5602008-10-29 10:16:30 +0530497{
Sujith2660b812009-02-09 13:27:26 +0530498 *txqs &= ah->intr_txqs;
499 ah->intr_txqs &= ~(*txqs);
Sujithf1dc5602008-10-29 10:16:30 +0530500}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400501EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
Sujithf1dc5602008-10-29 10:16:30 +0530502
Sujithcbe61d82009-02-09 13:27:12 +0530503bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530504 const struct ath9k_tx_queue_info *qinfo)
505{
506 u32 cw;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700507 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530508 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530509 struct ath9k_tx_queue_info *qi;
510
511 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700512 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
513 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530514 return false;
515 }
516
Sujith2660b812009-02-09 13:27:26 +0530517 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530518 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700519 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
520 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530521 return false;
522 }
523
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700524 ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530525
526 qi->tqi_ver = qinfo->tqi_ver;
527 qi->tqi_subtype = qinfo->tqi_subtype;
528 qi->tqi_qflags = qinfo->tqi_qflags;
529 qi->tqi_priority = qinfo->tqi_priority;
530 if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
531 qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
532 else
533 qi->tqi_aifs = INIT_AIFS;
534 if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
535 cw = min(qinfo->tqi_cwmin, 1024U);
536 qi->tqi_cwmin = 1;
537 while (qi->tqi_cwmin < cw)
538 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
539 } else
540 qi->tqi_cwmin = qinfo->tqi_cwmin;
541 if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
542 cw = min(qinfo->tqi_cwmax, 1024U);
543 qi->tqi_cwmax = 1;
544 while (qi->tqi_cwmax < cw)
545 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
546 } else
547 qi->tqi_cwmax = INIT_CWMAX;
548
549 if (qinfo->tqi_shretry != 0)
550 qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
551 else
552 qi->tqi_shretry = INIT_SH_RETRY;
553 if (qinfo->tqi_lgretry != 0)
554 qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
555 else
556 qi->tqi_lgretry = INIT_LG_RETRY;
557 qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
558 qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
559 qi->tqi_burstTime = qinfo->tqi_burstTime;
560 qi->tqi_readyTime = qinfo->tqi_readyTime;
561
562 switch (qinfo->tqi_subtype) {
563 case ATH9K_WME_UPSD:
564 if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
565 qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
566 break;
567 default:
568 break;
569 }
570
571 return true;
572}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400573EXPORT_SYMBOL(ath9k_hw_set_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530574
Sujithcbe61d82009-02-09 13:27:12 +0530575bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530576 struct ath9k_tx_queue_info *qinfo)
577{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700578 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530579 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530580 struct ath9k_tx_queue_info *qi;
581
582 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700583 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
584 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530585 return false;
586 }
587
Sujith2660b812009-02-09 13:27:26 +0530588 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530589 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700590 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
591 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530592 return false;
593 }
594
595 qinfo->tqi_qflags = qi->tqi_qflags;
596 qinfo->tqi_ver = qi->tqi_ver;
597 qinfo->tqi_subtype = qi->tqi_subtype;
598 qinfo->tqi_qflags = qi->tqi_qflags;
599 qinfo->tqi_priority = qi->tqi_priority;
600 qinfo->tqi_aifs = qi->tqi_aifs;
601 qinfo->tqi_cwmin = qi->tqi_cwmin;
602 qinfo->tqi_cwmax = qi->tqi_cwmax;
603 qinfo->tqi_shretry = qi->tqi_shretry;
604 qinfo->tqi_lgretry = qi->tqi_lgretry;
605 qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
606 qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
607 qinfo->tqi_burstTime = qi->tqi_burstTime;
608 qinfo->tqi_readyTime = qi->tqi_readyTime;
609
610 return true;
611}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400612EXPORT_SYMBOL(ath9k_hw_get_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530613
Sujithcbe61d82009-02-09 13:27:12 +0530614int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
Sujithf1dc5602008-10-29 10:16:30 +0530615 const struct ath9k_tx_queue_info *qinfo)
616{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700617 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530618 struct ath9k_tx_queue_info *qi;
Sujith2660b812009-02-09 13:27:26 +0530619 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530620 int q;
621
622 switch (type) {
623 case ATH9K_TX_QUEUE_BEACON:
624 q = pCap->total_queues - 1;
625 break;
626 case ATH9K_TX_QUEUE_CAB:
627 q = pCap->total_queues - 2;
628 break;
629 case ATH9K_TX_QUEUE_PSPOLL:
630 q = 1;
631 break;
632 case ATH9K_TX_QUEUE_UAPSD:
633 q = pCap->total_queues - 3;
634 break;
635 case ATH9K_TX_QUEUE_DATA:
636 for (q = 0; q < pCap->total_queues; q++)
Sujith2660b812009-02-09 13:27:26 +0530637 if (ah->txq[q].tqi_type ==
Sujithf1dc5602008-10-29 10:16:30 +0530638 ATH9K_TX_QUEUE_INACTIVE)
639 break;
640 if (q == pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700641 ath_print(common, ATH_DBG_FATAL,
642 "No available TX queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530643 return -1;
644 }
645 break;
646 default:
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700647 ath_print(common, ATH_DBG_FATAL,
648 "Invalid TX queue type: %u\n", type);
Sujithf1dc5602008-10-29 10:16:30 +0530649 return -1;
650 }
651
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700652 ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530653
Sujith2660b812009-02-09 13:27:26 +0530654 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530655 if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700656 ath_print(common, ATH_DBG_FATAL,
657 "TX queue: %u already active\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530658 return -1;
659 }
660 memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
661 qi->tqi_type = type;
662 if (qinfo == NULL) {
663 qi->tqi_qflags =
664 TXQ_FLAG_TXOKINT_ENABLE
665 | TXQ_FLAG_TXERRINT_ENABLE
666 | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
667 qi->tqi_aifs = INIT_AIFS;
668 qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
669 qi->tqi_cwmax = INIT_CWMAX;
670 qi->tqi_shretry = INIT_SH_RETRY;
671 qi->tqi_lgretry = INIT_LG_RETRY;
672 qi->tqi_physCompBuf = 0;
673 } else {
674 qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
675 (void) ath9k_hw_set_txq_props(ah, q, qinfo);
676 }
677
678 return q;
679}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400680EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530681
Sujithcbe61d82009-02-09 13:27:12 +0530682bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530683{
Sujith2660b812009-02-09 13:27:26 +0530684 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700685 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530686 struct ath9k_tx_queue_info *qi;
687
688 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700689 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
690 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530691 return false;
692 }
Sujith2660b812009-02-09 13:27:26 +0530693 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530694 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700695 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
696 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530697 return false;
698 }
699
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700700 ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530701
702 qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
Sujith2660b812009-02-09 13:27:26 +0530703 ah->txok_interrupt_mask &= ~(1 << q);
704 ah->txerr_interrupt_mask &= ~(1 << q);
705 ah->txdesc_interrupt_mask &= ~(1 << q);
706 ah->txeol_interrupt_mask &= ~(1 << q);
707 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530708 ath9k_hw_set_txq_interrupts(ah, qi);
709
710 return true;
711}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400712EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530713
Sujithcbe61d82009-02-09 13:27:12 +0530714bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530715{
Sujith2660b812009-02-09 13:27:26 +0530716 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700717 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530718 struct ath9k_channel *chan = ah->curchan;
Sujithf1dc5602008-10-29 10:16:30 +0530719 struct ath9k_tx_queue_info *qi;
720 u32 cwMin, chanCwMin, value;
721
722 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700723 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
724 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530725 return false;
726 }
727
Sujith2660b812009-02-09 13:27:26 +0530728 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530729 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700730 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
731 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530732 return true;
733 }
734
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700735 ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530736
737 if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
738 if (chan && IS_CHAN_B(chan))
739 chanCwMin = INIT_CWMIN_11B;
740 else
741 chanCwMin = INIT_CWMIN;
742
743 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
744 } else
745 cwMin = qi->tqi_cwmin;
746
747 REG_WRITE(ah, AR_DLCL_IFS(q),
748 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
749 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
750 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
751
752 REG_WRITE(ah, AR_DRETRY_LIMIT(q),
753 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
754 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
755 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
756
757 REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
758 REG_WRITE(ah, AR_DMISC(q),
759 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
760
761 if (qi->tqi_cbrPeriod) {
762 REG_WRITE(ah, AR_QCBRCFG(q),
763 SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
764 SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
765 REG_WRITE(ah, AR_QMISC(q),
766 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
767 (qi->tqi_cbrOverflowLimit ?
768 AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
769 }
770 if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
771 REG_WRITE(ah, AR_QRDYTIMECFG(q),
772 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
773 AR_Q_RDYTIMECFG_EN);
774 }
775
776 REG_WRITE(ah, AR_DCHNTIME(q),
777 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
778 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
779
780 if (qi->tqi_burstTime
781 && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
782 REG_WRITE(ah, AR_QMISC(q),
783 REG_READ(ah, AR_QMISC(q)) |
784 AR_Q_MISC_RDYTIME_EXP_POLICY);
785
786 }
787
788 if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
789 REG_WRITE(ah, AR_DMISC(q),
790 REG_READ(ah, AR_DMISC(q)) |
791 AR_D_MISC_POST_FR_BKOFF_DIS);
792 }
793 if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
794 REG_WRITE(ah, AR_DMISC(q),
795 REG_READ(ah, AR_DMISC(q)) |
796 AR_D_MISC_FRAG_BKOFF_EN);
797 }
798 switch (qi->tqi_type) {
799 case ATH9K_TX_QUEUE_BEACON:
800 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
801 | AR_Q_MISC_FSP_DBA_GATED
802 | AR_Q_MISC_BEACON_USE
803 | AR_Q_MISC_CBR_INCR_DIS1);
804
805 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
806 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
807 AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
808 | AR_D_MISC_BEACON_USE
809 | AR_D_MISC_POST_FR_BKOFF_DIS);
810 break;
811 case ATH9K_TX_QUEUE_CAB:
812 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
813 | AR_Q_MISC_FSP_DBA_GATED
814 | AR_Q_MISC_CBR_INCR_DIS1
815 | AR_Q_MISC_CBR_INCR_DIS0);
816 value = (qi->tqi_readyTime -
Sujith2660b812009-02-09 13:27:26 +0530817 (ah->config.sw_beacon_response_time -
818 ah->config.dma_beacon_response_time) -
819 ah->config.additional_swba_backoff) * 1024;
Sujithf1dc5602008-10-29 10:16:30 +0530820 REG_WRITE(ah, AR_QRDYTIMECFG(q),
821 value | AR_Q_RDYTIMECFG_EN);
822 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
823 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
824 AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
825 break;
826 case ATH9K_TX_QUEUE_PSPOLL:
827 REG_WRITE(ah, AR_QMISC(q),
828 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
829 break;
830 case ATH9K_TX_QUEUE_UAPSD:
831 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
832 AR_D_MISC_POST_FR_BKOFF_DIS);
833 break;
834 default:
835 break;
836 }
837
838 if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
839 REG_WRITE(ah, AR_DMISC(q),
840 REG_READ(ah, AR_DMISC(q)) |
841 SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
842 AR_D_MISC_ARB_LOCKOUT_CNTRL) |
843 AR_D_MISC_POST_FR_BKOFF_DIS);
844 }
845
846 if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530847 ah->txok_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530848 else
Sujith2660b812009-02-09 13:27:26 +0530849 ah->txok_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530850 if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530851 ah->txerr_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530852 else
Sujith2660b812009-02-09 13:27:26 +0530853 ah->txerr_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530854 if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530855 ah->txdesc_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530856 else
Sujith2660b812009-02-09 13:27:26 +0530857 ah->txdesc_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530858 if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530859 ah->txeol_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530860 else
Sujith2660b812009-02-09 13:27:26 +0530861 ah->txeol_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530862 if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530863 ah->txurn_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530864 else
Sujith2660b812009-02-09 13:27:26 +0530865 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530866 ath9k_hw_set_txq_interrupts(ah, qi);
867
868 return true;
869}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400870EXPORT_SYMBOL(ath9k_hw_resettxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530871
Sujithcbe61d82009-02-09 13:27:12 +0530872int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700873 struct ath_rx_status *rs, u64 tsf)
Sujithf1dc5602008-10-29 10:16:30 +0530874{
875 struct ar5416_desc ads;
876 struct ar5416_desc *adsp = AR5416DESC(ds);
877 u32 phyerr;
878
879 if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
880 return -EINPROGRESS;
881
882 ads.u.rx = adsp->u.rx;
883
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700884 rs->rs_status = 0;
885 rs->rs_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530886
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700887 rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
888 rs->rs_tstamp = ads.AR_RcvTimestamp;
Sujithf1dc5602008-10-29 10:16:30 +0530889
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400890 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700891 rs->rs_rssi = ATH9K_RSSI_BAD;
892 rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
893 rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
894 rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
895 rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
896 rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
897 rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400898 } else {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700899 rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
900 rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400901 AR_RxRSSIAnt00);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700902 rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400903 AR_RxRSSIAnt01);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700904 rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400905 AR_RxRSSIAnt02);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700906 rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400907 AR_RxRSSIAnt10);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700908 rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400909 AR_RxRSSIAnt11);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700910 rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400911 AR_RxRSSIAnt12);
912 }
Sujithf1dc5602008-10-29 10:16:30 +0530913 if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700914 rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
Sujithf1dc5602008-10-29 10:16:30 +0530915 else
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700916 rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
Sujithf1dc5602008-10-29 10:16:30 +0530917
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700918 rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
919 rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
Sujithf1dc5602008-10-29 10:16:30 +0530920
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700921 rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
922 rs->rs_moreaggr =
Sujithf1dc5602008-10-29 10:16:30 +0530923 (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700924 rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
925 rs->rs_flags =
Sujithf1dc5602008-10-29 10:16:30 +0530926 (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700927 rs->rs_flags |=
Sujithf1dc5602008-10-29 10:16:30 +0530928 (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
929
930 if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700931 rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
Sujithf1dc5602008-10-29 10:16:30 +0530932 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700933 rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
Sujithf1dc5602008-10-29 10:16:30 +0530934 if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700935 rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
Sujithf1dc5602008-10-29 10:16:30 +0530936
937 if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
938 if (ads.ds_rxstatus8 & AR_CRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700939 rs->rs_status |= ATH9K_RXERR_CRC;
Sujithf1dc5602008-10-29 10:16:30 +0530940 else if (ads.ds_rxstatus8 & AR_PHYErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700941 rs->rs_status |= ATH9K_RXERR_PHY;
Sujithf1dc5602008-10-29 10:16:30 +0530942 phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700943 rs->rs_phyerr = phyerr;
Sujithf1dc5602008-10-29 10:16:30 +0530944 } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700945 rs->rs_status |= ATH9K_RXERR_DECRYPT;
Sujithf1dc5602008-10-29 10:16:30 +0530946 else if (ads.ds_rxstatus8 & AR_MichaelErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700947 rs->rs_status |= ATH9K_RXERR_MIC;
Sujithf1dc5602008-10-29 10:16:30 +0530948 }
949
950 return 0;
951}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400952EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530953
Sujith54e4cec2009-08-07 09:45:09 +0530954void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530955 u32 size, u32 flags)
956{
957 struct ar5416_desc *ads = AR5416DESC(ds);
Sujith2660b812009-02-09 13:27:26 +0530958 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530959
960 ads->ds_ctl1 = size & AR_BufLen;
961 if (flags & ATH9K_RXDESC_INTREQ)
962 ads->ds_ctl1 |= AR_RxIntrReq;
963
964 ads->ds_rxstatus8 &= ~AR_RxDone;
965 if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
966 memset(&(ads->u), 0, sizeof(ads->u));
Sujithf1dc5602008-10-29 10:16:30 +0530967}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400968EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530969
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500970/*
971 * This can stop or re-enables RX.
972 *
973 * If bool is set this will kill any frame which is currently being
974 * transferred between the MAC and baseband and also prevent any new
975 * frames from getting started.
976 */
Sujithcbe61d82009-02-09 13:27:12 +0530977bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
Sujithf1dc5602008-10-29 10:16:30 +0530978{
979 u32 reg;
980
981 if (set) {
982 REG_SET_BIT(ah, AR_DIAG_SW,
983 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
984
Sujith0caa7b12009-02-16 13:23:20 +0530985 if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
986 0, AH_WAIT_TIMEOUT)) {
Sujithf1dc5602008-10-29 10:16:30 +0530987 REG_CLR_BIT(ah, AR_DIAG_SW,
988 (AR_DIAG_RX_DIS |
989 AR_DIAG_RX_ABORT));
990
991 reg = REG_READ(ah, AR_OBS_BUS_1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700992 ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
993 "RX failed to go idle in 10 ms RXSM=0x%x\n",
994 reg);
Sujithf1dc5602008-10-29 10:16:30 +0530995
996 return false;
997 }
998 } else {
999 REG_CLR_BIT(ah, AR_DIAG_SW,
1000 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
1001 }
1002
1003 return true;
1004}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001005EXPORT_SYMBOL(ath9k_hw_setrxabort);
Sujithf1dc5602008-10-29 10:16:30 +05301006
Sujithcbe61d82009-02-09 13:27:12 +05301007void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
Sujithf1dc5602008-10-29 10:16:30 +05301008{
1009 REG_WRITE(ah, AR_RXDP, rxdp);
1010}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001011EXPORT_SYMBOL(ath9k_hw_putrxbuf);
Sujithf1dc5602008-10-29 10:16:30 +05301012
Sujithcbe61d82009-02-09 13:27:12 +05301013void ath9k_hw_startpcureceive(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301014{
Sujithf1dc5602008-10-29 10:16:30 +05301015 ath9k_enable_mib_counters(ah);
1016
1017 ath9k_ani_reset(ah);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +05301018
Senthil Balasubramanian8aa15e12008-12-08 19:43:50 +05301019 REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
Sujithf1dc5602008-10-29 10:16:30 +05301020}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001021EXPORT_SYMBOL(ath9k_hw_startpcureceive);
Sujithf1dc5602008-10-29 10:16:30 +05301022
Sujithcbe61d82009-02-09 13:27:12 +05301023void ath9k_hw_stoppcurecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301024{
1025 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
1026
1027 ath9k_hw_disable_mib_counters(ah);
1028}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001029EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
Sujithf1dc5602008-10-29 10:16:30 +05301030
Sujithcbe61d82009-02-09 13:27:12 +05301031bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301032{
Sujith0caa7b12009-02-16 13:23:20 +05301033#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
1034#define AH_RX_TIME_QUANTUM 100 /* usec */
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001035 struct ath_common *common = ath9k_hw_common(ah);
Sujith0caa7b12009-02-16 13:23:20 +05301036 int i;
1037
Sujithf1dc5602008-10-29 10:16:30 +05301038 REG_WRITE(ah, AR_CR, AR_CR_RXD);
1039
Sujith0caa7b12009-02-16 13:23:20 +05301040 /* Wait for rx enable bit to go low */
1041 for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
1042 if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
1043 break;
1044 udelay(AH_TIME_QUANTUM);
1045 }
1046
1047 if (i == 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001048 ath_print(common, ATH_DBG_FATAL,
1049 "DMA failed to stop in %d ms "
1050 "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
1051 AH_RX_STOP_DMA_TIMEOUT / 1000,
1052 REG_READ(ah, AR_CR),
1053 REG_READ(ah, AR_DIAG_SW));
Sujithf1dc5602008-10-29 10:16:30 +05301054 return false;
1055 } else {
1056 return true;
1057 }
Sujith0caa7b12009-02-16 13:23:20 +05301058
1059#undef AH_RX_TIME_QUANTUM
1060#undef AH_RX_STOP_DMA_TIMEOUT
Sujithf1dc5602008-10-29 10:16:30 +05301061}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001062EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
Luis R. Rodriguez536b3a72009-10-06 21:19:11 -04001063
1064int ath9k_hw_beaconq_setup(struct ath_hw *ah)
1065{
1066 struct ath9k_tx_queue_info qi;
1067
1068 memset(&qi, 0, sizeof(qi));
1069 qi.tqi_aifs = 1;
1070 qi.tqi_cwmin = 0;
1071 qi.tqi_cwmax = 0;
1072 /* NB: don't enable any interrupts */
1073 return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
1074}
1075EXPORT_SYMBOL(ath9k_hw_beaconq_setup);