From: Paul Stewart Date: Sat, 18 Feb 2012 20:53:05 +0000 (-0800) Subject: CHROMIUMOS: Move ath recv hang messages behind a flag X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=e1418079ce0dcc40cff76da06f40f8c5edf9b5d4;p=cascardo%2Flinux.git CHROMIUMOS: Move ath recv hang messages behind a flag Signed-off-by: Paul Stewart BUG=None TEST=Load kernel Change-Id: Icf8b75f710c30cbd2554693fcd52c8cbdce915bd Reviewed-on: https://gerrit.chromium.org/gerrit/16219 Reviewed-by: Benson Leung Reviewed-by: Sam Leffler Tested-by: Paul Stewart Commit-Ready: Paul Stewart [ Rebase-3.3: s/ATH_DBG_RX_STUCK/RX_STUCK when used by ath_dbg() macro -ggg ] --- diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index c54b7d37bff1..fa90d05892c9 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -242,6 +242,7 @@ enum ATH_DEBUG { ATH_DBG_BSTUCK = 0x00008000, ATH_DBG_MCI = 0x00010000, ATH_DBG_DFS = 0x00020000, + ATH_DBG_RX_STUCK = 0x00040000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index a66a13b76848..c865049ed443 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -565,3 +565,22 @@ void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start, ath9k_hw_reset_txstatus_ring(ah); } EXPORT_SYMBOL(ath9k_hw_setup_statusring); + +void ar9003_hw_dump_txdesc(struct ath_hw *ah) +{ + struct ar9003_txs *ads; + struct ath_common *common = ath9k_hw_common(ah); + u32 status, i, len = 0; + u8 buf[1200]; + + memset(buf, 0, sizeof(buf)); + ath_dbg(common, RX_STUCK, "ts_tail %d\n", ah->ts_tail); + + for (i = 0; i < ah->ts_size; i++) { + ads = &ah->ts_ring[i]; + status = ACCESS_ONCE(ads->status8); + len += sprintf(buf + len, "%d ", status & AR_TxDone); + } + ath_dbg(common, RX_STUCK, "ring status: %s\n", buf); +} +EXPORT_SYMBOL(ar9003_hw_dump_txdesc); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 600aca9fe6b1..60032b286e3a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1504,3 +1504,51 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_RESTART, val); } EXPORT_SYMBOL(ar9003_hw_disable_phy_restart); + +void ar9003_hw_dump_ani_reg(struct ath_hw *ah) +{ + u32 reg; + struct ath_common *common = ath9k_hw_common(ah); + + reg = REG_READ(ah, AR_PHY_FIND_SIG_LOW); + ath_dbg(common, RX_STUCK, "FIRStep Low = 0x%x (%d)\n", + MS(reg, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW), + MS(reg, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW)); + reg = REG_READ(ah, AR_PHY_DESIRED_SZ); + ath_dbg(common, RX_STUCK, "Total Desired = 0x%x (%d)\n", + MS(reg, AR_PHY_DESIRED_SZ_TOT_DES), + MS(reg, AR_PHY_DESIRED_SZ_TOT_DES)); + ath_dbg(common, RX_STUCK, "ADC Desired = 0x%x (%d)\n", + MS(reg, AR_PHY_DESIRED_SZ_ADC), + MS(reg, AR_PHY_DESIRED_SZ_ADC)); + reg = REG_READ(ah, AR_PHY_FIND_SIG); + ath_dbg(common, RX_STUCK, "FIRStep = 0x%x (%d)\n", + MS(reg, AR_PHY_FIND_SIG_FIRSTEP), + MS(reg, AR_PHY_FIND_SIG_FIRSTEP)); + reg = REG_READ(ah, AR_PHY_AGC); + ath_dbg(common, RX_STUCK, "Coarse High = 0x%x (%d)\n", + MS(reg, AR_PHY_AGC_COARSE_HIGH), + MS(reg, AR_PHY_AGC_COARSE_HIGH)); + ath_dbg(common, RX_STUCK, "Coarse Low = 0x%x (%d)\n", + MS(reg, AR_PHY_AGC_COARSE_LOW), + MS(reg, AR_PHY_AGC_COARSE_LOW)); + ath_dbg(common, RX_STUCK, "Coarse Power Constant = 0x%x (%d)\n", + MS(reg, AR_PHY_AGC_COARSE_PWR_CONST), + MS(reg, AR_PHY_AGC_COARSE_PWR_CONST)); + reg = REG_READ(ah, AR_PHY_TIMING5); + ath_dbg(common, RX_STUCK, "Enable Cyclic Power Thresh = %d\n", + MS(reg, AR_PHY_TIMING5_CYCPWR_THR1_ENABLE)); + ath_dbg(common, RX_STUCK, "Cyclic Power Thresh = 0x%x (%d)\n", + MS(reg, AR_PHY_TIMING5_CYCPWR_THR1), + MS(reg, AR_PHY_TIMING5_CYCPWR_THR1)); + ath_dbg(common, RX_STUCK, "Cyclic Power Thresh 1A= 0x%x (%d)\n", + MS(reg, AR_PHY_TIMING5_CYCPWR_THR1A), + MS(reg, AR_PHY_TIMING5_CYCPWR_THR1A)); + reg = REG_READ(ah, AR_PHY_DAG_CTRLCCK); + ath_dbg(common, RX_STUCK, "Barker RSSI Thresh Enable = %d\n", + MS(reg, AR_PHY_DAG_CTRLCCK_EN_RSSI_THR)); + ath_dbg(common, RX_STUCK, "Barker RSSI Thresh = 0x%x (%d)\n", + MS(reg, AR_PHY_DAG_CTRLCCK_RSSI_THR), + MS(reg, AR_PHY_DAG_CTRLCCK_RSSI_THR)); +} +EXPORT_SYMBOL(ar9003_hw_dump_ani_reg); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index fa84e37bf091..c3a3cdb84c10 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -3074,3 +3074,65 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len) hw_name[used] = '\0'; } EXPORT_SYMBOL(ath9k_hw_name); + +#define DCU_COMPLETE_STATE 1 +#define NUM_STATUS_READS 50 +bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +{ + u32 dma_dbg_4 = 0, dma_dbg_5 = 0, dma_dbg_6; + u32 cur_chain_state = 0; + int i, hang_pos, hang_state = 0; + + dma_dbg_6 = REG_READ(ah, AR_DMADBG_6); + + if ((dma_dbg_6 & 0x3) != DCU_COMPLETE_STATE) { + ath_dbg(ath9k_hw_common(ah), RX_STUCK, + "MAC Hang signature not found at DCU complete\n"); + return false; + } + + dma_dbg_5 = REG_READ(ah, AR_DMADBG_5); + for (hang_pos = 3; hang_pos >= 0; hang_pos--) { + hang_state = (dma_dbg_5 >> (5 * hang_pos)) & 0x1f; + if (hang_state) + goto hang_check_iter; + } + + dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); + for (hang_pos = 5; hang_pos >= 0; hang_pos--) { + hang_state = (dma_dbg_4 >> (5 * hang_pos)) & 0x1f; + if (hang_state) + goto hang_check_iter; + } + + ath_dbg(ath9k_hw_common(ah), RX_STUCK, + "MAC Hang signature 1 not found\n"); + return false; + +hang_check_iter: + ath_dbg(ath9k_hw_common(ah), RX_STUCK, + "DMA Registers: %x %x %x Hang pos: %d\n", + dma_dbg_4, dma_dbg_5, dma_dbg_6, hang_pos); + + + for (i = 0; i < NUM_STATUS_READS; i++) { + if (dma_dbg_4) { + dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); + cur_chain_state = (dma_dbg_4 >> (5 * hang_pos)) & 0x1f; + } else { + dma_dbg_5 = REG_READ(ah, AR_DMADBG_5); + cur_chain_state = (dma_dbg_5 >> (5 * hang_pos)) & 0x1f; + } + dma_dbg_6 = REG_READ(ah, AR_DMADBG_6); + + if (((dma_dbg_6 & 0x3) != DCU_COMPLETE_STATE) || + (cur_chain_state != hang_state)) + return false; + } + + ath_dbg(ath9k_hw_common(ah), RX_STUCK, + "MAC Hang signature 1 found\n"); + + return true; +} +EXPORT_SYMBOL(ath9k_hw_detect_mac_hang); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 798ea57252b4..32c2247318b7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -661,6 +661,270 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_tx_node_cleanup(sc, an); } +void ath_rx_poll_work(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; + struct ath9k_nfcal_hist *h = sc->caldata.nfCalHist; + static u32 iter, match_count; + static u64 last_run; + unsigned long flags; + u32 rx_clear, rx, tx, delay = 10, reg; + int i, j; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; + u8 nread; + + if (jiffies_to_msecs(jiffies - last_run) > 30) + iter = match_count = 0; + else { + if (atomic_read(&sc->stop_rx_poll) && iter) { + iter = match_count = 0; + return; + } + iter += 1; + } + sc->ps_flags |= PS_WAIT_FOR_BEACON; + ath9k_ps_wakeup(sc); + + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + + rx_clear = common->cc_rxpoll.rx_busy * 100 / common->cc_rxpoll.cycles; + rx = common->cc_rxpoll.rx_frame * 100 / common->cc_rxpoll.cycles; + tx = common->cc_rxpoll.tx_frame * 100 / common->cc_rxpoll.cycles; + memset(&common->cc_rxpoll, 0, sizeof(common->cc_rxpoll)); + + spin_unlock_irqrestore(&common->cc_lock, flags); + + ath_dbg(common, RX_STUCK, + "--------------------------------------------------\n"); + ath_dbg(common, RX_STUCK, "Iteration: %d\n", iter); + ath_dbg(common, RX_STUCK, "Cycle Counters:\n"); + ath_dbg(common, RX_STUCK, + "rx_clear = %d%% rx_frame %d%% tx_frame %d%%\n", + rx_clear, rx, tx); + + ath_dbg(common, RX_STUCK, "IMR %08x IER %08x intr_cnt %d\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER), + atomic_read(&ah->intr_ref_cnt)); + ar9003_hw_dump_txdesc(ah); + + REG_SET_BIT(ah, AR_DIAG_SW, 0x8080000); + for (i = 0; i < 5; i++) { + ath_dbg(common, RX_STUCK, + "OBS_BUS_1(0x806c) = %08x " + "OBS_BUS_CTRL(0x8068) = %08x\n", + REG_READ(ah, AR_OBS_BUS_1), + REG_READ(ah, AR_OBS_BUS_CTRL)); + } + ath_dbg(common, RX_STUCK, + "DIAG_SW(0x8048) = %08x MAC_PCU_LOGIC_ANALYZER(0x8264) = %08x" + " PCU_MISC_MODE2(0x8344) = %08x\n", + REG_READ(ah, AR_DIAG_SW), + REG_READ(ah, AR_MAC_PCU_LOGIC_ANALYZER), + REG_READ(ah, AR_PCU_MISC_MODE2)); + + ath_dbg(common, RX_STUCK, "0x100 = %08x 0x104 = %08x\n", + REG_READ(ah, 0x100), REG_READ(ah, 0x104)); + for (i = 0; i < 10; i++) + ath_dbg(common, RX_STUCK, "QSTS(%d) = %08x\n", + i, REG_READ(ah, AR_QSTS(i))); + + ath_dbg(common, RX_STUCK, "Rxdp: hp %08x lp %08x\n", + REG_READ(ah, AR_HP_RXDP), REG_READ(ah, AR_LP_RXDP)); + ath_dbg(common, RX_STUCK, + "rx filter: %08x\n", REG_READ(ah, AR_RX_FILTER)); + + ath_dbg(common, RX_STUCK, "DMADBG dump:\n"); + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + ath_dbg(common, RX_STUCK, "%d: %08x ", + i, REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)))); + ath_dbg(common, RX_STUCK, "\n"); + + ath_dbg(common, RX_STUCK, "BB Debug dump:\n"); + /* Step 1a: Set bit 23 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x00800000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2a: Set register 0xa364 to 0x1000 */ + reg = 0x1000; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3a: Read bits 17:0 of register 0x9c20 */ + reg = REG_READ(ah, 0x9c20); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x1000] 0x9c20[17:0] = 0x%x\n", reg); + + /* Step 1b: Set bit 23 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x00800000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2b: Set register 0xa364 to 0x1400 */ + reg = 0x1400; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3b: Read bits 17:0 of register 0x9c20 */ + reg = REG_READ(ah, 0x9c20); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x1400] 0x9c20[17:0] = 0x%x\n", reg); + + /* Step 1c: Set bit 23 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x00800000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2c: Set register 0xa364 to 0x3C00 */ + reg = 0x3c00; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3c: Read bits 17:0 of register 0x9c20 */ + reg = REG_READ(ah, 0x9c20); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x3C00] 0x9c20[17:0] = 0x%x\n", reg); + + /* Step 1d: Set bit 24 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x001040000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2d: Set register 0xa364 to 0x5005D */ + reg = 0x5005D; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3d: Read bits 17:0 of register 0xa368 */ + reg = REG_READ(ah, 0xa368); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x5005D] 0xa368[17:0] = 0x%x\n", reg); + + /* Step 1e: Set bit 24 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x001040000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2e: Set register 0xa364 to 0x7005D */ + reg = 0x7005D; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3e: Read bits 17:0 of register 0xa368 */ + reg = REG_READ(ah, 0xa368); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x7005D] 0xa368[17:0] = 0x%x\n", reg); + + /* Step 1f: Set bit 24 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x001000000; + reg |= 0x40000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2f: Set register 0xa364 to 0x3005D */ + reg = 0x3005D; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3f: Read bits 17:0 of register 0xa368 */ + reg = REG_READ(ah, 0xa368); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x3005D] 0xa368[17:0] = 0x%x\n", reg); + + /* Step 1g: Set bit 24 of register 0xa360 to 0 */ + reg = REG_READ(ah, 0xa360); + reg &= ~0x001000000; + reg |= 0x40000; + REG_WRITE(ah, 0xa360, reg); + + /* Step 2g: Set register 0xa364 to 0x6005D */ + reg = 0x6005D; + REG_WRITE(ah, 0xa364, reg); + + /* Step 3g: Read bits 17:0 of register 0xa368 */ + reg = REG_READ(ah, 0xa368); + reg &= 0x0003ffff; + ath_dbg(common, RX_STUCK, + "Test Control Status [0x6005D] 0xa368[17:0] = 0x%x\n", reg); + + ar9003_hw_dump_ani_reg(ah); + + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "WATCHDOG", + sc->debug.stats.istats.bb_watchdog); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "RXORN", sc->debug.stats.istats.rxorn); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "TX", sc->debug.stats.istats.txok); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "TXURN", sc->debug.stats.istats.txurn); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "MIB", sc->debug.stats.istats.mib); + ath_dbg(common, RX_STUCK, "%8s: %10u\n", "RXPHY", + sc->debug.stats.istats.rxphyerr); + ath_dbg(common, RX_STUCK, "%8s: %10u\n", "RXKCM", + sc->debug.stats.istats.rx_keycache_miss); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "BMISS", sc->debug.stats.istats.bmiss); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "CST", sc->debug.stats.istats.cst); + ath_dbg(common, RX_STUCK, + "%8s: %10u\n", "GTT", sc->debug.stats.istats.gtt); + + ath_dbg(common, RX_STUCK, "Noise floor dump:\n"); + ath_dbg(common, RX_STUCK, + "Channel Noise Floor : %d\n", ah->noise); + ath_dbg(common, RX_STUCK, + "Chain | privNF | # Readings | NF Readings\n"); + for (i = 0; i < 6; i++) { + if (!(chainmask & (1 << i)) || + ((i >= 3) && !conf_is_ht40(conf))) + continue; + + nread = 5 - h[i].invalidNFcount; + ath_dbg(common, RX_STUCK, + " %d\t %d\t %d\t\t", i, h[i].privNF, nread); + for (j = 0; j < nread; j++) + ath_dbg(common, RX_STUCK, + " %d", h[i].nfCalBuffer[j]); + ath_dbg(common, RX_STUCK, "\n"); + } + + last_run = jiffies; + if (rx_clear > 98) { + ath_dbg(common, RX_STUCK, + "rx clear %d tx %d matched count %d\n", + rx_clear, tx, match_count); + if (match_count++ > 9) { + ath9k_ps_restore(sc); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + iter = match_count = 0; + return; + } + } else if (ath9k_hw_detect_mac_hang(ah)) { + ath_dbg(common, RX_STUCK, "MAC hang signature found\n"); + ath9k_ps_restore(sc); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + iter = match_count = 0; + return; + } else if (iter >= 15) { + iter = match_count = 0; + delay = 200; + } + ath9k_ps_restore(sc); + atomic_set(&sc->stop_rx_poll, 0); + mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies(delay)); +} void ath9k_tasklet(unsigned long data) {