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 | */ | |
16 | #include "hw.h" | |
b622a720 | 17 | #include "ar9003_mac.h" |
ae3bb6d4 VT |
18 | |
19 | static void ar9003_hw_rx_enable(struct ath_hw *hw) | |
20 | { | |
21 | REG_WRITE(hw, AR_CR, 0); | |
22 | } | |
23 | ||
2b63a41d FF |
24 | static void |
25 | ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) | |
26 | { | |
27 | struct ar9003_txc *ads = ds; | |
28 | int checksum = 0; | |
29 | u32 val, ctl12, ctl17; | |
30 | ||
31 | val = (ATHEROS_VENDOR_ID << AR_DescId_S) | | |
32 | (1 << AR_TxRxDesc_S) | | |
33 | (1 << AR_CtrlStat_S) | | |
34 | (i->qcu << AR_TxQcuNum_S) | 0x17; | |
35 | ||
36 | checksum += val; | |
37 | ACCESS_ONCE(ads->info) = val; | |
38 | ||
39 | checksum += i->link; | |
40 | ACCESS_ONCE(ads->link) = i->link; | |
41 | ||
42 | checksum += i->buf_addr[0]; | |
43 | ACCESS_ONCE(ads->data0) = i->buf_addr[0]; | |
44 | checksum += i->buf_addr[1]; | |
45 | ACCESS_ONCE(ads->data1) = i->buf_addr[1]; | |
46 | checksum += i->buf_addr[2]; | |
47 | ACCESS_ONCE(ads->data2) = i->buf_addr[2]; | |
48 | checksum += i->buf_addr[3]; | |
49 | ACCESS_ONCE(ads->data3) = i->buf_addr[3]; | |
50 | ||
51 | checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen); | |
52 | ACCESS_ONCE(ads->ctl3) = val; | |
53 | checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen); | |
54 | ACCESS_ONCE(ads->ctl5) = val; | |
55 | checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen); | |
56 | ACCESS_ONCE(ads->ctl7) = val; | |
57 | checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen); | |
58 | ACCESS_ONCE(ads->ctl9) = val; | |
59 | ||
60 | checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff); | |
61 | ACCESS_ONCE(ads->ctl10) = checksum; | |
62 | ||
63 | if (i->is_first || i->is_last) { | |
64 | ACCESS_ONCE(ads->ctl13) = set11nTries(i->rates, 0) | |
65 | | set11nTries(i->rates, 1) | |
66 | | set11nTries(i->rates, 2) | |
67 | | set11nTries(i->rates, 3) | |
68 | | (i->dur_update ? AR_DurUpdateEna : 0) | |
69 | | SM(0, AR_BurstDur); | |
70 | ||
71 | ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0) | |
72 | | set11nRate(i->rates, 1) | |
73 | | set11nRate(i->rates, 2) | |
74 | | set11nRate(i->rates, 3); | |
75 | } else { | |
76 | ACCESS_ONCE(ads->ctl13) = 0; | |
77 | ACCESS_ONCE(ads->ctl14) = 0; | |
78 | } | |
79 | ||
80 | ads->ctl20 = 0; | |
81 | ads->ctl21 = 0; | |
82 | ads->ctl22 = 0; | |
83 | ||
84 | ctl17 = SM(i->keytype, AR_EncrType); | |
85 | if (!i->is_first) { | |
86 | ACCESS_ONCE(ads->ctl11) = 0; | |
87 | ACCESS_ONCE(ads->ctl12) = i->is_last ? 0 : AR_TxMore; | |
88 | ACCESS_ONCE(ads->ctl15) = 0; | |
89 | ACCESS_ONCE(ads->ctl16) = 0; | |
90 | ACCESS_ONCE(ads->ctl17) = ctl17; | |
91 | ACCESS_ONCE(ads->ctl18) = 0; | |
92 | ACCESS_ONCE(ads->ctl19) = 0; | |
93 | return; | |
94 | } | |
95 | ||
96 | ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) | |
97 | | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | |
98 | | SM(i->txpower, AR_XmitPower) | |
99 | | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | |
100 | | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) | |
101 | | (i->flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0) | |
102 | | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) | |
103 | | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : | |
104 | (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0)); | |
105 | ||
106 | ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ? | |
107 | SM(i->keyix, AR_DestIdx) : 0) | |
108 | | SM(i->type, AR_FrameType) | |
109 | | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) | |
110 | | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) | |
111 | | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); | |
112 | ||
113 | ctl17 |= (i->flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); | |
114 | switch (i->aggr) { | |
115 | case AGGR_BUF_FIRST: | |
116 | ctl17 |= SM(i->aggr_len, AR_AggrLen); | |
117 | /* fall through */ | |
118 | case AGGR_BUF_MIDDLE: | |
119 | ctl12 |= AR_IsAggr | AR_MoreAggr; | |
120 | ctl17 |= SM(i->ndelim, AR_PadDelim); | |
121 | break; | |
122 | case AGGR_BUF_LAST: | |
123 | ctl12 |= AR_IsAggr; | |
124 | break; | |
125 | case AGGR_BUF_NONE: | |
126 | break; | |
127 | } | |
128 | ||
129 | val = (i->flags & ATH9K_TXDESC_PAPRD) >> ATH9K_TXDESC_PAPRD_S; | |
130 | ctl12 |= SM(val, AR_PAPRDChainMask); | |
131 | ||
132 | ACCESS_ONCE(ads->ctl12) = ctl12; | |
133 | ACCESS_ONCE(ads->ctl17) = ctl17; | |
134 | ||
135 | ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) | |
136 | | set11nPktDurRTSCTS(i->rates, 1); | |
137 | ||
138 | ACCESS_ONCE(ads->ctl16) = set11nPktDurRTSCTS(i->rates, 2) | |
139 | | set11nPktDurRTSCTS(i->rates, 3); | |
140 | ||
141 | ACCESS_ONCE(ads->ctl18) = set11nRateFlags(i->rates, 0) | |
142 | | set11nRateFlags(i->rates, 1) | |
143 | | set11nRateFlags(i->rates, 2) | |
144 | | set11nRateFlags(i->rates, 3) | |
145 | | SM(i->rtscts_rate, AR_RTSCTSRate); | |
146 | ||
147 | ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; | |
148 | } | |
149 | ||
eb823253 VT |
150 | static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) |
151 | { | |
152 | int checksum; | |
153 | ||
154 | checksum = ads->info + ads->link | |
155 | + ads->data0 + ads->ctl3 | |
156 | + ads->data1 + ads->ctl5 | |
157 | + ads->data2 + ads->ctl7 | |
158 | + ads->data3 + ads->ctl9; | |
159 | ||
160 | return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum; | |
161 | } | |
162 | ||
87d5efbb VT |
163 | static void ar9003_hw_set_desc_link(void *ds, u32 ds_link) |
164 | { | |
eb823253 VT |
165 | struct ar9003_txc *ads = ds; |
166 | ||
167 | ads->link = ds_link; | |
168 | ads->ctl10 &= ~AR_TxPtrChkSum; | |
169 | ads->ctl10 |= ar9003_calc_ptr_chksum(ads); | |
87d5efbb VT |
170 | } |
171 | ||
55e82df4 VT |
172 | static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) |
173 | { | |
6c84ce08 VT |
174 | u32 isr = 0; |
175 | u32 mask2 = 0; | |
176 | struct ath9k_hw_capabilities *pCap = &ah->caps; | |
177 | u32 sync_cause = 0; | |
178 | struct ath_common *common = ath9k_hw_common(ah); | |
179 | ||
180 | if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { | |
181 | if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) | |
182 | == AR_RTC_STATUS_ON) | |
183 | isr = REG_READ(ah, AR_ISR); | |
184 | } | |
185 | ||
186 | sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; | |
187 | ||
188 | *masked = 0; | |
189 | ||
190 | if (!isr && !sync_cause) | |
191 | return false; | |
192 | ||
193 | if (isr) { | |
194 | if (isr & AR_ISR_BCNMISC) { | |
195 | u32 isr2; | |
196 | isr2 = REG_READ(ah, AR_ISR_S2); | |
197 | ||
198 | mask2 |= ((isr2 & AR_ISR_S2_TIM) >> | |
199 | MAP_ISR_S2_TIM); | |
200 | mask2 |= ((isr2 & AR_ISR_S2_DTIM) >> | |
201 | MAP_ISR_S2_DTIM); | |
202 | mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >> | |
203 | MAP_ISR_S2_DTIMSYNC); | |
204 | mask2 |= ((isr2 & AR_ISR_S2_CABEND) >> | |
205 | MAP_ISR_S2_CABEND); | |
206 | mask2 |= ((isr2 & AR_ISR_S2_GTT) << | |
207 | MAP_ISR_S2_GTT); | |
208 | mask2 |= ((isr2 & AR_ISR_S2_CST) << | |
209 | MAP_ISR_S2_CST); | |
210 | mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >> | |
211 | MAP_ISR_S2_TSFOOR); | |
aea702b7 LR |
212 | mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >> |
213 | MAP_ISR_S2_BB_WATCHDOG); | |
6c84ce08 VT |
214 | |
215 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
216 | REG_WRITE(ah, AR_ISR_S2, isr2); | |
217 | isr &= ~AR_ISR_BCNMISC; | |
218 | } | |
219 | } | |
220 | ||
221 | if ((pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) | |
222 | isr = REG_READ(ah, AR_ISR_RAC); | |
223 | ||
224 | if (isr == 0xffffffff) { | |
225 | *masked = 0; | |
226 | return false; | |
227 | } | |
228 | ||
229 | *masked = isr & ATH9K_INT_COMMON; | |
230 | ||
231 | if (ah->config.rx_intr_mitigation) | |
232 | if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) | |
233 | *masked |= ATH9K_INT_RXLP; | |
234 | ||
235 | if (ah->config.tx_intr_mitigation) | |
236 | if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM)) | |
237 | *masked |= ATH9K_INT_TX; | |
238 | ||
239 | if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR)) | |
240 | *masked |= ATH9K_INT_RXLP; | |
241 | ||
242 | if (isr & AR_ISR_HP_RXOK) | |
243 | *masked |= ATH9K_INT_RXHP; | |
244 | ||
245 | if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) { | |
246 | *masked |= ATH9K_INT_TX; | |
247 | ||
248 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
249 | u32 s0, s1; | |
250 | s0 = REG_READ(ah, AR_ISR_S0); | |
251 | REG_WRITE(ah, AR_ISR_S0, s0); | |
252 | s1 = REG_READ(ah, AR_ISR_S1); | |
253 | REG_WRITE(ah, AR_ISR_S1, s1); | |
254 | ||
255 | isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR | | |
256 | AR_ISR_TXEOL); | |
257 | } | |
258 | } | |
259 | ||
260 | if (isr & AR_ISR_GENTMR) { | |
261 | u32 s5; | |
262 | ||
263 | if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) | |
264 | s5 = REG_READ(ah, AR_ISR_S5_S); | |
265 | else | |
266 | s5 = REG_READ(ah, AR_ISR_S5); | |
267 | ||
268 | ah->intr_gen_timer_trigger = | |
269 | MS(s5, AR_ISR_S5_GENTIMER_TRIG); | |
270 | ||
271 | ah->intr_gen_timer_thresh = | |
272 | MS(s5, AR_ISR_S5_GENTIMER_THRESH); | |
273 | ||
274 | if (ah->intr_gen_timer_trigger) | |
275 | *masked |= ATH9K_INT_GENTIMER; | |
276 | ||
277 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
278 | REG_WRITE(ah, AR_ISR_S5, s5); | |
279 | isr &= ~AR_ISR_GENTMR; | |
280 | } | |
281 | ||
282 | } | |
283 | ||
284 | *masked |= mask2; | |
285 | ||
286 | if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { | |
287 | REG_WRITE(ah, AR_ISR, isr); | |
288 | ||
289 | (void) REG_READ(ah, AR_ISR); | |
290 | } | |
aea702b7 LR |
291 | |
292 | if (*masked & ATH9K_INT_BB_WATCHDOG) | |
293 | ar9003_hw_bb_watchdog_read(ah); | |
6c84ce08 VT |
294 | } |
295 | ||
296 | if (sync_cause) { | |
297 | if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { | |
298 | REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); | |
299 | REG_WRITE(ah, AR_RC, 0); | |
300 | *masked |= ATH9K_INT_FATAL; | |
301 | } | |
302 | ||
303 | if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) | |
226afe68 JP |
304 | ath_dbg(common, ATH_DBG_INTERRUPT, |
305 | "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); | |
6c84ce08 | 306 | |
6fe14002 | 307 | REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); |
6c84ce08 VT |
308 | (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); |
309 | ||
310 | } | |
55e82df4 VT |
311 | return true; |
312 | } | |
313 | ||
cc610ac0 VT |
314 | static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, |
315 | bool is_firstseg, bool is_lastseg, | |
316 | const void *ds0, dma_addr_t buf_addr, | |
317 | unsigned int qcu) | |
318 | { | |
994089db VT |
319 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
320 | unsigned int descid = 0; | |
321 | ||
322 | ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) | | |
323 | (1 << AR_TxRxDesc_S) | | |
324 | (1 << AR_CtrlStat_S) | | |
325 | (qcu << AR_TxQcuNum_S) | 0x17; | |
326 | ||
327 | ads->data0 = buf_addr; | |
328 | ads->data1 = 0; | |
329 | ads->data2 = 0; | |
330 | ads->data3 = 0; | |
331 | ||
332 | ads->ctl3 = (seglen << AR_BufLen_S); | |
333 | ads->ctl3 &= AR_BufLen; | |
334 | ||
335 | /* Fill in pointer checksum and descriptor id */ | |
60f8cc60 | 336 | ads->ctl10 = (descid << AR_TxDescId_S); |
994089db VT |
337 | |
338 | if (is_firstseg) { | |
339 | ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore); | |
340 | } else if (is_lastseg) { | |
341 | ads->ctl11 = 0; | |
342 | ads->ctl12 = 0; | |
343 | ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13; | |
344 | ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14; | |
345 | } else { | |
346 | /* XXX Intermediate descriptor in a multi-descriptor frame.*/ | |
347 | ads->ctl11 = 0; | |
348 | ads->ctl12 = AR_TxMore; | |
349 | ads->ctl13 = 0; | |
350 | ads->ctl14 = 0; | |
351 | } | |
cc610ac0 VT |
352 | } |
353 | ||
354 | static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, | |
355 | struct ath_tx_status *ts) | |
356 | { | |
dcfcbd59 | 357 | struct ar9003_txc *txc = (struct ar9003_txc *) ds; |
994089db | 358 | struct ar9003_txs *ads; |
e0e9bc82 | 359 | u32 status; |
994089db VT |
360 | |
361 | ads = &ah->ts_ring[ah->ts_tail]; | |
362 | ||
e0e9bc82 FF |
363 | status = ACCESS_ONCE(ads->status8); |
364 | if ((status & AR_TxDone) == 0) | |
994089db VT |
365 | return -EINPROGRESS; |
366 | ||
dcfcbd59 RM |
367 | ts->qid = MS(ads->ds_info, AR_TxQcuNum); |
368 | if (!txc || (MS(txc->info, AR_TxQcuNum) == ts->qid)) | |
369 | ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; | |
370 | else | |
371 | return -ENOENT; | |
994089db VT |
372 | |
373 | if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) || | |
374 | (MS(ads->ds_info, AR_TxRxDesc) != 1)) { | |
226afe68 JP |
375 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT, |
376 | "Tx Descriptor error %x\n", ads->ds_info); | |
994089db VT |
377 | memset(ads, 0, sizeof(*ads)); |
378 | return -EIO; | |
379 | } | |
380 | ||
e0e9bc82 FF |
381 | ts->ts_rateindex = MS(status, AR_FinalTxIdx); |
382 | ts->ts_seqnum = MS(status, AR_SeqNum); | |
383 | ts->tid = MS(status, AR_TxTid); | |
384 | ||
994089db | 385 | ts->desc_id = MS(ads->status1, AR_TxDescId); |
994089db VT |
386 | ts->ts_tstamp = ads->status4; |
387 | ts->ts_status = 0; | |
388 | ts->ts_flags = 0; | |
389 | ||
2a15b394 RM |
390 | if (status & AR_TxOpExceeded) |
391 | ts->ts_status |= ATH9K_TXERR_XTXOP; | |
e0e9bc82 FF |
392 | status = ACCESS_ONCE(ads->status2); |
393 | ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); | |
394 | ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); | |
395 | ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); | |
396 | if (status & AR_TxBaStatus) { | |
397 | ts->ts_flags |= ATH9K_TX_BA; | |
398 | ts->ba_low = ads->status5; | |
399 | ts->ba_high = ads->status6; | |
400 | } | |
401 | ||
402 | status = ACCESS_ONCE(ads->status3); | |
403 | if (status & AR_ExcessiveRetries) | |
994089db | 404 | ts->ts_status |= ATH9K_TXERR_XRETRY; |
e0e9bc82 | 405 | if (status & AR_Filtered) |
994089db | 406 | ts->ts_status |= ATH9K_TXERR_FILT; |
e0e9bc82 | 407 | if (status & AR_FIFOUnderrun) { |
994089db VT |
408 | ts->ts_status |= ATH9K_TXERR_FIFO; |
409 | ath9k_hw_updatetxtriglevel(ah, true); | |
410 | } | |
e0e9bc82 | 411 | if (status & AR_TxTimerExpired) |
994089db | 412 | ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; |
e0e9bc82 | 413 | if (status & AR_DescCfgErr) |
994089db | 414 | ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; |
e0e9bc82 | 415 | if (status & AR_TxDataUnderrun) { |
994089db VT |
416 | ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; |
417 | ath9k_hw_updatetxtriglevel(ah, true); | |
418 | } | |
e0e9bc82 | 419 | if (status & AR_TxDelimUnderrun) { |
994089db VT |
420 | ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; |
421 | ath9k_hw_updatetxtriglevel(ah, true); | |
422 | } | |
e0e9bc82 FF |
423 | ts->ts_shortretry = MS(status, AR_RTSFailCnt); |
424 | ts->ts_longretry = MS(status, AR_DataFailCnt); | |
425 | ts->ts_virtcol = MS(status, AR_VirtRetryCnt); | |
426 | ||
427 | status = ACCESS_ONCE(ads->status7); | |
428 | ts->ts_rssi = MS(status, AR_TxRSSICombined); | |
429 | ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); | |
430 | ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); | |
431 | ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); | |
994089db VT |
432 | |
433 | memset(ads, 0, sizeof(*ads)); | |
434 | ||
cc610ac0 VT |
435 | return 0; |
436 | } | |
994089db | 437 | |
cc610ac0 | 438 | static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, |
994089db | 439 | u32 pktlen, enum ath9k_pkt_type type, u32 txpower, |
a75c0629 | 440 | u8 keyIx, enum ath9k_key_type keyType, u32 flags) |
cc610ac0 | 441 | { |
994089db VT |
442 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
443 | ||
597a94b3 FF |
444 | if (txpower > ah->txpower_limit) |
445 | txpower = ah->txpower_limit; | |
446 | ||
994089db VT |
447 | if (txpower > 63) |
448 | txpower = 63; | |
449 | ||
450 | ads->ctl11 = (pktlen & AR_FrameLen) | |
451 | | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) | |
452 | | SM(txpower, AR_XmitPower) | |
453 | | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) | |
994089db VT |
454 | | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) |
455 | | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); | |
456 | ||
457 | ads->ctl12 = | |
458 | (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) | |
459 | | SM(type, AR_FrameType) | |
460 | | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) | |
461 | | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) | |
462 | | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); | |
463 | ||
ce01805a LR |
464 | ads->ctl17 = SM(keyType, AR_EncrType) | |
465 | (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); | |
994089db VT |
466 | ads->ctl18 = 0; |
467 | ads->ctl19 = AR_Not_Sounding; | |
468 | ||
469 | ads->ctl20 = 0; | |
470 | ads->ctl21 = 0; | |
471 | ads->ctl22 = 0; | |
cc610ac0 VT |
472 | } |
473 | ||
5519541d FF |
474 | static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) |
475 | { | |
476 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; | |
477 | ||
478 | if (val) | |
479 | ads->ctl11 |= AR_ClrDestMask; | |
480 | else | |
481 | ads->ctl11 &= ~AR_ClrDestMask; | |
482 | } | |
483 | ||
cc610ac0 VT |
484 | static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, |
485 | void *lastds, | |
486 | u32 durUpdateEn, u32 rtsctsRate, | |
487 | u32 rtsctsDuration, | |
488 | struct ath9k_11n_rate_series series[], | |
489 | u32 nseries, u32 flags) | |
490 | { | |
994089db VT |
491 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
492 | struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds; | |
493 | u_int32_t ctl11; | |
494 | ||
495 | if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { | |
496 | ctl11 = ads->ctl11; | |
497 | ||
498 | if (flags & ATH9K_TXDESC_RTSENA) { | |
499 | ctl11 &= ~AR_CTSEnable; | |
500 | ctl11 |= AR_RTSEnable; | |
501 | } else { | |
502 | ctl11 &= ~AR_RTSEnable; | |
503 | ctl11 |= AR_CTSEnable; | |
504 | } | |
505 | ||
506 | ads->ctl11 = ctl11; | |
507 | } else { | |
508 | ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable)); | |
509 | } | |
cc610ac0 | 510 | |
994089db VT |
511 | ads->ctl13 = set11nTries(series, 0) |
512 | | set11nTries(series, 1) | |
513 | | set11nTries(series, 2) | |
514 | | set11nTries(series, 3) | |
515 | | (durUpdateEn ? AR_DurUpdateEna : 0) | |
516 | | SM(0, AR_BurstDur); | |
517 | ||
518 | ads->ctl14 = set11nRate(series, 0) | |
519 | | set11nRate(series, 1) | |
520 | | set11nRate(series, 2) | |
521 | | set11nRate(series, 3); | |
522 | ||
523 | ads->ctl15 = set11nPktDurRTSCTS(series, 0) | |
524 | | set11nPktDurRTSCTS(series, 1); | |
525 | ||
526 | ads->ctl16 = set11nPktDurRTSCTS(series, 2) | |
527 | | set11nPktDurRTSCTS(series, 3); | |
528 | ||
529 | ads->ctl18 = set11nRateFlags(series, 0) | |
530 | | set11nRateFlags(series, 1) | |
531 | | set11nRateFlags(series, 2) | |
532 | | set11nRateFlags(series, 3) | |
533 | | SM(rtsctsRate, AR_RTSCTSRate); | |
534 | ads->ctl19 = AR_Not_Sounding; | |
535 | ||
536 | last_ads->ctl13 = ads->ctl13; | |
537 | last_ads->ctl14 = ads->ctl14; | |
cc610ac0 VT |
538 | } |
539 | ||
540 | static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, | |
541 | u32 aggrLen) | |
542 | { | |
994089db | 543 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
cc610ac0 | 544 | |
994089db VT |
545 | ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); |
546 | ||
7a12dfdb RM |
547 | ads->ctl17 &= ~AR_AggrLen; |
548 | ads->ctl17 |= SM(aggrLen, AR_AggrLen); | |
cc610ac0 VT |
549 | } |
550 | ||
551 | static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, | |
552 | u32 numDelims) | |
553 | { | |
994089db VT |
554 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
555 | unsigned int ctl17; | |
556 | ||
557 | ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); | |
558 | ||
559 | /* | |
560 | * We use a stack variable to manipulate ctl6 to reduce uncached | |
561 | * read modify, modfiy, write. | |
562 | */ | |
563 | ctl17 = ads->ctl17; | |
564 | ctl17 &= ~AR_PadDelim; | |
565 | ctl17 |= SM(numDelims, AR_PadDelim); | |
566 | ads->ctl17 = ctl17; | |
cc610ac0 VT |
567 | } |
568 | ||
569 | static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) | |
570 | { | |
994089db | 571 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
cc610ac0 | 572 | |
994089db VT |
573 | ads->ctl12 |= AR_IsAggr; |
574 | ads->ctl12 &= ~AR_MoreAggr; | |
575 | ads->ctl17 &= ~AR_PadDelim; | |
cc610ac0 VT |
576 | } |
577 | ||
578 | static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds) | |
579 | { | |
994089db | 580 | struct ar9003_txc *ads = (struct ar9003_txc *) ds; |
cc610ac0 | 581 | |
994089db | 582 | ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr); |
cc610ac0 VT |
583 | } |
584 | ||
717f6bed FF |
585 | void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) |
586 | { | |
587 | struct ar9003_txc *ads = ds; | |
588 | ||
589 | ads->ctl12 |= SM(chains, AR_PAPRDChainMask); | |
590 | } | |
591 | EXPORT_SYMBOL(ar9003_hw_set_paprd_txdesc); | |
592 | ||
ae3bb6d4 VT |
593 | void ar9003_hw_attach_mac_ops(struct ath_hw *hw) |
594 | { | |
595 | struct ath_hw_ops *ops = ath9k_hw_ops(hw); | |
596 | ||
597 | ops->rx_enable = ar9003_hw_rx_enable; | |
87d5efbb | 598 | ops->set_desc_link = ar9003_hw_set_desc_link; |
55e82df4 | 599 | ops->get_isr = ar9003_hw_get_isr; |
2b63a41d | 600 | ops->set_txdesc = ar9003_set_txdesc; |
cc610ac0 VT |
601 | ops->fill_txdesc = ar9003_hw_fill_txdesc; |
602 | ops->proc_txdesc = ar9003_hw_proc_txdesc; | |
603 | ops->set11n_txdesc = ar9003_hw_set11n_txdesc; | |
604 | ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario; | |
605 | ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first; | |
606 | ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle; | |
607 | ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; | |
608 | ops->clr11n_aggr = ar9003_hw_clr11n_aggr; | |
5519541d | 609 | ops->set_clrdmask = ar9003_hw_set_clrdmask; |
ae3bb6d4 | 610 | } |
ad7b8060 VT |
611 | |
612 | void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) | |
613 | { | |
614 | REG_WRITE(ah, AR_DATABUF_SIZE, buf_size & AR_DATABUF_SIZE_MASK); | |
615 | } | |
616 | EXPORT_SYMBOL(ath9k_hw_set_rx_bufsize); | |
617 | ||
618 | void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp, | |
619 | enum ath9k_rx_qtype qtype) | |
620 | { | |
621 | if (qtype == ATH9K_RX_QUEUE_HP) | |
622 | REG_WRITE(ah, AR_HP_RXDP, rxdp); | |
623 | else | |
624 | REG_WRITE(ah, AR_LP_RXDP, rxdp); | |
625 | } | |
626 | EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma); | |
627 | ||
628 | int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, | |
629 | void *buf_addr) | |
630 | { | |
631 | struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr; | |
632 | unsigned int phyerr; | |
633 | ||
634 | /* TODO: byte swap on big endian for ar9300_10 */ | |
635 | ||
cca1fe1a RM |
636 | if (!rxs) { |
637 | if ((rxsp->status11 & AR_RxDone) == 0) | |
638 | return -EINPROGRESS; | |
ad7b8060 | 639 | |
cca1fe1a RM |
640 | if (MS(rxsp->ds_info, AR_DescId) != 0x168c) |
641 | return -EINVAL; | |
ad7b8060 | 642 | |
cca1fe1a RM |
643 | if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) |
644 | return -EINPROGRESS; | |
ad7b8060 | 645 | |
b5c80475 | 646 | return 0; |
cca1fe1a | 647 | } |
b5c80475 | 648 | |
ad7b8060 VT |
649 | rxs->rs_status = 0; |
650 | rxs->rs_flags = 0; | |
651 | ||
652 | rxs->rs_datalen = rxsp->status2 & AR_DataLen; | |
653 | rxs->rs_tstamp = rxsp->status3; | |
654 | ||
655 | /* XXX: Keycache */ | |
656 | rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); | |
657 | rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); | |
658 | rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); | |
659 | rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); | |
660 | rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); | |
661 | rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); | |
662 | rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); | |
663 | ||
664 | if (rxsp->status11 & AR_RxKeyIdxValid) | |
665 | rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); | |
666 | else | |
667 | rxs->rs_keyix = ATH9K_RXKEYIX_INVALID; | |
668 | ||
669 | rxs->rs_rate = MS(rxsp->status1, AR_RxRate); | |
670 | rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0; | |
671 | ||
672 | rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0; | |
673 | rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0; | |
674 | rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7); | |
675 | rxs->rs_flags = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0; | |
676 | rxs->rs_flags |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0; | |
677 | ||
678 | rxs->evm0 = rxsp->status6; | |
679 | rxs->evm1 = rxsp->status7; | |
680 | rxs->evm2 = rxsp->status8; | |
681 | rxs->evm3 = rxsp->status9; | |
682 | rxs->evm4 = (rxsp->status10 & 0xffff); | |
683 | ||
684 | if (rxsp->status11 & AR_PreDelimCRCErr) | |
685 | rxs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE; | |
686 | ||
687 | if (rxsp->status11 & AR_PostDelimCRCErr) | |
688 | rxs->rs_flags |= ATH9K_RX_DELIM_CRC_POST; | |
689 | ||
690 | if (rxsp->status11 & AR_DecryptBusyErr) | |
691 | rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY; | |
692 | ||
693 | if ((rxsp->status11 & AR_RxFrameOK) == 0) { | |
9171acc7 LR |
694 | /* |
695 | * AR_CRCErr will bet set to true if we're on the last | |
696 | * subframe and the AR_PostDelimCRCErr is caught. | |
697 | * In a way this also gives us a guarantee that when | |
698 | * (!(AR_CRCErr) && (AR_PostDelimCRCErr)) we cannot | |
699 | * possibly be reviewing the last subframe. AR_CRCErr | |
700 | * is the CRC of the actual data. | |
701 | */ | |
1c30cc19 | 702 | if (rxsp->status11 & AR_CRCErr) |
ad7b8060 | 703 | rxs->rs_status |= ATH9K_RXERR_CRC; |
115dad7a | 704 | else if (rxsp->status11 & AR_PHYErr) { |
ad7b8060 | 705 | phyerr = MS(rxsp->status11, AR_PHYErrCode); |
9171acc7 LR |
706 | /* |
707 | * If we reach a point here where AR_PostDelimCRCErr is | |
708 | * true it implies we're *not* on the last subframe. In | |
709 | * in that case that we know already that the CRC of | |
710 | * the frame was OK, and MAC would send an ACK for that | |
711 | * subframe, even if we did get a phy error of type | |
712 | * ATH9K_PHYERR_OFDM_RESTART. This is only applicable | |
713 | * to frame that are prior to the last subframe. | |
714 | * The AR_PostDelimCRCErr is the CRC for the MPDU | |
715 | * delimiter, which contains the 4 reserved bits, | |
716 | * the MPDU length (12 bits), and follows the MPDU | |
717 | * delimiter for an A-MPDU subframe (0x4E = 'N' ASCII). | |
718 | */ | |
719 | if ((phyerr == ATH9K_PHYERR_OFDM_RESTART) && | |
720 | (rxsp->status11 & AR_PostDelimCRCErr)) { | |
721 | rxs->rs_phyerr = 0; | |
722 | } else { | |
723 | rxs->rs_status |= ATH9K_RXERR_PHY; | |
724 | rxs->rs_phyerr = phyerr; | |
725 | } | |
726 | ||
115dad7a | 727 | } else if (rxsp->status11 & AR_DecryptCRCErr) |
ad7b8060 | 728 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; |
115dad7a | 729 | else if (rxsp->status11 & AR_MichaelErr) |
ad7b8060 | 730 | rxs->rs_status |= ATH9K_RXERR_MIC; |
0472ade0 | 731 | else if (rxsp->status11 & AR_KeyMiss) |
3ae74c33 | 732 | rxs->rs_status |= ATH9K_RXERR_DECRYPT; |
ad7b8060 VT |
733 | } |
734 | ||
735 | return 0; | |
736 | } | |
737 | EXPORT_SYMBOL(ath9k_hw_process_rxdesc_edma); | |
744d4025 VT |
738 | |
739 | void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah) | |
740 | { | |
741 | ah->ts_tail = 0; | |
742 | ||
743 | memset((void *) ah->ts_ring, 0, | |
744 | ah->ts_size * sizeof(struct ar9003_txs)); | |
745 | ||
226afe68 JP |
746 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_XMIT, |
747 | "TS Start 0x%x End 0x%x Virt %p, Size %d\n", | |
748 | ah->ts_paddr_start, ah->ts_paddr_end, | |
749 | ah->ts_ring, ah->ts_size); | |
744d4025 VT |
750 | |
751 | REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start); | |
752 | REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end); | |
753 | } | |
754 | ||
755 | void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, | |
756 | u32 ts_paddr_start, | |
757 | u8 size) | |
758 | { | |
759 | ||
760 | ah->ts_paddr_start = ts_paddr_start; | |
761 | ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs)); | |
762 | ah->ts_size = size; | |
763 | ah->ts_ring = (struct ar9003_txs *) ts_start; | |
764 | ||
765 | ath9k_hw_reset_txstatus_ring(ah); | |
766 | } | |
767 | EXPORT_SYMBOL(ath9k_hw_setup_statusring); |