ath9k_hw: add support for the AR9003 baseband watchdog

The baseband watchdog will monitor blocks of the baseband
through timers and will issue an interrupt when things are
detected to be stalled. It is only available on the AR9003
family.

Cc: Sam Ng <sam.ng@atheros.com>
Cc: Paul Shaw <paul.shaw@atheros.com>
Cc: Don Breslin <don.breslin@atheros.com>
Cc: Cliff Holden <cliff.holden@atheros.com
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Luis R. Rodriguez 2010-05-13 13:33:43 -04:00 committed by John W. Linville
parent ec8aa669b8
commit aea702b70a
7 changed files with 166 additions and 31 deletions

View file

@ -90,6 +90,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
MAP_ISR_S2_CST);
mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
MAP_ISR_S2_TSFOOR);
mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >>
MAP_ISR_S2_BB_WATCHDOG);
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR_S2, isr2);
@ -167,6 +169,9 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
(void) REG_READ(ah, AR_ISR);
}
if (*masked & ATH9K_INT_BB_WATCHDOG)
ar9003_hw_bb_watchdog_read(ah);
}
if (sync_cause) {

View file

@ -47,6 +47,7 @@
#define MAP_ISR_S2_DTIMSYNC 7
#define MAP_ISR_S2_DTIM 7
#define MAP_ISR_S2_TSFOOR 4
#define MAP_ISR_S2_BB_WATCHDOG 6
#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)

View file

@ -1132,3 +1132,122 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->do_getnf = ar9003_hw_do_getnf;
priv_ops->loadnf = ar9003_hw_loadnf;
}
void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u32 idle_tmo_ms = ah->bb_watchdog_timeout_ms;
u32 val, idle_count;
if (!idle_tmo_ms) {
/* disable IRQ, disable chip-reset for BB panic */
REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) &
~(AR_PHY_WATCHDOG_RST_ENABLE |
AR_PHY_WATCHDOG_IRQ_ENABLE));
/* disable watchdog in non-IDLE mode, disable in IDLE mode */
REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
REG_READ(ah, AR_PHY_WATCHDOG_CTL_1) &
~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
AR_PHY_WATCHDOG_IDLE_ENABLE));
ath_print(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
return;
}
/* enable IRQ, disable chip-reset for BB watchdog */
val = REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) & AR_PHY_WATCHDOG_CNTL2_MASK;
REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
(val | AR_PHY_WATCHDOG_IRQ_ENABLE) &
~AR_PHY_WATCHDOG_RST_ENABLE);
/* bound limit to 10 secs */
if (idle_tmo_ms > 10000)
idle_tmo_ms = 10000;
/*
* The time unit for watchdog event is 2^15 44/88MHz cycles.
*
* For HT20 we have a time unit of 2^15/44 MHz = .74 ms per tick
* For HT40 we have a time unit of 2^15/88 MHz = .37 ms per tick
*
* Given we use fast clock now in 5 GHz, these time units should
* be common for both 2 GHz and 5 GHz.
*/
idle_count = (100 * idle_tmo_ms) / 74;
if (ah->curchan && IS_CHAN_HT40(ah->curchan))
idle_count = (100 * idle_tmo_ms) / 37;
/*
* enable watchdog in non-IDLE mode, disable in IDLE mode,
* set idle time-out.
*/
REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
AR_PHY_WATCHDOG_IDLE_MASK |
(AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
ath_print(common, ATH_DBG_RESET,
"Enabled BB Watchdog timeout (%u ms)\n",
idle_tmo_ms);
}
void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
{
/*
* we want to avoid printing in ISR context so we save the
* watchdog status to be printed later in bottom half context.
*/
ah->bb_watchdog_last_status = REG_READ(ah, AR_PHY_WATCHDOG_STATUS);
/*
* the watchdog timer should reset on status read but to be sure
* sure we write 0 to the watchdog status bit.
*/
REG_WRITE(ah, AR_PHY_WATCHDOG_STATUS,
ah->bb_watchdog_last_status & ~AR_PHY_WATCHDOG_STATUS_CLR);
}
void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
if (likely(!(common->debug_mask & ATH_DBG_RESET)))
return;
status = ah->bb_watchdog_last_status;
ath_print(common, ATH_DBG_RESET,
"\n==== BB update: BB status=0x%08x ====\n", status);
ath_print(common, ATH_DBG_RESET,
"** BB state: wd=%u det=%u rdar=%u rOFDM=%d "
"rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
MS(status, AR_PHY_WATCHDOG_INFO),
MS(status, AR_PHY_WATCHDOG_DET_HANG),
MS(status, AR_PHY_WATCHDOG_RADAR_SM),
MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
MS(status, AR_PHY_WATCHDOG_AGC_SM),
MS(status,AR_PHY_WATCHDOG_SRCH_SM));
ath_print(common, ATH_DBG_RESET,
"** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
ath_print(common, ATH_DBG_RESET,
"** BB mode: BB_gen_controls=0x%08x **\n",
REG_READ(ah, AR_PHY_GEN_CTRL));
if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
ath_print(common, ATH_DBG_RESET,
"** BB busy times: rx_clear=%d%%, "
"rx_frame=%d%%, tx_frame=%d%% **\n",
rxc_pcnt, rxf_pcnt, txf_pcnt);
ath_print(common, ATH_DBG_RESET,
"==== BB update: done ====\n\n");
}
EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);

View file

@ -483,10 +483,10 @@
#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0 (AR_SM_BASE + 0x450)
#define AR_PHY_PANIC_WD_STATUS (AR_SM_BASE + 0x5c0)
#define AR_PHY_PANIC_WD_CTL_1 (AR_SM_BASE + 0x5c4)
#define AR_PHY_PANIC_WD_CTL_2 (AR_SM_BASE + 0x5c8)
#define AR_PHY_BT_CTL (AR_SM_BASE + 0x5cc)
#define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0)
#define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4)
#define AR_PHY_WATCHDOG_CTL_2 (AR_SM_BASE + 0x5c8)
#define AR_PHY_WATCHDOG_CTL (AR_SM_BASE + 0x5cc)
#define AR_PHY_ONLY_WARMRESET (AR_SM_BASE + 0x5d0)
#define AR_PHY_ONLY_CTL (AR_SM_BASE + 0x5d4)
#define AR_PHY_ECO_CTRL (AR_SM_BASE + 0x5dc)
@ -812,35 +812,35 @@
#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001
#define AR_PHY_BB_PANIC_IDLE_ENABLE 0x00000002
#define AR_PHY_BB_PANIC_IDLE_MASK 0xFFFF0000
#define AR_PHY_BB_PANIC_NON_IDLE_MASK 0x0000FFFC
#define AR_PHY_WATCHDOG_NON_IDLE_ENABLE 0x00000001
#define AR_PHY_WATCHDOG_IDLE_ENABLE 0x00000002
#define AR_PHY_WATCHDOG_IDLE_MASK 0xFFFF0000
#define AR_PHY_WATCHDOG_NON_IDLE_MASK 0x0000FFFC
#define AR_PHY_BB_PANIC_RST_ENABLE 0x00000002
#define AR_PHY_BB_PANIC_IRQ_ENABLE 0x00000004
#define AR_PHY_BB_PANIC_CNTL2_MASK 0xFFFFFFF9
#define AR_PHY_WATCHDOG_RST_ENABLE 0x00000002
#define AR_PHY_WATCHDOG_IRQ_ENABLE 0x00000004
#define AR_PHY_WATCHDOG_CNTL2_MASK 0xFFFFFFF9
#define AR_PHY_BB_WD_STATUS 0x00000007
#define AR_PHY_BB_WD_STATUS_S 0
#define AR_PHY_BB_WD_DET_HANG 0x00000008
#define AR_PHY_BB_WD_DET_HANG_S 3
#define AR_PHY_BB_WD_RADAR_SM 0x000000F0
#define AR_PHY_BB_WD_RADAR_SM_S 4
#define AR_PHY_BB_WD_RX_OFDM_SM 0x00000F00
#define AR_PHY_BB_WD_RX_OFDM_SM_S 8
#define AR_PHY_BB_WD_RX_CCK_SM 0x0000F000
#define AR_PHY_BB_WD_RX_CCK_SM_S 12
#define AR_PHY_BB_WD_TX_OFDM_SM 0x000F0000
#define AR_PHY_BB_WD_TX_OFDM_SM_S 16
#define AR_PHY_BB_WD_TX_CCK_SM 0x00F00000
#define AR_PHY_BB_WD_TX_CCK_SM_S 20
#define AR_PHY_BB_WD_AGC_SM 0x0F000000
#define AR_PHY_BB_WD_AGC_SM_S 24
#define AR_PHY_BB_WD_SRCH_SM 0xF0000000
#define AR_PHY_BB_WD_SRCH_SM_S 28
#define AR_PHY_WATCHDOG_INFO 0x00000007
#define AR_PHY_WATCHDOG_INFO_S 0
#define AR_PHY_WATCHDOG_DET_HANG 0x00000008
#define AR_PHY_WATCHDOG_DET_HANG_S 3
#define AR_PHY_WATCHDOG_RADAR_SM 0x000000F0
#define AR_PHY_WATCHDOG_RADAR_SM_S 4
#define AR_PHY_WATCHDOG_RX_OFDM_SM 0x00000F00
#define AR_PHY_WATCHDOG_RX_OFDM_SM_S 8
#define AR_PHY_WATCHDOG_RX_CCK_SM 0x0000F000
#define AR_PHY_WATCHDOG_RX_CCK_SM_S 12
#define AR_PHY_WATCHDOG_TX_OFDM_SM 0x000F0000
#define AR_PHY_WATCHDOG_TX_OFDM_SM_S 16
#define AR_PHY_WATCHDOG_TX_CCK_SM 0x00F00000
#define AR_PHY_WATCHDOG_TX_CCK_SM_S 20
#define AR_PHY_WATCHDOG_AGC_SM 0x0F000000
#define AR_PHY_WATCHDOG_AGC_SM_S 24
#define AR_PHY_WATCHDOG_SRCH_SM 0xF0000000
#define AR_PHY_WATCHDOG_SRCH_SM_S 28
#define AR_PHY_BB_WD_STATUS_CLR 0x00000008
#define AR_PHY_WATCHDOG_STATUS_CLR 0x00000008
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);

View file

@ -627,6 +627,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ar9003_hw_set_nf_limits(ah);
ath9k_init_nfcal_hist_buffer(ah);
ah->bb_watchdog_timeout_ms = 25;
common->state = ATH_HW_INITIALIZED;
@ -1441,6 +1442,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9300_20_OR_LATER(ah)) {
ath9k_hw_loadnf(ah, curchan);
ath9k_hw_start_nfcal(ah);
ar9003_hw_bb_watchdog_config(ah);
}
return 0;

View file

@ -279,6 +279,7 @@ enum ath9k_int {
ATH9K_INT_TX = 0x00000040,
ATH9K_INT_TXDESC = 0x00000080,
ATH9K_INT_TIM_TIMER = 0x00000100,
ATH9K_INT_BB_WATCHDOG = 0x00000400,
ATH9K_INT_TXURN = 0x00000800,
ATH9K_INT_MIB = 0x00001000,
ATH9K_INT_RXPHY = 0x00004000,
@ -789,6 +790,9 @@ struct ath_hw {
u32 ts_paddr_end;
u16 ts_tail;
u8 ts_size;
u32 bb_watchdog_last_status;
u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@ -910,10 +914,13 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
/*
* Code specifric to AR9003, we stuff these here to avoid callbacks
* Code specific to AR9003, we stuff these here to avoid callbacks
* for older families
*/
void ar9003_hw_set_nf_limits(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
/* Hardware family op attach helpers */
void ar5008_hw_attach_phy_ops(struct ath_hw *ah);

View file

@ -222,6 +222,7 @@
#define AR_ISR_S2 0x008c
#define AR_ISR_S2_QCU_TXURN 0x000003FF
#define AR_ISR_S2_BB_WATCHDOG 0x00010000
#define AR_ISR_S2_CST 0x00400000
#define AR_ISR_S2_GTT 0x00800000
#define AR_ISR_S2_TIM 0x01000000