Commit 61c4fa72 authored by Felix Fietkau's avatar Felix Fietkau

mt76: mt7615: implement hardware reset support

When the firmware detects a problem, it needs the host to stop/reset DMA and
resume it again when the hardware state has been reset.
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent f347f81a
......@@ -35,7 +35,8 @@ struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
timeout = expires - jiffies;
wait_event_timeout(dev->mmio.mcu.wait,
!skb_queue_empty(&dev->mmio.mcu.res_q),
(!skb_queue_empty(&dev->mmio.mcu.res_q) ||
test_bit(MT76_MCU_RESET, &dev->phy.state)),
timeout);
return skb_dequeue(&dev->mmio.mcu.res_q);
}
......
......@@ -274,6 +274,7 @@ enum {
MT76_STATE_MCU_RUNNING,
MT76_SCANNING,
MT76_RESET,
MT76_MCU_RESET,
MT76_REMOVED,
MT76_READING_STATS,
};
......
......@@ -265,7 +265,8 @@ int mt7615_dma_init(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN);
/* enable interrupts for TX/RX rings */
mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL);
mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
if (is_mt7622(&dev->mt76))
mt7622_dma_sched_init(dev);
......
......@@ -447,6 +447,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7615_mac_reset_work);
ret = mt7622_wmac_init(dev);
if (ret)
......
......@@ -1782,6 +1782,131 @@ void mt7615_mac_work(struct work_struct *work)
MT7615_WATCHDOG_TIME);
}
static bool
mt7615_wait_reset_state(struct mt7615_dev *dev, u32 state)
{
bool ret;
ret = wait_event_timeout(dev->reset_wait,
(READ_ONCE(dev->reset_state) & state),
MT7615_RESET_TIMEOUT);
WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
return ret;
}
static void
mt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct ieee80211_hw *hw = priv;
mt7615_mcu_set_bcn(hw, vif, vif->bss_conf.enable_beacon);
}
static void
mt7615_update_beacons(struct mt7615_dev *dev)
{
ieee80211_iterate_active_interfaces(dev->mt76.hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7615_update_vif_beacon, dev->mt76.hw);
if (!dev->mt76.phy2)
return;
ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7615_update_vif_beacon, dev->mt76.phy2->hw);
}
static void
mt7615_dma_reset(struct mt7615_dev *dev)
{
int i;
mt76_clear(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
usleep_range(1000, 2000);
for (i = 0; i < __MT_TXQ_MAX; i++)
mt76_queue_tx_cleanup(dev, i, true);
for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++)
mt76_queue_rx_reset(dev, i);
mt76_set(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
}
void mt7615_mac_reset_work(struct work_struct *work)
{
struct mt7615_dev *dev;
dev = container_of(work, struct mt7615_dev, reset_work);
if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA))
return;
ieee80211_stop_queues(mt76_hw(dev));
if (dev->mt76.phy2)
ieee80211_stop_queues(dev->mt76.phy2->hw);
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mmio.mcu.wait);
cancel_delayed_work_sync(&dev->mt76.mac_work);
/* lock/unlock all queues to ensure that no tx is pending */
mt76_txq_schedule_all(&dev->mphy);
if (dev->mt76.phy2)
mt76_txq_schedule_all(dev->mt76.phy2);
tasklet_disable(&dev->mt76.tx_tasklet);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
napi_disable(&dev->mt76.tx_napi);
mutex_lock(&dev->mt76.mutex);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED);
if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7615_dma_reset(dev);
mt76_wr(dev, MT_WPDMA_MEM_RNG_ERR, 0);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_INIT);
mt7615_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
}
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
tasklet_enable(&dev->mt76.tx_tasklet);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
napi_enable(&dev->mt76.napi[0]);
napi_schedule(&dev->mt76.napi[0]);
napi_enable(&dev->mt76.napi[1]);
napi_schedule(&dev->mt76.napi[1]);
ieee80211_wake_queues(mt76_hw(dev));
if (dev->mt76.phy2)
ieee80211_wake_queues(dev->mt76.phy2->hw);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
mutex_unlock(&dev->mt76.mutex);
mt7615_update_beacons(dev);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7615_WATCHDOG_TIME);
}
static void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy)
{
struct mt7615_dev *dev = phy->dev;
......
......@@ -53,6 +53,16 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
napi_schedule(&dev->mt76.napi[1]);
}
if (intr & MT_INT_MCU_CMD) {
u32 val = mt76_rr(dev, MT_MCU_CMD);
if (val & MT_MCU_CMD_ERROR_MASK) {
dev->reset_state = val;
ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
wake_up(&dev->reset_wait);
}
}
return IRQ_HANDLED;
}
......
......@@ -18,6 +18,7 @@
MT7615_MAX_INTERFACES)
#define MT7615_WATCHDOG_TIME (HZ / 10)
#define MT7615_RESET_TIMEOUT (30 * HZ)
#define MT7615_RATE_RETRY 2
#define MT7615_TX_RING_SIZE 1024
......@@ -156,6 +157,10 @@ struct mt7615_dev {
struct work_struct mcu_work;
struct work_struct reset_work;
wait_queue_head_t reset_wait;
u32 reset_state;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
......@@ -352,6 +357,7 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb);
int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
void mt7615_mac_reset_work(struct work_struct *work);
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
......
......@@ -35,6 +35,12 @@
#define MT_CFG_LPCR_HOST_FW_OWN BIT(0)
#define MT_CFG_LPCR_HOST_DRV_OWN BIT(1)
#define MT_MCU_INT_EVENT MT_HIF(0x1f8)
#define MT_MCU_INT_EVENT_PDMA_STOPPED BIT(0)
#define MT_MCU_INT_EVENT_PDMA_INIT BIT(1)
#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
#define MT_INT_SOURCE_CSR MT_HIF(0x200)
#define MT_INT_MASK_CSR MT_HIF(0x204)
#define MT_DELAY_INT_CFG MT_HIF(0x210)
......@@ -43,6 +49,7 @@
#define MT_INT_RX_DONE_ALL GENMASK(1, 0)
#define MT_INT_TX_DONE_ALL GENMASK(19, 4)
#define MT_INT_TX_DONE(_n) BIT((_n) + 4)
#define MT_INT_MCU_CMD BIT(30)
#define MT_WPDMA_GLO_CFG MT_HIF(0x208)
#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0)
......@@ -63,6 +70,22 @@
#define MT_WPDMA_RST_IDX MT_HIF(0x20c)
#define MT_WPDMA_MEM_RNG_ERR MT_HIF(0x224)
#define MT_MCU_CMD MT_HIF(0x234)
#define MT_MCU_CMD_CLEAR_FW_OWN BIT(0)
#define MT_MCU_CMD_STOP_PDMA_FW_RELOAD BIT(1)
#define MT_MCU_CMD_STOP_PDMA BIT(2)
#define MT_MCU_CMD_RESET_DONE BIT(3)
#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
#define MT_MCU_CMD_NORMAL_STATE BIT(5)
#define MT_MCU_CMD_LMAC_ERROR BIT(24)
#define MT_MCU_CMD_PSE_ERROR BIT(25)
#define MT_MCU_CMD_PLE_ERROR BIT(26)
#define MT_MCU_CMD_PDMA_ERROR BIT(27)
#define MT_MCU_CMD_PCIE_ERROR BIT(28)
#define MT_MCU_CMD_ERROR_MASK (GENMASK(5, 1) | GENMASK(28, 24))
#define MT_TX_RING_BASE MT_HIF(0x300)
#define MT_RX_RING_BASE MT_HIF(0x400)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment