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