2010-04-15 17:39:28 -04:00
/*
2011-05-17 13:36:18 +05:30
* Copyright ( c ) 2008 - 2011 Atheros Communications Inc .
2010-04-15 17:39:28 -04:00
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include "hw.h"
2011-05-27 16:14:23 -04:00
# include <linux/export.h>
2010-04-15 17:39:28 -04:00
# define AR_BufLen 0x00000fff
static void ar9002_hw_rx_enable ( struct ath_hw * ah )
{
REG_WRITE ( ah , AR_CR , AR_CR_RXE ) ;
}
static void ar9002_hw_set_desc_link ( void * ds , u32 ds_link )
{
( ( struct ath_desc * ) ds ) - > ds_link = ds_link ;
}
2013-12-19 18:01:48 +01:00
static bool ar9002_hw_get_isr ( struct ath_hw * ah , enum ath9k_int * masked ,
u32 * sync_cause_p )
2010-04-15 17:39:28 -04:00
{
u32 isr = 0 ;
u32 mask2 = 0 ;
struct ath9k_hw_capabilities * pCap = & ah - > caps ;
u32 sync_cause = 0 ;
bool fatal_int = false ;
struct ath_common * common = ath9k_hw_common ( ah ) ;
if ( ! AR_SREV_9100 ( ah ) ) {
if ( REG_READ ( ah , AR_INTR_ASYNC_CAUSE ) & AR_INTR_MAC_IRQ ) {
if ( ( REG_READ ( ah , AR_RTC_STATUS ) & AR_RTC_STATUS_M )
= = AR_RTC_STATUS_ON ) {
isr = REG_READ ( ah , AR_ISR ) ;
}
}
sync_cause = REG_READ ( ah , AR_INTR_SYNC_CAUSE ) &
AR_INTR_SYNC_DEFAULT ;
* masked = 0 ;
if ( ! isr & & ! sync_cause )
return false ;
} else {
* masked = 0 ;
isr = REG_READ ( ah , AR_ISR ) ;
}
if ( isr ) {
if ( isr & AR_ISR_BCNMISC ) {
u32 isr2 ;
isr2 = REG_READ ( ah , AR_ISR_S2 ) ;
if ( isr2 & AR_ISR_S2_TIM )
mask2 | = ATH9K_INT_TIM ;
if ( isr2 & AR_ISR_S2_DTIM )
mask2 | = ATH9K_INT_DTIM ;
if ( isr2 & AR_ISR_S2_DTIMSYNC )
mask2 | = ATH9K_INT_DTIMSYNC ;
if ( isr2 & ( AR_ISR_S2_CABEND ) )
mask2 | = ATH9K_INT_CABEND ;
if ( isr2 & AR_ISR_S2_GTT )
mask2 | = ATH9K_INT_GTT ;
if ( isr2 & AR_ISR_S2_CST )
mask2 | = ATH9K_INT_CST ;
if ( isr2 & AR_ISR_S2_TSFOOR )
mask2 | = ATH9K_INT_TSFOOR ;
2013-12-16 07:04:59 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED ) ) {
REG_WRITE ( ah , AR_ISR_S2 , isr2 ) ;
isr & = ~ AR_ISR_BCNMISC ;
}
2010-04-15 17:39:28 -04:00
}
2013-12-16 07:04:59 +05:30
if ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED )
isr = REG_READ ( ah , AR_ISR_RAC ) ;
2010-04-15 17:39:28 -04:00
if ( isr = = 0xffffffff ) {
* masked = 0 ;
return false ;
}
* masked = isr & ATH9K_INT_COMMON ;
2010-10-15 20:03:29 +02:00
if ( isr & ( AR_ISR_RXMINTR | AR_ISR_RXINTM |
AR_ISR_RXOK | AR_ISR_RXERR ) )
2010-04-15 17:39:28 -04:00
* masked | = ATH9K_INT_RX ;
2010-10-15 20:03:29 +02:00
2010-04-15 17:39:28 -04:00
if ( isr &
( AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
AR_ISR_TXEOL ) ) {
u32 s0_s , s1_s ;
* masked | = ATH9K_INT_TX ;
2013-12-16 07:04:59 +05:30
if ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED ) {
s0_s = REG_READ ( ah , AR_ISR_S0_S ) ;
s1_s = REG_READ ( ah , AR_ISR_S1_S ) ;
} else {
s0_s = REG_READ ( ah , AR_ISR_S0 ) ;
REG_WRITE ( ah , AR_ISR_S0 , s0_s ) ;
s1_s = REG_READ ( ah , AR_ISR_S1 ) ;
REG_WRITE ( ah , AR_ISR_S1 , s1_s ) ;
isr & = ~ ( AR_ISR_TXOK |
AR_ISR_TXDESC |
AR_ISR_TXERR |
AR_ISR_TXEOL ) ;
}
2010-04-15 17:39:28 -04:00
ah - > intr_txqs | = MS ( s0_s , AR_ISR_S0_QCU_TXOK ) ;
ah - > intr_txqs | = MS ( s0_s , AR_ISR_S0_QCU_TXDESC ) ;
ah - > intr_txqs | = MS ( s1_s , AR_ISR_S1_QCU_TXERR ) ;
ah - > intr_txqs | = MS ( s1_s , AR_ISR_S1_QCU_TXEOL ) ;
}
if ( isr & AR_ISR_RXORN ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , INTERRUPT ,
2010-12-02 19:12:37 -08:00
" receive FIFO overrun interrupt \n " ) ;
2010-04-15 17:39:28 -04:00
}
* masked | = mask2 ;
}
2013-12-16 07:04:59 +05:30
if ( ! AR_SREV_9100 ( ah ) & & ( isr & AR_ISR_GENTMR ) ) {
2010-04-15 17:39:28 -04:00
u32 s5_s ;
2013-12-16 07:04:59 +05:30
if ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED ) {
s5_s = REG_READ ( ah , AR_ISR_S5_S ) ;
} else {
s5_s = REG_READ ( ah , AR_ISR_S5 ) ;
}
2010-10-15 20:03:29 +02:00
ah - > intr_gen_timer_trigger =
2010-04-15 17:39:28 -04:00
MS ( s5_s , AR_ISR_S5_GENTIMER_TRIG ) ;
2010-10-15 20:03:29 +02:00
ah - > intr_gen_timer_thresh =
MS ( s5_s , AR_ISR_S5_GENTIMER_THRESH ) ;
2010-04-15 17:39:28 -04:00
2010-10-15 20:03:29 +02:00
if ( ah - > intr_gen_timer_trigger )
* masked | = ATH9K_INT_GENTIMER ;
2010-04-15 17:39:28 -04:00
2010-10-15 20:03:29 +02:00
if ( ( s5_s & AR_ISR_S5_TIM_TIMER ) & &
! ( pCap - > hw_caps & ATH9K_HW_CAP_AUTOSLEEP ) )
* masked | = ATH9K_INT_TIM_TIMER ;
2013-12-16 07:04:59 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED ) ) {
REG_WRITE ( ah , AR_ISR_S5 , s5_s ) ;
isr & = ~ AR_ISR_GENTMR ;
}
2010-04-15 17:39:28 -04:00
}
2013-12-16 07:04:59 +05:30
if ( ! ( pCap - > hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED ) ) {
REG_WRITE ( ah , AR_ISR , isr ) ;
REG_READ ( ah , AR_ISR ) ;
}
if ( AR_SREV_9100 ( ah ) )
return true ;
2010-04-15 17:39:28 -04:00
if ( sync_cause ) {
2013-12-19 18:01:48 +01:00
if ( sync_cause_p )
* sync_cause_p = sync_cause ;
2010-04-15 17:39:28 -04:00
fatal_int =
( sync_cause &
( AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR ) )
? true : false ;
if ( fatal_int ) {
if ( sync_cause & AR_INTR_SYNC_HOST1_FATAL ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , ANY ,
2010-12-02 19:12:37 -08:00
" received PCI FATAL interrupt \n " ) ;
2010-04-15 17:39:28 -04:00
}
if ( sync_cause & AR_INTR_SYNC_HOST1_PERR ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , ANY ,
2010-12-02 19:12:37 -08:00
" received PCI PERR interrupt \n " ) ;
2010-04-15 17:39:28 -04:00
}
* masked | = ATH9K_INT_FATAL ;
}
if ( sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , INTERRUPT ,
2010-12-02 19:12:37 -08:00
" AR_INTR_SYNC_RADM_CPL_TIMEOUT \n " ) ;
2010-04-15 17:39:28 -04:00
REG_WRITE ( ah , AR_RC , AR_RC_HOSTIF ) ;
REG_WRITE ( ah , AR_RC , 0 ) ;
* masked | = ATH9K_INT_FATAL ;
}
if ( sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT ) {
2011-12-15 14:55:53 -08:00
ath_dbg ( common , INTERRUPT ,
2010-12-02 19:12:37 -08:00
" AR_INTR_SYNC_LOCAL_TIMEOUT \n " ) ;
2010-04-15 17:39:28 -04:00
}
REG_WRITE ( ah , AR_INTR_SYNC_CAUSE_CLR , sync_cause ) ;
( void ) REG_READ ( ah , AR_INTR_SYNC_CAUSE_CLR ) ;
}
return true ;
}
2011-09-14 21:24:21 +02:00
static void
ar9002_set_txdesc ( struct ath_hw * ah , void * ds , struct ath_tx_info * i )
{
struct ar5416_desc * ads = AR5416DESC ( ds ) ;
u32 ctl1 , ctl6 ;
ads - > ds_txstatus0 = ads - > ds_txstatus1 = 0 ;
ads - > ds_txstatus2 = ads - > ds_txstatus3 = 0 ;
ads - > ds_txstatus4 = ads - > ds_txstatus5 = 0 ;
ads - > ds_txstatus6 = ads - > ds_txstatus7 = 0 ;
ads - > ds_txstatus8 = ads - > ds_txstatus9 = 0 ;
ACCESS_ONCE ( ads - > ds_link ) = i - > link ;
ACCESS_ONCE ( ads - > ds_data ) = i - > buf_addr [ 0 ] ;
ctl1 = i - > buf_len [ 0 ] | ( i - > is_last ? 0 : AR_TxMore ) ;
ctl6 = SM ( i - > keytype , AR_EncrType ) ;
if ( AR_SREV_9285 ( ah ) ) {
ads - > ds_ctl8 = 0 ;
ads - > ds_ctl9 = 0 ;
ads - > ds_ctl10 = 0 ;
ads - > ds_ctl11 = 0 ;
}
if ( ( i - > is_first | | i - > is_last ) & &
i - > aggr ! = AGGR_BUF_MIDDLE & & i - > aggr ! = AGGR_BUF_LAST ) {
ACCESS_ONCE ( ads - > ds_ctl2 ) = set11nTries ( i - > rates , 0 )
| set11nTries ( i - > rates , 1 )
| set11nTries ( i - > rates , 2 )
| set11nTries ( i - > rates , 3 )
| ( i - > dur_update ? AR_DurUpdateEna : 0 )
| SM ( 0 , AR_BurstDur ) ;
ACCESS_ONCE ( ads - > ds_ctl3 ) = set11nRate ( i - > rates , 0 )
| set11nRate ( i - > rates , 1 )
| set11nRate ( i - > rates , 2 )
| set11nRate ( i - > rates , 3 ) ;
} else {
ACCESS_ONCE ( ads - > ds_ctl2 ) = 0 ;
ACCESS_ONCE ( ads - > ds_ctl3 ) = 0 ;
}
if ( ! i - > is_first ) {
ACCESS_ONCE ( ads - > ds_ctl0 ) = 0 ;
ACCESS_ONCE ( ads - > ds_ctl1 ) = ctl1 ;
ACCESS_ONCE ( ads - > ds_ctl6 ) = ctl6 ;
return ;
}
ctl1 | = ( i - > keyix ! = ATH9K_TXKEYIX_INVALID ? SM ( i - > keyix , AR_DestIdx ) : 0 )
| SM ( i - > type , AR_FrameType )
| ( i - > flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0 )
| ( i - > flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0 )
| ( i - > flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0 ) ;
switch ( i - > aggr ) {
case AGGR_BUF_FIRST :
ctl6 | = SM ( i - > aggr_len , AR_AggrLen ) ;
/* fall through */
case AGGR_BUF_MIDDLE :
ctl1 | = AR_IsAggr | AR_MoreAggr ;
ctl6 | = SM ( i - > ndelim , AR_PadDelim ) ;
break ;
case AGGR_BUF_LAST :
ctl1 | = AR_IsAggr ;
break ;
case AGGR_BUF_NONE :
break ;
}
ACCESS_ONCE ( ads - > ds_ctl0 ) = ( i - > pkt_len & AR_FrameLen )
| ( i - > flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0 )
2014-11-25 00:21:41 +01:00
| SM ( i - > txpower [ 0 ] , AR_XmitPower0 )
2011-09-14 21:24:21 +02:00
| ( i - > flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0 )
| ( i - > flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0 )
| ( i - > keyix ! = ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0 )
| ( i - > flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0 )
| ( i - > flags & ATH9K_TXDESC_RTSENA ? AR_RTSEnable :
( i - > flags & ATH9K_TXDESC_CTSENA ? AR_CTSEnable : 0 ) ) ;
ACCESS_ONCE ( ads - > ds_ctl1 ) = ctl1 ;
ACCESS_ONCE ( ads - > ds_ctl6 ) = ctl6 ;
if ( i - > aggr = = AGGR_BUF_MIDDLE | | i - > aggr = = AGGR_BUF_LAST )
return ;
ACCESS_ONCE ( ads - > ds_ctl4 ) = set11nPktDurRTSCTS ( i - > rates , 0 )
| set11nPktDurRTSCTS ( i - > rates , 1 ) ;
ACCESS_ONCE ( ads - > ds_ctl5 ) = set11nPktDurRTSCTS ( i - > rates , 2 )
| set11nPktDurRTSCTS ( i - > rates , 3 ) ;
ACCESS_ONCE ( ads - > ds_ctl7 ) = set11nRateFlags ( i - > rates , 0 )
| set11nRateFlags ( i - > rates , 1 )
| set11nRateFlags ( i - > rates , 2 )
| set11nRateFlags ( i - > rates , 3 )
| SM ( i - > rtscts_rate , AR_RTSCTSRate ) ;
2014-07-16 23:20:10 +02:00
2014-11-25 00:21:41 +01:00
ACCESS_ONCE ( ads - > ds_ctl9 ) = SM ( i - > txpower [ 1 ] , AR_XmitPower1 ) ;
ACCESS_ONCE ( ads - > ds_ctl10 ) = SM ( i - > txpower [ 2 ] , AR_XmitPower2 ) ;
ACCESS_ONCE ( ads - > ds_ctl11 ) = SM ( i - > txpower [ 3 ] , AR_XmitPower3 ) ;
2011-09-14 21:24:21 +02:00
}
2010-04-15 17:39:28 -04:00
static int ar9002_hw_proc_txdesc ( struct ath_hw * ah , void * ds ,
struct ath_tx_status * ts )
{
struct ar5416_desc * ads = AR5416DESC ( ds ) ;
2010-10-15 20:03:30 +02:00
u32 status ;
2010-04-15 17:39:28 -04:00
2010-10-15 20:03:30 +02:00
status = ACCESS_ONCE ( ads - > ds_txstatus9 ) ;
if ( ( status & AR_TxDone ) = = 0 )
2010-04-15 17:39:28 -04:00
return - EINPROGRESS ;
ts - > ts_tstamp = ads - > AR_SendTimestamp ;
ts - > ts_status = 0 ;
ts - > ts_flags = 0 ;
2010-10-15 20:03:30 +02:00
if ( status & AR_TxOpExceeded )
ts - > ts_status | = ATH9K_TXERR_XTXOP ;
ts - > tid = MS ( status , AR_TxTid ) ;
ts - > ts_rateindex = MS ( status , AR_FinalTxIdx ) ;
ts - > ts_seqnum = MS ( status , AR_SeqNum ) ;
status = ACCESS_ONCE ( ads - > ds_txstatus0 ) ;
ts - > ts_rssi_ctl0 = MS ( status , AR_TxRSSIAnt00 ) ;
ts - > ts_rssi_ctl1 = MS ( status , AR_TxRSSIAnt01 ) ;
ts - > ts_rssi_ctl2 = MS ( status , AR_TxRSSIAnt02 ) ;
if ( status & AR_TxBaStatus ) {
ts - > ts_flags | = ATH9K_TX_BA ;
ts - > ba_low = ads - > AR_BaBitmapLow ;
ts - > ba_high = ads - > AR_BaBitmapHigh ;
}
status = ACCESS_ONCE ( ads - > ds_txstatus1 ) ;
if ( status & AR_FrmXmitOK )
2010-04-15 17:39:28 -04:00
ts - > ts_status | = ATH9K_TX_ACKED ;
2010-10-21 02:47:23 +02:00
else {
if ( status & AR_ExcessiveRetries )
ts - > ts_status | = ATH9K_TXERR_XRETRY ;
if ( status & AR_Filtered )
ts - > ts_status | = ATH9K_TXERR_FILT ;
if ( status & AR_FIFOUnderrun ) {
ts - > ts_status | = ATH9K_TXERR_FIFO ;
ath9k_hw_updatetxtriglevel ( ah , true ) ;
}
2010-04-15 17:39:28 -04:00
}
2010-10-15 20:03:30 +02:00
if ( status & AR_TxTimerExpired )
2010-04-15 17:39:28 -04:00
ts - > ts_status | = ATH9K_TXERR_TIMER_EXPIRED ;
2010-10-15 20:03:30 +02:00
if ( status & AR_DescCfgErr )
2010-04-15 17:39:28 -04:00
ts - > ts_flags | = ATH9K_TX_DESC_CFG_ERR ;
2010-10-15 20:03:30 +02:00
if ( status & AR_TxDataUnderrun ) {
2010-04-15 17:39:28 -04:00
ts - > ts_flags | = ATH9K_TX_DATA_UNDERRUN ;
ath9k_hw_updatetxtriglevel ( ah , true ) ;
}
2010-10-15 20:03:30 +02:00
if ( status & AR_TxDelimUnderrun ) {
2010-04-15 17:39:28 -04:00
ts - > ts_flags | = ATH9K_TX_DELIM_UNDERRUN ;
ath9k_hw_updatetxtriglevel ( ah , true ) ;
}
2010-10-15 20:03:30 +02:00
ts - > ts_shortretry = MS ( status , AR_RTSFailCnt ) ;
ts - > ts_longretry = MS ( status , AR_DataFailCnt ) ;
ts - > ts_virtcol = MS ( status , AR_VirtRetryCnt ) ;
2010-04-15 17:39:28 -04:00
2010-10-15 20:03:30 +02:00
status = ACCESS_ONCE ( ads - > ds_txstatus5 ) ;
ts - > ts_rssi = MS ( status , AR_TxRSSICombined ) ;
ts - > ts_rssi_ext0 = MS ( status , AR_TxRSSIAnt10 ) ;
ts - > ts_rssi_ext1 = MS ( status , AR_TxRSSIAnt11 ) ;
ts - > ts_rssi_ext2 = MS ( status , AR_TxRSSIAnt12 ) ;
2010-04-15 17:39:28 -04:00
ts - > evm0 = ads - > AR_TxEVM0 ;
ts - > evm1 = ads - > AR_TxEVM1 ;
ts - > evm2 = ads - > AR_TxEVM2 ;
return 0 ;
}
2014-09-30 11:24:23 +02:00
static int ar9002_hw_get_duration ( struct ath_hw * ah , const void * ds , int index )
{
struct ar5416_desc * ads = AR5416DESC ( ds ) ;
switch ( index ) {
case 0 :
return MS ( ACCESS_ONCE ( ads - > ds_ctl4 ) , AR_PacketDur0 ) ;
case 1 :
return MS ( ACCESS_ONCE ( ads - > ds_ctl4 ) , AR_PacketDur1 ) ;
case 2 :
return MS ( ACCESS_ONCE ( ads - > ds_ctl5 ) , AR_PacketDur2 ) ;
case 3 :
return MS ( ACCESS_ONCE ( ads - > ds_ctl5 ) , AR_PacketDur3 ) ;
default :
return - 1 ;
}
}
2010-04-15 17:39:28 -04:00
void ath9k_hw_setuprxdesc ( struct ath_hw * ah , struct ath_desc * ds ,
u32 size , u32 flags )
{
struct ar5416_desc * ads = AR5416DESC ( ds ) ;
ads - > ds_ctl1 = size & AR_BufLen ;
if ( flags & ATH9K_RXDESC_INTREQ )
ads - > ds_ctl1 | = AR_RxIntrReq ;
2012-03-14 16:40:27 +01:00
memset ( & ads - > u . rx , 0 , sizeof ( ads - > u . rx ) ) ;
2010-04-15 17:39:28 -04:00
}
EXPORT_SYMBOL ( ath9k_hw_setuprxdesc ) ;
void ar9002_hw_attach_mac_ops ( struct ath_hw * ah )
{
struct ath_hw_ops * ops = ath9k_hw_ops ( ah ) ;
ops - > rx_enable = ar9002_hw_rx_enable ;
ops - > set_desc_link = ar9002_hw_set_desc_link ;
ops - > get_isr = ar9002_hw_get_isr ;
2011-09-14 21:24:21 +02:00
ops - > set_txdesc = ar9002_set_txdesc ;
2010-04-15 17:39:28 -04:00
ops - > proc_txdesc = ar9002_hw_proc_txdesc ;
2014-09-30 11:24:23 +02:00
ops - > get_duration = ar9002_hw_get_duration ;
2010-04-15 17:39:28 -04:00
}