blob: 0c9c378616c6c46a91c4743eb90c9e2adf028b00 [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,
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -0400223 bool lastSeg, const struct ath_desc *ds0,
224 dma_addr_t buf_addr)
Sujithf1dc5602008-10-29 10:16:30 +0530225{
226 struct ar5416_desc *ads = AR5416DESC(ds);
227
Vasanthakumar Thiagarajan3f3a1c82010-04-15 17:38:42 -0400228 ads->ds_data = buf_addr;
229
Sujithf1dc5602008-10-29 10:16:30 +0530230 if (firstSeg) {
231 ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
232 } else if (lastSeg) {
233 ads->ds_ctl0 = 0;
234 ads->ds_ctl1 = segLen;
235 ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
236 ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
237 } else {
238 ads->ds_ctl0 = 0;
239 ads->ds_ctl1 = segLen | AR_TxMore;
240 ads->ds_ctl2 = 0;
241 ads->ds_ctl3 = 0;
242 }
243 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
244 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
245 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
246 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
247 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530248}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400249EXPORT_SYMBOL(ath9k_hw_filltxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530250
Sujithcbe61d82009-02-09 13:27:12 +0530251void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530252{
253 struct ar5416_desc *ads = AR5416DESC(ds);
254
255 ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
256 ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
257 ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
258 ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
259 ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
260}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400261EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530262
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700263int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds,
264 struct ath_tx_status *ts)
Sujithf1dc5602008-10-29 10:16:30 +0530265{
266 struct ar5416_desc *ads = AR5416DESC(ds);
267
268 if ((ads->ds_txstatus9 & AR_TxDone) == 0)
269 return -EINPROGRESS;
270
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700271 ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
272 ts->ts_tstamp = ads->AR_SendTimestamp;
273 ts->ts_status = 0;
274 ts->ts_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530275
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500276 if (ads->ds_txstatus1 & AR_FrmXmitOK)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700277 ts->ts_status |= ATH9K_TX_ACKED;
Sujithf1dc5602008-10-29 10:16:30 +0530278 if (ads->ds_txstatus1 & AR_ExcessiveRetries)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700279 ts->ts_status |= ATH9K_TXERR_XRETRY;
Sujithf1dc5602008-10-29 10:16:30 +0530280 if (ads->ds_txstatus1 & AR_Filtered)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700281 ts->ts_status |= ATH9K_TXERR_FILT;
Sujithdaa9deb2008-11-18 09:10:22 +0530282 if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700283 ts->ts_status |= ATH9K_TXERR_FIFO;
Sujithdaa9deb2008-11-18 09:10:22 +0530284 ath9k_hw_updatetxtriglevel(ah, true);
285 }
Sujithf1dc5602008-10-29 10:16:30 +0530286 if (ads->ds_txstatus9 & AR_TxOpExceeded)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700287 ts->ts_status |= ATH9K_TXERR_XTXOP;
Sujithf1dc5602008-10-29 10:16:30 +0530288 if (ads->ds_txstatus1 & AR_TxTimerExpired)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700289 ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
Sujithf1dc5602008-10-29 10:16:30 +0530290
291 if (ads->ds_txstatus1 & AR_DescCfgErr)
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700292 ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
Sujithf1dc5602008-10-29 10:16:30 +0530293 if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700294 ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530295 ath9k_hw_updatetxtriglevel(ah, true);
296 }
297 if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700298 ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
Sujithf1dc5602008-10-29 10:16:30 +0530299 ath9k_hw_updatetxtriglevel(ah, true);
300 }
301 if (ads->ds_txstatus0 & AR_TxBaStatus) {
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700302 ts->ts_flags |= ATH9K_TX_BA;
303 ts->ba_low = ads->AR_BaBitmapLow;
304 ts->ba_high = ads->AR_BaBitmapHigh;
Sujithf1dc5602008-10-29 10:16:30 +0530305 }
306
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700307 ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
308 switch (ts->ts_rateindex) {
Sujithf1dc5602008-10-29 10:16:30 +0530309 case 0:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700310 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
Sujithf1dc5602008-10-29 10:16:30 +0530311 break;
312 case 1:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700313 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
Sujithf1dc5602008-10-29 10:16:30 +0530314 break;
315 case 2:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700316 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
Sujithf1dc5602008-10-29 10:16:30 +0530317 break;
318 case 3:
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700319 ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
Sujithf1dc5602008-10-29 10:16:30 +0530320 break;
321 }
322
Felix Fietkaudb1a0522010-03-29 20:07:11 -0700323 ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
324 ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
325 ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
326 ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
327 ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
328 ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
329 ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
330 ts->evm0 = ads->AR_TxEVM0;
331 ts->evm1 = ads->AR_TxEVM1;
332 ts->evm2 = ads->AR_TxEVM2;
333 ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
334 ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
335 ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
336 ts->ts_antenna = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530337
338 return 0;
339}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400340EXPORT_SYMBOL(ath9k_hw_txprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530341
Sujithcbe61d82009-02-09 13:27:12 +0530342void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530343 u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
344 u32 keyIx, enum ath9k_key_type keyType, u32 flags)
345{
346 struct ar5416_desc *ads = AR5416DESC(ds);
Sujithf1dc5602008-10-29 10:16:30 +0530347
Sujith2660b812009-02-09 13:27:26 +0530348 txPower += ah->txpower_indexoffset;
Sujithf1dc5602008-10-29 10:16:30 +0530349 if (txPower > 63)
350 txPower = 63;
351
352 ads->ds_ctl0 = (pktLen & AR_FrameLen)
353 | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
354 | SM(txPower, AR_XmitPower)
355 | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
356 | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
357 | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
358 | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
359
360 ads->ds_ctl1 =
361 (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
362 | SM(type, AR_FrameType)
363 | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
364 | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
365 | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
366
367 ads->ds_ctl6 = SM(keyType, AR_EncrType);
368
Sujithe492d7c2010-03-17 14:25:17 +0530369 if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
Sujithf1dc5602008-10-29 10:16:30 +0530370 ads->ds_ctl8 = 0;
371 ads->ds_ctl9 = 0;
372 ads->ds_ctl10 = 0;
373 ads->ds_ctl11 = 0;
374 }
375}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400376EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530377
Sujithcbe61d82009-02-09 13:27:12 +0530378void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530379 struct ath_desc *lastds,
380 u32 durUpdateEn, u32 rtsctsRate,
381 u32 rtsctsDuration,
382 struct ath9k_11n_rate_series series[],
383 u32 nseries, u32 flags)
384{
385 struct ar5416_desc *ads = AR5416DESC(ds);
386 struct ar5416_desc *last_ads = AR5416DESC(lastds);
387 u32 ds_ctl0;
388
Sujithf1dc5602008-10-29 10:16:30 +0530389 if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
390 ds_ctl0 = ads->ds_ctl0;
391
392 if (flags & ATH9K_TXDESC_RTSENA) {
393 ds_ctl0 &= ~AR_CTSEnable;
394 ds_ctl0 |= AR_RTSEnable;
395 } else {
396 ds_ctl0 &= ~AR_RTSEnable;
397 ds_ctl0 |= AR_CTSEnable;
398 }
399
400 ads->ds_ctl0 = ds_ctl0;
401 } else {
402 ads->ds_ctl0 =
403 (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
404 }
405
406 ads->ds_ctl2 = set11nTries(series, 0)
407 | set11nTries(series, 1)
408 | set11nTries(series, 2)
409 | set11nTries(series, 3)
410 | (durUpdateEn ? AR_DurUpdateEna : 0)
411 | SM(0, AR_BurstDur);
412
413 ads->ds_ctl3 = set11nRate(series, 0)
414 | set11nRate(series, 1)
415 | set11nRate(series, 2)
416 | set11nRate(series, 3);
417
418 ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
419 | set11nPktDurRTSCTS(series, 1);
420
421 ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
422 | set11nPktDurRTSCTS(series, 3);
423
424 ads->ds_ctl7 = set11nRateFlags(series, 0)
425 | set11nRateFlags(series, 1)
426 | set11nRateFlags(series, 2)
427 | set11nRateFlags(series, 3)
428 | SM(rtsctsRate, AR_RTSCTSRate);
429 last_ads->ds_ctl2 = ads->ds_ctl2;
430 last_ads->ds_ctl3 = ads->ds_ctl3;
431}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400432EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
Sujithf1dc5602008-10-29 10:16:30 +0530433
Sujithcbe61d82009-02-09 13:27:12 +0530434void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530435 u32 aggrLen)
436{
437 struct ar5416_desc *ads = AR5416DESC(ds);
438
439 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
440 ads->ds_ctl6 &= ~AR_AggrLen;
441 ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
442}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400443EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
Sujithf1dc5602008-10-29 10:16:30 +0530444
Sujithcbe61d82009-02-09 13:27:12 +0530445void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530446 u32 numDelims)
447{
448 struct ar5416_desc *ads = AR5416DESC(ds);
449 unsigned int ctl6;
450
451 ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
452
453 ctl6 = ads->ds_ctl6;
454 ctl6 &= ~AR_PadDelim;
455 ctl6 |= SM(numDelims, AR_PadDelim);
456 ads->ds_ctl6 = ctl6;
457}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400458EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
Sujithf1dc5602008-10-29 10:16:30 +0530459
Sujithcbe61d82009-02-09 13:27:12 +0530460void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530461{
462 struct ar5416_desc *ads = AR5416DESC(ds);
463
464 ads->ds_ctl1 |= AR_IsAggr;
465 ads->ds_ctl1 &= ~AR_MoreAggr;
466 ads->ds_ctl6 &= ~AR_PadDelim;
467}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400468EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
Sujithf1dc5602008-10-29 10:16:30 +0530469
Sujithcbe61d82009-02-09 13:27:12 +0530470void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
Sujithf1dc5602008-10-29 10:16:30 +0530471{
472 struct ar5416_desc *ads = AR5416DESC(ds);
473
474 ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
475}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400476EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
Sujithf1dc5602008-10-29 10:16:30 +0530477
Sujithcbe61d82009-02-09 13:27:12 +0530478void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530479 u32 burstDuration)
480{
481 struct ar5416_desc *ads = AR5416DESC(ds);
482
483 ads->ds_ctl2 &= ~AR_BurstDur;
484 ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
485}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400486EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
Sujithf1dc5602008-10-29 10:16:30 +0530487
Sujithcbe61d82009-02-09 13:27:12 +0530488void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530489 u32 vmf)
490{
491 struct ar5416_desc *ads = AR5416DESC(ds);
492
493 if (vmf)
494 ads->ds_ctl0 |= AR_VirtMoreFrag;
495 else
496 ads->ds_ctl0 &= ~AR_VirtMoreFrag;
497}
498
Sujithcbe61d82009-02-09 13:27:12 +0530499void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
Sujithf1dc5602008-10-29 10:16:30 +0530500{
Sujith2660b812009-02-09 13:27:26 +0530501 *txqs &= ah->intr_txqs;
502 ah->intr_txqs &= ~(*txqs);
Sujithf1dc5602008-10-29 10:16:30 +0530503}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400504EXPORT_SYMBOL(ath9k_hw_gettxintrtxqs);
Sujithf1dc5602008-10-29 10:16:30 +0530505
Sujithcbe61d82009-02-09 13:27:12 +0530506bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530507 const struct ath9k_tx_queue_info *qinfo)
508{
509 u32 cw;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700510 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530511 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530512 struct ath9k_tx_queue_info *qi;
513
514 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700515 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
516 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530517 return false;
518 }
519
Sujith2660b812009-02-09 13:27:26 +0530520 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530521 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700522 ath_print(common, ATH_DBG_QUEUE, "Set TXQ properties, "
523 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530524 return false;
525 }
526
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700527 ath_print(common, ATH_DBG_QUEUE, "Set queue properties for: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530528
529 qi->tqi_ver = qinfo->tqi_ver;
530 qi->tqi_subtype = qinfo->tqi_subtype;
531 qi->tqi_qflags = qinfo->tqi_qflags;
532 qi->tqi_priority = qinfo->tqi_priority;
533 if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
534 qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
535 else
536 qi->tqi_aifs = INIT_AIFS;
537 if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
538 cw = min(qinfo->tqi_cwmin, 1024U);
539 qi->tqi_cwmin = 1;
540 while (qi->tqi_cwmin < cw)
541 qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
542 } else
543 qi->tqi_cwmin = qinfo->tqi_cwmin;
544 if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
545 cw = min(qinfo->tqi_cwmax, 1024U);
546 qi->tqi_cwmax = 1;
547 while (qi->tqi_cwmax < cw)
548 qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
549 } else
550 qi->tqi_cwmax = INIT_CWMAX;
551
552 if (qinfo->tqi_shretry != 0)
553 qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
554 else
555 qi->tqi_shretry = INIT_SH_RETRY;
556 if (qinfo->tqi_lgretry != 0)
557 qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
558 else
559 qi->tqi_lgretry = INIT_LG_RETRY;
560 qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
561 qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
562 qi->tqi_burstTime = qinfo->tqi_burstTime;
563 qi->tqi_readyTime = qinfo->tqi_readyTime;
564
565 switch (qinfo->tqi_subtype) {
566 case ATH9K_WME_UPSD:
567 if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
568 qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
569 break;
570 default:
571 break;
572 }
573
574 return true;
575}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400576EXPORT_SYMBOL(ath9k_hw_set_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530577
Sujithcbe61d82009-02-09 13:27:12 +0530578bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
Sujithf1dc5602008-10-29 10:16:30 +0530579 struct ath9k_tx_queue_info *qinfo)
580{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700581 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530582 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530583 struct ath9k_tx_queue_info *qi;
584
585 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700586 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
587 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530588 return false;
589 }
590
Sujith2660b812009-02-09 13:27:26 +0530591 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530592 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700593 ath_print(common, ATH_DBG_QUEUE, "Get TXQ properties, "
594 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530595 return false;
596 }
597
598 qinfo->tqi_qflags = qi->tqi_qflags;
599 qinfo->tqi_ver = qi->tqi_ver;
600 qinfo->tqi_subtype = qi->tqi_subtype;
601 qinfo->tqi_qflags = qi->tqi_qflags;
602 qinfo->tqi_priority = qi->tqi_priority;
603 qinfo->tqi_aifs = qi->tqi_aifs;
604 qinfo->tqi_cwmin = qi->tqi_cwmin;
605 qinfo->tqi_cwmax = qi->tqi_cwmax;
606 qinfo->tqi_shretry = qi->tqi_shretry;
607 qinfo->tqi_lgretry = qi->tqi_lgretry;
608 qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
609 qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
610 qinfo->tqi_burstTime = qi->tqi_burstTime;
611 qinfo->tqi_readyTime = qi->tqi_readyTime;
612
613 return true;
614}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400615EXPORT_SYMBOL(ath9k_hw_get_txq_props);
Sujithf1dc5602008-10-29 10:16:30 +0530616
Sujithcbe61d82009-02-09 13:27:12 +0530617int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
Sujithf1dc5602008-10-29 10:16:30 +0530618 const struct ath9k_tx_queue_info *qinfo)
619{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700620 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530621 struct ath9k_tx_queue_info *qi;
Sujith2660b812009-02-09 13:27:26 +0530622 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530623 int q;
624
625 switch (type) {
626 case ATH9K_TX_QUEUE_BEACON:
627 q = pCap->total_queues - 1;
628 break;
629 case ATH9K_TX_QUEUE_CAB:
630 q = pCap->total_queues - 2;
631 break;
632 case ATH9K_TX_QUEUE_PSPOLL:
633 q = 1;
634 break;
635 case ATH9K_TX_QUEUE_UAPSD:
636 q = pCap->total_queues - 3;
637 break;
638 case ATH9K_TX_QUEUE_DATA:
639 for (q = 0; q < pCap->total_queues; q++)
Sujith2660b812009-02-09 13:27:26 +0530640 if (ah->txq[q].tqi_type ==
Sujithf1dc5602008-10-29 10:16:30 +0530641 ATH9K_TX_QUEUE_INACTIVE)
642 break;
643 if (q == pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700644 ath_print(common, ATH_DBG_FATAL,
645 "No available TX queue\n");
Sujithf1dc5602008-10-29 10:16:30 +0530646 return -1;
647 }
648 break;
649 default:
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700650 ath_print(common, ATH_DBG_FATAL,
651 "Invalid TX queue type: %u\n", type);
Sujithf1dc5602008-10-29 10:16:30 +0530652 return -1;
653 }
654
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700655 ath_print(common, ATH_DBG_QUEUE, "Setup TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530656
Sujith2660b812009-02-09 13:27:26 +0530657 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530658 if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700659 ath_print(common, ATH_DBG_FATAL,
660 "TX queue: %u already active\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530661 return -1;
662 }
663 memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
664 qi->tqi_type = type;
665 if (qinfo == NULL) {
666 qi->tqi_qflags =
667 TXQ_FLAG_TXOKINT_ENABLE
668 | TXQ_FLAG_TXERRINT_ENABLE
669 | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
670 qi->tqi_aifs = INIT_AIFS;
671 qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
672 qi->tqi_cwmax = INIT_CWMAX;
673 qi->tqi_shretry = INIT_SH_RETRY;
674 qi->tqi_lgretry = INIT_LG_RETRY;
675 qi->tqi_physCompBuf = 0;
676 } else {
677 qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
678 (void) ath9k_hw_set_txq_props(ah, q, qinfo);
679 }
680
681 return q;
682}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400683EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530684
Sujithcbe61d82009-02-09 13:27:12 +0530685bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530686{
Sujith2660b812009-02-09 13:27:26 +0530687 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700688 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530689 struct ath9k_tx_queue_info *qi;
690
691 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700692 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
693 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530694 return false;
695 }
Sujith2660b812009-02-09 13:27:26 +0530696 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530697 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700698 ath_print(common, ATH_DBG_QUEUE, "Release TXQ, "
699 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530700 return false;
701 }
702
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700703 ath_print(common, ATH_DBG_QUEUE, "Release TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530704
705 qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
Sujith2660b812009-02-09 13:27:26 +0530706 ah->txok_interrupt_mask &= ~(1 << q);
707 ah->txerr_interrupt_mask &= ~(1 << q);
708 ah->txdesc_interrupt_mask &= ~(1 << q);
709 ah->txeol_interrupt_mask &= ~(1 << q);
710 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530711 ath9k_hw_set_txq_interrupts(ah, qi);
712
713 return true;
714}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400715EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530716
Sujithcbe61d82009-02-09 13:27:12 +0530717bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
Sujithf1dc5602008-10-29 10:16:30 +0530718{
Sujith2660b812009-02-09 13:27:26 +0530719 struct ath9k_hw_capabilities *pCap = &ah->caps;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700720 struct ath_common *common = ath9k_hw_common(ah);
Sujith2660b812009-02-09 13:27:26 +0530721 struct ath9k_channel *chan = ah->curchan;
Sujithf1dc5602008-10-29 10:16:30 +0530722 struct ath9k_tx_queue_info *qi;
723 u32 cwMin, chanCwMin, value;
724
725 if (q >= pCap->total_queues) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700726 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
727 "invalid queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530728 return false;
729 }
730
Sujith2660b812009-02-09 13:27:26 +0530731 qi = &ah->txq[q];
Sujithf1dc5602008-10-29 10:16:30 +0530732 if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700733 ath_print(common, ATH_DBG_QUEUE, "Reset TXQ, "
734 "inactive queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530735 return true;
736 }
737
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700738 ath_print(common, ATH_DBG_QUEUE, "Reset TX queue: %u\n", q);
Sujithf1dc5602008-10-29 10:16:30 +0530739
740 if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
741 if (chan && IS_CHAN_B(chan))
742 chanCwMin = INIT_CWMIN_11B;
743 else
744 chanCwMin = INIT_CWMIN;
745
746 for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
747 } else
748 cwMin = qi->tqi_cwmin;
749
750 REG_WRITE(ah, AR_DLCL_IFS(q),
751 SM(cwMin, AR_D_LCL_IFS_CWMIN) |
752 SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
753 SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
754
755 REG_WRITE(ah, AR_DRETRY_LIMIT(q),
756 SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
757 SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
758 SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
759
760 REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
761 REG_WRITE(ah, AR_DMISC(q),
762 AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
763
764 if (qi->tqi_cbrPeriod) {
765 REG_WRITE(ah, AR_QCBRCFG(q),
766 SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
767 SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
768 REG_WRITE(ah, AR_QMISC(q),
769 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
770 (qi->tqi_cbrOverflowLimit ?
771 AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
772 }
773 if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
774 REG_WRITE(ah, AR_QRDYTIMECFG(q),
775 SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
776 AR_Q_RDYTIMECFG_EN);
777 }
778
779 REG_WRITE(ah, AR_DCHNTIME(q),
780 SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
781 (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
782
783 if (qi->tqi_burstTime
784 && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
785 REG_WRITE(ah, AR_QMISC(q),
786 REG_READ(ah, AR_QMISC(q)) |
787 AR_Q_MISC_RDYTIME_EXP_POLICY);
788
789 }
790
791 if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
792 REG_WRITE(ah, AR_DMISC(q),
793 REG_READ(ah, AR_DMISC(q)) |
794 AR_D_MISC_POST_FR_BKOFF_DIS);
795 }
796 if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
797 REG_WRITE(ah, AR_DMISC(q),
798 REG_READ(ah, AR_DMISC(q)) |
799 AR_D_MISC_FRAG_BKOFF_EN);
800 }
801 switch (qi->tqi_type) {
802 case ATH9K_TX_QUEUE_BEACON:
803 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
804 | AR_Q_MISC_FSP_DBA_GATED
805 | AR_Q_MISC_BEACON_USE
806 | AR_Q_MISC_CBR_INCR_DIS1);
807
808 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
809 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
810 AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
811 | AR_D_MISC_BEACON_USE
812 | AR_D_MISC_POST_FR_BKOFF_DIS);
813 break;
814 case ATH9K_TX_QUEUE_CAB:
815 REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
816 | AR_Q_MISC_FSP_DBA_GATED
817 | AR_Q_MISC_CBR_INCR_DIS1
818 | AR_Q_MISC_CBR_INCR_DIS0);
819 value = (qi->tqi_readyTime -
Sujith2660b812009-02-09 13:27:26 +0530820 (ah->config.sw_beacon_response_time -
821 ah->config.dma_beacon_response_time) -
822 ah->config.additional_swba_backoff) * 1024;
Sujithf1dc5602008-10-29 10:16:30 +0530823 REG_WRITE(ah, AR_QRDYTIMECFG(q),
824 value | AR_Q_RDYTIMECFG_EN);
825 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
826 | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
827 AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
828 break;
829 case ATH9K_TX_QUEUE_PSPOLL:
830 REG_WRITE(ah, AR_QMISC(q),
831 REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
832 break;
833 case ATH9K_TX_QUEUE_UAPSD:
834 REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
835 AR_D_MISC_POST_FR_BKOFF_DIS);
836 break;
837 default:
838 break;
839 }
840
841 if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
842 REG_WRITE(ah, AR_DMISC(q),
843 REG_READ(ah, AR_DMISC(q)) |
844 SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
845 AR_D_MISC_ARB_LOCKOUT_CNTRL) |
846 AR_D_MISC_POST_FR_BKOFF_DIS);
847 }
848
849 if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530850 ah->txok_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530851 else
Sujith2660b812009-02-09 13:27:26 +0530852 ah->txok_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530853 if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530854 ah->txerr_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530855 else
Sujith2660b812009-02-09 13:27:26 +0530856 ah->txerr_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530857 if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530858 ah->txdesc_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530859 else
Sujith2660b812009-02-09 13:27:26 +0530860 ah->txdesc_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530861 if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530862 ah->txeol_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530863 else
Sujith2660b812009-02-09 13:27:26 +0530864 ah->txeol_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530865 if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
Sujith2660b812009-02-09 13:27:26 +0530866 ah->txurn_interrupt_mask |= 1 << q;
Sujithf1dc5602008-10-29 10:16:30 +0530867 else
Sujith2660b812009-02-09 13:27:26 +0530868 ah->txurn_interrupt_mask &= ~(1 << q);
Sujithf1dc5602008-10-29 10:16:30 +0530869 ath9k_hw_set_txq_interrupts(ah, qi);
870
871 return true;
872}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400873EXPORT_SYMBOL(ath9k_hw_resettxqueue);
Sujithf1dc5602008-10-29 10:16:30 +0530874
Sujithcbe61d82009-02-09 13:27:12 +0530875int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700876 struct ath_rx_status *rs, u64 tsf)
Sujithf1dc5602008-10-29 10:16:30 +0530877{
878 struct ar5416_desc ads;
879 struct ar5416_desc *adsp = AR5416DESC(ds);
880 u32 phyerr;
881
882 if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
883 return -EINPROGRESS;
884
885 ads.u.rx = adsp->u.rx;
886
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700887 rs->rs_status = 0;
888 rs->rs_flags = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530889
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700890 rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
891 rs->rs_tstamp = ads.AR_RcvTimestamp;
Sujithf1dc5602008-10-29 10:16:30 +0530892
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400893 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700894 rs->rs_rssi = ATH9K_RSSI_BAD;
895 rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
896 rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
897 rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
898 rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
899 rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
900 rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400901 } else {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700902 rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
903 rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400904 AR_RxRSSIAnt00);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700905 rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400906 AR_RxRSSIAnt01);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700907 rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400908 AR_RxRSSIAnt02);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700909 rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400910 AR_RxRSSIAnt10);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700911 rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400912 AR_RxRSSIAnt11);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700913 rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
Senthil Balasubramaniandd8b15b2009-07-14 20:17:08 -0400914 AR_RxRSSIAnt12);
915 }
Sujithf1dc5602008-10-29 10:16:30 +0530916 if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700917 rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
Sujithf1dc5602008-10-29 10:16:30 +0530918 else
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700919 rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
Sujithf1dc5602008-10-29 10:16:30 +0530920
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700921 rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
922 rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
Sujithf1dc5602008-10-29 10:16:30 +0530923
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700924 rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
925 rs->rs_moreaggr =
Sujithf1dc5602008-10-29 10:16:30 +0530926 (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700927 rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
928 rs->rs_flags =
Sujithf1dc5602008-10-29 10:16:30 +0530929 (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700930 rs->rs_flags |=
Sujithf1dc5602008-10-29 10:16:30 +0530931 (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
932
933 if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700934 rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
Sujithf1dc5602008-10-29 10:16:30 +0530935 if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700936 rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
Sujithf1dc5602008-10-29 10:16:30 +0530937 if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700938 rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
Sujithf1dc5602008-10-29 10:16:30 +0530939
940 if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
941 if (ads.ds_rxstatus8 & AR_CRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700942 rs->rs_status |= ATH9K_RXERR_CRC;
Sujithf1dc5602008-10-29 10:16:30 +0530943 else if (ads.ds_rxstatus8 & AR_PHYErr) {
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700944 rs->rs_status |= ATH9K_RXERR_PHY;
Sujithf1dc5602008-10-29 10:16:30 +0530945 phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700946 rs->rs_phyerr = phyerr;
Sujithf1dc5602008-10-29 10:16:30 +0530947 } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700948 rs->rs_status |= ATH9K_RXERR_DECRYPT;
Sujithf1dc5602008-10-29 10:16:30 +0530949 else if (ads.ds_rxstatus8 & AR_MichaelErr)
Felix Fietkau8e6f5aa2010-03-29 20:09:27 -0700950 rs->rs_status |= ATH9K_RXERR_MIC;
Sujithf1dc5602008-10-29 10:16:30 +0530951 }
952
953 return 0;
954}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400955EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530956
Sujith54e4cec2009-08-07 09:45:09 +0530957void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
Sujithf1dc5602008-10-29 10:16:30 +0530958 u32 size, u32 flags)
959{
960 struct ar5416_desc *ads = AR5416DESC(ds);
Sujith2660b812009-02-09 13:27:26 +0530961 struct ath9k_hw_capabilities *pCap = &ah->caps;
Sujithf1dc5602008-10-29 10:16:30 +0530962
963 ads->ds_ctl1 = size & AR_BufLen;
964 if (flags & ATH9K_RXDESC_INTREQ)
965 ads->ds_ctl1 |= AR_RxIntrReq;
966
967 ads->ds_rxstatus8 &= ~AR_RxDone;
968 if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
969 memset(&(ads->u), 0, sizeof(ads->u));
Sujithf1dc5602008-10-29 10:16:30 +0530970}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400971EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
Sujithf1dc5602008-10-29 10:16:30 +0530972
Luis R. Rodrigueze7824a52009-11-24 02:53:25 -0500973/*
974 * This can stop or re-enables RX.
975 *
976 * If bool is set this will kill any frame which is currently being
977 * transferred between the MAC and baseband and also prevent any new
978 * frames from getting started.
979 */
Sujithcbe61d82009-02-09 13:27:12 +0530980bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
Sujithf1dc5602008-10-29 10:16:30 +0530981{
982 u32 reg;
983
984 if (set) {
985 REG_SET_BIT(ah, AR_DIAG_SW,
986 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
987
Sujith0caa7b12009-02-16 13:23:20 +0530988 if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
989 0, AH_WAIT_TIMEOUT)) {
Sujithf1dc5602008-10-29 10:16:30 +0530990 REG_CLR_BIT(ah, AR_DIAG_SW,
991 (AR_DIAG_RX_DIS |
992 AR_DIAG_RX_ABORT));
993
994 reg = REG_READ(ah, AR_OBS_BUS_1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700995 ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
996 "RX failed to go idle in 10 ms RXSM=0x%x\n",
997 reg);
Sujithf1dc5602008-10-29 10:16:30 +0530998
999 return false;
1000 }
1001 } else {
1002 REG_CLR_BIT(ah, AR_DIAG_SW,
1003 (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
1004 }
1005
1006 return true;
1007}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001008EXPORT_SYMBOL(ath9k_hw_setrxabort);
Sujithf1dc5602008-10-29 10:16:30 +05301009
Sujithcbe61d82009-02-09 13:27:12 +05301010void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
Sujithf1dc5602008-10-29 10:16:30 +05301011{
1012 REG_WRITE(ah, AR_RXDP, rxdp);
1013}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001014EXPORT_SYMBOL(ath9k_hw_putrxbuf);
Sujithf1dc5602008-10-29 10:16:30 +05301015
Sujithcbe61d82009-02-09 13:27:12 +05301016void ath9k_hw_startpcureceive(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301017{
Sujithf1dc5602008-10-29 10:16:30 +05301018 ath9k_enable_mib_counters(ah);
1019
1020 ath9k_ani_reset(ah);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +05301021
Senthil Balasubramanian8aa15e12008-12-08 19:43:50 +05301022 REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
Sujithf1dc5602008-10-29 10:16:30 +05301023}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001024EXPORT_SYMBOL(ath9k_hw_startpcureceive);
Sujithf1dc5602008-10-29 10:16:30 +05301025
Sujithcbe61d82009-02-09 13:27:12 +05301026void ath9k_hw_stoppcurecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301027{
1028 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
1029
1030 ath9k_hw_disable_mib_counters(ah);
1031}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001032EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
Sujithf1dc5602008-10-29 10:16:30 +05301033
Sujithcbe61d82009-02-09 13:27:12 +05301034bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +05301035{
Sujith0caa7b12009-02-16 13:23:20 +05301036#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
1037#define AH_RX_TIME_QUANTUM 100 /* usec */
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001038 struct ath_common *common = ath9k_hw_common(ah);
Sujith0caa7b12009-02-16 13:23:20 +05301039 int i;
1040
Sujithf1dc5602008-10-29 10:16:30 +05301041 REG_WRITE(ah, AR_CR, AR_CR_RXD);
1042
Sujith0caa7b12009-02-16 13:23:20 +05301043 /* Wait for rx enable bit to go low */
1044 for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
1045 if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
1046 break;
1047 udelay(AH_TIME_QUANTUM);
1048 }
1049
1050 if (i == 0) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001051 ath_print(common, ATH_DBG_FATAL,
1052 "DMA failed to stop in %d ms "
1053 "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
1054 AH_RX_STOP_DMA_TIMEOUT / 1000,
1055 REG_READ(ah, AR_CR),
1056 REG_READ(ah, AR_DIAG_SW));
Sujithf1dc5602008-10-29 10:16:30 +05301057 return false;
1058 } else {
1059 return true;
1060 }
Sujith0caa7b12009-02-16 13:23:20 +05301061
1062#undef AH_RX_TIME_QUANTUM
1063#undef AH_RX_STOP_DMA_TIMEOUT
Sujithf1dc5602008-10-29 10:16:30 +05301064}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001065EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
Luis R. Rodriguez536b3a72009-10-06 21:19:11 -04001066
1067int ath9k_hw_beaconq_setup(struct ath_hw *ah)
1068{
1069 struct ath9k_tx_queue_info qi;
1070
1071 memset(&qi, 0, sizeof(qi));
1072 qi.tqi_aifs = 1;
1073 qi.tqi_cwmin = 0;
1074 qi.tqi_cwmax = 0;
1075 /* NB: don't enable any interrupts */
1076 return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
1077}
1078EXPORT_SYMBOL(ath9k_hw_beaconq_setup);