mt7921: introduce wifi chip reset support
Subsystems (2)
Lorenzo Bianconi
maintainercover mt7921: introduce wifi chip reset support
Introduce wifi chip reset support for mt7921 devices in order to recover from mcu hangs.
Lorenzo Bianconi (7):
mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl
msg
mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure
mt76: mt7921: introduce mt7921_run_firmware utility routine.
mt76: mt7921: introduce __mt7921_start utility routine
mt76: dma: introduce mt76_dma_queue_reset routine
mt76: dma: export mt76_dma_rx_cleanup routine
mt76: mt7921: add wifi reset support
drivers/net/wireless/mediatek/mt76/dma.c | 47 ++-- drivers/net/wireless/mediatek/mt76/mcu.c | 4 + drivers/net/wireless/mediatek/mt76/mt76.h | 9 +- .../net/wireless/mediatek/mt76/mt7921/init.c | 3 +- .../net/wireless/mediatek/mt76/mt7921/mac.c | 201 +++++++++++++----- .../net/wireless/mediatek/mt76/mt7921/main.c | 35 +-- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 47 ++-- .../wireless/mediatek/mt76/mt7921/mt7921.h | 6 +- .../net/wireless/mediatek/mt76/mt7921/regs.h | 4 + 9 files changed, 248 insertions(+), 108 deletions(-)
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 1/7 mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg
Reduce mcu timeout for the following uni mcu commands:
- MCU_UNI_CMD_SUSPEND
- MCU_UNI_CMD_OFFLOAD
- MCU_UNI_CMD_HIF_CTRL
This is a preliminary patch to introduce chip reset support
--- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +10 -2
@@ -222,8 +222,16 @@ mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,u32 val;u8 seq; -/* TODO: make dynamic based on msg type */ - mdev->mcu.timeout =20 *HZ ; +switch (cmd) { +case MCU_UNI_CMD_HIF_CTRL : +case MCU_UNI_CMD_SUSPEND : +case MCU_UNI_CMD_OFFLOAD : + mdev->mcu.timeout =HZ /3 ; +break ; +default : + mdev->mcu.timeout =3 *HZ ; +break ; + } seq = ++dev->mt76.mcu.msg_seq &0xf ;if (!seq)
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 2/7 mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure
In reply to Lorenzo BianconiIntroduce mcu_reset function pointer in mt76_mcu_ops structure in order to run hw related reset function for the mcu running on the chipset. This is a preliminary patch to introduce chip reset for mt7921 devices.
--- drivers/net/wireless/mediatek/mt76/mcu.c | 4 ++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + 2 files changed, 5 insertions(+)
drivers/net/wireless/mediatek/mt76/mcu.c +4 -0
@@ -99,6 +99,10 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,dev_kfree_skb (skb); }while (ret == -EAGAIN ); +/* notify driver code to reset the mcu */ +if (ret == -ETIMEDOUT && dev->mcu_ops->mcu_reset) + dev->mcu_ops->mcu_reset (dev); + out:mutex_unlock (&dev->mcu.mutex);
drivers/net/wireless/mediatek/mt76/mt76.h +1 -0
@@ -166,6 +166,7 @@ struct mt76_mcu_ops {int (*mcu_rd_rp)(struct mt76_dev *dev,u32 base,struct mt76_reg_pair *rp,int len);int (*mcu_restart)(struct mt76_dev *dev); +void (*mcu_reset)(struct mt76_dev *dev); };struct mt76_queue_ops {
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 3/7 mt76: mt7921: introduce mt7921_run_firmware utility routine.
In reply to Lorenzo BianconiThis is a preliminary patch to introduce chip reset for mt7921 devices.
--- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 32 +++++++++++-------- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 20 insertions(+), 13 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +19 -13
@@ -928,6 +928,24 @@ int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl) 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 = {
@@ -936,22 +954,10 @@ int mt7921_mcu_init(struct mt7921_dev *dev) .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)
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +1 -0
@@ -220,6 +220,7 @@ void mt7921_eeprom_init_sku(struct mt7921_dev *dev);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);
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 6/7 mt76: dma: export mt76_dma_rx_cleanup routine
In reply to Lorenzo BianconiExport mt76_dma_rx_cleanup routine in mt76_queue_ops data structure. This is a preliminary patch to introduce mt7921 chip reset support.
--- drivers/net/wireless/mediatek/mt76/dma.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/dma.c +1 -0
@@ -653,6 +653,7 @@ static const struct mt76_queue_ops mt76_dma_ops = { .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, };
drivers/net/wireless/mediatek/mt76/mt76.h +4 -1
@@ -191,6 +191,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);
@@ -794,7 +796,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev)#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__)
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 4/7 mt76: mt7921: introduce __mt7921_start utility routine
In reply to Lorenzo BianconiThis is a preliminary patch to introduce mt7921 chip reset support.
--- .../net/wireless/mediatek/mt76/mt7921/main.c | 35 +++++++++++-------- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + 2 files changed, 22 insertions(+), 14 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/main.c +21 -14
@@ -169,33 +169,40 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy) } } -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; }
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +1 -0
@@ -209,6 +209,7 @@ extern struct pci_driver mt7921_pci_driver;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);
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 5/7 mt76: dma: introduce mt76_dma_queue_reset routine
In reply to Lorenzo BianconiIntroduce mt76_dma_queue_reset utility routine to reset a given hw queue. This is a preliminary patch to introduce mt7921 chip reset support.
--- drivers/net/wireless/mediatek/mt76/dma.c | 46 ++++++++++++++--------- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++ 2 files changed, 31 insertions(+), 18 deletions(-)
drivers/net/wireless/mediatek/mt76/dma.c +28 -18
@@ -79,13 +79,38 @@ mt76_free_pending_txwi(struct mt76_dev *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 *dev, struct mt76_queue *q,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 ; }
@@ -201,15 +219,6 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,memset (e,0 ,sizeof (*e)); } -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) {
@@ -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,
drivers/net/wireless/mediatek/mt76/mt76.h +3 -0
@@ -192,6 +192,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 {
@@ -794,6 +796,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev)#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) && \
Signature · 1 line
2.29.2
Lorenzo Bianconi
maintainerPATCH 7/7 mt76: mt7921: add wifi reset support
In reply to Lorenzo BianconiIntroduce wifi chip reset support for mt7921 device to recover mcu hangs.
--- .../net/wireless/mediatek/mt76/mt7921/init.c | 3 +- .../net/wireless/mediatek/mt76/mt7921/mac.c | 201 +++++++++++++----- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 3 + .../wireless/mediatek/mt76/mt7921/mt7921.h | 4 +- .../net/wireless/mediatek/mt76/mt7921/regs.h | 4 + 5 files changed, 155 insertions(+), 60 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7921/init.c +1 -2
@@ -143,7 +143,7 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)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;
@@ -233,7 +233,6 @@ int mt7921_register_device(struct mt7921_dev *dev)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);
drivers/net/wireless/mediatek/mt76/mt7921/mac.c +145 -56
263 lines not on this page · raw message
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +3 -0
@@ -953,6 +953,7 @@ int mt7921_mcu_init(struct mt7921_dev *dev) .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;
@@ -1270,6 +1271,7 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)if (i ==MT7921_DRV_OWN_RETRY_COUNT ) {dev_err (dev->mt76.dev,"driver own failed\n" ); +mt7921_reset (&dev->mt76);return -EIO ; }
@@ -1296,6 +1298,7 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)if (i ==MT7921_DRV_OWN_RETRY_COUNT ) {dev_err (dev->mt76.dev,"firmware own failed\n" ); +mt7921_reset (&dev->mt76);return -EIO ; }
drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +2 -2
@@ -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, u32 addr, u32 mask, u32 val)#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_dev *mdev, struct ieee80211_vif *vif, 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,
drivers/net/wireless/mediatek/mt76/mt7921/regs.h +4 -0
@@ -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)
Signature · 1 line
2.29.2