From 2e6dcc48f137097f802aae24b6df39c07531e52e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 28 Feb 2016 20:45:13 +0100 Subject: [PATCH] mt7603: add another tx/rx watchdog check Signed-off-by: Felix Fietkau --- mt7603.h | 7 ++++-- mt7603_mac.c | 64 ++++++++++++++++++++++++++++++++++++++++++++------- mt7603_regs.h | 8 +++++++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/mt7603.h b/mt7603.h index 4f1f94fe..ee0f4824 100644 --- a/mt7603.h +++ b/mt7603.h @@ -33,7 +33,7 @@ #define MT7603_PRE_TBTT_TIME 5000 /* ms */ -#define MT7603_WATCHDOG_TIME 1000 /* ms */ +#define MT7603_WATCHDOG_TIME 100 /* ms */ #define MT7603_WATCHDOG_TIMEOUT 10 /* number of checks */ enum { @@ -124,7 +124,10 @@ struct mt7603_dev { u8 beacon_mask; u8 tx_check; - u8 rx_check; + u8 txrx_check; + + u16 tx_dma_idx[4]; + u16 rx_dma_idx; struct delayed_work mac_work; struct tasklet_struct tx_tasklet; diff --git a/mt7603_mac.c b/mt7603_mac.c index 65a1e2ff..c2556d60 100644 --- a/mt7603_mac.c +++ b/mt7603_mac.c @@ -994,9 +994,6 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev) napi_disable(&dev->mt76.napi[0]); napi_disable(&dev->mt76.napi[1]); - dev->tx_check = 0; - dev->rx_check = 0; - mt7603_beacon_set_timer(dev, -1, 0); mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF); @@ -1032,6 +1029,42 @@ static bool mt7603_tx_dma_busy(struct mt7603_dev *dev) return (val & BIT(8)) && (val & 0xf) != 0xf; } +static bool mt7603_tx_rx_dma_busy(struct mt7603_dev *dev) +{ + struct mt76_queue *q; + u32 dma_idx, prev_dma_idx, val; + int i; + + for (i = 0; i < 4; i++) { + q = &dev->mt76.q_tx[i]; + prev_dma_idx = dev->tx_dma_idx[i]; + dev->tx_dma_idx[i] = dma_idx = ioread32(&q->regs->dma_idx); + + if (dma_idx != prev_dma_idx || + dma_idx == ioread32(&q->regs->cpu_idx)) + continue; + + val = mt76_rr(dev, MT_FC_RSV_COUNT_0); + if (MT76_GET(MT_FC_RSV_COUNT_0_P0, val) > 0xa0) + break; + } + + if (i == 4) + return false; + + q = &dev->mt76.q_rx[0]; + prev_dma_idx = dev->rx_dma_idx; + dev->rx_dma_idx = dma_idx = ioread32(&q->regs->dma_idx); + if (dma_idx != prev_dma_idx) + return false; + + if (dma_idx == ioread32(&q->regs->cpu_idx)) + return false; + + val = mt76_rr(dev, MT_FC_SP2_Q0Q1); + return MT76_GET(MT_FC_SP2_Q0Q1_SRC_COUNT_Q0, val) > 0x20; +} + void mt7603_mac_work(struct work_struct *work) { struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mac_work.work); @@ -1041,18 +1074,33 @@ void mt7603_mac_work(struct work_struct *work) if (mt7603_tx_dma_busy(dev) || dev->tx_check >= MT7603_WATCHDOG_TIMEOUT) { - time = MT7603_WATCHDOG_TIME / 10; - if (WARN_ON_ONCE(++dev->tx_check >= MT7603_WATCHDOG_TIMEOUT)) { - mt7603_mac_watchdog_reset(dev); - goto out; - } + if (WARN_ON_ONCE(++dev->tx_check >= MT7603_WATCHDOG_TIMEOUT)) + goto reset; } else { dev->tx_check = 0; } + if (mt7603_tx_rx_dma_busy(dev) || + dev->txrx_check >= MT7603_WATCHDOG_TIMEOUT) { + + if (WARN_ON_ONCE(++dev->txrx_check >= MT7603_WATCHDOG_TIMEOUT)) + goto reset; + } else { + dev->txrx_check = 0; + } + out: ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, msecs_to_jiffies(time)); mutex_unlock(&dev->mutex); + return; + +reset: + dev->tx_check = 0; + dev->txrx_check = 0; + dev->rx_dma_idx = ~0; + memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx)); + mt7603_mac_watchdog_reset(dev); + goto out; } diff --git a/mt7603_regs.h b/mt7603_regs.h index 0b0d0298..09d166e3 100644 --- a/mt7603_regs.h +++ b/mt7603_regs.h @@ -115,6 +115,14 @@ #define MT_PSE_FRP_P2_RQ1 GENMASK(11, 9) #define MT_PSE_FRP_P2_RQ2 GENMASK(14, 12) +#define MT_FC_RSV_COUNT_0 MT_PSE(0x13c) +#define MT_FC_RSV_COUNT_0_P0 GENMASK(11, 0) +#define MT_FC_RSV_COUNT_0_P1 GENMASK(27, 16) + +#define MT_FC_SP2_Q0Q1 MT_PSE(0x14c) +#define MT_FC_SP2_Q0Q1_SRC_COUNT_Q0 GENMASK(11, 0) +#define MT_FC_SP2_Q0Q1_SRC_COUNT_Q1 GENMASK(27, 16) + #define MT_WF_PHY_BASE 0x10000 #define MT_WF_PHY_OFFSET 0x1000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))