Commit | Line | Data |
---|---|---|
ae3bb6d4 | 1 | /* |
5b68138e | 2 | * Copyright (c) 2010-2011 Atheros Communications Inc. |
ae3bb6d4 VT |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
ee40fa06 | 16 | #include <linux/export.h> |
ae3bb6d4 | 17 | #include "hw.h" |
b622a720 | 18 | #include "ar9003_mac.h" |
f4701b5a | 19 | #include "ar9003_mci.h" |
ae3bb6d4 VT |
20 | |
21 | static void ar9003_hw_rx_enable(struct ath_hw *hw) | |
22 | { | |
23 | REG_WRITE(hw, AR_CR, 0); | |
24 | } | |
25 | ||
2b63a41d FF |
26 | static void |
27 | ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |
28 | { | |
29 | struct ar9003_txc *ads = ds; | |
30 | int checksum = 0; | |
31 | u32 val, ctl12, ctl17; | |
9da27232 SM |
32 | u8 desc_len; |
33 | ||
34 | desc_len = (AR_SREV_9462(ah) ? 0x18 : 0x17); | |
2b63a41d FF |
35 | |
36 | val = (ATHEROS_VENDOR_ID << AR_DescId_S) | | |
37 | (1 << AR_TxRxDesc_S) | | |
38 | (1 << AR_CtrlStat_S) | | |
9da27232 | 39 | (i->qcu << AR_TxQcuNum_S) | desc_len; |
2b63a41d FF |
40 | |
41 | checksum += val; | |
42 | ACCESS_ONCE(ads->info) = val; | |
43 | ||
44 | checksum += i->link; | |
45 | ACCESS_ONCE(ads->link) = i->link; | |
46 | ||
47 | checksum += i->buf_addr[0]; | |
48 | ACCESS_ONCE(ads->data0) = i->buf_addr[0]; | |
49 | checksum += i->buf_addr[1]; | |
50 | ACCESS_ONCE(ads->data1) = i->buf_addr[1]; | |
51 | checksum += i->buf_addr[2]; | |
52 | ACCESS_ONCE(ads->data2) = i->buf_addr[2]; | |
53 | checksum += i->buf_addr[3]; | |
54 | ACCESS_ONCE(ads->data3) = i->buf_addr[3]; | |
55 | ||
56 | checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen); | |
57 | ACCESS_ONCE(ads->ctl3) = val; | |
58 | checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen); | |
59 | ACCESS_ONCE(ads->ctl5) = val; | |
60 | checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen); | |
61 | ACCESS_ONCE(ads->ctl7) = val; | |
62 | checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen); | |
63 | ACCESS_ONCE(ads->ctl9) = val; | |
64 | ||
65 | checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff); | |
66 | ACCESS_ONCE(ads->ctl10) = checksum; | |
67 | ||
68 | if (i->is_first || i->is_last) { | |
69 | ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0) | |
70 | | set11nTries(i->rates, 1) | |
71 | | set11nTries(i->rates, 2) | |
72 | | set11nTries(i->rates, 3) | |
73 | | (i->dur_update ? AR_DurUpdateEna : 0) | |
74 | | SM(0, AR_BurstDur); | |
75 | ||
76 | ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0) | |
77 | | set11nRate(i->rates, 1) | |
78 | | set11nRate(i->rates, 2) | |
79 | | set11nRate(i->rates, 3); | |
80 | } else { | |
81 | ACCESS_ONCE(ads->ctl13) = 0; | |
82 | ACCESS_ONCE(ads->ctl14) = 0; | |
83 | } | |
84 | ||
85 | ads->ctl20 = 0; | |
86 | ads->ctl21 = 0; | |
87 | ads->ctl22 = 0; | |
9da27232 | 88 | ads->ctl23 = 0; |
2b63a41d FF |
89 | |
90 | ctl17 = SM(i->keytype, AR_EncrType); | |
91 | if (!i->is_first) { | |
92 | ACCESS_ONCE(ads->ctl11) = 0; | |
93 | ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore; | |
94 | ACCESS_ONCE(ads->ctl15) = 0; | |
95 | ACCESS_ONCE(ads->ctl16) = 0; | |
96 | ACCESS_ONCE(ads->ctl17) = ctl17; | |
97 | ACCESS_ONCE(ads->ctl18) = 0; | |
98 | ACCESS_ONCE(ads->ctl19) = 0; | |
99 | return; | |
100 | } | |
101 | ||
102 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) | |
103 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | |
104 | | SM(i->txpower, AR_XmitPower) | |
105 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | |
106 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | |
107 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) | |
108 | | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | |
109 | | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : | |
110 | (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0)); | |
111 | ||
112 | ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ? | |
113 | SM(i->keyix, AR_DestIdx) : 0) | |
114 | | SM(i->type, AR_FrameType) | |
115 | | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) | |
116 | | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) | |
117 | | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); | |
118 | ||
119 | ctl17 |= (i->flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); | |
120 | switch (i->aggr) { | |
121 | case AGGR_BUF_FIRST: | |
122 | ctl17 |= SM(i->aggr_len, AR_AggrLen); | |
123 | /* fall through */ | |
124 | case AGGR_BUF_MIDDLE: | |
125 | ctl12 |= AR_IsAggr | AR_MoreAggr; | |
126 | ctl17 |= SM(i->ndelim, AR_PadDelim); | |
127 | break; | |
128 | case AGGR_BUF_LAST: | |
129 | ctl12 |= AR_IsAggr; | |
130 | break; | |
131 | case AGGR_BUF_NONE: | |
132 | break; | |
133 | } | |
134 | ||
135 | val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S; | |
136 | ctl12 |= SM(val, AR_PAPRDChainMask); | |
137 | ||
138 | ACCESS_ONCE(ads->ctl12) = ctl12; | |
139 | ACCESS_ONCE(ads->ctl17) = ctl17; | |
140 | ||
141 | ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) | |
142 | | set11nPktDurRTSCTS(i->rates, 1); | |
143 | ||
144 | ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2) | |
145 | | set11nPktDurRTSCTS(i->rates, 3); | |
146 | ||
147 | ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0) | |
148 | | set11nRateFlags(i->rates, 1) | |
149 | | set11nRateFlags(i->rates, 2) | |
150 | | set11nRateFlags(i->rates, 3) | |
151 | | SM(i->rtscts_rate, AR_RTSCTSRate); | |
152 | ||
153 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; | |
154 | } | |
155 | ||
eb823253 VT |
156 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) |
157 | { | |
158 | int checksum; | |
159 | ||
160 | checksum = ads->info + ads->link | |
161 | + ads->data0 + ads->ctl3 | |
162 | + ads->data1 + ads->ctl5 | |
163 | + ads->data2 + ads->ctl7 | |
164 | + ads->data3 + ads->ctl9; | |
165 | ||
166 | return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum; | |
167 | } | |
168 | ||
87d5efbb VT |
169 | static void ar9003_hw_set_desc_link(void *ds, u32 ds_link) |
170 | { | |
eb823253 VT |
171 | struct ar9003_txc *ads = ds; |
172 | ||
173 | ads->link = ds_link; | |
174 | ads->ctl10 &= ~AR_TxPtrChkSum; | |
175 | ads->ctl10 |= ar9003_calc_ptr_chksum(ads); | |
87d5efbb VT |
176 | } |
177 | ||
55e82df4 VT |
178 | static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) |
179 | { | |
6c84ce08 VT |
180 | u32 isr = 0; |
181 | u32 mask2 = 0; | |
182 | struct ath9k_hw_capabilities *pCap = &ah->caps; | |
6c84ce08 | 183 | struct ath_common *common = ath9k_hw_common(ah); |
4421d30f | 184 | u32 sync_cause = 0, async_cause; |
6c84ce08 | 185 | |
4421d30f MSS |
186 | async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); |
187 | ||
188 | if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) { | |
6c84ce08 VT |
189 | if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) |
190 | == AR_RTC_STATUS_ON) | |
191 | isr = REG_READ(ah, AR_ISR); | |
192 | } | |
193 | ||
4421d30f | 194 | |
6c84ce08 VT |
195 | sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; |
196 | ||
197 | *masked = 0; | |
198 | ||
93fdd594 | 199 | if (!isr && !sync_cause && !async_cause) |
6c84ce08 VT |
200 | return false; |
201 | ||
202 | if (isr) { | |
203 | if (isr & AR_ISR_BCNMISC) { | |
204 | u32 isr2; | |
205 | isr2 = REG_READ(ah, AR_ISR_S2); | |
206 | ||
207 | mask2 |= ((isr2 & AR_ISR_S2_TIM) >> | |
208 | MAP_ISR_S2_TIM); | |
209 | mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> | |
210 | MAP_ISR_S2_DTIM); | |
211 | mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> | |
212 | MAP_ISR_S2_DTIMSYNC); | |
213 | mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> | |
214 | MAP_ISR_S2_CABEND); | |
215 | mask2 |= ((isr2 & AR_ISR_S2_GTT) << | |
216 | MAP_ISR_S2_GTT); | |
217 | mask2 |= ((isr2 & AR_ISR_S2_CST) << | |
218 | MAP_ISR_S2_CST); | |
219 | mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> | |
220 | MAP_ISR_S2_TSFOOR); | |
aea702b7 LR |
221 | mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >> |
222 | MAP_ISR_S2_BB_WATCHDOG); | |
6c84ce08 VT |
223 | |
224 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
225 | REG_WRITE(ah, AR_ISR_S2, isr2); | |
226 | isr &= ~AR_ISR_BCNMISC; | |
227 | } | |
228 | } | |
229 | ||
230 | if ((pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) | |
231 | isr = REG_READ(ah, AR_ISR_RAC); | |
232 | ||
233 | if (isr == 0xffffffff) { | |
234 | *masked = 0; | |
235 | return false; | |
236 | } | |
237 | ||
238 | *masked = isr & ATH9K_INT_COMMON; | |
239 | ||
240 | if (ah->config.rx_intr_mitigation) | |
241 | if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) | |
242 | *masked |= ATH9K_INT_RXLP; | |
243 | ||
244 | if (ah->config.tx_intr_mitigation) | |
245 | if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) | |
246 | *masked |= ATH9K_INT_TX; | |
247 | ||
248 | if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) | |
249 | *masked |= ATH9K_INT_RXLP; | |
250 | ||
251 | if (isr & AR_ISR_HP_RXOK) | |
252 | *masked |= ATH9K_INT_RXHP; | |
253 | ||
254 | if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) { | |
255 | *masked |= ATH9K_INT_TX; | |
256 | ||
257 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
258 | u32 s0, s1; | |
259 | s0 = REG_READ(ah, AR_ISR_S0); | |
260 | REG_WRITE(ah, AR_ISR_S0, s0); | |
261 | s1 = REG_READ(ah, AR_ISR_S1); | |
262 | REG_WRITE(ah, AR_ISR_S1, s1); | |
263 | ||
264 | isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | | |
265 | AR_ISR_TXEOL); | |
266 | } | |
267 | } | |
268 | ||
269 | if (isr & AR_ISR_GENTMR) { | |
270 | u32 s5; | |
271 | ||
272 | if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) | |
273 | s5 = REG_READ(ah, AR_ISR_S5_S); | |
274 | else | |
275 | s5 = REG_READ(ah, AR_ISR_S5); | |
276 | ||
277 | ah->intr_gen_timer_trigger = | |
278 | MS(s5, AR_ISR_S5_GENTIMER_TRIG); | |
279 | ||
280 | ah->intr_gen_timer_thresh = | |
281 | MS(s5, AR_ISR_S5_GENTIMER_THRESH); | |
282 | ||
283 | if (ah->intr_gen_timer_trigger) | |
284 | *masked |= ATH9K_INT_GENTIMER; | |
285 | ||
286 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
287 | REG_WRITE(ah, AR_ISR_S5, s5); | |
288 | isr &= ~AR_ISR_GENTMR; | |
289 | } | |
290 | ||
291 | } | |
292 | ||
293 | *masked |= mask2; | |
294 | ||
295 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
296 | REG_WRITE(ah, AR_ISR, isr); | |
297 | ||
298 | (void) REG_READ(ah, AR_ISR); | |
299 | } | |
aea702b7 LR |
300 | |
301 | if (*masked & ATH9K_INT_BB_WATCHDOG) | |
302 | ar9003_hw_bb_watchdog_read(ah); | |
6c84ce08 VT |
303 | } |
304 | ||
5a1e2735 SM |
305 | if (async_cause & AR_INTR_ASYNC_MASK_MCI) |
306 | ar9003_mci_get_isr(ah, masked); | |
cc78d6b1 | 307 | |
6c84ce08 VT |
308 | if (sync_cause) { |
309 | if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { | |
310 | REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); | |
311 | REG_WRITE(ah, AR_RC, 0); | |
312 | *masked |= ATH9K_INT_FATAL; | |
313 | } | |
314 | ||
315 | if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) | |
d2182b69 | 316 | ath_dbg(common, INTERRUPT, |
226afe68 | 317 | "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); |
6c84ce08 | 318 | |
6fe14002 | 319 | REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); |
6c84ce08 VT |
320 | (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); |
321 | ||
322 | } | |
55e82df4 VT |
323 | return true; |
324 | } | |
325 | ||
cc610ac0 VT |
326 | static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, |
327 | struct ath_tx_status *ts) | |
328 | { | |
994089db | 329 | struct ar9003_txs *ads; |
e0e9bc82 | 330 | u32 status; |
994089db VT |
331 | |
332 | ads = &ah->ts_ring[ah->ts_tail]; | |
333 | ||
e0e9bc82 FF |
334 | status = ACCESS_ONCE(ads->status8); |
335 | if ((status & AR_TxDone) == 0) | |
994089db VT |
336 | return -EINPROGRESS; |
337 | ||
d6157bf7 | 338 | ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; |
994089db VT |
339 | |
340 | if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || | |
341 | (MS(ads->ds_info, AR_TxRxDesc) != 1)) { | |
d2182b69 | 342 | ath_dbg(ath9k_hw_common(ah), XMIT, |
226afe68 | 343 | "Tx Descriptor error %x\n", ads->ds_info); |
994089db VT |
344 | memset(ads, 0, sizeof(*ads)); |
345 | return -EIO; | |
346 | } | |
347 | ||
e0e9bc82 FF |
348 | ts->ts_rateindex = MS(status, AR_FinalTxIdx); |
349 | ts->ts_seqnum = MS(status, AR_SeqNum); | |
350 | ts->tid = MS(status, AR_TxTid); | |
351 | ||
d6157bf7 | 352 | ts->qid = MS(ads->ds_info, AR_TxQcuNum); |
994089db | 353 | ts->desc_id = MS(ads->status1, AR_TxDescId); |
994089db VT |
354 | ts->ts_tstamp = ads->status4; |
355 | ts->ts_status = 0; | |
356 | ts->ts_flags = 0; | |
357 | ||
2a15b394 RM |
358 | if (status & AR_TxOpExceeded) |
359 | ts->ts_status |= ATH9K_TXERR_XTXOP; | |
e0e9bc82 FF |
360 | status = ACCESS_ONCE(ads->status2); |
361 | ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); | |
362 | ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); | |
363 | ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); | |
364 | if (status & AR_TxBaStatus) { | |
365 | ts->ts_flags |= ATH9K_TX_BA; | |
366 | ts->ba_low = ads->status5; | |
367 | ts->ba_high = ads->status6; | |
368 | } | |
369 | ||
370 | status = ACCESS_ONCE(ads->status3); | |
371 | if (status & AR_ExcessiveRetries) | |
994089db | 372 | ts->ts_status |= ATH9K_TXERR_XRETRY; |
e0e9bc82 | 373 | if (status & AR_Filtered) |
994089db | 374 | ts->ts_status |= ATH9K_TXERR_FILT; |
e0e9bc82 | 375 | if (status & AR_FIFOUnderrun) { |
994089db VT |
376 | ts->ts_status |= ATH9K_TXERR_FIFO; |
377 | ath9k_hw_updatetxtriglevel(ah, true); | |
378 | } | |
e0e9bc82 | 379 | if (status & AR_TxTimerExpired) |
994089db | 380 | ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; |
e0e9bc82 | 381 | if (status & AR_DescCfgErr) |
994089db | 382 | ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; |
e0e9bc82 | 383 | if (status & AR_TxDataUnderrun) { |
994089db VT |
384 | ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; |
385 | ath9k_hw_updatetxtriglevel(ah, true); | |
386 | } | |
e0e9bc82 | 387 | if (status & AR_TxDelimUnderrun) { |
994089db VT |
388 | ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; |
389 | ath9k_hw_updatetxtriglevel(ah, true); | |
390 | } | |
e0e9bc82 FF |
391 | ts->ts_shortretry = MS(status, AR_RTSFailCnt); |
392 | ts->ts_longretry = MS(status, AR_DataFailCnt); | |
393 | ts->ts_virtcol = MS(status, AR_VirtRetryCnt); | |
394 | ||
395 | status = ACCESS_ONCE(ads->status7); | |
396 | ts->ts_rssi = MS(status, AR_TxRSSICombined); | |
397 | ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); | |
398 | ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); | |
399 | ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); | |
994089db VT |
400 | |
401 | memset(ads, 0, sizeof(*ads)); | |
402 | ||
cc610ac0 VT |
403 | return 0; |
404 | } | |
994089db | 405 | |
ae3bb6d4 VT |
406 | void ar9003_hw_attach_mac_ops(struct ath_hw *hw) |
407 | { | |
408 | struct ath_hw_ops *ops = ath9k_hw_ops(hw); | |
409 | ||
410 | ops->rx_enable = ar9003_hw_rx_enable; | |
87d5efbb | 411 | ops->set_desc_link = ar9003_hw_set_desc_link; |
55e82df4 | 412 | ops->get_isr = ar9003_hw_get_isr; |
2b63a41d | 413 | ops->set_txdesc = ar9003_set_txdesc; |
cc610ac0 | 414 | ops->proc_txdesc = ar9003_hw_proc_txdesc; |
ae3bb6d4 | 415 | } |
ad7b8060 VT |
416 | |
417 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) | |
418 | { | |
419 | REG_WRITE(ah, AR_DATABUF_SIZE, buf_size & AR_DATABUF_SIZE_MASK); | |
420 | } | |
421 | EXPORT_SYMBOL(ath9k_hw_set_rx_bufsize); | |
422 | ||
423 | void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp, | |
424 | enum ath9k_rx_qtype qtype) | |
425 | { | |
426 | if (qtype == ATH9K_RX_QUEUE_HP) | |
427 | REG_WRITE(ah, AR_HP_RXDP, rxdp); | |
428 | else | |
429 | REG_WRITE(ah, AR_LP_RXDP, rxdp); | |
430 | } | |
431 | EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma); | |
432 | ||
433 | int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |
434 | void *buf_addr) | |
435 | { | |
436 | struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; | |
437 | unsigned int phyerr; | |
438 | ||
3a2923e8 FF |
439 | if ((rxsp->status11 & AR_RxDone) == 0) |
440 | return -EINPROGRESS; | |
ad7b8060 | 441 | |
3a2923e8 FF |
442 | if (MS(rxsp->ds_info, AR_DescId) != 0x168c) |
443 | return -EINVAL; | |
ad7b8060 | 444 | |
3a2923e8 FF |
445 | if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) |
446 | return -EINPROGRESS; | |
b5c80475 | 447 | |
ad7b8060 VT |
448 | rxs->rs_status = 0; |
449 | rxs->rs_flags = 0; | |
450 | ||
451 | rxs->rs_datalen = rxsp->status2 & AR_DataLen; | |
452 | rxs->rs_tstamp = rxsp->status3; | |
453 | ||
454 | /* XXX: Keycache */ | |
455 | rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); | |
456 | rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); | |
457 | rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); | |
458 | rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); | |
459 | rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); | |
460 | rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); | |
461 | rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); | |
462 | ||
463 | if (rxsp->status11 & AR_RxKeyIdxValid) | |
464 | rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); | |
465 | else | |
466 | rxs->rs_keyix = ATH9K_RXKEYIX_INVALID; | |
467 | ||
468 | rxs->rs_rate = MS(rxsp->status1, AR_RxRate); | |
469 | rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0; | |
470 | ||
471 | rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; | |
472 | rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; | |
473 | rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); | |
474 | rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; | |
475 | rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; | |
476 | ||
477 | rxs->evm0 = rxsp->status6; | |
478 | rxs->evm1 = rxsp->status7; | |
479 | rxs->evm2 = rxsp->status8; | |
480 | rxs->evm3 = rxsp->status9; | |
481 | rxs->evm4 = (rxsp->status10 & 0xffff); | |
482 | ||
483 | if (rxsp->status11 & AR_PreDelimCRCErr) | |
484 | rxs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; | |
485 | ||
486 | if (rxsp->status11 & AR_PostDelimCRCErr) | |
487 | rxs->rs_flags |= ATH9K_RX_DELIM_CRC_POST; | |
488 | ||
489 | if (rxsp->status11 & AR_DecryptBusyErr) | |
490 | rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; | |
491 | ||
492 | if ((rxsp->status11 & AR_RxFrameOK) == 0) { | |
9171acc7 LR |
493 | /* |
494 | * AR_CRCErr will bet set to true if we're on the last | |
495 | * subframe and the AR_PostDelimCRCErr is caught. | |
496 | * In a way this also gives us a guarantee that when | |
497 | * (!(AR_CRCErr) && (AR_PostDelimCRCErr)) we cannot | |
498 | * possibly be reviewing the last subframe. AR_CRCErr | |
499 | * is the CRC of the actual data. | |
500 | */ | |
1c30cc19 | 501 | if (rxsp->status11 & AR_CRCErr) |
ad7b8060 | 502 | rxs->rs_status |= ATH9K_RXERR_CRC; |
f4fb4b21 ZK |
503 | else if (rxsp->status11 & AR_DecryptCRCErr) |
504 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; | |
505 | else if (rxsp->status11 & AR_MichaelErr) | |
506 | rxs->rs_status |= ATH9K_RXERR_MIC; | |
507 | if (rxsp->status11 & AR_PHYErr) { | |
ad7b8060 | 508 | phyerr = MS(rxsp->status11, AR_PHYErrCode); |
9171acc7 LR |
509 | /* |
510 | * If we reach a point here where AR_PostDelimCRCErr is | |
511 | * true it implies we're *not* on the last subframe. In | |
512 | * in that case that we know already that the CRC of | |
513 | * the frame was OK, and MAC would send an ACK for that | |
514 | * subframe, even if we did get a phy error of type | |
515 | * ATH9K_PHYERR_OFDM_RESTART. This is only applicable | |
516 | * to frame that are prior to the last subframe. | |
517 | * The AR_PostDelimCRCErr is the CRC for the MPDU | |
518 | * delimiter, which contains the 4 reserved bits, | |
519 | * the MPDU length (12 bits), and follows the MPDU | |
520 | * delimiter for an A-MPDU subframe (0x4E = 'N' ASCII). | |
521 | */ | |
522 | if ((phyerr == ATH9K_PHYERR_OFDM_RESTART) && | |
523 | (rxsp->status11 & AR_PostDelimCRCErr)) { | |
524 | rxs->rs_phyerr = 0; | |
525 | } else { | |
526 | rxs->rs_status |= ATH9K_RXERR_PHY; | |
527 | rxs->rs_phyerr = phyerr; | |
528 | } | |
f4fb4b21 | 529 | }; |
ad7b8060 VT |
530 | } |
531 | ||
7a532fe7 FF |
532 | if (rxsp->status11 & AR_KeyMiss) |
533 | rxs->rs_status |= ATH9K_RXERR_KEYMISS; | |
534 | ||
ad7b8060 VT |
535 | return 0; |
536 | } | |
537 | EXPORT_SYMBOL(ath9k_hw_process_rxdesc_edma); | |
744d4025 VT |
538 | |
539 | void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah) | |
540 | { | |
541 | ah->ts_tail = 0; | |
542 | ||
543 | memset((void *) ah->ts_ring, 0, | |
544 | ah->ts_size * sizeof(struct ar9003_txs)); | |
545 | ||
d2182b69 | 546 | ath_dbg(ath9k_hw_common(ah), XMIT, |
226afe68 JP |
547 | "TS Start 0x%x End 0x%x Virt %p, Size %d\n", |
548 | ah->ts_paddr_start, ah->ts_paddr_end, | |
549 | ah->ts_ring, ah->ts_size); | |
744d4025 VT |
550 | |
551 | REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start); | |
552 | REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end); | |
553 | } | |
554 | ||
555 | void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, | |
556 | u32 ts_paddr_start, | |
016c2177 | 557 | u16 size) |
744d4025 VT |
558 | { |
559 | ||
560 | ah->ts_paddr_start = ts_paddr_start; | |
561 | ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs)); | |
562 | ah->ts_size = size; | |
563 | ah->ts_ring = (struct ar9003_txs *) ts_start; | |
564 | ||
565 | ath9k_hw_reset_txstatus_ring(ah); | |
566 | } | |
567 | EXPORT_SYMBOL(ath9k_hw_setup_statusring); |