}
EXPORT_SYMBOL(ath9k_hw_name);
-#define DCU_COMPLETE_STATE 1
-#define NUM_STATUS_READS 50
+static bool ath9k_hw_check_dcs(u32 dma_dbg, int num_dcu_states,
+ int *hang_state, int *hang_pos)
+{
+ static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */
+ u32 chain_state, dcs_pos, i;
+
+ for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) {
+ chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f;
+ for (i = 0; i < 3; i++) {
+ if (chain_state == dcu_chain_state[i]) {
+ *hang_state = chain_state;
+ *hang_pos = dcs_pos;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#define DCU_COMPLETE_STATE 1
+#define DCU_COMPLETE_STATE_MASK 0x3
+#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;
+ u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4;
+ u32 i, hang_pos, hang_state;
- dma_dbg_6 = REG_READ(ah, AR_DMADBG_6);
+ comp_state = REG_READ(ah, AR_DMADBG_6);
- if ((dma_dbg_6 & 0x3) != DCU_COMPLETE_STATE) {
+ if ((comp_state & DCU_COMPLETE_STATE_MASK) != 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;
- }
+ chain_state = REG_READ(ah, dcs_reg);
+ if (ath9k_hw_check_dcs(chain_state, 6, &hang_state, &hang_pos))
+ 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;
- }
+ dcs_reg = AR_DMADBG_5;
+ chain_state = REG_READ(ah, dcs_reg);
+ if (ath9k_hw_check_dcs(chain_state, 4, &hang_state, &hang_pos))
+ goto hang_check_iter;
ath_dbg(ath9k_hw_common(ah), RX_STUCK,
"MAC Hang signature 1 not found\n");
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);
-
+ "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n",
+ chain_state, comp_state, hang_state, 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);
+ chain_state = REG_READ(ah, dcs_reg);
+ chain_state = (chain_state >> (5 * hang_pos)) & 0x1f;
+ comp_state = REG_READ(ah, AR_DMADBG_6);
- if (((dma_dbg_6 & 0x3) != DCU_COMPLETE_STATE) ||
- (cur_chain_state != hang_state))
+ if (((comp_state & DCU_COMPLETE_STATE_MASK) !=
+ DCU_COMPLETE_STATE) ||
+ (chain_state != hang_state))
return false;
}
if (sc->sc_flags & SC_OP_BEACONS)
ath_set_beacon(sc);
- if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
- mod_timer(&sc->rx_poll_timer,
- jiffies + msecs_to_jiffies(10));
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
if (!common->disable_ani)
ath_start_ani(common);
+ ath_start_rx_poll(sc, 100);
}
if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) {
ath_tx_node_cleanup(sc, an);
}
+void ath_start_rx_poll(struct ath_softc *sc, u32 nmsec)
+{
+ if (!AR_SREV_9300(sc->sc_ah))
+ return;
+
+ if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF))
+ return;
+
+ mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies(nmsec));
+}
+
void ath_rx_poll_work(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
static u32 iter, match_count;
static u64 last_run;
unsigned long flags;
- u32 rx_clear, rx, tx, delay = 10, reg;
- int i, j;
+ u32 rx_clear, rx, tx, reg;
+ int i, j, len;
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
- u8 nread;
+ u8 nread, nmsec = 10, buf[200];
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;
- }
+ else
iter += 1;
- }
- sc->ps_flags |= PS_WAIT_FOR_BEACON;
+
ath9k_ps_wakeup(sc);
spin_lock_irqsave(&common->cc_lock, flags);
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,
REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER),
atomic_read(&ah->intr_ref_cnt));
- ar9003_hw_dump_txdesc(ah);
+ ath_dbg(common, RX_STUCK, "ts tail %d\n", ah->ts_tail);
REG_SET_BIT(ah, AR_DIAG_SW, 0x8080000);
for (i = 0; i < 5; i++) {
"Chain | privNF | # Readings | NF Readings\n");
for (i = 0; i < 6; i++) {
if (!(chainmask & (1 << i)) ||
- ((i >= 3) && !conf_is_ht40(conf)))
+ ((i >= 3) && !conf_is_ht40(conf)))
continue;
+ memset(buf, 0, sizeof(buf));
+ len = 0;
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");
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%d ", h[i].nfCalBuffer[j]);
+ ath_dbg(common, RX_STUCK, " %d\t %d\t %d\t\t %s",
+ i, h[i].privNF, nread, buf);
}
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) {
+ ath_dbg(common, RESET,
+ "rx clear %d match count %d iteration %d\n",
+ rx_clear, match_count, iter);
+ if (match_count++ > 15)
+ goto queue_reset_work;
+ } else if (ath9k_hw_detect_mac_hang(ah))
+ goto queue_reset_work;
+ else if (iter >= 9) {
iter = match_count = 0;
- delay = 200;
+ nmsec = 200;
}
ath9k_ps_restore(sc);
- atomic_set(&sc->stop_rx_poll, 0);
- mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies(delay));
+ ath_start_rx_poll(sc, nmsec);
+ return;
+
+queue_reset_work:
+ ath9k_ps_restore(sc);
+ ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
+ iter = match_count = 0;
}
void ath9k_tasklet(unsigned long data)
if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
ath_set_beacon(sc); /* restart beacons */
- if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
- mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies(300));
-
+ ath_start_rx_poll(sc, 300);
ath9k_hw_set_interrupts(ah);
ath9k_hw_enable_interrupts(ah);
if (!common->disable_ani) {
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
- atomic_set(&sc->stop_rx_poll, 0);
- mod_timer(&sc->rx_poll_timer,
- jiffies + msecs_to_jiffies(300));
}
-
+ ath_start_rx_poll(sc, 300);
}
}