blob: a8dab23622f1b7311302e69718bafe992f356011 [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
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -040024static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
25{
26 ((struct ath_desc *) ds)->ds_link = ds_link;
27}
28
29static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
30{
31 *ds_link = &((struct ath_desc *)ds)->ds_link;
32}
33
Vasanthakumar Thiagarajancee1f622010-04-15 17:38:26 -040034void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
35{
36 struct ath_hw_ops *ops = ath9k_hw_ops(ah);
37
38 ops->rx_enable = ar9002_hw_rx_enable;
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -040039 ops->set_desc_link = ar9002_hw_set_desc_link;
40 ops->get_desc_link = ar9002_hw_get_desc_link;
Vasanthakumar Thiagarajancee1f622010-04-15 17:38:26 -040041}
Vasanthakumar Thiagarajan87d5efb2010-04-15 17:38:43 -040042
Sujithcbe61d82009-02-09 13:27:12 +053043static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053044 struct ath9k_tx_queue_info *qi)
45{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070046 ath_print(ath9k_hw_common(ah), ATH_DBG_INTERRUPT,
47 "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
48 ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
49 ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
50 ah->txurn_interrupt_mask);
Sujithf1dc5602008-10-29 10:16:30 +053051
52 REG_WRITE(ah, AR_IMR_S0,
Sujith2660b812009-02-09 13:27:26 +053053 SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
54 | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
Sujithf1dc5602008-10-29 10:16:30 +053055 REG_WRITE(ah, AR_IMR_S1,
Sujith2660b812009-02-09 13:27:26 +053056 SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
57 | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
Pavel Roskin74bad5c2010-02-23 18:15:27 -050058
59 ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
60 ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
61 REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
Sujithf1dc5602008-10-29 10:16:30 +053062}
63
Sujithcbe61d82009-02-09 13:27:12 +053064u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053065{
66 return REG_READ(ah, AR_QTXDP(q));
67}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040068EXPORT_SYMBOL(ath9k_hw_gettxbuf);
Sujithf1dc5602008-10-29 10:16:30 +053069
Sujith54e4cec2009-08-07 09:45:09 +053070void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
Sujithf1dc5602008-10-29 10:16:30 +053071{
72 REG_WRITE(ah, AR_QTXDP(q), txdp);
Sujithf1dc5602008-10-29 10:16:30 +053073}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040074EXPORT_SYMBOL(ath9k_hw_puttxbuf);
Sujithf1dc5602008-10-29 10:16:30 +053075
Sujith54e4cec2009-08-07 09:45:09 +053076void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053077{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070078 ath_print(ath9k_hw_common(ah), ATH_DBG_QUEUE,
79 "Enable TXE on queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +053080 REG_WRITE(ah, AR_Q_TXE, 1 << q);
Sujithf1dc5602008-10-29 10:16:30 +053081}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040082EXPORT_SYMBOL(ath9k_hw_txstart);
Sujithf1dc5602008-10-29 10:16:30 +053083
Sujithcbe61d82009-02-09 13:27:12 +053084u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +053085{
86 u32 npend;
87
88 npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
89 if (npend == 0) {
90
91 if (REG_READ(ah, AR_Q_TXE) & (1 << q))
92 npend = 1;
93 }
94
95 return npend;
96}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -040097EXPORT_SYMBOL(ath9k_hw_numtxpending);
Sujithf1dc5602008-10-29 10:16:30 +053098
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -050099/**
100 * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
101 *
102 * @ah: atheros hardware struct
103 * @bIncTrigLevel: whether or not the frame trigger level should be updated
104 *
105 * The frame trigger level specifies the minimum number of bytes,
106 * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
107 * before the PCU will initiate sending the frame on the air. This can
108 * mean we initiate transmit before a full frame is on the PCU TX FIFO.
109 * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
110 * first)
111 *
112 * Caution must be taken to ensure to set the frame trigger level based
113 * on the DMA request size. For example if the DMA request size is set to
114 * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
115 * there need to be enough space in the tx FIFO for the requested transfer
116 * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
117 * the threshold to a value beyond 6, then the transmit will hang.
118 *
119 * Current dual stream devices have a PCU TX FIFO size of 8 KB.
120 * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
121 * there is a hardware issue which forces us to use 2 KB instead so the
122 * frame trigger level must not exceed 2 KB for these chipsets.
123 */
Sujithcbe61d82009-02-09 13:27:12 +0530124bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
Sujithf1dc5602008-10-29 10:16:30 +0530125{
Sujithf1dc5602008-10-29 10:16:30 +0530126 u32 txcfg, curLevel, newLevel;
127 enum ath9k_int omask;
128
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -0500129 if (ah->tx_trig_level >= ah->config.max_txtrig_level)
Sujithf1dc5602008-10-29 10:16:30 +0530130 return false;
131
Pavel Roskin152d5302010-03-31 18:05:37 -0400132 omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
Sujithf1dc5602008-10-29 10:16:30 +0530133
134 txcfg = REG_READ(ah, AR_TXCFG);
135 curLevel = MS(txcfg, AR_FTRIG);
136 newLevel = curLevel;
137 if (bIncTrigLevel) {
Luis R. Rodriguezf4709fd2009-11-24 21:37:57 -0500138 if (curLevel < ah->config.max_txtrig_level)
Sujithf1dc5602008-10-29 10:16:30 +0530139 newLevel++;
140 } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
141 newLevel--;
142 if (newLevel != curLevel)
143 REG_WRITE(ah, AR_TXCFG,
144 (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
145
146 ath9k_hw_set_interrupts(ah, omask);
147
Sujith2660b812009-02-09 13:27:26 +0530148 ah->tx_trig_level = newLevel;
Sujithf1dc5602008-10-29 10:16:30 +0530149
150 return newLevel != curLevel;
151}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400152EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel);
Sujithf1dc5602008-10-29 10:16:30 +0530153
Sujithcbe61d82009-02-09 13:27:12 +0530154bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530155{
Sujith94ff91d2009-01-27 15:06:38 +0530156#define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */
157#define ATH9K_TIME_QUANTUM 100 /* usec */
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700158 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530159 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujith94ff91d2009-01-27 15:06:38 +0530160 struct ath9k_tx_queue_info *qi;
Sujithf1dc5602008-10-29 10:16:30 +0530161 u32 tsfLow, j, wait;
Sujith94ff91d2009-01-27 15:06:38 +0530162 u32 wait_time = ATH9K_TX_STOP_DMA_TIMEOUT / ATH9K_TIME_QUANTUM;
163
164 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700165 ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
166 "invalid queue: %u\n", q);
Sujith94ff91d2009-01-27 15:06:38 +0530167 return false;
168 }
169
Sujith2660b812009-02-09 13:27:26 +0530170 qi = &ah->txq[q];
Sujith94ff91d2009-01-27 15:06:38 +0530171 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700172 ath_print(common, ATH_DBG_QUEUE, "Stopping TX DMA, "
173 "inactive queue: %u\n", q);
Sujith94ff91d2009-01-27 15:06:38 +0530174 return false;
175 }
Sujithf1dc5602008-10-29 10:16:30 +0530176
177 REG_WRITE(ah, AR_Q_TXD, 1 << q);
178
Sujith94ff91d2009-01-27 15:06:38 +0530179 for (wait = wait_time; wait != 0; wait--) {
Sujithf1dc5602008-10-29 10:16:30 +0530180 if (ath9k_hw_numtxpending(ah, q) == 0)
181 break;
Sujith94ff91d2009-01-27 15:06:38 +0530182 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530183 }
184
185 if (ath9k_hw_numtxpending(ah, q)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700186 ath_print(common, ATH_DBG_QUEUE,
187 "%s: Num of pending TX Frames %d on Q %d\n",
188 __func__, ath9k_hw_numtxpending(ah, q), q);
Sujithf1dc5602008-10-29 10:16:30 +0530189
190 for (j = 0; j < 2; j++) {
191 tsfLow = REG_READ(ah, AR_TSF_L32);
192 REG_WRITE(ah, AR_QUIET2,
193 SM(10, AR_QUIET2_QUIET_DUR));
194 REG_WRITE(ah, AR_QUIET_PERIOD, 100);
195 REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
196 REG_SET_BIT(ah, AR_TIMER_MODE,
197 AR_QUIET_TIMER_EN);
198
199 if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10))
200 break;
201
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700202 ath_print(common, ATH_DBG_QUEUE,
203 "TSF has moved while trying to set "
204 "quiet time TSF: 0x%08x\n", tsfLow);
Sujithf1dc5602008-10-29 10:16:30 +0530205 }
206
207 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
208
209 udelay(200);
210 REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
211
Sujith94ff91d2009-01-27 15:06:38 +0530212 wait = wait_time;
Sujithf1dc5602008-10-29 10:16:30 +0530213 while (ath9k_hw_numtxpending(ah, q)) {
214 if ((--wait) == 0) {
Sujithe8009e92009-12-14 14:57:08 +0530215 ath_print(common, ATH_DBG_FATAL,
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700216 "Failed to stop TX DMA in 100 "
217 "msec after killing last frame\n");
Sujithf1dc5602008-10-29 10:16:30 +0530218 break;
219 }
Sujith94ff91d2009-01-27 15:06:38 +0530220 udelay(ATH9K_TIME_QUANTUM);
Sujithf1dc5602008-10-29 10:16:30 +0530221 }
222
223 REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
224 }
225
226 REG_WRITE(ah, AR_Q_TXD, 0);
Sujithf1dc5602008-10-29 10:16:30 +0530227 return wait != 0;
Sujith94ff91d2009-01-27 15:06:38 +0530228
229#undef ATH9K_TX_STOP_DMA_TIMEOUT
230#undef ATH9K_TIME_QUANTUM
Sujithf1dc5602008-10-29 10:16:30 +0530231}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400232EXPORT_SYMBOL(ath9k_hw_stoptxdma);
Sujithf1dc5602008-10-29 10:16:30 +0530233
Sujith54e4cec2009-08-07 09:45:09 +0530234void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530235 u32 segLen, bool firstSeg,
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -0400236 bool lastSeg, const struct ath_desc *ds0,
237 dma_addr_t buf_addr)
Sujithf1dc5602008-10-29 10:16:30 +0530238{
239 struct ar5416_desc *ads = AR5416DESC(ds);
240
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -0400241 ads->ds_data = buf_addr;
242
Sujithf1dc5602008-10-29 10:16:30 +0530243 if (firstSeg) {
244 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
245 } else if (lastSeg) {
246 ads->ds_ctl0 = 0;
247 ads->ds_ctl1 = segLen;
248 ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
249 ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
250 } else {
251 ads->ds_ctl0 = 0;
252 ads->ds_ctl1 = segLen | AR_TxMore;
253 ads->ds_ctl2 = 0;
254 ads->ds_ctl3 = 0;
255 }
256 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
257 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
258 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
259 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
260 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530261}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400262EXPORT_SYMBOL(ath9k_hw_filltxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530263
Sujithcbe61d82009-02-09 13:27:12 +0530264void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530265{
266 struct ar5416_desc *ads = AR5416DESC(ds);
267
268 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
269 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
270 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
271 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
272 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
273}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400274EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530275
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700276int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds,
277 struct ath_tx_status *ts)
Sujithf1dc5602008-10-29 10:16:30 +0530278{
279 struct ar5416_desc *ads = AR5416DESC(ds);
280
281 if ((ads->ds_txstatus9 & AR_TxDone) == 0)
282 return -EINPROGRESS;
283
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700284 ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
285 ts->ts_tstamp = ads->AR_SendTimestamp;
286 ts->ts_status = 0;
287 ts->ts_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530288
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500289 if (ads->ds_txstatus1 & AR_FrmXmitOK)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700290 ts->ts_status |= ATH9K_TX_ACKED;
Sujithf1dc5602008-10-29 10:16:30 +0530291 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700292 ts->ts_status |= ATH9K_TXERR_XRETRY;
Sujithf1dc5602008-10-29 10:16:30 +0530293 if (ads->ds_txstatus1 & AR_Filtered)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700294 ts->ts_status |= ATH9K_TXERR_FILT;
Sujithdaa9deb2008-11-18 09:10:22 +0530295 if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700296 ts->ts_status |= ATH9K_TXERR_FIFO;
Sujithdaa9deb2008-11-18 09:10:22 +0530297 ath9k_hw_updatetxtriglevel(ah, true);
298 }
Sujithf1dc5602008-10-29 10:16:30 +0530299 if (ads->ds_txstatus9 & AR_TxOpExceeded)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700300 ts->ts_status |= ATH9K_TXERR_XTXOP;
Sujithf1dc5602008-10-29 10:16:30 +0530301 if (ads->ds_txstatus1 & AR_TxTimerExpired)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700302 ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
Sujithf1dc5602008-10-29 10:16:30 +0530303
304 if (ads->ds_txstatus1 & AR_DescCfgErr)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700305 ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
Sujithf1dc5602008-10-29 10:16:30 +0530306 if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700307 ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530308 ath9k_hw_updatetxtriglevel(ah, true);
309 }
310 if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700311 ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530312 ath9k_hw_updatetxtriglevel(ah, true);
313 }
314 if (ads->ds_txstatus0 & AR_TxBaStatus) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700315 ts->ts_flags |= ATH9K_TX_BA;
316 ts->ba_low = ads->AR_BaBitmapLow;
317 ts->ba_high = ads->AR_BaBitmapHigh;
Sujithf1dc5602008-10-29 10:16:30 +0530318 }
319
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700320 ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
321 switch (ts->ts_rateindex) {
Sujithf1dc5602008-10-29 10:16:30 +0530322 case 0:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700323 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
Sujithf1dc5602008-10-29 10:16:30 +0530324 break;
325 case 1:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700326 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
Sujithf1dc5602008-10-29 10:16:30 +0530327 break;
328 case 2:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700329 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
Sujithf1dc5602008-10-29 10:16:30 +0530330 break;
331 case 3:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700332 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
Sujithf1dc5602008-10-29 10:16:30 +0530333 break;
334 }
335
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700336 ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
337 ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
338 ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
339 ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
340 ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
341 ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
342 ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
343 ts->evm0 = ads->AR_TxEVM0;
344 ts->evm1 = ads->AR_TxEVM1;
345 ts->evm2 = ads->AR_TxEVM2;
346 ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
347 ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
348 ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
349 ts->ts_antenna = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530350
351 return 0;
352}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400353EXPORT_SYMBOL(ath9k_hw_txprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530354
Sujithcbe61d82009-02-09 13:27:12 +0530355void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530356 u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
357 u32 keyIx, enum ath9k_key_type keyType, u32 flags)
358{
359 struct ar5416_desc *ads = AR5416DESC(ds);
Sujithf1dc5602008-10-29 10:16:30 +0530360
Sujith2660b812009-02-09 13:27:26 +0530361 txPower += ah->txpower_indexoffset;
Sujithf1dc5602008-10-29 10:16:30 +0530362 if (txPower > 63)
363 txPower = 63;
364
365 ads->ds_ctl0 = (pktLen & AR_FrameLen)
366 | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
367 | SM(txPower, AR_XmitPower)
368 | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
369 | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
370 | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
371 | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
372
373 ads->ds_ctl1 =
374 (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
375 | SM(type, AR_FrameType)
376 | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
377 | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
378 | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
379
380 ads->ds_ctl6 = SM(keyType, AR_EncrType);
381
Sujithe492d7c2010-03-17 14:25:17 +0530382 if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
Sujithf1dc5602008-10-29 10:16:30 +0530383 ads->ds_ctl8 = 0;
384 ads->ds_ctl9 = 0;
385 ads->ds_ctl10 = 0;
386 ads->ds_ctl11 = 0;
387 }
388}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400389EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530390
Sujithcbe61d82009-02-09 13:27:12 +0530391void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530392 struct ath_desc *lastds,
393 u32 durUpdateEn, u32 rtsctsRate,
394 u32 rtsctsDuration,
395 struct ath9k_11n_rate_series series[],
396 u32 nseries, u32 flags)
397{
398 struct ar5416_desc *ads = AR5416DESC(ds);
399 struct ar5416_desc *last_ads = AR5416DESC(lastds);
400 u32 ds_ctl0;
401
Sujithf1dc5602008-10-29 10:16:30 +0530402 if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
403 ds_ctl0 = ads->ds_ctl0;
404
405 if (flags & ATH9K_TXDESC_RTSENA) {
406 ds_ctl0 &= ~AR_CTSEnable;
407 ds_ctl0 |= AR_RTSEnable;
408 } else {
409 ds_ctl0 &= ~AR_RTSEnable;
410 ds_ctl0 |= AR_CTSEnable;
411 }
412
413 ads->ds_ctl0 = ds_ctl0;
414 } else {
415 ads->ds_ctl0 =
416 (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
417 }
418
419 ads->ds_ctl2 = set11nTries(series, 0)
420 | set11nTries(series, 1)
421 | set11nTries(series, 2)
422 | set11nTries(series, 3)
423 | (durUpdateEn ? AR_DurUpdateEna : 0)
424 | SM(0, AR_BurstDur);
425
426 ads->ds_ctl3 = set11nRate(series, 0)
427 | set11nRate(series, 1)
428 | set11nRate(series, 2)
429 | set11nRate(series, 3);
430
431 ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
432 | set11nPktDurRTSCTS(series, 1);
433
434 ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
435 | set11nPktDurRTSCTS(series, 3);
436
437 ads->ds_ctl7 = set11nRateFlags(series, 0)
438 | set11nRateFlags(series, 1)
439 | set11nRateFlags(series, 2)
440 | set11nRateFlags(series, 3)
441 | SM(rtsctsRate, AR_RTSCTSRate);
442 last_ads->ds_ctl2 = ads->ds_ctl2;
443 last_ads->ds_ctl3 = ads->ds_ctl3;
444}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400445EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
Sujithf1dc5602008-10-29 10:16:30 +0530446
Sujithcbe61d82009-02-09 13:27:12 +0530447void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530448 u32 aggrLen)
449{
450 struct ar5416_desc *ads = AR5416DESC(ds);
451
452 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
453 ads->ds_ctl6 &= ~AR_AggrLen;
454 ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
455}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400456EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
Sujithf1dc5602008-10-29 10:16:30 +0530457
Sujithcbe61d82009-02-09 13:27:12 +0530458void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530459 u32 numDelims)
460{
461 struct ar5416_desc *ads = AR5416DESC(ds);
462 unsigned int ctl6;
463
464 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
465
466 ctl6 = ads->ds_ctl6;
467 ctl6 &= ~AR_PadDelim;
468 ctl6 |= SM(numDelims, AR_PadDelim);
469 ads->ds_ctl6 = ctl6;
470}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400471EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
Sujithf1dc5602008-10-29 10:16:30 +0530472
Sujithcbe61d82009-02-09 13:27:12 +0530473void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530474{
475 struct ar5416_desc *ads = AR5416DESC(ds);
476
477 ads->ds_ctl1 |= AR_IsAggr;
478 ads->ds_ctl1 &= ~AR_MoreAggr;
479 ads->ds_ctl6 &= ~AR_PadDelim;
480}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400481EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
Sujithf1dc5602008-10-29 10:16:30 +0530482
Sujithcbe61d82009-02-09 13:27:12 +0530483void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530484{
485 struct ar5416_desc *ads = AR5416DESC(ds);
486
487 ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
488}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400489EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
Sujithf1dc5602008-10-29 10:16:30 +0530490
Sujithcbe61d82009-02-09 13:27:12 +0530491void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530492 u32 burstDuration)
493{
494 struct ar5416_desc *ads = AR5416DESC(ds);
495
496 ads->ds_ctl2 &= ~AR_BurstDur;
497 ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
498}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400499EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
Sujithf1dc5602008-10-29 10:16:30 +0530500
Sujithcbe61d82009-02-09 13:27:12 +0530501void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530502 u32 vmf)
503{
504 struct ar5416_desc *ads = AR5416DESC(ds);
505
506 if (vmf)
507 ads->ds_ctl0 |= AR_VirtMoreFrag;
508 else
509 ads->ds_ctl0 &= ~AR_VirtMoreFrag;
510}
511
Sujithcbe61d82009-02-09 13:27:12 +0530512void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
Sujithf1dc5602008-10-29 10:16:30 +0530513{
Sujith2660b812009-02-09 13:27:26 +0530514 *txqs &= ah->intr_txqs;
515 ah->intr_txqs &= ~(*txqs);
Sujithf1dc5602008-10-29 10:16:30 +0530516}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400517EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
Sujithf1dc5602008-10-29 10:16:30 +0530518
Sujithcbe61d82009-02-09 13:27:12 +0530519bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530520 const struct ath9k_tx_queue_info *qinfo)
521{
522 u32 cw;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700523 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530524 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530525 struct ath9k_tx_queue_info *qi;
526
527 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700528 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
529 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530530 return false;
531 }
532
Sujith2660b812009-02-09 13:27:26 +0530533 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530534 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700535 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
536 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530537 return false;
538 }
539
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700540 ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530541
542 qi->tqi_ver = qinfo->tqi_ver;
543 qi->tqi_subtype = qinfo->tqi_subtype;
544 qi->tqi_qflags = qinfo->tqi_qflags;
545 qi->tqi_priority = qinfo->tqi_priority;
546 if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
547 qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
548 else
549 qi->tqi_aifs = INIT_AIFS;
550 if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
551 cw = min(qinfo->tqi_cwmin, 1024U);
552 qi->tqi_cwmin = 1;
553 while (qi->tqi_cwmin < cw)
554 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
555 } else
556 qi->tqi_cwmin = qinfo->tqi_cwmin;
557 if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
558 cw = min(qinfo->tqi_cwmax, 1024U);
559 qi->tqi_cwmax = 1;
560 while (qi->tqi_cwmax < cw)
561 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
562 } else
563 qi->tqi_cwmax = INIT_CWMAX;
564
565 if (qinfo->tqi_shretry != 0)
566 qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
567 else
568 qi->tqi_shretry = INIT_SH_RETRY;
569 if (qinfo->tqi_lgretry != 0)
570 qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
571 else
572 qi->tqi_lgretry = INIT_LG_RETRY;
573 qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
574 qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
575 qi->tqi_burstTime = qinfo->tqi_burstTime;
576 qi->tqi_readyTime = qinfo->tqi_readyTime;
577
578 switch (qinfo->tqi_subtype) {
579 case ATH9K_WME_UPSD:
580 if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
581 qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
582 break;
583 default:
584 break;
585 }
586
587 return true;
588}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400589EXPORT_SYMBOL(ath9k_hw_set_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530590
Sujithcbe61d82009-02-09 13:27:12 +0530591bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530592 struct ath9k_tx_queue_info *qinfo)
593{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700594 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530595 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530596 struct ath9k_tx_queue_info *qi;
597
598 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700599 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
600 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530601 return false;
602 }
603
Sujith2660b812009-02-09 13:27:26 +0530604 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530605 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700606 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
607 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530608 return false;
609 }
610
611 qinfo->tqi_qflags = qi->tqi_qflags;
612 qinfo->tqi_ver = qi->tqi_ver;
613 qinfo->tqi_subtype = qi->tqi_subtype;
614 qinfo->tqi_qflags = qi->tqi_qflags;
615 qinfo->tqi_priority = qi->tqi_priority;
616 qinfo->tqi_aifs = qi->tqi_aifs;
617 qinfo->tqi_cwmin = qi->tqi_cwmin;
618 qinfo->tqi_cwmax = qi->tqi_cwmax;
619 qinfo->tqi_shretry = qi->tqi_shretry;
620 qinfo->tqi_lgretry = qi->tqi_lgretry;
621 qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
622 qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
623 qinfo->tqi_burstTime = qi->tqi_burstTime;
624 qinfo->tqi_readyTime = qi->tqi_readyTime;
625
626 return true;
627}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400628EXPORT_SYMBOL(ath9k_hw_get_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530629
Sujithcbe61d82009-02-09 13:27:12 +0530630int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
Sujithf1dc5602008-10-29 10:16:30 +0530631 const struct ath9k_tx_queue_info *qinfo)
632{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700633 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530634 struct ath9k_tx_queue_info *qi;
Sujith2660b812009-02-09 13:27:26 +0530635 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530636 int q;
637
638 switch (type) {
639 case ATH9K_TX_QUEUE_BEACON:
640 q = pCap->total_queues - 1;
641 break;
642 case ATH9K_TX_QUEUE_CAB:
643 q = pCap->total_queues - 2;
644 break;
645 case ATH9K_TX_QUEUE_PSPOLL:
646 q = 1;
647 break;
648 case ATH9K_TX_QUEUE_UAPSD:
649 q = pCap->total_queues - 3;
650 break;
651 case ATH9K_TX_QUEUE_DATA:
652 for (q = 0; q < pCap->total_queues; q++)
Sujith2660b812009-02-09 13:27:26 +0530653 if (ah->txq[q].tqi_type ==
Sujithf1dc5602008-10-29 10:16:30 +0530654 ATH9K_TX_QUEUE_INACTIVE)
655 break;
656 if (q == pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700657 ath_print(common, ATH_DBG_FATAL,
658 "No available TX queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530659 return -1;
660 }
661 break;
662 default:
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700663 ath_print(common, ATH_DBG_FATAL,
664 "Invalid TX queue type: %u\n", type);
Sujithf1dc5602008-10-29 10:16:30 +0530665 return -1;
666 }
667
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700668 ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530669
Sujith2660b812009-02-09 13:27:26 +0530670 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530671 if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700672 ath_print(common, ATH_DBG_FATAL,
673 "TX queue: %u already active\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530674 return -1;
675 }
676 memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
677 qi->tqi_type = type;
678 if (qinfo == NULL) {
679 qi->tqi_qflags =
680 TXQ_FLAG_TXOKINT_ENABLE
681 | TXQ_FLAG_TXERRINT_ENABLE
682 | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
683 qi->tqi_aifs = INIT_AIFS;
684 qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
685 qi->tqi_cwmax = INIT_CWMAX;
686 qi->tqi_shretry = INIT_SH_RETRY;
687 qi->tqi_lgretry = INIT_LG_RETRY;
688 qi->tqi_physCompBuf = 0;
689 } else {
690 qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
691 (void) ath9k_hw_set_txq_props(ah, q, qinfo);
692 }
693
694 return q;
695}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400696EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530697
Sujithcbe61d82009-02-09 13:27:12 +0530698bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530699{
Sujith2660b812009-02-09 13:27:26 +0530700 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700701 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530702 struct ath9k_tx_queue_info *qi;
703
704 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700705 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
706 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530707 return false;
708 }
Sujith2660b812009-02-09 13:27:26 +0530709 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530710 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700711 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
712 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530713 return false;
714 }
715
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700716 ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530717
718 qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
Sujith2660b812009-02-09 13:27:26 +0530719 ah->txok_interrupt_mask &= ~(1 << q);
720 ah->txerr_interrupt_mask &= ~(1 << q);
721 ah->txdesc_interrupt_mask &= ~(1 << q);
722 ah->txeol_interrupt_mask &= ~(1 << q);
723 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530724 ath9k_hw_set_txq_interrupts(ah, qi);
725
726 return true;
727}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400728EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530729
Sujithcbe61d82009-02-09 13:27:12 +0530730bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530731{
Sujith2660b812009-02-09 13:27:26 +0530732 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700733 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530734 struct ath9k_channel *chan = ah->curchan;
Sujithf1dc5602008-10-29 10:16:30 +0530735 struct ath9k_tx_queue_info *qi;
736 u32 cwMin, chanCwMin, value;
737
738 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700739 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
740 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530741 return false;
742 }
743
Sujith2660b812009-02-09 13:27:26 +0530744 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530745 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700746 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
747 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530748 return true;
749 }
750
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700751 ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530752
753 if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
754 if (chan && IS_CHAN_B(chan))
755 chanCwMin = INIT_CWMIN_11B;
756 else
757 chanCwMin = INIT_CWMIN;
758
759 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
760 } else
761 cwMin = qi->tqi_cwmin;
762
763 REG_WRITE(ah, AR_DLCL_IFS(q),
764 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
765 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
766 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
767
768 REG_WRITE(ah, AR_DRETRY_LIMIT(q),
769 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
770 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
771 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
772
773 REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
774 REG_WRITE(ah, AR_DMISC(q),
775 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
776
777 if (qi->tqi_cbrPeriod) {
778 REG_WRITE(ah, AR_QCBRCFG(q),
779 SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
780 SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
781 REG_WRITE(ah, AR_QMISC(q),
782 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
783 (qi->tqi_cbrOverflowLimit ?
784 AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
785 }
786 if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
787 REG_WRITE(ah, AR_QRDYTIMECFG(q),
788 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
789 AR_Q_RDYTIMECFG_EN);
790 }
791
792 REG_WRITE(ah, AR_DCHNTIME(q),
793 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
794 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
795
796 if (qi->tqi_burstTime
797 && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
798 REG_WRITE(ah, AR_QMISC(q),
799 REG_READ(ah, AR_QMISC(q)) |
800 AR_Q_MISC_RDYTIME_EXP_POLICY);
801
802 }
803
804 if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
805 REG_WRITE(ah, AR_DMISC(q),
806 REG_READ(ah, AR_DMISC(q)) |
807 AR_D_MISC_POST_FR_BKOFF_DIS);
808 }
809 if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
810 REG_WRITE(ah, AR_DMISC(q),
811 REG_READ(ah, AR_DMISC(q)) |
812 AR_D_MISC_FRAG_BKOFF_EN);
813 }
814 switch (qi->tqi_type) {
815 case ATH9K_TX_QUEUE_BEACON:
816 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
817 | AR_Q_MISC_FSP_DBA_GATED
818 | AR_Q_MISC_BEACON_USE
819 | AR_Q_MISC_CBR_INCR_DIS1);
820
821 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
822 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
823 AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
824 | AR_D_MISC_BEACON_USE
825 | AR_D_MISC_POST_FR_BKOFF_DIS);
826 break;
827 case ATH9K_TX_QUEUE_CAB:
828 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
829 | AR_Q_MISC_FSP_DBA_GATED
830 | AR_Q_MISC_CBR_INCR_DIS1
831 | AR_Q_MISC_CBR_INCR_DIS0);
832 value = (qi->tqi_readyTime -
Sujith2660b812009-02-09 13:27:26 +0530833 (ah->config.sw_beacon_response_time -
834 ah->config.dma_beacon_response_time) -
835 ah->config.additional_swba_backoff) * 1024;
Sujithf1dc5602008-10-29 10:16:30 +0530836 REG_WRITE(ah, AR_QRDYTIMECFG(q),
837 value | AR_Q_RDYTIMECFG_EN);
838 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
839 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
840 AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
841 break;
842 case ATH9K_TX_QUEUE_PSPOLL:
843 REG_WRITE(ah, AR_QMISC(q),
844 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
845 break;
846 case ATH9K_TX_QUEUE_UAPSD:
847 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
848 AR_D_MISC_POST_FR_BKOFF_DIS);
849 break;
850 default:
851 break;
852 }
853
854 if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
855 REG_WRITE(ah, AR_DMISC(q),
856 REG_READ(ah, AR_DMISC(q)) |
857 SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
858 AR_D_MISC_ARB_LOCKOUT_CNTRL) |
859 AR_D_MISC_POST_FR_BKOFF_DIS);
860 }
861
862 if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530863 ah->txok_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530864 else
Sujith2660b812009-02-09 13:27:26 +0530865 ah->txok_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530866 if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530867 ah->txerr_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530868 else
Sujith2660b812009-02-09 13:27:26 +0530869 ah->txerr_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530870 if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530871 ah->txdesc_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530872 else
Sujith2660b812009-02-09 13:27:26 +0530873 ah->txdesc_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530874 if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530875 ah->txeol_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530876 else
Sujith2660b812009-02-09 13:27:26 +0530877 ah->txeol_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530878 if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530879 ah->txurn_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530880 else
Sujith2660b812009-02-09 13:27:26 +0530881 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530882 ath9k_hw_set_txq_interrupts(ah, qi);
883
884 return true;
885}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400886EXPORT_SYMBOL(ath9k_hw_resettxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530887
Sujithcbe61d82009-02-09 13:27:12 +0530888int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700889 struct ath_rx_status *rs, u64 tsf)
Sujithf1dc5602008-10-29 10:16:30 +0530890{
891 struct ar5416_desc ads;
892 struct ar5416_desc *adsp = AR5416DESC(ds);
893 u32 phyerr;
894
895 if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
896 return -EINPROGRESS;
897
898 ads.u.rx = adsp->u.rx;
899
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700900 rs->rs_status = 0;
901 rs->rs_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530902
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700903 rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
904 rs->rs_tstamp = ads.AR_RcvTimestamp;
Sujithf1dc5602008-10-29 10:16:30 +0530905
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400906 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700907 rs->rs_rssi = ATH9K_RSSI_BAD;
908 rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
909 rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
910 rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
911 rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
912 rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
913 rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400914 } else {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700915 rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
916 rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400917 AR_RxRSSIAnt00);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700918 rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400919 AR_RxRSSIAnt01);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700920 rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400921 AR_RxRSSIAnt02);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700922 rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400923 AR_RxRSSIAnt10);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700924 rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400925 AR_RxRSSIAnt11);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700926 rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400927 AR_RxRSSIAnt12);
928 }
Sujithf1dc5602008-10-29 10:16:30 +0530929 if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700930 rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
Sujithf1dc5602008-10-29 10:16:30 +0530931 else
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700932 rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
Sujithf1dc5602008-10-29 10:16:30 +0530933
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700934 rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
935 rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
Sujithf1dc5602008-10-29 10:16:30 +0530936
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700937 rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
938 rs->rs_moreaggr =
Sujithf1dc5602008-10-29 10:16:30 +0530939 (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700940 rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
941 rs->rs_flags =
Sujithf1dc5602008-10-29 10:16:30 +0530942 (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700943 rs->rs_flags |=
Sujithf1dc5602008-10-29 10:16:30 +0530944 (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
945
946 if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700947 rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
Sujithf1dc5602008-10-29 10:16:30 +0530948 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700949 rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
Sujithf1dc5602008-10-29 10:16:30 +0530950 if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700951 rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
Sujithf1dc5602008-10-29 10:16:30 +0530952
953 if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
954 if (ads.ds_rxstatus8 & AR_CRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700955 rs->rs_status |= ATH9K_RXERR_CRC;
Sujithf1dc5602008-10-29 10:16:30 +0530956 else if (ads.ds_rxstatus8 & AR_PHYErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700957 rs->rs_status |= ATH9K_RXERR_PHY;
Sujithf1dc5602008-10-29 10:16:30 +0530958 phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700959 rs->rs_phyerr = phyerr;
Sujithf1dc5602008-10-29 10:16:30 +0530960 } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700961 rs->rs_status |= ATH9K_RXERR_DECRYPT;
Sujithf1dc5602008-10-29 10:16:30 +0530962 else if (ads.ds_rxstatus8 & AR_MichaelErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700963 rs->rs_status |= ATH9K_RXERR_MIC;
Sujithf1dc5602008-10-29 10:16:30 +0530964 }
965
966 return 0;
967}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400968EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530969
Sujith54e4cec2009-08-07 09:45:09 +0530970void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530971 u32 size, u32 flags)
972{
973 struct ar5416_desc *ads = AR5416DESC(ds);
Sujith2660b812009-02-09 13:27:26 +0530974 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530975
976 ads->ds_ctl1 = size & AR_BufLen;
977 if (flags & ATH9K_RXDESC_INTREQ)
978 ads->ds_ctl1 |= AR_RxIntrReq;
979
980 ads->ds_rxstatus8 &= ~AR_RxDone;
981 if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
982 memset(&(ads->u), 0, sizeof(ads->u));
Sujithf1dc5602008-10-29 10:16:30 +0530983}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400984EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530985
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500986/*
987 * This can stop or re-enables RX.
988 *
989 * If bool is set this will kill any frame which is currently being
990 * transferred between the MAC and baseband and also prevent any new
991 * frames from getting started.
992 */
Sujithcbe61d82009-02-09 13:27:12 +0530993bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
Sujithf1dc5602008-10-29 10:16:30 +0530994{
995 u32 reg;
996
997 if (set) {
998 REG_SET_BIT(ah, AR_DIAG_SW,
999 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
1000
Sujith0caa7b12009-02-16 13:23:20 +05301001 if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
1002 0, AH_WAIT_TIMEOUT)) {
Sujithf1dc5602008-10-29 10:16:30 +05301003 REG_CLR_BIT(ah, AR_DIAG_SW,
1004 (AR_DIAG_RX_DIS |
1005 AR_DIAG_RX_ABORT));
1006
1007 reg = REG_READ(ah, AR_OBS_BUS_1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001008 ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
1009 "RX failed to go idle in 10 ms RXSM=0x%x\n",
1010 reg);
Sujithf1dc5602008-10-29 10:16:30 +05301011
1012 return false;
1013 }
1014 } else {
1015 REG_CLR_BIT(ah, AR_DIAG_SW,
1016 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
1017 }
1018
1019 return true;
1020}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001021EXPORT_SYMBOL(ath9k_hw_setrxabort);
Sujithf1dc5602008-10-29 10:16:30 +05301022
Sujithcbe61d82009-02-09 13:27:12 +05301023void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
Sujithf1dc5602008-10-29 10:16:30 +05301024{
1025 REG_WRITE(ah, AR_RXDP, rxdp);
1026}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001027EXPORT_SYMBOL(ath9k_hw_putrxbuf);
Sujithf1dc5602008-10-29 10:16:30 +05301028
Sujithcbe61d82009-02-09 13:27:12 +05301029void ath9k_hw_startpcureceive(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301030{
Sujithf1dc5602008-10-29 10:16:30 +05301031 ath9k_enable_mib_counters(ah);
1032
1033 ath9k_ani_reset(ah);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +05301034
Senthil Balasubramanian8aa15e12008-12-08 19:43:50 +05301035 REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
Sujithf1dc5602008-10-29 10:16:30 +05301036}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001037EXPORT_SYMBOL(ath9k_hw_startpcureceive);
Sujithf1dc5602008-10-29 10:16:30 +05301038
Sujithcbe61d82009-02-09 13:27:12 +05301039void ath9k_hw_stoppcurecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301040{
1041 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
1042
1043 ath9k_hw_disable_mib_counters(ah);
1044}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001045EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
Sujithf1dc5602008-10-29 10:16:30 +05301046
Sujithcbe61d82009-02-09 13:27:12 +05301047bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301048{
Sujith0caa7b12009-02-16 13:23:20 +05301049#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
1050#define AH_RX_TIME_QUANTUM 100 /* usec */
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001051 struct ath_common *common = ath9k_hw_common(ah);
Sujith0caa7b12009-02-16 13:23:20 +05301052 int i;
1053
Sujithf1dc5602008-10-29 10:16:30 +05301054 REG_WRITE(ah, AR_CR, AR_CR_RXD);
1055
Sujith0caa7b12009-02-16 13:23:20 +05301056 /* Wait for rx enable bit to go low */
1057 for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
1058 if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
1059 break;
1060 udelay(AH_TIME_QUANTUM);
1061 }
1062
1063 if (i == 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001064 ath_print(common, ATH_DBG_FATAL,
1065 "DMA failed to stop in %d ms "
1066 "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
1067 AH_RX_STOP_DMA_TIMEOUT / 1000,
1068 REG_READ(ah, AR_CR),
1069 REG_READ(ah, AR_DIAG_SW));
Sujithf1dc5602008-10-29 10:16:30 +05301070 return false;
1071 } else {
1072 return true;
1073 }
Sujith0caa7b12009-02-16 13:23:20 +05301074
1075#undef AH_RX_TIME_QUANTUM
1076#undef AH_RX_STOP_DMA_TIMEOUT
Sujithf1dc5602008-10-29 10:16:30 +05301077}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001078EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
Luis R. Rodriguez536b3a72009-10-06 21:19:11 -04001079
1080int ath9k_hw_beaconq_setup(struct ath_hw *ah)
1081{
1082 struct ath9k_tx_queue_info qi;
1083
1084 memset(&qi, 0, sizeof(qi));
1085 qi.tqi_aifs = 1;
1086 qi.tqi_cwmin = 0;
1087 qi.tqi_cwmax = 0;
1088 /* NB: don't enable any interrupts */
1089 return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
1090}
1091EXPORT_SYMBOL(ath9k_hw_beaconq_setup);