162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "hw.h" 1862306a36Sopenharmony_ci#include <linux/export.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define AR_BufLen 0x00000fff 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic void ar9002_hw_rx_enable(struct ath_hw *ah) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci REG_WRITE(ah, AR_CR, AR_CR_RXE(ah)); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void ar9002_hw_set_desc_link(void *ds, u32 ds_link) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci ((struct ath_desc*) ds)->ds_link = ds_link; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked, 3362306a36Sopenharmony_ci u32 *sync_cause_p) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci u32 isr = 0; 3662306a36Sopenharmony_ci u32 mask2 = 0; 3762306a36Sopenharmony_ci struct ath9k_hw_capabilities *pCap = &ah->caps; 3862306a36Sopenharmony_ci u32 sync_cause = 0; 3962306a36Sopenharmony_ci bool fatal_int = false; 4062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!AR_SREV_9100(ah)) { 4362306a36Sopenharmony_ci if (REG_READ(ah, AR_INTR_ASYNC_CAUSE(ah)) & AR_INTR_MAC_IRQ) { 4462306a36Sopenharmony_ci if ((REG_READ(ah, AR_RTC_STATUS(ah)) & AR_RTC_STATUS_M(ah)) 4562306a36Sopenharmony_ci == AR_RTC_STATUS_ON) { 4662306a36Sopenharmony_ci isr = REG_READ(ah, AR_ISR); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE(ah)) & 5162306a36Sopenharmony_ci AR_INTR_SYNC_DEFAULT; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci *masked = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (!isr && !sync_cause) 5662306a36Sopenharmony_ci return false; 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci *masked = 0; 5962306a36Sopenharmony_ci isr = REG_READ(ah, AR_ISR); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (isr) { 6362306a36Sopenharmony_ci if (isr & AR_ISR_BCNMISC) { 6462306a36Sopenharmony_ci u32 isr2; 6562306a36Sopenharmony_ci isr2 = REG_READ(ah, AR_ISR_S2); 6662306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_TIM) 6762306a36Sopenharmony_ci mask2 |= ATH9K_INT_TIM; 6862306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_DTIM) 6962306a36Sopenharmony_ci mask2 |= ATH9K_INT_DTIM; 7062306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_DTIMSYNC) 7162306a36Sopenharmony_ci mask2 |= ATH9K_INT_DTIMSYNC; 7262306a36Sopenharmony_ci if (isr2 & (AR_ISR_S2_CABEND)) 7362306a36Sopenharmony_ci mask2 |= ATH9K_INT_CABEND; 7462306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_GTT) 7562306a36Sopenharmony_ci mask2 |= ATH9K_INT_GTT; 7662306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_CST) 7762306a36Sopenharmony_ci mask2 |= ATH9K_INT_CST; 7862306a36Sopenharmony_ci if (isr2 & AR_ISR_S2_TSFOOR) 7962306a36Sopenharmony_ci mask2 |= ATH9K_INT_TSFOOR; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { 8262306a36Sopenharmony_ci REG_WRITE(ah, AR_ISR_S2, isr2); 8362306a36Sopenharmony_ci isr &= ~AR_ISR_BCNMISC; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) 8862306a36Sopenharmony_ci isr = REG_READ(ah, AR_ISR_RAC); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (isr == 0xffffffff) { 9162306a36Sopenharmony_ci *masked = 0; 9262306a36Sopenharmony_ci return false; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci *masked = isr & ATH9K_INT_COMMON; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM | 9862306a36Sopenharmony_ci AR_ISR_RXOK | AR_ISR_RXERR)) 9962306a36Sopenharmony_ci *masked |= ATH9K_INT_RX; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (isr & 10262306a36Sopenharmony_ci (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | 10362306a36Sopenharmony_ci AR_ISR_TXEOL)) { 10462306a36Sopenharmony_ci u32 s0_s, s1_s; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci *masked |= ATH9K_INT_TX; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { 10962306a36Sopenharmony_ci s0_s = REG_READ(ah, AR_ISR_S0_S); 11062306a36Sopenharmony_ci s1_s = REG_READ(ah, AR_ISR_S1_S); 11162306a36Sopenharmony_ci } else { 11262306a36Sopenharmony_ci s0_s = REG_READ(ah, AR_ISR_S0); 11362306a36Sopenharmony_ci REG_WRITE(ah, AR_ISR_S0, s0_s); 11462306a36Sopenharmony_ci s1_s = REG_READ(ah, AR_ISR_S1); 11562306a36Sopenharmony_ci REG_WRITE(ah, AR_ISR_S1, s1_s); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci isr &= ~(AR_ISR_TXOK | 11862306a36Sopenharmony_ci AR_ISR_TXDESC | 11962306a36Sopenharmony_ci AR_ISR_TXERR | 12062306a36Sopenharmony_ci AR_ISR_TXEOL); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ah->intr_txqs = MS(s0_s, AR_ISR_S0_QCU_TXOK); 12462306a36Sopenharmony_ci ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC); 12562306a36Sopenharmony_ci ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR); 12662306a36Sopenharmony_ci ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (isr & AR_ISR_RXORN) { 13062306a36Sopenharmony_ci ath_dbg(common, INTERRUPT, 13162306a36Sopenharmony_ci "receive FIFO overrun interrupt\n"); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci *masked |= mask2; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) { 13862306a36Sopenharmony_ci u32 s5_s; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) { 14162306a36Sopenharmony_ci s5_s = REG_READ(ah, AR_ISR_S5_S(ah)); 14262306a36Sopenharmony_ci } else { 14362306a36Sopenharmony_ci s5_s = REG_READ(ah, AR_ISR_S5); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ah->intr_gen_timer_trigger = 14762306a36Sopenharmony_ci MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ah->intr_gen_timer_thresh = 15062306a36Sopenharmony_ci MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (ah->intr_gen_timer_trigger) 15362306a36Sopenharmony_ci *masked |= ATH9K_INT_GENTIMER; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if ((s5_s & AR_ISR_S5_TIM_TIMER) && 15662306a36Sopenharmony_ci !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) 15762306a36Sopenharmony_ci *masked |= ATH9K_INT_TIM_TIMER; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { 16062306a36Sopenharmony_ci REG_WRITE(ah, AR_ISR_S5, s5_s); 16162306a36Sopenharmony_ci isr &= ~AR_ISR_GENTMR; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) { 16662306a36Sopenharmony_ci REG_WRITE(ah, AR_ISR, isr); 16762306a36Sopenharmony_ci REG_READ(ah, AR_ISR); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (AR_SREV_9100(ah)) 17162306a36Sopenharmony_ci return true; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (sync_cause) { 17462306a36Sopenharmony_ci if (sync_cause_p) 17562306a36Sopenharmony_ci *sync_cause_p = sync_cause; 17662306a36Sopenharmony_ci fatal_int = 17762306a36Sopenharmony_ci (sync_cause & 17862306a36Sopenharmony_ci (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR)) 17962306a36Sopenharmony_ci ? true : false; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (fatal_int) { 18262306a36Sopenharmony_ci if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { 18362306a36Sopenharmony_ci ath_dbg(common, ANY, 18462306a36Sopenharmony_ci "received PCI FATAL interrupt\n"); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { 18762306a36Sopenharmony_ci ath_dbg(common, ANY, 18862306a36Sopenharmony_ci "received PCI PERR interrupt\n"); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci *masked |= ATH9K_INT_FATAL; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { 19362306a36Sopenharmony_ci ath_dbg(common, INTERRUPT, 19462306a36Sopenharmony_ci "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); 19562306a36Sopenharmony_ci REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); 19662306a36Sopenharmony_ci REG_WRITE(ah, AR_RC, 0); 19762306a36Sopenharmony_ci *masked |= ATH9K_INT_FATAL; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { 20062306a36Sopenharmony_ci ath_dbg(common, INTERRUPT, 20162306a36Sopenharmony_ci "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR(ah), sync_cause); 20562306a36Sopenharmony_ci (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR(ah)); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return true; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void 21262306a36Sopenharmony_ciar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct ar5416_desc *ads = AR5416DESC(ds); 21562306a36Sopenharmony_ci u32 ctl1, ctl6; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ads->ds_txstatus0 = ads->ds_txstatus1 = 0; 21862306a36Sopenharmony_ci ads->ds_txstatus2 = ads->ds_txstatus3 = 0; 21962306a36Sopenharmony_ci ads->ds_txstatus4 = ads->ds_txstatus5 = 0; 22062306a36Sopenharmony_ci ads->ds_txstatus6 = ads->ds_txstatus7 = 0; 22162306a36Sopenharmony_ci ads->ds_txstatus8 = ads->ds_txstatus9 = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci WRITE_ONCE(ads->ds_link, i->link); 22462306a36Sopenharmony_ci WRITE_ONCE(ads->ds_data, i->buf_addr[0]); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore); 22762306a36Sopenharmony_ci ctl6 = SM(i->keytype, AR_EncrType); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (AR_SREV_9285(ah)) { 23062306a36Sopenharmony_ci ads->ds_ctl8 = 0; 23162306a36Sopenharmony_ci ads->ds_ctl9 = 0; 23262306a36Sopenharmony_ci ads->ds_ctl10 = 0; 23362306a36Sopenharmony_ci ads->ds_ctl11 = 0; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if ((i->is_first || i->is_last) && 23762306a36Sopenharmony_ci i->aggr != AGGR_BUF_MIDDLE && i->aggr != AGGR_BUF_LAST) { 23862306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl2, set11nTries(i->rates, 0) 23962306a36Sopenharmony_ci | set11nTries(i->rates, 1) 24062306a36Sopenharmony_ci | set11nTries(i->rates, 2) 24162306a36Sopenharmony_ci | set11nTries(i->rates, 3) 24262306a36Sopenharmony_ci | (i->dur_update ? AR_DurUpdateEna : 0) 24362306a36Sopenharmony_ci | SM(0, AR_BurstDur)); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl3, set11nRate(i->rates, 0) 24662306a36Sopenharmony_ci | set11nRate(i->rates, 1) 24762306a36Sopenharmony_ci | set11nRate(i->rates, 2) 24862306a36Sopenharmony_ci | set11nRate(i->rates, 3)); 24962306a36Sopenharmony_ci } else { 25062306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl2, 0); 25162306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl3, 0); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!i->is_first) { 25562306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl0, 0); 25662306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl1, ctl1); 25762306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl6, ctl6); 25862306a36Sopenharmony_ci return; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci ctl1 |= (i->keyix != ATH9K_TXKEYIX_INVALID ? SM(i->keyix, AR_DestIdx) : 0) 26262306a36Sopenharmony_ci | SM(i->type, AR_FrameType) 26362306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) 26462306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) 26562306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci switch (i->aggr) { 26862306a36Sopenharmony_ci case AGGR_BUF_FIRST: 26962306a36Sopenharmony_ci ctl6 |= SM(i->aggr_len, AR_AggrLen); 27062306a36Sopenharmony_ci fallthrough; 27162306a36Sopenharmony_ci case AGGR_BUF_MIDDLE: 27262306a36Sopenharmony_ci ctl1 |= AR_IsAggr | AR_MoreAggr; 27362306a36Sopenharmony_ci ctl6 |= SM(i->ndelim, AR_PadDelim); 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci case AGGR_BUF_LAST: 27662306a36Sopenharmony_ci ctl1 |= AR_IsAggr; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci case AGGR_BUF_NONE: 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl0, (i->pkt_len & AR_FrameLen) 28362306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) 28462306a36Sopenharmony_ci | SM(i->txpower[0], AR_XmitPower0) 28562306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) 28662306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) 28762306a36Sopenharmony_ci | (i->keyix != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) 28862306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) 28962306a36Sopenharmony_ci | (i->flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable : 29062306a36Sopenharmony_ci (i->flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0))); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl1, ctl1); 29362306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl6, ctl6); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (i->aggr == AGGR_BUF_MIDDLE || i->aggr == AGGR_BUF_LAST) 29662306a36Sopenharmony_ci return; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl4, set11nPktDurRTSCTS(i->rates, 0) 29962306a36Sopenharmony_ci | set11nPktDurRTSCTS(i->rates, 1)); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl5, set11nPktDurRTSCTS(i->rates, 2) 30262306a36Sopenharmony_ci | set11nPktDurRTSCTS(i->rates, 3)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl7, 30562306a36Sopenharmony_ci set11nRateFlags(i->rates, 0) | set11nChainSel(i->rates, 0) 30662306a36Sopenharmony_ci | set11nRateFlags(i->rates, 1) | set11nChainSel(i->rates, 1) 30762306a36Sopenharmony_ci | set11nRateFlags(i->rates, 2) | set11nChainSel(i->rates, 2) 30862306a36Sopenharmony_ci | set11nRateFlags(i->rates, 3) | set11nChainSel(i->rates, 3) 30962306a36Sopenharmony_ci | SM(i->rtscts_rate, AR_RTSCTSRate)); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl9, SM(i->txpower[1], AR_XmitPower1)); 31262306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl10, SM(i->txpower[2], AR_XmitPower2)); 31362306a36Sopenharmony_ci WRITE_ONCE(ads->ds_ctl11, SM(i->txpower[3], AR_XmitPower3)); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, 31762306a36Sopenharmony_ci struct ath_tx_status *ts) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct ar5416_desc *ads = AR5416DESC(ds); 32062306a36Sopenharmony_ci u32 status; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci status = READ_ONCE(ads->ds_txstatus9); 32362306a36Sopenharmony_ci if ((status & AR_TxDone) == 0) 32462306a36Sopenharmony_ci return -EINPROGRESS; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ts->ts_tstamp = ads->AR_SendTimestamp; 32762306a36Sopenharmony_ci ts->ts_status = 0; 32862306a36Sopenharmony_ci ts->ts_flags = 0; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (status & AR_TxOpExceeded) 33162306a36Sopenharmony_ci ts->ts_status |= ATH9K_TXERR_XTXOP; 33262306a36Sopenharmony_ci ts->tid = MS(status, AR_TxTid); 33362306a36Sopenharmony_ci ts->ts_rateindex = MS(status, AR_FinalTxIdx); 33462306a36Sopenharmony_ci ts->ts_seqnum = MS(status, AR_SeqNum); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci status = READ_ONCE(ads->ds_txstatus0); 33762306a36Sopenharmony_ci ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); 33862306a36Sopenharmony_ci ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); 33962306a36Sopenharmony_ci ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); 34062306a36Sopenharmony_ci if (status & AR_TxBaStatus) { 34162306a36Sopenharmony_ci ts->ts_flags |= ATH9K_TX_BA; 34262306a36Sopenharmony_ci ts->ba_low = ads->AR_BaBitmapLow; 34362306a36Sopenharmony_ci ts->ba_high = ads->AR_BaBitmapHigh; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci status = READ_ONCE(ads->ds_txstatus1); 34762306a36Sopenharmony_ci if (status & AR_FrmXmitOK) 34862306a36Sopenharmony_ci ts->ts_status |= ATH9K_TX_ACKED; 34962306a36Sopenharmony_ci else { 35062306a36Sopenharmony_ci if (status & AR_ExcessiveRetries) 35162306a36Sopenharmony_ci ts->ts_status |= ATH9K_TXERR_XRETRY; 35262306a36Sopenharmony_ci if (status & AR_Filtered) 35362306a36Sopenharmony_ci ts->ts_status |= ATH9K_TXERR_FILT; 35462306a36Sopenharmony_ci if (status & AR_FIFOUnderrun) { 35562306a36Sopenharmony_ci ts->ts_status |= ATH9K_TXERR_FIFO; 35662306a36Sopenharmony_ci ath9k_hw_updatetxtriglevel(ah, true); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci if (status & AR_TxTimerExpired) 36062306a36Sopenharmony_ci ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; 36162306a36Sopenharmony_ci if (status & AR_DescCfgErr) 36262306a36Sopenharmony_ci ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; 36362306a36Sopenharmony_ci if (status & AR_TxDataUnderrun) { 36462306a36Sopenharmony_ci ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; 36562306a36Sopenharmony_ci ath9k_hw_updatetxtriglevel(ah, true); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci if (status & AR_TxDelimUnderrun) { 36862306a36Sopenharmony_ci ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; 36962306a36Sopenharmony_ci ath9k_hw_updatetxtriglevel(ah, true); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci ts->ts_shortretry = MS(status, AR_RTSFailCnt); 37262306a36Sopenharmony_ci ts->ts_longretry = MS(status, AR_DataFailCnt); 37362306a36Sopenharmony_ci ts->ts_virtcol = MS(status, AR_VirtRetryCnt); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci status = READ_ONCE(ads->ds_txstatus5); 37662306a36Sopenharmony_ci ts->ts_rssi = MS(status, AR_TxRSSICombined); 37762306a36Sopenharmony_ci ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); 37862306a36Sopenharmony_ci ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); 37962306a36Sopenharmony_ci ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ts->evm0 = ads->AR_TxEVM0; 38262306a36Sopenharmony_ci ts->evm1 = ads->AR_TxEVM1; 38362306a36Sopenharmony_ci ts->evm2 = ads->AR_TxEVM2; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int ar9002_hw_get_duration(struct ath_hw *ah, const void *ds, int index) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct ar5416_desc *ads = AR5416DESC(ds); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci switch (index) { 39362306a36Sopenharmony_ci case 0: 39462306a36Sopenharmony_ci return MS(READ_ONCE(ads->ds_ctl4), AR_PacketDur0); 39562306a36Sopenharmony_ci case 1: 39662306a36Sopenharmony_ci return MS(READ_ONCE(ads->ds_ctl4), AR_PacketDur1); 39762306a36Sopenharmony_ci case 2: 39862306a36Sopenharmony_ci return MS(READ_ONCE(ads->ds_ctl5), AR_PacketDur2); 39962306a36Sopenharmony_ci case 3: 40062306a36Sopenharmony_ci return MS(READ_ONCE(ads->ds_ctl5), AR_PacketDur3); 40162306a36Sopenharmony_ci default: 40262306a36Sopenharmony_ci return -1; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_civoid ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, 40762306a36Sopenharmony_ci u32 size, u32 flags) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct ar5416_desc *ads = AR5416DESC(ds); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci ads->ds_ctl1 = size & AR_BufLen; 41262306a36Sopenharmony_ci if (flags & ATH9K_RXDESC_INTREQ) 41362306a36Sopenharmony_ci ads->ds_ctl1 |= AR_RxIntrReq; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci memset(&ads->u.rx, 0, sizeof(ads->u.rx)); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ciEXPORT_SYMBOL(ath9k_hw_setuprxdesc); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_civoid ar9002_hw_attach_mac_ops(struct ath_hw *ah) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct ath_hw_ops *ops = ath9k_hw_ops(ah); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ops->rx_enable = ar9002_hw_rx_enable; 42462306a36Sopenharmony_ci ops->set_desc_link = ar9002_hw_set_desc_link; 42562306a36Sopenharmony_ci ops->get_isr = ar9002_hw_get_isr; 42662306a36Sopenharmony_ci ops->set_txdesc = ar9002_set_txdesc; 42762306a36Sopenharmony_ci ops->proc_txdesc = ar9002_hw_proc_txdesc; 42862306a36Sopenharmony_ci ops->get_duration = ar9002_hw_get_duration; 42962306a36Sopenharmony_ci} 430