mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
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: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
f347f81a8a
commit
61c4fa7219
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user