Message ID | 3e6ef9fb1d2e09d415b4c489cc9c62134a05b3c1.1668024217.git.ryder.lee@mediatek.com |
---|---|
State | Superseded |
Headers | show |
Series | [v3,1/4] wifi: mt76: mt7915: rework mt7915_dma_reset() | expand |
> From: Bo Jiao <bo.jiao@mediatek.com> > > Add mt7915_reset() and refactor mt7915_mac_reset_work() to support > full system recovery. > > Co-developed-by: Ryder Lee <ryder.lee@mediatek.com> > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> > Signed-off-by: Bo Jiao <bo.jiao@mediatek.com> > --- > change since v2 - change dev_info to make it easier to see that firmware crashed while looking at dmesg. > --- > .../net/wireless/mediatek/mt76/mt7915/init.c | 11 +- > .../net/wireless/mediatek/mt76/mt7915/mac.c | 214 +++++++++++++++++- > .../net/wireless/mediatek/mt76/mt7915/main.c | 18 +- > .../net/wireless/mediatek/mt76/mt7915/mcu.c | 24 +- > .../net/wireless/mediatek/mt76/mt7915/mmio.c | 7 +- > .../wireless/mediatek/mt76/mt7915/mt7915.h | 15 +- > .../net/wireless/mediatek/mt76/mt7915/regs.h | 4 + > 7 files changed, 267 insertions(+), 26 deletions(-) > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > index 324db5291c85..1f39aa3e3f3d 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > @@ -262,9 +262,8 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, > mt7915_led_set_config(led_cdev, 0xff, 0); > } > > -static void > -mt7915_init_txpower(struct mt7915_dev *dev, > - struct ieee80211_supported_band *sband) > +void mt7915_init_txpower(struct mt7915_dev *dev, > + struct ieee80211_supported_band *sband) > { > int i, n_chains = hweight8(dev->mphy.antenna_mask); > int nss_delta = mt76_tx_power_nss_delta(n_chains); > @@ -446,7 +445,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) > mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); > } > > -static void mt7915_mac_init(struct mt7915_dev *dev) > +void mt7915_mac_init(struct mt7915_dev *dev) > { > int i; > u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; > @@ -476,7 +475,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev) > } > } > > -static int mt7915_txbf_init(struct mt7915_dev *dev) > +int mt7915_txbf_init(struct mt7915_dev *dev) > { > int ret; > > @@ -1117,6 +1116,8 @@ int mt7915_register_device(struct mt7915_dev *dev) > goto unreg_thermal; > } > > + dev->recovery.hw_init_done = true; > + > mt7915_init_debugfs(&dev->phy); > > return 0; > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > index 3b1259f14de6..69ce3b39aa53 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > @@ -1265,7 +1265,7 @@ mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) > bool ret; > > ret = wait_event_timeout(dev->reset_wait, > - (READ_ONCE(dev->reset_state) & state), > + (READ_ONCE(dev->recovery.state) & state), > MT7915_RESET_TIMEOUT); > > WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); > @@ -1320,6 +1320,171 @@ void mt7915_tx_token_put(struct mt7915_dev *dev) > idr_destroy(&dev->mt76.token); > } > > +static int > +mt7915_mac_restart(struct mt7915_dev *dev) > +{ > + struct mt7915_phy *phy2; > + struct mt76_phy *ext_phy; > + struct mt76_dev *mdev = &dev->mt76; > + int i, ret; > + u32 irq_mask; > + > + ext_phy = dev->mt76.phys[MT_BAND1]; > + phy2 = ext_phy ? ext_phy->priv : NULL; > + > + if (dev->hif2) { > + mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); > + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); > + } > + > + if (dev_is_pci(mdev->dev)) { > + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); > + if (dev->hif2) > + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); > + } > + > + set_bit(MT76_RESET, &dev->mphy.state); > + set_bit(MT76_MCU_RESET, &dev->mphy.state); > + wake_up(&dev->mt76.mcu.wait); > + if (ext_phy) { > + set_bit(MT76_RESET, &ext_phy->state); > + set_bit(MT76_MCU_RESET, &ext_phy->state); > + } > + > + /* lock/unlock all queues to ensure that no tx is pending */ > + mt76_txq_schedule_all(&dev->mphy); > + if (ext_phy) > + mt76_txq_schedule_all(ext_phy); > + > + /* disable all tx/rx napi */ > + mt76_worker_disable(&dev->mt76.tx_worker); > + mt76_for_each_q_rx(mdev, i) { > + if (mdev->q_rx[i].ndesc) > + napi_disable(&dev->mt76.napi[i]); > + } > + napi_disable(&dev->mt76.tx_napi); > + > + /* token reinit */ > + mt7915_tx_token_put(dev); > + idr_init(&dev->mt76.token); > + > + mt7915_dma_reset(dev, true); > + > + local_bh_disable(); > + mt76_for_each_q_rx(mdev, i) { > + if (mdev->q_rx[i].ndesc) { > + napi_enable(&dev->mt76.napi[i]); > + napi_schedule(&dev->mt76.napi[i]); > + } > + } > + local_bh_enable(); > + clear_bit(MT76_MCU_RESET, &dev->mphy.state); > + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); > + > + mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); > + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); > + > + if (dev->hif2) { > + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); irq_mask is used uninitialized here. Moreover is mt7915_mac_restart() and full-reset compatible with wed support? it seems in mt7915_dual_hif_set_irq_mask() we took a different approach. Regards, Lorenzo > + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); > + } > + if (dev_is_pci(mdev->dev)) { > + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); > + if (dev->hif2) > + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); > + } > + > + /* load firmware */ > + ret = mt7915_mcu_init_firmware(dev); > + if (ret) > + goto out; > + > + /* set the necessary init items */ > + ret = mt7915_mcu_set_eeprom(dev); > + if (ret) > + goto out; > + > + mt7915_mac_init(dev); > + mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); > + mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); > + ret = mt7915_txbf_init(dev); > + > + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { > + ret = mt7915_run(dev->mphy.hw); > + if (ret) > + goto out; > + } > + > + if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) { > + ret = mt7915_run(ext_phy->hw); > + if (ret) > + goto out; > + } > + > +out: > + /* reset done */ > + clear_bit(MT76_RESET, &dev->mphy.state); > + if (phy2) > + clear_bit(MT76_RESET, &phy2->mt76->state); > + > + local_bh_disable(); > + napi_enable(&dev->mt76.tx_napi); > + napi_schedule(&dev->mt76.tx_napi); > + local_bh_enable(); > + > + mt76_worker_enable(&dev->mt76.tx_worker); > + > + return ret; > +} > + > +static void > +mt7915_mac_full_reset(struct mt7915_dev *dev) > +{ > + struct mt7915_phy *phy2; > + struct mt76_phy *ext_phy; > + int i; > + > + ext_phy = dev->mt76.phys[MT_BAND1]; > + phy2 = ext_phy ? ext_phy->priv : NULL; > + > + dev->recovery.hw_full_reset = true; > + > + wake_up(&dev->mt76.mcu.wait); > + ieee80211_stop_queues(mt76_hw(dev)); > + if (ext_phy) > + ieee80211_stop_queues(ext_phy->hw); > + > + cancel_delayed_work_sync(&dev->mphy.mac_work); > + if (ext_phy) > + cancel_delayed_work_sync(&ext_phy->mac_work); > + > + mutex_lock(&dev->mt76.mutex); > + for (i = 0; i < 10; i++) { > + if (!mt7915_mac_restart(dev)) > + break; > + } > + mutex_unlock(&dev->mt76.mutex); > + > + if (i == 10) > + dev_err(dev->mt76.dev, "chip full reset failed\n"); > + > + ieee80211_restart_hw(mt76_hw(dev)); > + if (ext_phy) > + ieee80211_restart_hw(ext_phy->hw); > + > + ieee80211_wake_queues(mt76_hw(dev)); > + if (ext_phy) > + ieee80211_wake_queues(ext_phy->hw); > + > + dev->recovery.hw_full_reset = false; > + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, > + MT7915_WATCHDOG_TIME); > + if (ext_phy) > + ieee80211_queue_delayed_work(ext_phy->hw, > + &ext_phy->mac_work, > + MT7915_WATCHDOG_TIME); > +} > + > /* system error recovery */ > void mt7915_mac_reset_work(struct work_struct *work) > { > @@ -1332,7 +1497,28 @@ void mt7915_mac_reset_work(struct work_struct *work) > ext_phy = dev->mt76.phys[MT_BAND1]; > phy2 = ext_phy ? ext_phy->priv : NULL; > > - if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) > + /* chip full reset */ > + if (dev->recovery.restart) { > + /* disable WA/WM WDT */ > + mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, > + MT_MCU_CMD_WDT_MASK); > + > + mt7915_mac_full_reset(dev); > + > + /* enable mcu irq */ > + mt7915_irq_enable(dev, MT_INT_MCU_CMD); > + mt7915_irq_disable(dev, 0); > + > + /* enable WA/WM WDT */ > + mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); > + > + dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; > + dev->recovery.restart = false; > + return; > + } > + > + /* chip partial reset */ > + if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) > return; > > ieee80211_stop_queues(mt76_hw(dev)); > @@ -1406,6 +1592,30 @@ void mt7915_mac_reset_work(struct work_struct *work) > MT7915_WATCHDOG_TIME); > } > > +void mt7915_reset(struct mt7915_dev *dev) > +{ > + if (!dev->recovery.hw_init_done) > + return; > + > + if (dev->recovery.hw_full_reset) > + return; > + > + /* wm/wa exception: do full recovery */ > + if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { > + dev->recovery.restart = true; > + dev_info(dev->mt76.dev, > + "%s indicated firmware crash, attempting recovery\n", > + wiphy_name(dev->mt76.hw->wiphy)); > + > + mt7915_irq_disable(dev, MT_INT_MCU_CMD); > + queue_work(dev->mt76.wq, &dev->reset_work); > + return; > + } > + > + queue_work(dev->mt76.wq, &dev->reset_work); > + wake_up(&dev->reset_wait); > +} > + > void mt7915_mac_update_stats(struct mt7915_phy *phy) > { > struct mt7915_dev *dev = phy->dev; > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c > index 6de49b93387e..32c362965dc4 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c > @@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev) > return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); > } > > -static int mt7915_start(struct ieee80211_hw *hw) > +int mt7915_run(struct ieee80211_hw *hw) > { > struct mt7915_dev *dev = mt7915_hw_dev(hw); > struct mt7915_phy *phy = mt7915_hw_phy(hw); > bool running; > int ret; > > - flush_work(&dev->init_work); > - > - mutex_lock(&dev->mt76.mutex); > - > running = mt7915_dev_running(dev); > > if (!running) { > @@ -80,6 +76,18 @@ static int mt7915_start(struct ieee80211_hw *hw) > mt7915_mac_reset_counters(phy); > > out: > + return ret; > +} > + > +static int mt7915_start(struct ieee80211_hw *hw) > +{ > + struct mt7915_dev *dev = mt7915_hw_dev(hw); > + int ret; > + > + flush_work(&dev->init_work); > + > + mutex_lock(&dev->mt76.mutex); > + ret = mt7915_run(hw); > mutex_unlock(&dev->mt76.mutex); > > return ret; > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > index 65ae959859e7..17fe29d8fd71 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > @@ -2249,18 +2249,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) > sizeof(req), true); > } > > -int mt7915_mcu_init(struct mt7915_dev *dev) > +int mt7915_mcu_init_firmware(struct mt7915_dev *dev) > { > - static const struct mt76_mcu_ops mt7915_mcu_ops = { > - .headroom = sizeof(struct mt76_connac2_mcu_txd), > - .mcu_skb_send_msg = mt7915_mcu_send_message, > - .mcu_parse_response = mt7915_mcu_parse_response, > - .mcu_restart = mt76_connac_mcu_restart, > - }; > int ret; > > - dev->mt76.mcu_ops = &mt7915_mcu_ops; > - > /* force firmware operation mode into normal state, > * which should be set before firmware download stage. > */ > @@ -2309,6 +2301,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev) > MCU_WA_PARAM_RED, 0, 0); > } > > +int mt7915_mcu_init(struct mt7915_dev *dev) > +{ > + static const struct mt76_mcu_ops mt7915_mcu_ops = { > + .headroom = sizeof(struct mt76_connac2_mcu_txd), > + .mcu_skb_send_msg = mt7915_mcu_send_message, > + .mcu_parse_response = mt7915_mcu_parse_response, > + .mcu_restart = mt76_connac_mcu_restart, > + }; > + > + dev->mt76.mcu_ops = &mt7915_mcu_ops; > + > + return mt7915_mcu_init_firmware(dev); > +} > + > void mt7915_mcu_exit(struct mt7915_dev *dev) > { > __mt76_mcu_restart(&dev->mt76); > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > index be1b8ea711c7..032af46289af 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > @@ -746,10 +746,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) > u32 val = mt76_rr(dev, MT_MCU_CMD); > > mt76_wr(dev, MT_MCU_CMD, val); > - if (val & MT_MCU_CMD_ERROR_MASK) { > - dev->reset_state = val; > - queue_work(dev->mt76.wq, &dev->reset_work); > - wake_up(&dev->reset_wait); > + if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { > + dev->recovery.state = val; > + mt7915_reset(dev); > } > } > } > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > index 5af26e60e902..49caf7b21a20 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > @@ -303,7 +303,13 @@ struct mt7915_dev { > struct work_struct rc_work; > struct work_struct reset_work; > wait_queue_head_t reset_wait; > - u32 reset_state; > + > + struct { > + u32 state; > + bool hw_full_reset:1; > + bool hw_init_done:1; > + bool restart:1; > + } recovery; > > struct list_head sta_rc_list; > struct list_head sta_poll_list; > @@ -444,7 +450,13 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); > void mt7915_dma_prefetch(struct mt7915_dev *dev); > void mt7915_dma_cleanup(struct mt7915_dev *dev); > int mt7915_dma_reset(struct mt7915_dev *dev, bool force); > +int mt7915_txbf_init(struct mt7915_dev *dev); > +void mt7915_init_txpower(struct mt7915_dev *dev, > + struct ieee80211_supported_band *sband); > +void mt7915_reset(struct mt7915_dev *dev); > +int mt7915_run(struct ieee80211_hw *hw); > int mt7915_mcu_init(struct mt7915_dev *dev); > +int mt7915_mcu_init_firmware(struct mt7915_dev *dev); > int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, > struct mt7915_vif *mvif, > struct mt7915_twt_flow *flow, > @@ -544,6 +556,7 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) > mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); > } > > +void mt7915_mac_init(struct mt7915_dev *dev); > u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw); > bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); > void mt7915_mac_reset_counters(struct mt7915_phy *phy); > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > index 5180dd931835..9120380d74c6 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > @@ -541,6 +541,8 @@ enum offs_rev { > #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) > #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) > > +#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) > + > #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) > #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) > #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) > @@ -709,6 +711,8 @@ enum offs_rev { > #define MT_MCU_CMD_NORMAL_STATE BIT(5) > #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) > > +#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) > + > /* TOP RGU */ > #define MT_TOP_RGU_BASE 0x18000000 > #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0)) > -- > 2.36.1 >
> > From: Bo Jiao <bo.jiao@mediatek.com> > > > > Add mt7915_reset() and refactor mt7915_mac_reset_work() to support > > full system recovery. > > > > Co-developed-by: Ryder Lee <ryder.lee@mediatek.com> > > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> > > Signed-off-by: Bo Jiao <bo.jiao@mediatek.com> > > --- > > change since v2 - change dev_info to make it easier to see that firmware crashed while looking at dmesg. > > --- > > .../net/wireless/mediatek/mt76/mt7915/init.c | 11 +- > > .../net/wireless/mediatek/mt76/mt7915/mac.c | 214 +++++++++++++++++- > > .../net/wireless/mediatek/mt76/mt7915/main.c | 18 +- > > .../net/wireless/mediatek/mt76/mt7915/mcu.c | 24 +- > > .../net/wireless/mediatek/mt76/mt7915/mmio.c | 7 +- > > .../wireless/mediatek/mt76/mt7915/mt7915.h | 15 +- > > .../net/wireless/mediatek/mt76/mt7915/regs.h | 4 + > > 7 files changed, 267 insertions(+), 26 deletions(-) > > > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > index 324db5291c85..1f39aa3e3f3d 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > @@ -262,9 +262,8 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, > > mt7915_led_set_config(led_cdev, 0xff, 0); > > } > > > > -static void > > -mt7915_init_txpower(struct mt7915_dev *dev, > > - struct ieee80211_supported_band *sband) > > +void mt7915_init_txpower(struct mt7915_dev *dev, > > + struct ieee80211_supported_band *sband) > > { > > int i, n_chains = hweight8(dev->mphy.antenna_mask); > > int nss_delta = mt76_tx_power_nss_delta(n_chains); > > @@ -446,7 +445,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) > > mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); > > } > > > > -static void mt7915_mac_init(struct mt7915_dev *dev) > > +void mt7915_mac_init(struct mt7915_dev *dev) > > { > > int i; > > u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; > > @@ -476,7 +475,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev) > > } > > } > > > > -static int mt7915_txbf_init(struct mt7915_dev *dev) > > +int mt7915_txbf_init(struct mt7915_dev *dev) > > { > > int ret; > > > > @@ -1117,6 +1116,8 @@ int mt7915_register_device(struct mt7915_dev *dev) > > goto unreg_thermal; > > } > > > > + dev->recovery.hw_init_done = true; > > + > > mt7915_init_debugfs(&dev->phy); > > > > return 0; > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > index 3b1259f14de6..69ce3b39aa53 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > @@ -1265,7 +1265,7 @@ mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) > > bool ret; > > > > ret = wait_event_timeout(dev->reset_wait, > > - (READ_ONCE(dev->reset_state) & state), > > + (READ_ONCE(dev->recovery.state) & state), > > MT7915_RESET_TIMEOUT); > > > > WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); > > @@ -1320,6 +1320,171 @@ void mt7915_tx_token_put(struct mt7915_dev *dev) > > idr_destroy(&dev->mt76.token); > > } > > > > +static int > > +mt7915_mac_restart(struct mt7915_dev *dev) > > +{ > > + struct mt7915_phy *phy2; > > + struct mt76_phy *ext_phy; > > + struct mt76_dev *mdev = &dev->mt76; > > + int i, ret; > > + u32 irq_mask; > > + > > + ext_phy = dev->mt76.phys[MT_BAND1]; > > + phy2 = ext_phy ? ext_phy->priv : NULL; > > + > > + if (dev->hif2) { > > + mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); > > + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); > > + } > > + > > + if (dev_is_pci(mdev->dev)) { > > + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); > > + if (dev->hif2) > > + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); > > + } > > + > > + set_bit(MT76_RESET, &dev->mphy.state); > > + set_bit(MT76_MCU_RESET, &dev->mphy.state); > > + wake_up(&dev->mt76.mcu.wait); > > + if (ext_phy) { > > + set_bit(MT76_RESET, &ext_phy->state); > > + set_bit(MT76_MCU_RESET, &ext_phy->state); > > + } > > + > > + /* lock/unlock all queues to ensure that no tx is pending */ > > + mt76_txq_schedule_all(&dev->mphy); > > + if (ext_phy) > > + mt76_txq_schedule_all(ext_phy); > > + > > + /* disable all tx/rx napi */ > > + mt76_worker_disable(&dev->mt76.tx_worker); > > + mt76_for_each_q_rx(mdev, i) { > > + if (mdev->q_rx[i].ndesc) > > + napi_disable(&dev->mt76.napi[i]); > > + } > > + napi_disable(&dev->mt76.tx_napi); > > + > > + /* token reinit */ > > + mt7915_tx_token_put(dev); > > + idr_init(&dev->mt76.token); > > + > > + mt7915_dma_reset(dev, true); > > + > > + local_bh_disable(); > > + mt76_for_each_q_rx(mdev, i) { > > + if (mdev->q_rx[i].ndesc) { > > + napi_enable(&dev->mt76.napi[i]); > > + napi_schedule(&dev->mt76.napi[i]); > > + } > > + } > > + local_bh_enable(); > > + clear_bit(MT76_MCU_RESET, &dev->mphy.state); > > + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); > > + > > + mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); > > + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); > > + > > + if (dev->hif2) { > > + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); > > irq_mask is used uninitialized here. > Moreover is mt7915_mac_restart() and full-reset compatible with wed support? > it seems in mt7915_dual_hif_set_irq_mask() we took a different approach. > > Regards, > Lorenzo should we do something similar to the patch below? diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index c76c5cc398e9..9c99c3014a79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1386,7 +1386,6 @@ mt7915_mac_restart(struct mt7915_dev *dev) struct mt76_phy *ext_phy; struct mt76_dev *mdev = &dev->mt76; int i, ret; - u32 irq_mask; ext_phy = dev->mt76.phys[MT_BAND1]; phy2 = ext_phy ? ext_phy->priv : NULL; @@ -1440,11 +1439,17 @@ mt7915_mac_restart(struct mt7915_dev *dev) clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); - mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); - mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + mtk_wed_device_irq_get(wed, ~0); + } else { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + } if (dev->hif2) { - mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); + mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); } if (dev_is_pci(mdev->dev)) { > > > + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); > > + } > > + if (dev_is_pci(mdev->dev)) { > > + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); > > + if (dev->hif2) > > + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff); > > + } > > + > > + /* load firmware */ > > + ret = mt7915_mcu_init_firmware(dev); > > + if (ret) > > + goto out; > > + > > + /* set the necessary init items */ > > + ret = mt7915_mcu_set_eeprom(dev); > > + if (ret) > > + goto out; > > + > > + mt7915_mac_init(dev); > > + mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); > > + mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); > > + ret = mt7915_txbf_init(dev); > > + > > + if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { > > + ret = mt7915_run(dev->mphy.hw); > > + if (ret) > > + goto out; > > + } > > + > > + if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) { > > + ret = mt7915_run(ext_phy->hw); > > + if (ret) > > + goto out; > > + } > > + > > +out: > > + /* reset done */ > > + clear_bit(MT76_RESET, &dev->mphy.state); > > + if (phy2) > > + clear_bit(MT76_RESET, &phy2->mt76->state); > > + > > + local_bh_disable(); > > + napi_enable(&dev->mt76.tx_napi); > > + napi_schedule(&dev->mt76.tx_napi); > > + local_bh_enable(); > > + > > + mt76_worker_enable(&dev->mt76.tx_worker); > > + > > + return ret; > > +} > > + > > +static void > > +mt7915_mac_full_reset(struct mt7915_dev *dev) > > +{ > > + struct mt7915_phy *phy2; > > + struct mt76_phy *ext_phy; > > + int i; > > + > > + ext_phy = dev->mt76.phys[MT_BAND1]; > > + phy2 = ext_phy ? ext_phy->priv : NULL; > > + > > + dev->recovery.hw_full_reset = true; > > + > > + wake_up(&dev->mt76.mcu.wait); > > + ieee80211_stop_queues(mt76_hw(dev)); > > + if (ext_phy) > > + ieee80211_stop_queues(ext_phy->hw); > > + > > + cancel_delayed_work_sync(&dev->mphy.mac_work); > > + if (ext_phy) > > + cancel_delayed_work_sync(&ext_phy->mac_work); > > + > > + mutex_lock(&dev->mt76.mutex); > > + for (i = 0; i < 10; i++) { > > + if (!mt7915_mac_restart(dev)) > > + break; > > + } > > + mutex_unlock(&dev->mt76.mutex); > > + > > + if (i == 10) > > + dev_err(dev->mt76.dev, "chip full reset failed\n"); > > + > > + ieee80211_restart_hw(mt76_hw(dev)); > > + if (ext_phy) > > + ieee80211_restart_hw(ext_phy->hw); > > + > > + ieee80211_wake_queues(mt76_hw(dev)); > > + if (ext_phy) > > + ieee80211_wake_queues(ext_phy->hw); > > + > > + dev->recovery.hw_full_reset = false; > > + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, > > + MT7915_WATCHDOG_TIME); > > + if (ext_phy) > > + ieee80211_queue_delayed_work(ext_phy->hw, > > + &ext_phy->mac_work, > > + MT7915_WATCHDOG_TIME); > > +} > > + > > /* system error recovery */ > > void mt7915_mac_reset_work(struct work_struct *work) > > { > > @@ -1332,7 +1497,28 @@ void mt7915_mac_reset_work(struct work_struct *work) > > ext_phy = dev->mt76.phys[MT_BAND1]; > > phy2 = ext_phy ? ext_phy->priv : NULL; > > > > - if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) > > + /* chip full reset */ > > + if (dev->recovery.restart) { > > + /* disable WA/WM WDT */ > > + mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA, > > + MT_MCU_CMD_WDT_MASK); > > + > > + mt7915_mac_full_reset(dev); > > + > > + /* enable mcu irq */ > > + mt7915_irq_enable(dev, MT_INT_MCU_CMD); > > + mt7915_irq_disable(dev, 0); > > + > > + /* enable WA/WM WDT */ > > + mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); > > + > > + dev->recovery.state = MT_MCU_CMD_NORMAL_STATE; > > + dev->recovery.restart = false; > > + return; > > + } > > + > > + /* chip partial reset */ > > + if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA)) > > return; > > > > ieee80211_stop_queues(mt76_hw(dev)); > > @@ -1406,6 +1592,30 @@ void mt7915_mac_reset_work(struct work_struct *work) > > MT7915_WATCHDOG_TIME); > > } > > > > +void mt7915_reset(struct mt7915_dev *dev) > > +{ > > + if (!dev->recovery.hw_init_done) > > + return; > > + > > + if (dev->recovery.hw_full_reset) > > + return; > > + > > + /* wm/wa exception: do full recovery */ > > + if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) { > > + dev->recovery.restart = true; > > + dev_info(dev->mt76.dev, > > + "%s indicated firmware crash, attempting recovery\n", > > + wiphy_name(dev->mt76.hw->wiphy)); > > + > > + mt7915_irq_disable(dev, MT_INT_MCU_CMD); > > + queue_work(dev->mt76.wq, &dev->reset_work); > > + return; > > + } > > + > > + queue_work(dev->mt76.wq, &dev->reset_work); > > + wake_up(&dev->reset_wait); > > +} > > + > > void mt7915_mac_update_stats(struct mt7915_phy *phy) > > { > > struct mt7915_dev *dev = phy->dev; > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c > > index 6de49b93387e..32c362965dc4 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c > > @@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev) > > return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); > > } > > > > -static int mt7915_start(struct ieee80211_hw *hw) > > +int mt7915_run(struct ieee80211_hw *hw) > > { > > struct mt7915_dev *dev = mt7915_hw_dev(hw); > > struct mt7915_phy *phy = mt7915_hw_phy(hw); > > bool running; > > int ret; > > > > - flush_work(&dev->init_work); > > - > > - mutex_lock(&dev->mt76.mutex); > > - > > running = mt7915_dev_running(dev); > > > > if (!running) { > > @@ -80,6 +76,18 @@ static int mt7915_start(struct ieee80211_hw *hw) > > mt7915_mac_reset_counters(phy); > > > > out: > > + return ret; > > +} > > + > > +static int mt7915_start(struct ieee80211_hw *hw) > > +{ > > + struct mt7915_dev *dev = mt7915_hw_dev(hw); > > + int ret; > > + > > + flush_work(&dev->init_work); > > + > > + mutex_lock(&dev->mt76.mutex); > > + ret = mt7915_run(hw); > > mutex_unlock(&dev->mt76.mutex); > > > > return ret; > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > > index 65ae959859e7..17fe29d8fd71 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c > > @@ -2249,18 +2249,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) > > sizeof(req), true); > > } > > > > -int mt7915_mcu_init(struct mt7915_dev *dev) > > +int mt7915_mcu_init_firmware(struct mt7915_dev *dev) > > { > > - static const struct mt76_mcu_ops mt7915_mcu_ops = { > > - .headroom = sizeof(struct mt76_connac2_mcu_txd), > > - .mcu_skb_send_msg = mt7915_mcu_send_message, > > - .mcu_parse_response = mt7915_mcu_parse_response, > > - .mcu_restart = mt76_connac_mcu_restart, > > - }; > > int ret; > > > > - dev->mt76.mcu_ops = &mt7915_mcu_ops; > > - > > /* force firmware operation mode into normal state, > > * which should be set before firmware download stage. > > */ > > @@ -2309,6 +2301,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev) > > MCU_WA_PARAM_RED, 0, 0); > > } > > > > +int mt7915_mcu_init(struct mt7915_dev *dev) > > +{ > > + static const struct mt76_mcu_ops mt7915_mcu_ops = { > > + .headroom = sizeof(struct mt76_connac2_mcu_txd), > > + .mcu_skb_send_msg = mt7915_mcu_send_message, > > + .mcu_parse_response = mt7915_mcu_parse_response, > > + .mcu_restart = mt76_connac_mcu_restart, > > + }; > > + > > + dev->mt76.mcu_ops = &mt7915_mcu_ops; > > + > > + return mt7915_mcu_init_firmware(dev); > > +} > > + > > void mt7915_mcu_exit(struct mt7915_dev *dev) > > { > > __mt76_mcu_restart(&dev->mt76); > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > > index be1b8ea711c7..032af46289af 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c > > @@ -746,10 +746,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) > > u32 val = mt76_rr(dev, MT_MCU_CMD); > > > > mt76_wr(dev, MT_MCU_CMD, val); > > - if (val & MT_MCU_CMD_ERROR_MASK) { > > - dev->reset_state = val; > > - queue_work(dev->mt76.wq, &dev->reset_work); > > - wake_up(&dev->reset_wait); > > + if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { > > + dev->recovery.state = val; > > + mt7915_reset(dev); > > } > > } > > } > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > > index 5af26e60e902..49caf7b21a20 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h > > @@ -303,7 +303,13 @@ struct mt7915_dev { > > struct work_struct rc_work; > > struct work_struct reset_work; > > wait_queue_head_t reset_wait; > > - u32 reset_state; > > + > > + struct { > > + u32 state; > > + bool hw_full_reset:1; > > + bool hw_init_done:1; > > + bool restart:1; > > + } recovery; > > > > struct list_head sta_rc_list; > > struct list_head sta_poll_list; > > @@ -444,7 +450,13 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); > > void mt7915_dma_prefetch(struct mt7915_dev *dev); > > void mt7915_dma_cleanup(struct mt7915_dev *dev); > > int mt7915_dma_reset(struct mt7915_dev *dev, bool force); > > +int mt7915_txbf_init(struct mt7915_dev *dev); > > +void mt7915_init_txpower(struct mt7915_dev *dev, > > + struct ieee80211_supported_band *sband); > > +void mt7915_reset(struct mt7915_dev *dev); > > +int mt7915_run(struct ieee80211_hw *hw); > > int mt7915_mcu_init(struct mt7915_dev *dev); > > +int mt7915_mcu_init_firmware(struct mt7915_dev *dev); > > int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, > > struct mt7915_vif *mvif, > > struct mt7915_twt_flow *flow, > > @@ -544,6 +556,7 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) > > mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); > > } > > > > +void mt7915_mac_init(struct mt7915_dev *dev); > > u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw); > > bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); > > void mt7915_mac_reset_counters(struct mt7915_phy *phy); > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > > index 5180dd931835..9120380d74c6 100644 > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h > > @@ -541,6 +541,8 @@ enum offs_rev { > > #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) > > #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) > > > > +#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) > > + > > #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) > > #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) > > #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) > > @@ -709,6 +711,8 @@ enum offs_rev { > > #define MT_MCU_CMD_NORMAL_STATE BIT(5) > > #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) > > > > +#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) > > + > > /* TOP RGU */ > > #define MT_TOP_RGU_BASE 0x18000000 > > #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0)) > > -- > > 2.36.1 > >
On Sat, 2022-11-12 at 17:13 +0100, Lorenzo Bianconi wrote: > > > From: Bo Jiao <bo.jiao@mediatek.com> > > > > > > Add mt7915_reset() and refactor mt7915_mac_reset_work() to > > > support > > > full system recovery. > > > > > > Co-developed-by: Ryder Lee <ryder.lee@mediatek.com> > > > Signed-off-by: Ryder Lee <ryder.lee@mediatek.com> > > > Signed-off-by: Bo Jiao <bo.jiao@mediatek.com> > > > --- > > > change since v2 - change dev_info to make it easier to see that > > > firmware crashed while looking at dmesg. > > > --- > > > .../net/wireless/mediatek/mt76/mt7915/init.c | 11 +- > > > .../net/wireless/mediatek/mt76/mt7915/mac.c | 214 > > > +++++++++++++++++- > > > .../net/wireless/mediatek/mt76/mt7915/main.c | 18 +- > > > .../net/wireless/mediatek/mt76/mt7915/mcu.c | 24 +- > > > .../net/wireless/mediatek/mt76/mt7915/mmio.c | 7 +- > > > .../wireless/mediatek/mt76/mt7915/mt7915.h | 15 +- > > > .../net/wireless/mediatek/mt76/mt7915/regs.h | 4 + > > > 7 files changed, 267 insertions(+), 26 deletions(-) > > > > > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > > b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > > index 324db5291c85..1f39aa3e3f3d 100644 > > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c > > > @@ -262,9 +262,8 @@ static void mt7915_led_set_brightness(struct > > > led_classdev *led_cdev, > > > mt7915_led_set_config(led_cdev, 0xff, 0); > > > } > > > > > > -static void > > > -mt7915_init_txpower(struct mt7915_dev *dev, > > > - struct ieee80211_supported_band *sband) > > > +void mt7915_init_txpower(struct mt7915_dev *dev, > > > + struct ieee80211_supported_band *sband) > > > { > > > int i, n_chains = hweight8(dev->mphy.antenna_mask); > > > int nss_delta = mt76_tx_power_nss_delta(n_chains); > > > @@ -446,7 +445,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, > > > u8 band) > > > mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); > > > } > > > > > > -static void mt7915_mac_init(struct mt7915_dev *dev) > > > +void mt7915_mac_init(struct mt7915_dev *dev) > > > { > > > int i; > > > u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; > > > @@ -476,7 +475,7 @@ static void mt7915_mac_init(struct mt7915_dev > > > *dev) > > > } > > > } > > > > > > -static int mt7915_txbf_init(struct mt7915_dev *dev) > > > +int mt7915_txbf_init(struct mt7915_dev *dev) > > > { > > > int ret; > > > > > > @@ -1117,6 +1116,8 @@ int mt7915_register_device(struct > > > mt7915_dev *dev) > > > goto unreg_thermal; > > > } > > > > > > + dev->recovery.hw_init_done = true; > > > + > > > mt7915_init_debugfs(&dev->phy); > > > > > > return 0; > > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > > b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > > index 3b1259f14de6..69ce3b39aa53 100644 > > > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > > > @@ -1265,7 +1265,7 @@ mt7915_wait_reset_state(struct mt7915_dev > > > *dev, u32 state) > > > bool ret; > > > > > > ret = wait_event_timeout(dev->reset_wait, > > > - (READ_ONCE(dev->reset_state) & state), > > > + (READ_ONCE(dev->recovery.state) & > > > state), > > > MT7915_RESET_TIMEOUT); > > > > > > WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); > > > @@ -1320,6 +1320,171 @@ void mt7915_tx_token_put(struct > > > mt7915_dev *dev) > > > idr_destroy(&dev->mt76.token); > > > } > > > > > > +static int > > > +mt7915_mac_restart(struct mt7915_dev *dev) > > > +{ > > > + struct mt7915_phy *phy2; > > > + struct mt76_phy *ext_phy; > > > + struct mt76_dev *mdev = &dev->mt76; > > > + int i, ret; > > > + u32 irq_mask; > > > + > > > + ext_phy = dev->mt76.phys[MT_BAND1]; > > > + phy2 = ext_phy ? ext_phy->priv : NULL; > > > + > > > + if (dev->hif2) { > > > + mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); > > > + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); > > > + } > > > + > > > + if (dev_is_pci(mdev->dev)) { > > > + mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); > > > + if (dev->hif2) > > > + mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); > > > + } > > > + > > > + set_bit(MT76_RESET, &dev->mphy.state); > > > + set_bit(MT76_MCU_RESET, &dev->mphy.state); > > > + wake_up(&dev->mt76.mcu.wait); > > > + if (ext_phy) { > > > + set_bit(MT76_RESET, &ext_phy->state); > > > + set_bit(MT76_MCU_RESET, &ext_phy->state); > > > + } > > > + > > > + /* lock/unlock all queues to ensure that no tx is pending */ > > > + mt76_txq_schedule_all(&dev->mphy); > > > + if (ext_phy) > > > + mt76_txq_schedule_all(ext_phy); > > > + > > > + /* disable all tx/rx napi */ > > > + mt76_worker_disable(&dev->mt76.tx_worker); > > > + mt76_for_each_q_rx(mdev, i) { > > > + if (mdev->q_rx[i].ndesc) > > > + napi_disable(&dev->mt76.napi[i]); > > > + } > > > + napi_disable(&dev->mt76.tx_napi); > > > + > > > + /* token reinit */ > > > + mt7915_tx_token_put(dev); > > > + idr_init(&dev->mt76.token); > > > + > > > + mt7915_dma_reset(dev, true); > > > + > > > + local_bh_disable(); > > > + mt76_for_each_q_rx(mdev, i) { > > > + if (mdev->q_rx[i].ndesc) { > > > + napi_enable(&dev->mt76.napi[i]); > > > + napi_schedule(&dev->mt76.napi[i]); > > > + } > > > + } > > > + local_bh_enable(); > > > + clear_bit(MT76_MCU_RESET, &dev->mphy.state); > > > + clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); > > > + > > > + mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); > > > + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); > > > + > > > + if (dev->hif2) { > > > + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); > > > > irq_mask is used uninitialized here. > > Moreover is mt7915_mac_restart() and full-reset compatible with wed > > support? > > it seems in mt7915_dual_hif_set_irq_mask() we took a different > > approach. > > > > Regards, > > Lorenzo > > should we do something similar to the patch below? > > diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > index c76c5cc398e9..9c99c3014a79 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c > @@ -1386,7 +1386,6 @@ mt7915_mac_restart(struct mt7915_dev *dev) > struct mt76_phy *ext_phy; > struct mt76_dev *mdev = &dev->mt76; > int i, ret; > - u32 irq_mask; > > ext_phy = dev->mt76.phys[MT_BAND1]; > phy2 = ext_phy ? ext_phy->priv : NULL; > @@ -1440,11 +1439,17 @@ mt7915_mac_restart(struct mt7915_dev *dev) > clear_bit(MT76_MCU_RESET, &dev->mphy.state); > clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); > > - mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); > - mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); > + if (mtk_wed_device_active(&mdev->mmio.wed)) { > + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, > + mdev->mmio.irqmask); > + mtk_wed_device_irq_get(wed, ~0); > + } else { > + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); > + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); > + } > > if (dev->hif2) { > - mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); > + mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask); > mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); Yes we should use dev->mt76.mmio.irqmask...somehow we added irq_mask here. @Felix, could you help to fold this? As for wed_device I think we need another patch to suppor its SER as it needs to take mtk_eth into account, and actually there's a patch in MTK's git01 repo. Ryder
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index e4fa240834d8..38360f940747 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -50,23 +50,37 @@ static void mt7915_dma_config(struct mt7915_dev *dev) #define TXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__TXQ(q), (wfdma), (int), (id)) if (is_mt7915(&dev->mt76)) { - RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7915_RXQ_BAND0); - RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, MT7915_RXQ_MCU_WM); - RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, MT7915_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7915_RXQ_BAND1); - RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, MT7915_RXQ_MCU_WA_EXT); - RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, MT7915_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, + MT7915_RXQ_BAND0); + RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, + MT7915_RXQ_MCU_WM); + RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, + MT7915_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, + MT7915_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, + MT7915_RXQ_MCU_WA_EXT); + RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, + MT7915_RXQ_MCU_WA); TXQ_CONFIG(0, WFDMA1, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA1, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); - MCUQ_CONFIG(MT_MCUQ_WM, WFDMA1, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); - MCUQ_CONFIG(MT_MCUQ_WA, WFDMA1, MT_INT_TX_DONE_MCU_WA, MT7915_TXQ_MCU_WA); - MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA1, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); + MCUQ_CONFIG(MT_MCUQ_WM, WFDMA1, MT_INT_TX_DONE_MCU_WM, + MT7915_TXQ_MCU_WM); + MCUQ_CONFIG(MT_MCUQ_WA, WFDMA1, MT_INT_TX_DONE_MCU_WA, + MT7915_TXQ_MCU_WA); + MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA1, MT_INT_TX_DONE_FWDL, + MT7915_TXQ_FWDL); } else { - RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7916_RXQ_MCU_WM); - RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, MT7916_RXQ_MCU_WA_EXT); - MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); - MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA_MT7916, MT7915_TXQ_MCU_WA); - MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); + RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, + MT7916_RXQ_MCU_WM); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, + MT7916_RXQ_MCU_WA_EXT); + MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, + MT7915_TXQ_MCU_WM); + MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA_MT7916, + MT7915_TXQ_MCU_WA); + MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, + MT7915_TXQ_FWDL); if (is_mt7916(&dev->mt76) && mtk_wed_device_active(&dev->mt76.mmio.wed)) { RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_WED_RX_DONE_BAND0_MT7916, @@ -77,16 +91,23 @@ static void mt7915_dma_config(struct mt7915_dev *dev) MT7916_RXQ_BAND1); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); - TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0, MT7915_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_WED_TX_DONE_BAND1, MT7915_TXQ_BAND1); + TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0, + MT7915_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_WED_TX_DONE_BAND1, + MT7915_TXQ_BAND1); } else { - RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, MT7916_RXQ_BAND0); - RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7916_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, + MT7916_RXQ_BAND0); + RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, + MT7916_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, + MT7916_RXQ_BAND1); RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); - TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7915_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7915_TXQ_BAND1); } } } @@ -514,6 +535,53 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return 0; } +int mt7915_dma_reset(struct mt7915_dev *dev, bool force) +{ + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; + int i; + + /* clean up hw queues */ + for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) { + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); + if (mphy_ext) + mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true); + } + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++) + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); + + /* reset wfsys */ + if (force) + mt7915_wfsys_reset(dev); + + mt7915_dma_disable(dev, force); + + /* reset hw queues */ + for (i = 0; i < __MT_TXQ_MAX; i++) { + mt76_queue_reset(dev, dev->mphy.q_tx[i]); + if (mphy_ext) + mt76_queue_reset(dev, mphy_ext->q_tx[i]); + } + + for (i = 0; i < __MT_MCUQ_MAX; i++) + mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); + + mt76_tx_status_check(&dev->mt76, true); + + mt7915_dma_enable(dev); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_rx_reset(dev, i); + + return 0; +} + void mt7915_dma_cleanup(struct mt7915_dev *dev) { mt7915_dma_disable(dev, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 324f0f58572b..3b1259f14de6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1306,73 +1306,6 @@ mt7915_update_beacons(struct mt7915_dev *dev) mt7915_update_vif_beacon, mphy_ext->hw); } -static void -mt7915_dma_reset(struct mt7915_dev *dev) -{ - struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; - u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); - int i; - - mt76_clear(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); - - if (is_mt7915(&dev->mt76)) - mt76_clear(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN); - if (dev->hif2) { - mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); - - if (is_mt7915(&dev->mt76)) - mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN); - } - - usleep_range(1000, 2000); - - for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); - if (mphy_ext) - mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true); - } - - for (i = 0; i < __MT_MCUQ_MAX; i++) - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); - - mt76_for_each_q_rx(&dev->mt76, i) - mt76_queue_rx_reset(dev, i); - - mt76_tx_status_check(&dev->mt76, true); - - /* re-init prefetch settings after reset */ - mt7915_dma_prefetch(dev); - - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); - if (is_mt7915(&dev->mt76)) - mt76_set(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN | - MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); - if (dev->hif2) { - mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); - - if (is_mt7915(&dev->mt76)) - mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN | - MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); - } -} - void mt7915_tx_token_put(struct mt7915_dev *dev) { struct mt76_txwi_cache *txwi; @@ -1424,7 +1357,7 @@ void mt7915_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { - mt7915_dma_reset(dev); + mt7915_dma_reset(dev, false); mt7915_tx_token_put(dev); idr_init(&dev->mt76.token); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index fe6a6d3b0a32..5af26e60e902 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -443,6 +443,7 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band); int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); +int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_mcu_init(struct mt7915_dev *dev); int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, struct mt7915_vif *mvif,