From: Greg Kroah-Hartman Date: Fri, 9 Jul 2021 13:09:50 +0000 (+0200) Subject: 5.12-stable patches X-Git-Tag: v4.4.275~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=af0c3454737131b97aaf2243bd330165126a913c;p=thirdparty%2Fkernel%2Fstable-queue.git 5.12-stable patches added patches: mt76-dma-export-mt76_dma_rx_cleanup-routine.patch mt76-dma-introduce-mt76_dma_queue_reset-routine.patch mt76-mt7921-abort-uncompleted-scan-by-wifi-reset.patch mt76-mt7921-add-wifi-reset-support.patch mt76-mt7921-check-mcu-returned-values-in-mt7921_start.patch mt76-mt7921-get-rid-of-mcu_reset-function-pointer.patch mt76-mt7921-introduce-__mt7921_start-utility-routine.patch mt76-mt7921-introduce-mt7921_run_firmware-utility-routine.patch --- diff --git a/queue-5.12/mt76-dma-export-mt76_dma_rx_cleanup-routine.patch b/queue-5.12/mt76-dma-export-mt76_dma_rx_cleanup-routine.patch new file mode 100644 index 00000000000..117649d6d71 --- /dev/null +++ b/queue-5.12/mt76-dma-export-mt76_dma_rx_cleanup-routine.patch @@ -0,0 +1,55 @@ +From c001df978e4cb88975147ddd2c829c9e12a55076 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 7 Mar 2021 19:20:50 +0100 +Subject: mt76: dma: export mt76_dma_rx_cleanup routine + +From: Lorenzo Bianconi + +commit c001df978e4cb88975147ddd2c829c9e12a55076 upstream. + +Export mt76_dma_rx_cleanup routine in mt76_queue_ops data structure. +This is a preliminary patch to introduce mt7921 chip reset support. + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/dma.c | 1 + + drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -653,6 +653,7 @@ static const struct mt76_queue_ops mt76_ + .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, + .tx_queue_skb = mt76_dma_tx_queue_skb, + .tx_cleanup = mt76_dma_tx_cleanup, ++ .rx_cleanup = mt76_dma_rx_cleanup, + .rx_reset = mt76_dma_rx_reset, + .kick = mt76_dma_kick_queue, + }; +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -190,6 +190,8 @@ struct mt76_queue_ops { + void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q, + bool flush); + ++ void (*rx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q); ++ + void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); + + void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q); +@@ -786,7 +788,8 @@ static inline u16 mt76_rev(struct mt76_d + #define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__) + #define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mt76), __VA_ARGS__) + #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) +-#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) ++#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) ++#define mt76_queue_rx_cleanup(dev, ...) (dev)->mt76.queue_ops->rx_cleanup(&((dev)->mt76), __VA_ARGS__) + #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) + #define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__) + diff --git a/queue-5.12/mt76-dma-introduce-mt76_dma_queue_reset-routine.patch b/queue-5.12/mt76-dma-introduce-mt76_dma_queue_reset-routine.patch new file mode 100644 index 00000000000..8ad6c3950eb --- /dev/null +++ b/queue-5.12/mt76-dma-introduce-mt76_dma_queue_reset-routine.patch @@ -0,0 +1,126 @@ +From 3990465db6829c91e8ebfde51ba2d98885020249 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 7 Mar 2021 19:20:49 +0100 +Subject: mt76: dma: introduce mt76_dma_queue_reset routine + +From: Lorenzo Bianconi + +commit 3990465db6829c91e8ebfde51ba2d98885020249 upstream. + +Introduce mt76_dma_queue_reset utility routine to reset a given hw +queue. This is a preliminary patch to introduce mt7921 chip reset +support. + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/dma.c | 46 ++++++++++++++++++------------ + drivers/net/wireless/mediatek/mt76/mt76.h | 3 + + 2 files changed, 31 insertions(+), 18 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/dma.c ++++ b/drivers/net/wireless/mediatek/mt76/dma.c +@@ -79,13 +79,38 @@ mt76_free_pending_txwi(struct mt76_dev * + local_bh_enable(); + } + ++static void ++mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) ++{ ++ writel(q->desc_dma, &q->regs->desc_base); ++ writel(q->ndesc, &q->regs->ring_size); ++ q->head = readl(&q->regs->dma_idx); ++ q->tail = q->head; ++} ++ ++static void ++mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) ++{ ++ int i; ++ ++ if (!q) ++ return; ++ ++ /* clear descriptors */ ++ for (i = 0; i < q->ndesc; i++) ++ q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); ++ ++ writel(0, &q->regs->cpu_idx); ++ writel(0, &q->regs->dma_idx); ++ mt76_dma_sync_idx(dev, q); ++} ++ + static int + mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, + int idx, int n_desc, int bufsize, + u32 ring_base) + { + int size; +- int i; + + spin_lock_init(&q->lock); + spin_lock_init(&q->cleanup_lock); +@@ -105,14 +130,7 @@ mt76_dma_alloc_queue(struct mt76_dev *de + if (!q->entry) + return -ENOMEM; + +- /* clear descriptors */ +- for (i = 0; i < q->ndesc; i++) +- q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); +- +- writel(q->desc_dma, &q->regs->desc_base); +- writel(0, &q->regs->cpu_idx); +- writel(0, &q->regs->dma_idx); +- writel(q->ndesc, &q->regs->ring_size); ++ mt76_dma_queue_reset(dev, q); + + return 0; + } +@@ -202,15 +220,6 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev + } + + static void +-mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) +-{ +- writel(q->desc_dma, &q->regs->desc_base); +- writel(q->ndesc, &q->regs->ring_size); +- q->head = readl(&q->regs->dma_idx); +- q->tail = q->head; +-} +- +-static void + mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) + { + wmb(); +@@ -640,6 +649,7 @@ mt76_dma_init(struct mt76_dev *dev) + static const struct mt76_queue_ops mt76_dma_ops = { + .init = mt76_dma_init, + .alloc = mt76_dma_alloc_queue, ++ .reset_q = mt76_dma_queue_reset, + .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, + .tx_queue_skb = mt76_dma_tx_queue_skb, + .tx_cleanup = mt76_dma_tx_cleanup, +--- a/drivers/net/wireless/mediatek/mt76/mt76.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76.h +@@ -191,6 +191,8 @@ struct mt76_queue_ops { + bool flush); + + void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); ++ ++ void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q); + }; + + enum mt76_wcid_flags { +@@ -786,6 +788,7 @@ static inline u16 mt76_rev(struct mt76_d + #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) + #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) + #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) ++#define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__) + + #define mt76_for_each_q_rx(dev, i) \ + for (i = 0; i < ARRAY_SIZE((dev)->q_rx) && \ diff --git a/queue-5.12/mt76-mt7921-abort-uncompleted-scan-by-wifi-reset.patch b/queue-5.12/mt76-mt7921-abort-uncompleted-scan-by-wifi-reset.patch new file mode 100644 index 00000000000..e97be70fb52 --- /dev/null +++ b/queue-5.12/mt76-mt7921-abort-uncompleted-scan-by-wifi-reset.patch @@ -0,0 +1,41 @@ +From e513ae49088bbb0d00299a9f996f88f08cca7dc6 Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Fri, 16 Apr 2021 23:30:36 +0800 +Subject: mt76: mt7921: abort uncompleted scan by wifi reset + +From: Sean Wang + +commit e513ae49088bbb0d00299a9f996f88f08cca7dc6 upstream. + +Scan abort should be required for the uncompleted hardware scan +interrupted by wifi reset. Otherwise, it is possible that the scan +request after wifi reset gets error code -EBUSY from mac80211 and +then blocks the reconnectting to the access point. + +Fixes: 0c1ce9884607 ("mt76: mt7921: add wifi reset support") +Signed-off-by: Sean Wang +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +@@ -1386,6 +1386,14 @@ void mt7921_mac_reset_work(struct work_s + if (i == 10) + dev_err(dev->mt76.dev, "chip reset failed\n"); + ++ if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) { ++ struct cfg80211_scan_info info = { ++ .aborted = true, ++ }; ++ ++ ieee80211_scan_completed(dev->mphy.hw, &info); ++ } ++ + ieee80211_wake_queues(hw); + ieee80211_iterate_active_interfaces(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, diff --git a/queue-5.12/mt76-mt7921-add-wifi-reset-support.patch b/queue-5.12/mt76-mt7921-add-wifi-reset-support.patch new file mode 100644 index 00000000000..13de4526fb0 --- /dev/null +++ b/queue-5.12/mt76-mt7921-add-wifi-reset-support.patch @@ -0,0 +1,381 @@ +From 0c1ce988460765ece1ba8eacd00533eefb6e666a Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 7 Mar 2021 19:20:51 +0100 +Subject: mt76: mt7921: add wifi reset support + +From: Lorenzo Bianconi + +commit 0c1ce988460765ece1ba8eacd00533eefb6e666a upstream. + +Introduce wifi chip reset support for mt7921 device to recover mcu +hangs. + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/mt7921/init.c | 3 + drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 203 +++++++++++++++------ + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 4 + drivers/net/wireless/mediatek/mt76/mt7921/regs.h | 4 + 5 files changed, 156 insertions(+), 61 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c +@@ -142,7 +142,7 @@ mt7921_mac_init_band(struct mt7921_dev * + mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); + } + +-static void mt7921_mac_init(struct mt7921_dev *dev) ++void mt7921_mac_init(struct mt7921_dev *dev) + { + int i; + +@@ -232,7 +232,6 @@ int mt7921_register_device(struct mt7921 + 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, mt7921_mac_reset_work); + + ret = mt7921_init_hardware(dev); +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +@@ -1184,43 +1184,77 @@ void mt7921_update_channel(struct mt76_d + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); + } + +-static bool +-mt7921_wait_reset_state(struct mt7921_dev *dev, u32 state) ++static int ++mt7921_wfsys_reset(struct mt7921_dev *dev) + { +- bool ret; ++ mt76_set(dev, 0x70002600, BIT(0)); ++ msleep(200); ++ mt76_clear(dev, 0x70002600, BIT(0)); + +- ret = wait_event_timeout(dev->reset_wait, +- (READ_ONCE(dev->reset_state) & state), +- MT7921_RESET_TIMEOUT); +- +- WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); +- return ret; ++ return __mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B, ++ WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500); + } + + static void +-mt7921_dma_reset(struct mt7921_phy *phy) ++mt7921_dma_reset(struct mt7921_dev *dev) + { +- struct mt7921_dev *dev = phy->dev; + int i; + +- mt76_clear(dev, MT_WFDMA0_GLO_CFG, +- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); ++ /* reset */ ++ mt76_clear(dev, MT_WFDMA0_RST, ++ MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); ++ ++ mt76_set(dev, MT_WFDMA0_RST, ++ MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST); + +- usleep_range(1000, 2000); ++ /* disable WFDMA0 */ ++ mt76_clear(dev, MT_WFDMA0_GLO_CFG, ++ MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | ++ MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | ++ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | ++ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO | ++ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); ++ ++ mt76_poll(dev, MT_WFDMA0_GLO_CFG, ++ MT_WFDMA0_GLO_CFG_TX_DMA_BUSY | ++ MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000); + +- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], true); ++ /* reset hw queues */ + for (i = 0; i < __MT_TXQ_MAX; i++) +- mt76_queue_tx_cleanup(dev, phy->mt76->q_tx[i], true); ++ mt76_queue_reset(dev, dev->mphy.q_tx[i]); + +- mt76_for_each_q_rx(&dev->mt76, i) { +- mt76_queue_rx_reset(dev, i); +- } ++ for (i = 0; i < __MT_MCUQ_MAX; i++) ++ mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + +- /* re-init prefetch settings after reset */ ++ mt76_for_each_q_rx(&dev->mt76, i) ++ mt76_queue_reset(dev, &dev->mt76.q_rx[i]); ++ ++ /* configure perfetch settings */ + mt7921_dma_prefetch(dev); + ++ /* reset dma idx */ ++ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); ++ ++ /* configure delay interrupt */ ++ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); ++ ++ mt76_set(dev, MT_WFDMA0_GLO_CFG, ++ MT_WFDMA0_GLO_CFG_TX_WB_DDONE | ++ MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | ++ MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | ++ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | ++ MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | ++ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); ++ + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); ++ ++ mt76_set(dev, 0x54000120, BIT(1)); ++ ++ /* enable interrupts for TX/RX rings */ ++ mt7921_irq_enable(dev, ++ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | ++ MT_INT_MCU_CMD); + } + + void mt7921_tx_token_put(struct mt7921_dev *dev) +@@ -1244,71 +1278,125 @@ void mt7921_tx_token_put(struct mt7921_d + idr_destroy(&dev->token); + } + +-/* system error recovery */ +-void mt7921_mac_reset_work(struct work_struct *work) ++static void ++mt7921_vif_connect_iter(void *priv, u8 *mac, ++ struct ieee80211_vif *vif) + { +- struct mt7921_dev *dev; ++ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; ++ struct mt7921_dev *dev = mvif->phy->dev; + +- dev = container_of(work, struct mt7921_dev, reset_work); ++ ieee80211_disconnect(vif, true); + +- if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) +- return; ++ mt76_connac_mcu_uni_add_dev(&dev->mphy, vif, &mvif->sta.wcid, true); ++ mt7921_mcu_set_tx(dev, vif); ++} ++ ++static int ++mt7921_mac_reset(struct mt7921_dev *dev) ++{ ++ int i, err; + +- ieee80211_stop_queues(mt76_hw(dev)); ++ mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); ++ ++ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); ++ mt76_wr(dev, MT_PCIE_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); +- cancel_delayed_work_sync(&dev->mphy.mac_work); ++ skb_queue_purge(&dev->mt76.mcu.res_q); + +- /* lock/unlock all queues to ensure that no tx is pending */ + mt76_txq_schedule_all(&dev->mphy); + + mt76_worker_disable(&dev->mt76.tx_worker); +- napi_disable(&dev->mt76.napi[0]); +- napi_disable(&dev->mt76.napi[1]); +- napi_disable(&dev->mt76.napi[2]); ++ napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); ++ napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); ++ napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); + napi_disable(&dev->mt76.tx_napi); + +- mt7921_mutex_acquire(dev); +- +- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); +- + mt7921_tx_token_put(dev); + idr_init(&dev->token); + +- if (mt7921_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { +- mt7921_dma_reset(&dev->phy); ++ /* 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); + +- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT); +- mt7921_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE); +- } ++ for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++) ++ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); + +- clear_bit(MT76_MCU_RESET, &dev->mphy.state); +- clear_bit(MT76_RESET, &dev->mphy.state); ++ mt76_for_each_q_rx(&dev->mt76, i) ++ mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); ++ ++ mt7921_wfsys_reset(dev); ++ mt7921_dma_reset(dev); ++ ++ mt76_for_each_q_rx(&dev->mt76, i) { ++ mt76_queue_rx_reset(dev, i); ++ napi_enable(&dev->mt76.napi[i]); ++ napi_schedule(&dev->mt76.napi[i]); ++ } + +- mt76_worker_enable(&dev->mt76.tx_worker); + napi_enable(&dev->mt76.tx_napi); + napi_schedule(&dev->mt76.tx_napi); ++ mt76_worker_enable(&dev->mt76.tx_worker); + +- napi_enable(&dev->mt76.napi[0]); +- napi_schedule(&dev->mt76.napi[0]); ++ clear_bit(MT76_MCU_RESET, &dev->mphy.state); + +- napi_enable(&dev->mt76.napi[1]); +- napi_schedule(&dev->mt76.napi[1]); ++ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0); ++ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); ++ mt7921_irq_enable(dev, ++ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL | ++ MT_INT_MCU_CMD); + +- napi_enable(&dev->mt76.napi[2]); +- napi_schedule(&dev->mt76.napi[2]); ++ err = mt7921_run_firmware(dev); ++ if (err) ++ return err; + +- ieee80211_wake_queues(mt76_hw(dev)); ++ err = mt7921_mcu_set_eeprom(dev); ++ if (err) ++ return err; + +- mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); +- mt7921_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); ++ mt7921_mac_init(dev); ++ return __mt7921_start(&dev->phy); ++} + +- mt7921_mutex_release(dev); ++/* system error recovery */ ++void mt7921_mac_reset_work(struct work_struct *work) ++{ ++ struct ieee80211_hw *hw; ++ struct mt7921_dev *dev; ++ int i; + +- ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, +- MT7921_WATCHDOG_TIME); ++ dev = container_of(work, struct mt7921_dev, reset_work); ++ hw = mt76_hw(dev); ++ ++ dev_err(dev->mt76.dev, "chip reset\n"); ++ ieee80211_stop_queues(hw); ++ ++ cancel_delayed_work_sync(&dev->mphy.mac_work); ++ cancel_delayed_work_sync(&dev->pm.ps_work); ++ cancel_work_sync(&dev->pm.wake_work); ++ ++ mutex_lock(&dev->mt76.mutex); ++ for (i = 0; i < 10; i++) { ++ if (!mt7921_mac_reset(dev)) ++ break; ++ } ++ mutex_unlock(&dev->mt76.mutex); ++ ++ if (i == 10) ++ dev_err(dev->mt76.dev, "chip reset failed\n"); ++ ++ ieee80211_wake_queues(hw); ++ ieee80211_iterate_active_interfaces(hw, ++ IEEE80211_IFACE_ITER_RESUME_ALL, ++ mt7921_vif_connect_iter, 0); ++} ++ ++void mt7921_reset(struct mt76_dev *mdev) ++{ ++ struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76); ++ ++ queue_work(dev->mt76.wq, &dev->reset_work); + } + + static void +@@ -1505,4 +1593,5 @@ void mt7921_coredump_work(struct work_st + } + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); ++ mt7921_reset(&dev->mt76); + } +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +@@ -952,6 +952,7 @@ int mt7921_mcu_init(struct mt7921_dev *d + .mcu_skb_send_msg = mt7921_mcu_send_message, + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_restart = mt7921_mcu_restart, ++ .mcu_reset = mt7921_reset, + }; + + dev->mt76.mcu_ops = &mt7921_mcu_ops; +@@ -1269,6 +1270,7 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_ + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "driver own failed\n"); ++ mt7921_reset(&dev->mt76); + return -EIO; + } + +@@ -1295,6 +1297,7 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_d + + if (i == MT7921_DRV_OWN_RETRY_COUNT) { + dev_err(dev->mt76.dev, "firmware own failed\n"); ++ mt7921_reset(&dev->mt76); + return -EIO; + } + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -151,8 +151,6 @@ struct mt7921_dev { + + struct work_struct init_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; +@@ -283,6 +281,7 @@ mt7921_l1_rmw(struct mt7921_dev *dev, u3 + #define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val) + #define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0) + ++void mt7921_mac_init(struct mt7921_dev *dev); + bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask); + void mt7921_mac_reset_counters(struct mt7921_phy *phy); + void mt7921_mac_write_txwi(struct mt7921_dev *dev, __le32 *txwi, +@@ -298,6 +297,7 @@ void mt7921_mac_sta_remove(struct mt76_d + struct ieee80211_sta *sta); + void mt7921_mac_work(struct work_struct *work); + void mt7921_mac_reset_work(struct work_struct *work); ++void mt7921_reset(struct mt76_dev *mdev); + int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, +--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +@@ -418,6 +418,10 @@ + #define PCIE_LPCR_HOST_CLR_OWN BIT(1) + #define PCIE_LPCR_HOST_SET_OWN BIT(0) + ++#define MT_WFSYS_SW_RST_B 0x18000140 ++#define WFSYS_SW_RST_B BIT(0) ++#define WFSYS_SW_INIT_DONE BIT(4) ++ + #define MT_CONN_ON_MISC 0x7c0600f0 + #define MT_TOP_MISC2_FW_N9_RDY GENMASK(1, 0) + diff --git a/queue-5.12/mt76-mt7921-check-mcu-returned-values-in-mt7921_start.patch b/queue-5.12/mt76-mt7921-check-mcu-returned-values-in-mt7921_start.patch new file mode 100644 index 00000000000..cce256bce00 --- /dev/null +++ b/queue-5.12/mt76-mt7921-check-mcu-returned-values-in-mt7921_start.patch @@ -0,0 +1,60 @@ +From f92f81d35ac26f8a519866f1b561743fe70e33a5 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 26 Feb 2021 12:17:23 +0100 +Subject: mt76: mt7921: check mcu returned values in mt7921_start + +From: Lorenzo Bianconi + +commit f92f81d35ac26f8a519866f1b561743fe70e33a5 upstream. + +Properly check returned values from mcu utility routines in +mt7921_start. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -172,22 +172,31 @@ static int mt7921_start(struct ieee80211 + { + struct mt7921_dev *dev = mt7921_hw_dev(hw); + struct mt7921_phy *phy = mt7921_hw_phy(hw); ++ int err; + + mt7921_mutex_acquire(dev); + +- mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); +- mt76_connac_mcu_set_channel_domain(phy->mt76); ++ err = mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); ++ if (err) ++ goto out; ++ ++ err = mt76_connac_mcu_set_channel_domain(phy->mt76); ++ if (err) ++ goto out; ++ ++ err = mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); ++ if (err) ++ goto out; + +- mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + mt7921_mac_reset_counters(phy); + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); + + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT7921_WATCHDOG_TIME); +- ++out: + mt7921_mutex_release(dev); + +- return 0; ++ return err; + } + + static void mt7921_stop(struct ieee80211_hw *hw) diff --git a/queue-5.12/mt76-mt7921-get-rid-of-mcu_reset-function-pointer.patch b/queue-5.12/mt76-mt7921-get-rid-of-mcu_reset-function-pointer.patch new file mode 100644 index 00000000000..662a2afb960 --- /dev/null +++ b/queue-5.12/mt76-mt7921-get-rid-of-mcu_reset-function-pointer.patch @@ -0,0 +1,48 @@ +From d43b3257621dfe57c71d875afd3f624b9a042fc5 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 21 Apr 2021 12:28:33 +0200 +Subject: mt76: mt7921: get rid of mcu_reset function pointer + +From: Lorenzo Bianconi + +commit d43b3257621dfe57c71d875afd3f624b9a042fc5 upstream. + +since mcu_reset it used only by mt7921, move the reset callback to +mt7921_mcu_parse_response routine and get rid of the function pointer. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Link: https://lore.kernel.org/linux-wireless/364293ec8609dd254067d8173c1599526ffd662c.1619000828.git.lorenzo@kernel.org/ +Signed-off-by: Deren Wu +Cc: # 5.12: f92f81d35ac2 mt76: mt7921: check mcu returned values in mt7921_start +Cc: # 5.12: d32464e68ffc mt76: mt7921: introduce mt7921_run_firmware utility routine. +Cc: # 5.12: 1f7396acfef4 mt76: mt7921: introduce __mt7921_start utility routine +Cc: # 5.12: 3990465db682 mt76: dma: introduce mt76_dma_queue_reset routine +Cc: # 5.12: c001df978e4c mt76: dma: export mt76_dma_rx_cleanup routine +Cc: # 5.12: 0c1ce9884607 mt76: mt7921: add wifi reset support +Cc: # 5.12: e513ae49088b mt76: mt7921: abort uncompleted scan by wifi reset +Cc: # 5.12 +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +@@ -161,6 +161,8 @@ mt7921_mcu_parse_response(struct mt76_de + if (!skb) { + dev_err(mdev->dev, "Message %d (seq %d) timeout\n", + cmd, seq); ++ mt7921_reset(mdev); ++ + return -ETIMEDOUT; + } + +@@ -952,7 +954,6 @@ int mt7921_mcu_init(struct mt7921_dev *d + .mcu_skb_send_msg = mt7921_mcu_send_message, + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_restart = mt7921_mcu_restart, +- .mcu_reset = mt7921_reset, + }; + + dev->mt76.mcu_ops = &mt7921_mcu_ops; diff --git a/queue-5.12/mt76-mt7921-introduce-__mt7921_start-utility-routine.patch b/queue-5.12/mt76-mt7921-introduce-__mt7921_start-utility-routine.patch new file mode 100644 index 00000000000..1f0fd0c68c1 --- /dev/null +++ b/queue-5.12/mt76-mt7921-introduce-__mt7921_start-utility-routine.patch @@ -0,0 +1,90 @@ +From 1f7396acfef4691b8cf4a3e631fd3f59d779c0f2 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 7 Mar 2021 19:20:48 +0100 +Subject: mt76: mt7921: introduce __mt7921_start utility routine + +From: Lorenzo Bianconi + +commit 1f7396acfef4691b8cf4a3e631fd3f59d779c0f2 upstream. + +This is a preliminary patch to introduce mt7921 chip reset support. + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/mt7921/main.c | 35 ++++++++++++--------- + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 22 insertions(+), 14 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -168,33 +168,40 @@ void mt7921_set_stream_he_caps(struct mt + } + } + +-static int mt7921_start(struct ieee80211_hw *hw) ++int __mt7921_start(struct mt7921_phy *phy) + { +- struct mt7921_dev *dev = mt7921_hw_dev(hw); +- struct mt7921_phy *phy = mt7921_hw_phy(hw); ++ struct mt76_phy *mphy = phy->mt76; + int err; + +- mt7921_mutex_acquire(dev); +- +- err = mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, true, false); ++ err = mt76_connac_mcu_set_mac_enable(mphy->dev, 0, true, false); + if (err) +- goto out; ++ return err; + +- err = mt76_connac_mcu_set_channel_domain(phy->mt76); ++ err = mt76_connac_mcu_set_channel_domain(mphy); + if (err) +- goto out; ++ return err; + + err = mt7921_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH); + if (err) +- goto out; ++ return err; + + mt7921_mac_reset_counters(phy); +- set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ++ set_bit(MT76_STATE_RUNNING, &mphy->state); + +- ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, ++ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, + MT7921_WATCHDOG_TIME); +-out: +- mt7921_mutex_release(dev); ++ ++ return 0; ++} ++ ++static int mt7921_start(struct ieee80211_hw *hw) ++{ ++ struct mt7921_phy *phy = mt7921_hw_phy(hw); ++ int err; ++ ++ mt7921_mutex_acquire(phy->dev); ++ err = __mt7921_start(phy); ++ mt7921_mutex_release(phy->dev); + + return err; + } +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -209,6 +209,7 @@ extern struct pci_driver mt7921_pci_driv + + u32 mt7921_reg_map(struct mt7921_dev *dev, u32 addr); + ++int __mt7921_start(struct mt7921_phy *phy); + int mt7921_register_device(struct mt7921_dev *dev); + void mt7921_unregister_device(struct mt7921_dev *dev); + int mt7921_eeprom_init(struct mt7921_dev *dev); diff --git a/queue-5.12/mt76-mt7921-introduce-mt7921_run_firmware-utility-routine.patch b/queue-5.12/mt76-mt7921-introduce-mt7921_run_firmware-utility-routine.patch new file mode 100644 index 00000000000..d4991d0d83a --- /dev/null +++ b/queue-5.12/mt76-mt7921-introduce-mt7921_run_firmware-utility-routine.patch @@ -0,0 +1,84 @@ +From d32464e68ffc9cbec4960cd06f05bf48b3b3703f Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sun, 7 Mar 2021 19:20:47 +0100 +Subject: mt76: mt7921: introduce mt7921_run_firmware utility routine. + +From: Lorenzo Bianconi + +commit d32464e68ffc9cbec4960cd06f05bf48b3b3703f upstream. + +This is a preliminary patch to introduce chip reset for mt7921 devices. + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Cc: Deren Wu +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 32 ++++++++++++--------- + drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 20 insertions(+), 13 deletions(-) + +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +@@ -927,6 +927,24 @@ int mt7921_mcu_fw_log_2_host(struct mt79 + sizeof(data), false); + } + ++int mt7921_run_firmware(struct mt7921_dev *dev) ++{ ++ int err; ++ ++ err = mt7921_driver_own(dev); ++ if (err) ++ return err; ++ ++ err = mt7921_load_firmware(dev); ++ if (err) ++ return err; ++ ++ set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); ++ mt7921_mcu_fw_log_2_host(dev, 1); ++ ++ return 0; ++} ++ + int mt7921_mcu_init(struct mt7921_dev *dev) + { + static const struct mt76_mcu_ops mt7921_mcu_ops = { +@@ -935,22 +953,10 @@ int mt7921_mcu_init(struct mt7921_dev *d + .mcu_parse_response = mt7921_mcu_parse_response, + .mcu_restart = mt7921_mcu_restart, + }; +- int ret; + + dev->mt76.mcu_ops = &mt7921_mcu_ops; + +- ret = mt7921_driver_own(dev); +- if (ret) +- return ret; +- +- ret = mt7921_load_firmware(dev); +- if (ret) +- return ret; +- +- set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); +- mt7921_mcu_fw_log_2_host(dev, 1); +- +- return 0; ++ return mt7921_run_firmware(dev); + } + + void mt7921_mcu_exit(struct mt7921_dev *dev) +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -220,6 +220,7 @@ void mt7921_eeprom_init_sku(struct mt792 + int mt7921_dma_init(struct mt7921_dev *dev); + void mt7921_dma_prefetch(struct mt7921_dev *dev); + void mt7921_dma_cleanup(struct mt7921_dev *dev); ++int mt7921_run_firmware(struct mt7921_dev *dev); + int mt7921_mcu_init(struct mt7921_dev *dev); + int mt7921_mcu_add_bss_info(struct mt7921_phy *phy, + struct ieee80211_vif *vif, int enable); diff --git a/queue-5.12/series b/queue-5.12/series index fb1985523c5..b2e244d6660 100644 --- a/queue-5.12/series +++ b/queue-5.12/series @@ -1,3 +1,11 @@ hexagon-fix-build-errors.patch hexagon-add-target-builtins-to-kernel.patch hexagon-change-jumps-to-must-extend-in-futex_atomic_.patch +mt76-mt7921-check-mcu-returned-values-in-mt7921_start.patch +mt76-mt7921-introduce-mt7921_run_firmware-utility-routine.patch +mt76-mt7921-introduce-__mt7921_start-utility-routine.patch +mt76-dma-introduce-mt76_dma_queue_reset-routine.patch +mt76-dma-export-mt76_dma_rx_cleanup-routine.patch +mt76-mt7921-add-wifi-reset-support.patch +mt76-mt7921-abort-uncompleted-scan-by-wifi-reset.patch +mt76-mt7921-get-rid-of-mcu_reset-function-pointer.patch