2 * Copyright (c) 2008-2011 Atheros Communications Inc.
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.
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.
18 #include <linux/export.h>
20 #define AR_BufLen 0x00000fff
22 static void ar9002_hw_rx_enable(struct ath_hw
*ah
)
24 REG_WRITE(ah
, AR_CR
, AR_CR_RXE
);
27 static void ar9002_hw_set_desc_link(void *ds
, u32 ds_link
)
29 ((struct ath_desc
*) ds
)->ds_link
= ds_link
;
32 static bool ar9002_hw_get_isr(struct ath_hw
*ah
, enum ath9k_int
*masked
)
36 struct ath9k_hw_capabilities
*pCap
= &ah
->caps
;
38 bool fatal_int
= false;
39 struct ath_common
*common
= ath9k_hw_common(ah
);
41 if (!AR_SREV_9100(ah
)) {
42 if (REG_READ(ah
, AR_INTR_ASYNC_CAUSE
) & AR_INTR_MAC_IRQ
) {
43 if ((REG_READ(ah
, AR_RTC_STATUS
) & AR_RTC_STATUS_M
)
44 == AR_RTC_STATUS_ON
) {
45 isr
= REG_READ(ah
, AR_ISR
);
49 sync_cause
= REG_READ(ah
, AR_INTR_SYNC_CAUSE
) &
54 if (!isr
&& !sync_cause
)
58 isr
= REG_READ(ah
, AR_ISR
);
62 if (isr
& AR_ISR_BCNMISC
) {
64 isr2
= REG_READ(ah
, AR_ISR_S2
);
65 if (isr2
& AR_ISR_S2_TIM
)
66 mask2
|= ATH9K_INT_TIM
;
67 if (isr2
& AR_ISR_S2_DTIM
)
68 mask2
|= ATH9K_INT_DTIM
;
69 if (isr2
& AR_ISR_S2_DTIMSYNC
)
70 mask2
|= ATH9K_INT_DTIMSYNC
;
71 if (isr2
& (AR_ISR_S2_CABEND
))
72 mask2
|= ATH9K_INT_CABEND
;
73 if (isr2
& AR_ISR_S2_GTT
)
74 mask2
|= ATH9K_INT_GTT
;
75 if (isr2
& AR_ISR_S2_CST
)
76 mask2
|= ATH9K_INT_CST
;
77 if (isr2
& AR_ISR_S2_TSFOOR
)
78 mask2
|= ATH9K_INT_TSFOOR
;
80 if (!(pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
)) {
81 REG_WRITE(ah
, AR_ISR_S2
, isr2
);
82 isr
&= ~AR_ISR_BCNMISC
;
86 if (pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
)
87 isr
= REG_READ(ah
, AR_ISR_RAC
);
89 if (isr
== 0xffffffff) {
94 *masked
= isr
& ATH9K_INT_COMMON
;
96 if (isr
& (AR_ISR_RXMINTR
| AR_ISR_RXINTM
|
97 AR_ISR_RXOK
| AR_ISR_RXERR
))
98 *masked
|= ATH9K_INT_RX
;
101 (AR_ISR_TXOK
| AR_ISR_TXDESC
| AR_ISR_TXERR
|
105 *masked
|= ATH9K_INT_TX
;
107 if (pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
) {
108 s0_s
= REG_READ(ah
, AR_ISR_S0_S
);
109 s1_s
= REG_READ(ah
, AR_ISR_S1_S
);
111 s0_s
= REG_READ(ah
, AR_ISR_S0
);
112 REG_WRITE(ah
, AR_ISR_S0
, s0_s
);
113 s1_s
= REG_READ(ah
, AR_ISR_S1
);
114 REG_WRITE(ah
, AR_ISR_S1
, s1_s
);
116 isr
&= ~(AR_ISR_TXOK
|
122 ah
->intr_txqs
|= MS(s0_s
, AR_ISR_S0_QCU_TXOK
);
123 ah
->intr_txqs
|= MS(s0_s
, AR_ISR_S0_QCU_TXDESC
);
124 ah
->intr_txqs
|= MS(s1_s
, AR_ISR_S1_QCU_TXERR
);
125 ah
->intr_txqs
|= MS(s1_s
, AR_ISR_S1_QCU_TXEOL
);
128 if (isr
& AR_ISR_RXORN
) {
129 ath_dbg(common
, INTERRUPT
,
130 "receive FIFO overrun interrupt\n");
136 if (!AR_SREV_9100(ah
) && (isr
& AR_ISR_GENTMR
)) {
139 if (pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
) {
140 s5_s
= REG_READ(ah
, AR_ISR_S5_S
);
142 s5_s
= REG_READ(ah
, AR_ISR_S5
);
145 ah
->intr_gen_timer_trigger
=
146 MS(s5_s
, AR_ISR_S5_GENTIMER_TRIG
);
148 ah
->intr_gen_timer_thresh
=
149 MS(s5_s
, AR_ISR_S5_GENTIMER_THRESH
);
151 if (ah
->intr_gen_timer_trigger
)
152 *masked
|= ATH9K_INT_GENTIMER
;
154 if ((s5_s
& AR_ISR_S5_TIM_TIMER
) &&
155 !(pCap
->hw_caps
& ATH9K_HW_CAP_AUTOSLEEP
))
156 *masked
|= ATH9K_INT_TIM_TIMER
;
158 if (!(pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
)) {
159 REG_WRITE(ah
, AR_ISR_S5
, s5_s
);
160 isr
&= ~AR_ISR_GENTMR
;
164 if (!(pCap
->hw_caps
& ATH9K_HW_CAP_RAC_SUPPORTED
)) {
165 REG_WRITE(ah
, AR_ISR
, isr
);
166 REG_READ(ah
, AR_ISR
);
169 if (AR_SREV_9100(ah
))
173 ath9k_debug_sync_cause(common
, sync_cause
);
176 (AR_INTR_SYNC_HOST1_FATAL
| AR_INTR_SYNC_HOST1_PERR
))
180 if (sync_cause
& AR_INTR_SYNC_HOST1_FATAL
) {
182 "received PCI FATAL interrupt\n");
184 if (sync_cause
& AR_INTR_SYNC_HOST1_PERR
) {
186 "received PCI PERR interrupt\n");
188 *masked
|= ATH9K_INT_FATAL
;
190 if (sync_cause
& AR_INTR_SYNC_RADM_CPL_TIMEOUT
) {
191 ath_dbg(common
, INTERRUPT
,
192 "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
193 REG_WRITE(ah
, AR_RC
, AR_RC_HOSTIF
);
194 REG_WRITE(ah
, AR_RC
, 0);
195 *masked
|= ATH9K_INT_FATAL
;
197 if (sync_cause
& AR_INTR_SYNC_LOCAL_TIMEOUT
) {
198 ath_dbg(common
, INTERRUPT
,
199 "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
202 REG_WRITE(ah
, AR_INTR_SYNC_CAUSE_CLR
, sync_cause
);
203 (void) REG_READ(ah
, AR_INTR_SYNC_CAUSE_CLR
);
210 ar9002_set_txdesc(struct ath_hw
*ah
, void *ds
, struct ath_tx_info
*i
)
212 struct ar5416_desc
*ads
= AR5416DESC(ds
);
215 ads
->ds_txstatus0
= ads
->ds_txstatus1
= 0;
216 ads
->ds_txstatus2
= ads
->ds_txstatus3
= 0;
217 ads
->ds_txstatus4
= ads
->ds_txstatus5
= 0;
218 ads
->ds_txstatus6
= ads
->ds_txstatus7
= 0;
219 ads
->ds_txstatus8
= ads
->ds_txstatus9
= 0;
221 ACCESS_ONCE(ads
->ds_link
) = i
->link
;
222 ACCESS_ONCE(ads
->ds_data
) = i
->buf_addr
[0];
224 ctl1
= i
->buf_len
[0] | (i
->is_last
? 0 : AR_TxMore
);
225 ctl6
= SM(i
->keytype
, AR_EncrType
);
227 if (AR_SREV_9285(ah
)) {
234 if ((i
->is_first
|| i
->is_last
) &&
235 i
->aggr
!= AGGR_BUF_MIDDLE
&& i
->aggr
!= AGGR_BUF_LAST
) {
236 ACCESS_ONCE(ads
->ds_ctl2
) = set11nTries(i
->rates
, 0)
237 | set11nTries(i
->rates
, 1)
238 | set11nTries(i
->rates
, 2)
239 | set11nTries(i
->rates
, 3)
240 | (i
->dur_update
? AR_DurUpdateEna
: 0)
241 | SM(0, AR_BurstDur
);
243 ACCESS_ONCE(ads
->ds_ctl3
) = set11nRate(i
->rates
, 0)
244 | set11nRate(i
->rates
, 1)
245 | set11nRate(i
->rates
, 2)
246 | set11nRate(i
->rates
, 3);
248 ACCESS_ONCE(ads
->ds_ctl2
) = 0;
249 ACCESS_ONCE(ads
->ds_ctl3
) = 0;
253 ACCESS_ONCE(ads
->ds_ctl0
) = 0;
254 ACCESS_ONCE(ads
->ds_ctl1
) = ctl1
;
255 ACCESS_ONCE(ads
->ds_ctl6
) = ctl6
;
259 ctl1
|= (i
->keyix
!= ATH9K_TXKEYIX_INVALID
? SM(i
->keyix
, AR_DestIdx
) : 0)
260 | SM(i
->type
, AR_FrameType
)
261 | (i
->flags
& ATH9K_TXDESC_NOACK
? AR_NoAck
: 0)
262 | (i
->flags
& ATH9K_TXDESC_EXT_ONLY
? AR_ExtOnly
: 0)
263 | (i
->flags
& ATH9K_TXDESC_EXT_AND_CTL
? AR_ExtAndCtl
: 0);
267 ctl6
|= SM(i
->aggr_len
, AR_AggrLen
);
269 case AGGR_BUF_MIDDLE
:
270 ctl1
|= AR_IsAggr
| AR_MoreAggr
;
271 ctl6
|= SM(i
->ndelim
, AR_PadDelim
);
280 ACCESS_ONCE(ads
->ds_ctl0
) = (i
->pkt_len
& AR_FrameLen
)
281 | (i
->flags
& ATH9K_TXDESC_VMF
? AR_VirtMoreFrag
: 0)
282 | SM(i
->txpower
, AR_XmitPower
)
283 | (i
->flags
& ATH9K_TXDESC_VEOL
? AR_VEOL
: 0)
284 | (i
->flags
& ATH9K_TXDESC_INTREQ
? AR_TxIntrReq
: 0)
285 | (i
->keyix
!= ATH9K_TXKEYIX_INVALID
? AR_DestIdxValid
: 0)
286 | (i
->flags
& ATH9K_TXDESC_CLRDMASK
? AR_ClrDestMask
: 0)
287 | (i
->flags
& ATH9K_TXDESC_RTSENA
? AR_RTSEnable
:
288 (i
->flags
& ATH9K_TXDESC_CTSENA
? AR_CTSEnable
: 0));
290 ACCESS_ONCE(ads
->ds_ctl1
) = ctl1
;
291 ACCESS_ONCE(ads
->ds_ctl6
) = ctl6
;
293 if (i
->aggr
== AGGR_BUF_MIDDLE
|| i
->aggr
== AGGR_BUF_LAST
)
296 ACCESS_ONCE(ads
->ds_ctl4
) = set11nPktDurRTSCTS(i
->rates
, 0)
297 | set11nPktDurRTSCTS(i
->rates
, 1);
299 ACCESS_ONCE(ads
->ds_ctl5
) = set11nPktDurRTSCTS(i
->rates
, 2)
300 | set11nPktDurRTSCTS(i
->rates
, 3);
302 ACCESS_ONCE(ads
->ds_ctl7
) = set11nRateFlags(i
->rates
, 0)
303 | set11nRateFlags(i
->rates
, 1)
304 | set11nRateFlags(i
->rates
, 2)
305 | set11nRateFlags(i
->rates
, 3)
306 | SM(i
->rtscts_rate
, AR_RTSCTSRate
);
309 static int ar9002_hw_proc_txdesc(struct ath_hw
*ah
, void *ds
,
310 struct ath_tx_status
*ts
)
312 struct ar5416_desc
*ads
= AR5416DESC(ds
);
315 status
= ACCESS_ONCE(ads
->ds_txstatus9
);
316 if ((status
& AR_TxDone
) == 0)
319 ts
->ts_tstamp
= ads
->AR_SendTimestamp
;
323 if (status
& AR_TxOpExceeded
)
324 ts
->ts_status
|= ATH9K_TXERR_XTXOP
;
325 ts
->tid
= MS(status
, AR_TxTid
);
326 ts
->ts_rateindex
= MS(status
, AR_FinalTxIdx
);
327 ts
->ts_seqnum
= MS(status
, AR_SeqNum
);
329 status
= ACCESS_ONCE(ads
->ds_txstatus0
);
330 ts
->ts_rssi_ctl0
= MS(status
, AR_TxRSSIAnt00
);
331 ts
->ts_rssi_ctl1
= MS(status
, AR_TxRSSIAnt01
);
332 ts
->ts_rssi_ctl2
= MS(status
, AR_TxRSSIAnt02
);
333 if (status
& AR_TxBaStatus
) {
334 ts
->ts_flags
|= ATH9K_TX_BA
;
335 ts
->ba_low
= ads
->AR_BaBitmapLow
;
336 ts
->ba_high
= ads
->AR_BaBitmapHigh
;
339 status
= ACCESS_ONCE(ads
->ds_txstatus1
);
340 if (status
& AR_FrmXmitOK
)
341 ts
->ts_status
|= ATH9K_TX_ACKED
;
343 if (status
& AR_ExcessiveRetries
)
344 ts
->ts_status
|= ATH9K_TXERR_XRETRY
;
345 if (status
& AR_Filtered
)
346 ts
->ts_status
|= ATH9K_TXERR_FILT
;
347 if (status
& AR_FIFOUnderrun
) {
348 ts
->ts_status
|= ATH9K_TXERR_FIFO
;
349 ath9k_hw_updatetxtriglevel(ah
, true);
352 if (status
& AR_TxTimerExpired
)
353 ts
->ts_status
|= ATH9K_TXERR_TIMER_EXPIRED
;
354 if (status
& AR_DescCfgErr
)
355 ts
->ts_flags
|= ATH9K_TX_DESC_CFG_ERR
;
356 if (status
& AR_TxDataUnderrun
) {
357 ts
->ts_flags
|= ATH9K_TX_DATA_UNDERRUN
;
358 ath9k_hw_updatetxtriglevel(ah
, true);
360 if (status
& AR_TxDelimUnderrun
) {
361 ts
->ts_flags
|= ATH9K_TX_DELIM_UNDERRUN
;
362 ath9k_hw_updatetxtriglevel(ah
, true);
364 ts
->ts_shortretry
= MS(status
, AR_RTSFailCnt
);
365 ts
->ts_longretry
= MS(status
, AR_DataFailCnt
);
366 ts
->ts_virtcol
= MS(status
, AR_VirtRetryCnt
);
368 status
= ACCESS_ONCE(ads
->ds_txstatus5
);
369 ts
->ts_rssi
= MS(status
, AR_TxRSSICombined
);
370 ts
->ts_rssi_ext0
= MS(status
, AR_TxRSSIAnt10
);
371 ts
->ts_rssi_ext1
= MS(status
, AR_TxRSSIAnt11
);
372 ts
->ts_rssi_ext2
= MS(status
, AR_TxRSSIAnt12
);
374 ts
->evm0
= ads
->AR_TxEVM0
;
375 ts
->evm1
= ads
->AR_TxEVM1
;
376 ts
->evm2
= ads
->AR_TxEVM2
;
381 void ath9k_hw_setuprxdesc(struct ath_hw
*ah
, struct ath_desc
*ds
,
384 struct ar5416_desc
*ads
= AR5416DESC(ds
);
386 ads
->ds_ctl1
= size
& AR_BufLen
;
387 if (flags
& ATH9K_RXDESC_INTREQ
)
388 ads
->ds_ctl1
|= AR_RxIntrReq
;
390 memset(&ads
->u
.rx
, 0, sizeof(ads
->u
.rx
));
392 EXPORT_SYMBOL(ath9k_hw_setuprxdesc
);
394 void ar9002_hw_attach_mac_ops(struct ath_hw
*ah
)
396 struct ath_hw_ops
*ops
= ath9k_hw_ops(ah
);
398 ops
->rx_enable
= ar9002_hw_rx_enable
;
399 ops
->set_desc_link
= ar9002_hw_set_desc_link
;
400 ops
->get_isr
= ar9002_hw_get_isr
;
401 ops
->set_txdesc
= ar9002_set_txdesc
;
402 ops
->proc_txdesc
= ar9002_hw_proc_txdesc
;