* [PATCH 0/7] mt7921: introduce wifi chip reset support
@ 2021-03-07 18:20 Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 1/7] mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg Lorenzo Bianconi
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
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(-)
--
2.29.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/7] mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 2/7] mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure Lorenzo Bianconi
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
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
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 58de7f32a625..1c686e4abd80 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -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)
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/7] mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 1/7] mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 3/7] mt76: mt7921: introduce mt7921_run_firmware utility routine Lorenzo Bianconi
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
Introduce 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.
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/mcu.c | 4 ++++
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index d3a5e2c4f12a..70624cd07449 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 5d3438d86d2a..bbe6a70851c8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -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 {
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/7] mt76: mt7921: introduce mt7921_run_firmware utility routine.
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 1/7] mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 2/7] mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 4/7] mt76: mt7921: introduce __mt7921_start " Lorenzo Bianconi
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
This is a preliminary patch to introduce chip reset for mt7921 devices.
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../net/wireless/mediatek/mt76/mt7921/mcu.c | 32 +++++++++++--------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 1 +
2 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 1c686e4abd80..cbe35c76189e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -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)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 2979d06ee0ad..72dc2ba8fd40 100644
--- 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 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);
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/7] mt76: mt7921: introduce __mt7921_start utility routine
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
` (2 preceding siblings ...)
2021-03-07 18:20 ` [PATCH 3/7] mt76: mt7921: introduce mt7921_run_firmware utility routine Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 5/7] mt76: dma: introduce mt76_dma_queue_reset routine Lorenzo Bianconi
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
This is a preliminary patch to introduce mt7921 chip reset support.
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../net/wireless/mediatek/mt76/mt7921/main.c | 35 +++++++++++--------
.../wireless/mediatek/mt76/mt7921/mt7921.h | 1 +
2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 409bae30b8d9..66abadc6537a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -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;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 72dc2ba8fd40..c1404a7f9ffb 100644
--- 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_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);
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/7] mt76: dma: introduce mt76_dma_queue_reset routine
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
` (3 preceding siblings ...)
2021-03-07 18:20 ` [PATCH 4/7] mt76: mt7921: introduce __mt7921_start " Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 6/7] mt76: dma: export mt76_dma_rx_cleanup routine Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 7/7] mt76: mt7921: add wifi reset support Lorenzo Bianconi
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
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 <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 46 ++++++++++++++---------
drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++
2 files changed, 31 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 19098b852d0a..82711d69ec94 100644
--- 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 *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,
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index bbe6a70851c8..f306a9c71ebf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -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) && \
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 6/7] mt76: dma: export mt76_dma_rx_cleanup routine
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
` (4 preceding siblings ...)
2021-03-07 18:20 ` [PATCH 5/7] mt76: dma: introduce mt76_dma_queue_reset routine Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 7/7] mt76: mt7921: add wifi reset support Lorenzo Bianconi
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
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 <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/wireless/mediatek/mt76/dma.c | 1 +
drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 82711d69ec94..6d85d8d20d59 100644
--- 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_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,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index f306a9c71ebf..28e53385884c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -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__)
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 7/7] mt76: mt7921: add wifi reset support
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
` (5 preceding siblings ...)
2021-03-07 18:20 ` [PATCH 6/7] mt76: dma: export mt76_dma_rx_cleanup routine Lorenzo Bianconi
@ 2021-03-07 18:20 ` Lorenzo Bianconi
6 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2021-03-07 18:20 UTC (permalink / raw)
To: nbd; +Cc: linux-wireless, lorenzo.bianconi, sean.wang
Introduce wifi chip reset support for mt7921 device to recover mcu
hangs.
Co-developed-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
.../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(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 4070f7156aa5..262c9d150bf0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 804c1caafe88..8a059b73c12f 100644
--- 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_dev *mdev)
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;
+ /* 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);
+
+ /* 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_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);
- usleep_range(1000, 2000);
+ 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]);
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
- /* re-init prefetch settings after reset */
+ /* 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_dev *dev)
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;
+
+ mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
- ieee80211_stop_queues(mt76_hw(dev));
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt7921_l1_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);
+ mt7921_l1_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_struct *work)
}
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
GFP_KERNEL);
+ mt7921_reset(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index cbe35c76189e..ec73cf4ae7cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -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;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index c1404a7f9ffb..df3c9730876c 100644
--- 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, 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,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
index b66e15c8ab70..035fa472fa7d 100644
--- 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)
--
2.29.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-03-07 18:22 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-07 18:20 [PATCH 0/7] mt7921: introduce wifi chip reset support Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 1/7] mt76: mt7921: reduce mcu timeouts for suspend, offload and hif_ctrl msg Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 2/7] mt76: introduce mcu_reset function pointer in mt76_mcu_ops structure Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 3/7] mt76: mt7921: introduce mt7921_run_firmware utility routine Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 4/7] mt76: mt7921: introduce __mt7921_start " Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 5/7] mt76: dma: introduce mt76_dma_queue_reset routine Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 6/7] mt76: dma: export mt76_dma_rx_cleanup routine Lorenzo Bianconi
2021-03-07 18:20 ` [PATCH 7/7] mt76: mt7921: add wifi reset support Lorenzo Bianconi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.