blob: 34b74bb4052777fa7fcf3370a24d1eb2e0e3024c [file] [log] [blame]
developerbd398d52022-06-06 20:53:24 +08001From 295dac8799e536a2d5dc53e727e246e469739853 Mon Sep 17 00:00:00 2001
developere3d01472022-05-09 14:01:49 +08002From: Bo Jiao <Bo.Jiao@mediatek.com>
developerbd398d52022-06-06 20:53:24 +08003Date: Mon, 6 Jun 2022 20:18:15 +0800
4Subject: [PATCH 1006/1007] mt76: mt7915: add L0.5 system error recovery
5 support
developere3d01472022-05-09 14:01:49 +08006
developere3d01472022-05-09 14:01:49 +08007---
8 mt7915/debugfs.c | 88 ++++++++++++---
9 mt7915/dma.c | 48 ++++++++
10 mt7915/init.c | 8 +-
11 mt7915/mac.c | 280 +++++++++++++++++++++++++++++++++++++----------
12 mt7915/main.c | 20 +++-
13 mt7915/mcu.c | 96 ++++++++++++++--
14 mt7915/mcu.h | 3 +-
15 mt7915/mmio.c | 8 +-
16 mt7915/mt7915.h | 23 ++++
17 mt7915/regs.h | 16 +++
18 10 files changed, 493 insertions(+), 97 deletions(-)
19
20diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
developerbd398d52022-06-06 20:53:24 +080021index 27eae83b..c75d9e5b 100644
developere3d01472022-05-09 14:01:49 +080022--- a/mt7915/debugfs.c
23+++ b/mt7915/debugfs.c
developerbd398d52022-06-06 20:53:24 +080024@@ -52,12 +52,17 @@ static ssize_t
developere3d01472022-05-09 14:01:49 +080025 mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
26 size_t count, loff_t *ppos)
27 {
28+#define SER_LEVEL GENMASK(3, 0)
29+#define SER_ACTION GENMASK(11, 8)
30+
31 struct mt7915_phy *phy = file->private_data;
32 struct mt7915_dev *dev = phy->dev;
33- bool ext_phy = phy != &dev->phy;
34+ u8 ser_action, ser_set, set_val;
35+ u8 band_idx = phy->band_idx;
36 char buf[16];
37 int ret = 0;
38 u16 val;
39+ u32 intr;
40
41 if (count >= sizeof(buf))
42 return -EINVAL;
developerbd398d52022-06-06 20:53:24 +080043@@ -73,28 +78,71 @@ mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
developere3d01472022-05-09 14:01:49 +080044 if (kstrtou16(buf, 0, &val))
45 return -EINVAL;
46
47- switch (val) {
48+ ser_action = FIELD_GET(SER_ACTION, val);
49+ ser_set = set_val = FIELD_GET(SER_LEVEL, val);
50+
51+ switch (ser_action) {
52 case SER_QUERY:
53 /* grab firmware SER stats */
54- ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy);
55+ ser_set = 0;
56 break;
57- case SER_SET_RECOVER_L1:
58- case SER_SET_RECOVER_L2:
59- case SER_SET_RECOVER_L3_RX_ABORT:
60- case SER_SET_RECOVER_L3_TX_ABORT:
61- case SER_SET_RECOVER_L3_TX_DISABLE:
62- case SER_SET_RECOVER_L3_BF:
63- ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy);
64- if (ret)
65- return ret;
66-
67- ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy);
68+ case SER_SET:
69+ /*
70+ * 0x100: disable system error recovery function.
71+ * 0x101: enable system error recovery function.
72+ * 0x103: enable l0.5 recover function.
73+ */
74+ ser_set = !!set_val;
75+
76+ dev->ser.reset_enable = ser_set;
77+ intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
78+ if (dev->ser.reset_enable)
79+ intr |= MT_MCU_CMD_WDT_MASK;
80+ else
81+ intr &= ~MT_MCU_CMD_WDT_MASK;
82+ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
83 break;
84- default:
85+ case SER_ENABLE:
86+ /*
87+ * 0x200: enable system error tracking.
88+ * 0x201: enable system error L1 recover.
89+ * 0x202: enable system error L2 recover.
90+ * 0x203: enable system error L3 rx abort.
91+ * 0x204: enable system error L3 tx abort.
92+ * 0x205: enable system error L3 tx disable.
93+ * 0x206: enable system error L3 bf recover.
94+ * 0x207: enable system error all recover.
95+ */
96+ ser_set = set_val > 7 ? 0x7f : BIT(set_val);
97+ break;
98+ case SER_RECOVER:
99+ /*
100+ * 0x300: trigger L0.5 recover.
101+ * 0x301: trigger L1 recover.
102+ * 0x302: trigger L2 recover.
103+ * 0x303: trigger L3 rx abort.
104+ * 0x304: trigger L3 tx abort
105+ * 0x305: trigger L3 tx disable.
106+ * 0x306: trigger L3 bf recover.
107+ */
108+ if (!ser_set) {
109+ if (dev->ser.reset_enable) {
110+ dev->reset_state |= MT_MCU_CMD_WDT_MASK;
111+ mt7915_reset(dev);
112+ } else {
113+ dev_info(dev->mt76.dev, "SER: chip full recovery not enable\n");
114+ }
115+ goto out;
116+ }
117 break;
118+ default:
119+ goto out;
120 }
121-
122- return ret ? ret : count;
123+ ret = mt7915_mcu_set_ser(dev, ser_action, ser_set, band_idx);
124+ if (ret)
125+ return ret;
126+out:
127+ return count;
128 }
129
130 static ssize_t
developerbd398d52022-06-06 20:53:24 +0800131@@ -143,6 +191,12 @@ mt7915_fw_ser_get(struct file *file, char __user *user_buf,
developere3d01472022-05-09 14:01:49 +0800132 "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n",
133 mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
134
135+ desc += scnprintf(buff + desc, bufsz - desc,
136+ "\nWF RESET STATUS: EN %d, WM %d, WA %d\n",
137+ dev->ser.reset_enable,
138+ dev->ser.wf_reset_wm_count,
139+ dev->ser.wf_reset_wa_count);
140+
141 ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
142 kfree(buff);
143 return ret;
144diff --git a/mt7915/dma.c b/mt7915/dma.c
145index c2d655cd..9e3d14db 100644
146--- a/mt7915/dma.c
147+++ b/mt7915/dma.c
148@@ -486,6 +486,54 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
149 return 0;
150 }
151
152+int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
153+{
154+ struct mt76_phy *mphy_ext = dev->mt76.phy2;
155+ int i;
156+
157+ /* clean up hw queues */
158+ for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) {
159+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
160+ if (mphy_ext)
161+ mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
162+ }
163+
164+ for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++)
165+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
166+
167+ mt76_for_each_q_rx(&dev->mt76, i)
168+ mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
169+
170+ /* reset wfsys */
171+ if (force)
172+ mt7915_wfsys_reset(dev);
173+
174+ /* disable wfdma */
175+ mt7915_dma_disable(dev, force);
176+
177+ /* reset hw queues */
178+ for (i = 0; i < __MT_TXQ_MAX; i++) {
179+ mt76_queue_reset(dev, dev->mphy.q_tx[i]);
180+ if (mphy_ext)
181+ mt76_queue_reset(dev, mphy_ext->q_tx[i]);
182+ }
183+
184+ for (i = 0; i < __MT_MCUQ_MAX; i++)
185+ mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
186+
187+ mt76_for_each_q_rx(&dev->mt76, i)
188+ mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
189+
190+ mt76_tx_status_check(&dev->mt76, true);
191+
192+ mt7915_dma_enable(dev);
193+
194+ mt76_for_each_q_rx(&dev->mt76, i)
195+ mt76_queue_rx_reset(dev, i);
196+
197+ return 0;
198+}
199+
200 void mt7915_dma_cleanup(struct mt7915_dev *dev)
201 {
202 mt7915_dma_disable(dev, true);
203diff --git a/mt7915/init.c b/mt7915/init.c
developerbd398d52022-06-06 20:53:24 +0800204index b4404aec..80ada114 100644
developere3d01472022-05-09 14:01:49 +0800205--- a/mt7915/init.c
206+++ b/mt7915/init.c
207@@ -262,7 +262,7 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
208 mt7915_led_set_config(led_cdev, 0xff, 0);
209 }
210
211-static void
212+void
213 mt7915_init_txpower(struct mt7915_dev *dev,
214 struct ieee80211_supported_band *sband)
215 {
developerbd398d52022-06-06 20:53:24 +0800216@@ -448,7 +448,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
developere3d01472022-05-09 14:01:49 +0800217 mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
218 }
219
220-static void mt7915_mac_init(struct mt7915_dev *dev)
221+void mt7915_mac_init(struct mt7915_dev *dev)
222 {
223 int i;
224 u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
developerbd398d52022-06-06 20:53:24 +0800225@@ -478,7 +478,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
developere3d01472022-05-09 14:01:49 +0800226 }
227 }
228
229-static int mt7915_txbf_init(struct mt7915_dev *dev)
230+int mt7915_txbf_init(struct mt7915_dev *dev)
231 {
232 int ret;
233
developerbd398d52022-06-06 20:53:24 +0800234@@ -1160,6 +1160,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
developere3d01472022-05-09 14:01:49 +0800235
236 mt7915_init_debugfs(&dev->phy);
237
238+ dev->ser.hw_init_done = true;
239+
240 return 0;
241
242 unreg_thermal:
243diff --git a/mt7915/mac.c b/mt7915/mac.c
developerbd398d52022-06-06 20:53:24 +0800244index 9af0644f..a9ebbf12 100644
developere3d01472022-05-09 14:01:49 +0800245--- a/mt7915/mac.c
246+++ b/mt7915/mac.c
247@@ -3,6 +3,7 @@
248
249 #include <linux/etherdevice.h>
250 #include <linux/timekeeping.h>
251+#include <linux/pci.h>
252 #include "mt7915.h"
253 #include "../dma.h"
254 #include "mac.h"
developerbd398d52022-06-06 20:53:24 +0800255@@ -2063,85 +2064,188 @@ mt7915_update_beacons(struct mt7915_dev *dev)
developere3d01472022-05-09 14:01:49 +0800256 mt7915_update_vif_beacon, dev->mt76.phy2->hw);
257 }
258
259-static void
260-mt7915_dma_reset(struct mt7915_dev *dev)
261+void mt7915_tx_token_put(struct mt7915_dev *dev)
262 {
263- struct mt76_phy *mphy_ext = dev->mt76.phy2;
264- u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
265- int i;
266+ struct mt76_txwi_cache *txwi;
267+ int id;
268
269- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
270- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
271- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
272+ spin_lock_bh(&dev->mt76.token_lock);
273+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
274+ mt7915_txwi_free(dev, txwi, NULL, NULL);
275+ dev->mt76.token_count--;
276+ }
277+ spin_unlock_bh(&dev->mt76.token_lock);
278+ idr_destroy(&dev->mt76.token);
279+}
280
281- if (is_mt7915(&dev->mt76))
282- mt76_clear(dev, MT_WFDMA1_GLO_CFG,
283- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
284- MT_WFDMA1_GLO_CFG_RX_DMA_EN);
285+static int
286+mt7915_mac_reset(struct mt7915_dev *dev)
287+{
288+ struct mt7915_phy *phy2;
289+ struct mt76_phy *ext_phy;
290+ struct mt76_dev *mdev = &dev->mt76;
291+ int i, ret;
292+ u32 irq_mask;
293+
294+ ext_phy = dev->mt76.phy2;
295+ phy2 = ext_phy ? ext_phy->priv : NULL;
296+
297+ /* irq disable */
298+ mt76_wr(dev, MT_INT_MASK_CSR, 0x0);
299+ mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
300 if (dev->hif2) {
301- mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
302- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
303- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
304+ mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
305+ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
306+ }
307+ if (dev_is_pci(mdev->dev)) {
308+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
309+ if (dev->hif2)
310+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
311+ }
312
313- if (is_mt7915(&dev->mt76))
314- mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
315- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
316- MT_WFDMA1_GLO_CFG_RX_DMA_EN);
317+ set_bit(MT76_RESET, &dev->mphy.state);
318+ set_bit(MT76_MCU_RESET, &dev->mphy.state);
319+ wake_up(&dev->mt76.mcu.wait);
320+ if (ext_phy) {
321+ set_bit(MT76_RESET, &ext_phy->state);
322+ set_bit(MT76_MCU_RESET, &ext_phy->state);
323 }
324
325- usleep_range(1000, 2000);
326+ /* lock/unlock all queues to ensure that no tx is pending */
327+ mt76_txq_schedule_all(&dev->mphy);
328+ if (ext_phy)
329+ mt76_txq_schedule_all(ext_phy);
330
331- for (i = 0; i < __MT_TXQ_MAX; i++) {
332- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
333- if (mphy_ext)
334- mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
335+ /* disable all tx/rx napi */
336+ mt76_worker_disable(&dev->mt76.tx_worker);
337+ mt76_for_each_q_rx(mdev, i) {
338+ if (mdev->q_rx[i].ndesc)
339+ napi_disable(&dev->mt76.napi[i]);
340 }
341+ napi_disable(&dev->mt76.tx_napi);
342
343- for (i = 0; i < __MT_MCUQ_MAX; i++)
344- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
345-
346- mt76_for_each_q_rx(&dev->mt76, i)
347- mt76_queue_rx_reset(dev, i);
348+ /* token reinit */
349+ mt7915_tx_token_put(dev);
350+ idr_init(&dev->mt76.token);
351
352- mt76_tx_status_check(&dev->mt76, true);
353+ mt7915_dma_reset(dev, true);
354
355- /* re-init prefetch settings after reset */
356- mt7915_dma_prefetch(dev);
357+ local_bh_disable();
358+ mt76_for_each_q_rx(mdev, i) {
359+ if (mdev->q_rx[i].ndesc) {
360+ napi_enable(&dev->mt76.napi[i]);
361+ napi_schedule(&dev->mt76.napi[i]);
362+ }
363+ }
364+ local_bh_enable();
365+ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
366+ clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
367
368- mt76_set(dev, MT_WFDMA0_GLO_CFG,
369- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
370- if (is_mt7915(&dev->mt76))
371- mt76_set(dev, MT_WFDMA1_GLO_CFG,
372- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
373- MT_WFDMA1_GLO_CFG_RX_DMA_EN |
374- MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
375- MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
376+ mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
377+ mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
378 if (dev->hif2) {
379- mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
380- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
381- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
382+ mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
383+ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
384+ }
385+ if (dev_is_pci(mdev->dev)) {
386+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
387+ if (dev->hif2)
388+ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
389+ }
developerbd398d52022-06-06 20:53:24 +0800390
391- if (is_mt7915(&dev->mt76))
392- mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
393- MT_WFDMA1_GLO_CFG_TX_DMA_EN |
394- MT_WFDMA1_GLO_CFG_RX_DMA_EN |
395- MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
396- MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
developere3d01472022-05-09 14:01:49 +0800397+ /* load firmware */
398+ ret = mt7915_run_firmware(dev);
399+ if (ret)
400+ goto out;
401+
402+ /* set the necessary init items */
403+ ret = mt7915_mcu_set_eeprom(dev, dev->flash_mode);
404+ if (ret)
405+ goto out;
406+
407+ mt7915_mac_init(dev);
408+ mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
409+ mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
410+ ret = mt7915_txbf_init(dev);
developerbd398d52022-06-06 20:53:24 +0800411+
developere3d01472022-05-09 14:01:49 +0800412+ if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
413+ ret = __mt7915_start(dev->mphy.hw);
414+ if (ret)
415+ goto out;
developerbd398d52022-06-06 20:53:24 +0800416 }
developere3d01472022-05-09 14:01:49 +0800417+
418+ if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) {
419+ ret = __mt7915_start(ext_phy->hw);
420+ if (ret)
421+ goto out;
developerbd398d52022-06-06 20:53:24 +0800422+ }
developere3d01472022-05-09 14:01:49 +0800423+
424+out:
425+ /* reset done */
426+ clear_bit(MT76_RESET, &dev->mphy.state);
427+ if (phy2)
428+ clear_bit(MT76_RESET, &phy2->mt76->state);
429+
430+ local_bh_disable();
431+ napi_enable(&dev->mt76.tx_napi);
432+ napi_schedule(&dev->mt76.tx_napi);
433+ local_bh_enable();
434+
435+ mt76_worker_enable(&dev->mt76.tx_worker);
436+
437+ return ret;
438 }
439
440-void mt7915_tx_token_put(struct mt7915_dev *dev)
441+static void
442+mt7915_mac_full_reset(struct mt7915_dev *dev)
443 {
444- struct mt76_txwi_cache *txwi;
445- int id;
446+ struct mt7915_phy *phy2;
447+ struct mt76_phy *ext_phy;
448+ int i;
449
450- spin_lock_bh(&dev->mt76.token_lock);
451- idr_for_each_entry(&dev->mt76.token, txwi, id) {
452- mt7915_txwi_free(dev, txwi, NULL, NULL);
453- dev->mt76.token_count--;
454+ ext_phy = dev->mt76.phy2;
455+ phy2 = ext_phy ? ext_phy->priv : NULL;
456+
457+ dev->ser.hw_full_reset = true;
458+ if (READ_ONCE(dev->reset_state) & MT_MCU_CMD_WA_WDT)
459+ dev->ser.wf_reset_wa_count++;
460+ else
461+ dev->ser.wf_reset_wm_count++;
462+
463+ wake_up(&dev->mt76.mcu.wait);
464+ ieee80211_stop_queues(mt76_hw(dev));
465+ if (ext_phy)
466+ ieee80211_stop_queues(ext_phy->hw);
467+
468+ cancel_delayed_work_sync(&dev->mphy.mac_work);
469+ if (ext_phy)
470+ cancel_delayed_work_sync(&ext_phy->mac_work);
471+
472+ mutex_lock(&dev->mt76.mutex);
473+ for (i = 0; i < 10; i++) {
474+ if (!mt7915_mac_reset(dev))
475+ break;
476 }
477- spin_unlock_bh(&dev->mt76.token_lock);
478- idr_destroy(&dev->mt76.token);
479+ mutex_unlock(&dev->mt76.mutex);
480+
481+ if (i == 10)
482+ dev_err(dev->mt76.dev, "chip full reset failed\n");
483+
484+ ieee80211_restart_hw(mt76_hw(dev));
485+ if (ext_phy)
486+ ieee80211_restart_hw(ext_phy->hw);
487+
488+ ieee80211_wake_queues(mt76_hw(dev));
489+ if (ext_phy)
490+ ieee80211_wake_queues(ext_phy->hw);
491+
492+ dev->ser.hw_full_reset = false;
493+ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
494+ MT7915_WATCHDOG_TIME);
495+ if (ext_phy)
496+ ieee80211_queue_delayed_work(ext_phy->hw,
497+ &ext_phy->mac_work,
498+ MT7915_WATCHDOG_TIME);
499 }
500
501 /* system error recovery */
developerbd398d52022-06-06 20:53:24 +0800502@@ -2156,6 +2260,36 @@ void mt7915_mac_reset_work(struct work_struct *work)
developere3d01472022-05-09 14:01:49 +0800503 ext_phy = dev->mt76.phy2;
504 phy2 = ext_phy ? ext_phy->priv : NULL;
505
506+ /* chip full reset */
507+ if (dev->ser.reset_type == SER_TYPE_FULL_RESET) {
508+ u32 intr;
509+
510+ /* disable WA/WM WDT */
511+ intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
512+ intr &= ~MT_MCU_CMD_WDT_MASK;
513+ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
514+
515+ mt7915_mac_full_reset(dev);
516+
517+ /* enable the mcu irq*/
518+ mt7915_irq_enable(dev, MT_INT_MCU_CMD);
519+ mt7915_irq_disable(dev, 0);
520+
521+ /* re-enable WA/WM WDT */
522+ intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
523+ intr |= MT_MCU_CMD_WDT_MASK;
524+ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
525+
526+ dev->reset_state = MT_MCU_CMD_NORMAL_STATE;
527+ dev->ser.reset_type = SER_TYPE_NONE;
528+ dev_info(dev->mt76.dev, "SER: chip full reset completed, WM %d, WA %d\n",
529+ dev->ser.wf_reset_wm_count,
530+ dev->ser.wf_reset_wa_count);
531+ return;
532+ }
533+
534+ /* chip partial reset */
535+ dev->ser.reset_type = SER_TYPE_NONE;
536 if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
537 return;
538
developerbd398d52022-06-06 20:53:24 +0800539@@ -2181,7 +2315,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
developere3d01472022-05-09 14:01:49 +0800540 mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
541
542 if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
543- mt7915_dma_reset(dev);
544+ mt7915_dma_reset(dev, false);
545
546 mt7915_tx_token_put(dev);
547 idr_init(&dev->mt76.token);
developerbd398d52022-06-06 20:53:24 +0800548@@ -2230,6 +2364,34 @@ void mt7915_mac_reset_work(struct work_struct *work)
developere3d01472022-05-09 14:01:49 +0800549 MT7915_WATCHDOG_TIME);
550 }
551
552+void mt7915_reset(struct mt7915_dev *dev)
553+{
554+ if (!dev->ser.hw_init_done)
555+ return;
556+
557+ if (dev->ser.hw_full_reset)
558+ return;
559+
560+ /* wm/wa exception: do full recovery */
561+ if (READ_ONCE(dev->reset_state) & MT_MCU_CMD_WDT_MASK) {
562+ dev_info(dev->mt76.dev, "SER: chip full recovery start, WM %d, WA %d\n",
563+ dev->ser.wf_reset_wm_count,
564+ dev->ser.wf_reset_wa_count);
565+
566+ dev->ser.reset_type = SER_TYPE_FULL_RESET;
567+
568+ mt7915_irq_disable(dev, MT_INT_MCU_CMD);
569+ queue_work(dev->mt76.wq, &dev->reset_work);
570+ return;
571+ }
572+
573+ dev_info(dev->mt76.dev, "SER: chip partial recovery, reset_state(0x%08X)\n",
574+ READ_ONCE(dev->reset_state));
575+ dev->ser.reset_type = SER_TYPE_PARTIAL_RESET;
576+ queue_work(dev->mt76.wq, &dev->reset_work);
577+ wake_up(&dev->reset_wait);
578+}
579+
580 void mt7915_mac_update_stats(struct mt7915_phy *phy)
581 {
582 struct mt7915_dev *dev = phy->dev;
583diff --git a/mt7915/main.c b/mt7915/main.c
developerbd398d52022-06-06 20:53:24 +0800584index 24bc12f5..082e27d4 100644
developere3d01472022-05-09 14:01:49 +0800585--- a/mt7915/main.c
586+++ b/mt7915/main.c
587@@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev)
588 return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
589 }
590
591-static int mt7915_start(struct ieee80211_hw *hw)
592+int __mt7915_start(struct ieee80211_hw *hw)
593 {
594 struct mt7915_dev *dev = mt7915_hw_dev(hw);
595 struct mt7915_phy *phy = mt7915_hw_phy(hw);
596 bool running;
597 int ret;
598
599- flush_work(&dev->init_work);
600-
601- mutex_lock(&dev->mt76.mutex);
602-
603 running = mt7915_dev_running(dev);
604
605 if (!running) {
606@@ -80,6 +76,19 @@ static int mt7915_start(struct ieee80211_hw *hw)
607 mt7915_mac_reset_counters(phy);
608
609 out:
610+ return ret;
611+}
612+
613+static int mt7915_start(struct ieee80211_hw *hw)
614+{
615+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
616+ bool running;
617+ int ret;
618+
619+ flush_work(&dev->init_work);
620+
621+ mutex_lock(&dev->mt76.mutex);
622+ ret = __mt7915_start(hw);
623 mutex_unlock(&dev->mt76.mutex);
624
625 return ret;
626@@ -91,6 +100,7 @@ static void mt7915_stop(struct ieee80211_hw *hw)
627 struct mt7915_phy *phy = mt7915_hw_phy(hw);
628
629 cancel_delayed_work_sync(&phy->mt76->mac_work);
630+ cancel_work_sync(&dev->reset_work);
631
632 mutex_lock(&dev->mt76.mutex);
633
634diff --git a/mt7915/mcu.c b/mt7915/mcu.c
developerbd398d52022-06-06 20:53:24 +0800635index 495f2368..4a921a50 100644
developere3d01472022-05-09 14:01:49 +0800636--- a/mt7915/mcu.c
637+++ b/mt7915/mcu.c
developerbd398d52022-06-06 20:53:24 +0800638@@ -207,19 +207,90 @@ mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
developere3d01472022-05-09 14:01:49 +0800639 ht_mcs[nss] = sta->ht_cap.mcs.rx_mask[nss] & mask[nss];
640 }
641
642+static int
643+mt7915_fw_exception_chk(struct mt7915_dev *dev)
644+{
645+ u32 reg_val;
646+
647+ reg_val = mt76_rr(dev, MT_EXCEPTION_ADDR);
648+
649+ if (is_mt7915(&dev->mt76))
650+ reg_val >>= 8;
651+
652+ return !!(reg_val & 0xff);
653+}
654+
655+static void
656+mt7915_fw_heart_beat_chk(struct mt7915_dev *dev)
657+{
658+#define WM_TIMEOUT_COUNT_CHECK 5
659+#define WM_HANG_COUNT_CHECK 9
660+ static u32 cidx_rec[5], didx_rec[5];
661+ u32 cnt, cidx, didx, queue;
662+ u32 idx, i;
663+
664+ if (dev->ser.hw_full_reset)
665+ return;
666+
667+ if (dev->ser.cmd_fail_cnt >= WM_TIMEOUT_COUNT_CHECK) {
668+ cnt = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 4);
669+ cidx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 8);
670+ didx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 12);
671+ queue = (didx > cidx) ?
672+ (didx - cidx - 1) : (didx - cidx + cnt - 1);
673+
674+ idx = (dev->ser.cmd_fail_cnt - WM_TIMEOUT_COUNT_CHECK) % 5;
675+ cidx_rec[idx] = cidx;
676+ didx_rec[idx] = didx;
677+
678+ if ((cnt - 1) == queue &&
679+ dev->ser.cmd_fail_cnt >= WM_HANG_COUNT_CHECK) {
680+
681+ for (i = 0; i < 5; i++) {
682+ if (cidx_rec[i] != cidx ||
683+ didx_rec[i] != didx)
684+ return;
685+ }
686+ dev_err(dev->mt76.dev, "detect mem dma hang!\n");
687+ if (dev->ser.reset_enable) {
688+ dev->reset_state |= MT_MCU_CMD_WDT_MASK;
689+ mt7915_reset(dev);
690+ }
691+ dev->ser.cmd_fail_cnt = 0;
692+ }
693+ }
694+}
695+
696 static int
697 mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
698 struct sk_buff *skb, int seq)
699 {
700+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
701 struct mt7915_mcu_rxd *rxd;
702 int ret = 0;
703
704 if (!skb) {
705 dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
706 cmd, seq);
707+
708+ dev->ser.cmd_fail_cnt++;
709+
710+ if (dev->ser.cmd_fail_cnt < 5) {
711+ int exp_type = mt7915_fw_exception_chk(dev);
712+
713+ dev_err(mdev->dev, "Fw is status(%d)\n", exp_type);
714+ if (exp_type && dev->ser.reset_enable) {
715+ dev->reset_state |= MT_MCU_CMD_WDT_MASK;
716+ mt7915_reset(dev);
717+ }
718+ }
719+ mt7915_fw_heart_beat_chk(dev);
720+
721 return -ETIMEDOUT;
722 }
723
724+ dev->ser.cmd_fail_cnt = 0;
725+
726 rxd = (struct mt7915_mcu_rxd *)skb->data;
727 if (seq != rxd->seq)
728 return -EAGAIN;
developerbd398d52022-06-06 20:53:24 +0800729@@ -2549,18 +2620,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
developere3d01472022-05-09 14:01:49 +0800730 sizeof(req), true);
731 }
732
733-int mt7915_mcu_init(struct mt7915_dev *dev)
734+int mt7915_run_firmware(struct mt7915_dev *dev)
735 {
736- static const struct mt76_mcu_ops mt7915_mcu_ops = {
737- .headroom = sizeof(struct mt7915_mcu_txd),
738- .mcu_skb_send_msg = mt7915_mcu_send_message,
739- .mcu_parse_response = mt7915_mcu_parse_response,
740- .mcu_restart = mt76_connac_mcu_restart,
741- };
742 int ret;
743
744- dev->mt76.mcu_ops = &mt7915_mcu_ops;
745-
746 /* force firmware operation mode into normal state,
747 * which should be set before firmware download stage.
748 */
developerbd398d52022-06-06 20:53:24 +0800749@@ -2609,6 +2672,21 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
developere3d01472022-05-09 14:01:49 +0800750 MCU_WA_PARAM_RED, 0, 0);
751 }
752
753+int mt7915_mcu_init(struct mt7915_dev *dev)
754+{
755+ static const struct mt76_mcu_ops mt7915_mcu_ops = {
756+ .headroom = sizeof(struct mt7915_mcu_txd),
757+ .mcu_skb_send_msg = mt7915_mcu_send_message,
758+ .mcu_parse_response = mt7915_mcu_parse_response,
759+ .mcu_restart = mt76_connac_mcu_restart,
760+ };
761+ int ret;
762+
763+ dev->mt76.mcu_ops = &mt7915_mcu_ops;
764+
765+ return mt7915_run_firmware(dev);
766+}
767+
768 void mt7915_mcu_exit(struct mt7915_dev *dev)
769 {
770 __mt76_mcu_restart(&dev->mt76);
771diff --git a/mt7915/mcu.h b/mt7915/mcu.h
developerbd398d52022-06-06 20:53:24 +0800772index 364ea0dd..44d3722e 100644
developere3d01472022-05-09 14:01:49 +0800773--- a/mt7915/mcu.h
774+++ b/mt7915/mcu.h
developerbd398d52022-06-06 20:53:24 +0800775@@ -489,8 +489,9 @@ enum {
developere3d01472022-05-09 14:01:49 +0800776
777 enum {
778 SER_QUERY,
779+ SER_SET,
780 /* recovery */
781- SER_SET_RECOVER_L1,
782+ SER_SET_RECOVER_L1 = 1,
783 SER_SET_RECOVER_L2,
784 SER_SET_RECOVER_L3_RX_ABORT,
785 SER_SET_RECOVER_L3_TX_ABORT,
786diff --git a/mt7915/mmio.c b/mt7915/mmio.c
developerbd398d52022-06-06 20:53:24 +0800787index 71945ba9..ba61ce2e 100644
developere3d01472022-05-09 14:01:49 +0800788--- a/mt7915/mmio.c
789+++ b/mt7915/mmio.c
developerbd398d52022-06-06 20:53:24 +0800790@@ -24,6 +24,7 @@ static const u32 mt7915_reg[] = {
developere3d01472022-05-09 14:01:49 +0800791 [INFRA_MCU_ADDR_END] = 0x7c3fffff,
developerbd398d52022-06-06 20:53:24 +0800792 [FW_EXCEPTION_ADDR] = 0x219848,
developere3d01472022-05-09 14:01:49 +0800793 [SWDEF_BASE_ADDR] = 0x41f200,
794+ [EXCEPTION_BASE_ADDR] = 0x219848,
795 };
796
797 static const u32 mt7916_reg[] = {
developerbd398d52022-06-06 20:53:24 +0800798@@ -40,6 +41,7 @@ static const u32 mt7916_reg[] = {
developere3d01472022-05-09 14:01:49 +0800799 [INFRA_MCU_ADDR_END] = 0x7c085fff,
developerbd398d52022-06-06 20:53:24 +0800800 [FW_EXCEPTION_ADDR] = 0x022050bc,
developere3d01472022-05-09 14:01:49 +0800801 [SWDEF_BASE_ADDR] = 0x411400,
802+ [EXCEPTION_BASE_ADDR] = 0x022050BC,
803 };
804
805 static const u32 mt7986_reg[] = {
developerbd398d52022-06-06 20:53:24 +0800806@@ -56,6 +58,7 @@ static const u32 mt7986_reg[] = {
developere3d01472022-05-09 14:01:49 +0800807 [INFRA_MCU_ADDR_END] = 0x7c085fff,
developerbd398d52022-06-06 20:53:24 +0800808 [FW_EXCEPTION_ADDR] = 0x02204ffc,
developere3d01472022-05-09 14:01:49 +0800809 [SWDEF_BASE_ADDR] = 0x411400,
810+ [EXCEPTION_BASE_ADDR] = 0x02204FFC,
811 };
812
813 static const u32 mt7915_offs[] = {
developerbd398d52022-06-06 20:53:24 +0800814@@ -613,10 +616,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
developere3d01472022-05-09 14:01:49 +0800815 u32 val = mt76_rr(dev, MT_MCU_CMD);
816
817 mt76_wr(dev, MT_MCU_CMD, val);
818- if (val & MT_MCU_CMD_ERROR_MASK) {
819+ if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
820 dev->reset_state = val;
821- queue_work(dev->mt76.wq, &dev->reset_work);
822- wake_up(&dev->reset_wait);
823+ mt7915_reset(dev);
824 }
825 }
826 }
827diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
developerbd398d52022-06-06 20:53:24 +0800828index 80a17a7d..ae5ac72f 100644
developere3d01472022-05-09 14:01:49 +0800829--- a/mt7915/mt7915.h
830+++ b/mt7915/mt7915.h
developerbd398d52022-06-06 20:53:24 +0800831@@ -353,6 +353,15 @@ struct mt7915_dev {
developere3d01472022-05-09 14:01:49 +0800832 struct work_struct reset_work;
833 wait_queue_head_t reset_wait;
834 u32 reset_state;
835+ struct {
836+ bool hw_full_reset:1;
837+ bool hw_init_done:1;
838+ bool reset_enable:1;
839+ u32 reset_type;
840+ u32 cmd_fail_cnt;
841+ u32 wf_reset_wm_count;
842+ u32 wf_reset_wa_count;
843+ }ser;
844
845 struct list_head sta_rc_list;
846 struct list_head sta_poll_list;
developerbd398d52022-06-06 20:53:24 +0800847@@ -416,6 +425,12 @@ enum {
developere3d01472022-05-09 14:01:49 +0800848 __MT_WFDMA_MAX,
849 };
850
851+enum {
852+ SER_TYPE_NONE,
853+ SER_TYPE_PARTIAL_RESET,
854+ SER_TYPE_FULL_RESET,
855+};
856+
857 enum {
858 MT_CTX0,
859 MT_HIF0 = 0x0,
developerbd398d52022-06-06 20:53:24 +0800860@@ -527,6 +542,14 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band);
developere3d01472022-05-09 14:01:49 +0800861 int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2);
862 void mt7915_dma_prefetch(struct mt7915_dev *dev);
863 void mt7915_dma_cleanup(struct mt7915_dev *dev);
864+void mt7915_reset(struct mt7915_dev *dev);
865+int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
866+int __mt7915_start(struct ieee80211_hw *hw);
867+void mt7915_init_txpower(struct mt7915_dev *dev,
868+ struct ieee80211_supported_band *sband);
869+int mt7915_txbf_init(struct mt7915_dev *dev);
870+void mt7915_mac_init(struct mt7915_dev *dev);
871+int mt7915_run_firmware(struct mt7915_dev *dev);
872 int mt7915_mcu_init(struct mt7915_dev *dev);
873 int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
874 struct mt7915_vif *mvif,
875diff --git a/mt7915/regs.h b/mt7915/regs.h
developerbd398d52022-06-06 20:53:24 +0800876index c7c9e411..47bae86e 100644
developere3d01472022-05-09 14:01:49 +0800877--- a/mt7915/regs.h
878+++ b/mt7915/regs.h
developerbd398d52022-06-06 20:53:24 +0800879@@ -32,6 +32,7 @@ enum reg_rev {
developere3d01472022-05-09 14:01:49 +0800880 INFRA_MCU_ADDR_END,
developerbd398d52022-06-06 20:53:24 +0800881 FW_EXCEPTION_ADDR,
developere3d01472022-05-09 14:01:49 +0800882 SWDEF_BASE_ADDR,
883+ EXCEPTION_BASE_ADDR,
884 __MT_REG_MAX,
885 };
886
developerbd398d52022-06-06 20:53:24 +0800887@@ -113,6 +114,11 @@ enum offs_rev {
developere3d01472022-05-09 14:01:49 +0800888 #define __REG(id) (dev->reg.reg_rev[(id)])
889 #define __OFFS(id) (dev->reg.offs_rev[(id)])
890
891+/* MEM WFDMA */
892+#define WF_WFDMA_MEM_DMA 0x58000000
893+
894+#define WF_WFDMA_MEM_DMA_RX_RING_CTL (WF_WFDMA_MEM_DMA + (0x510))
895+
896 /* MCU WFDMA0 */
897 #define MT_MCU_WFDMA0_BASE 0x2000
898 #define MT_MCU_WFDMA0(ofs) (MT_MCU_WFDMA0_BASE + (ofs))
developerbd398d52022-06-06 20:53:24 +0800899@@ -565,6 +571,10 @@ enum offs_rev {
developere3d01472022-05-09 14:01:49 +0800900 #define MT_WFDMA0_PRI_DLY_INT_CFG1 MT_WFDMA0(0x2f4)
901 #define MT_WFDMA0_PRI_DLY_INT_CFG2 MT_WFDMA0(0x2f8)
902
903+#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
904+#define MT_WFDMA0_MT_WA_WDT_INT BIT(31)
905+#define MT_WFDMA0_MT_WM_WDT_INT BIT(30)
906+
907 /* WFDMA1 */
908 #define MT_WFDMA1_BASE 0xd5000
909 #define MT_WFDMA1(ofs) (MT_WFDMA1_BASE + (ofs))
developerbd398d52022-06-06 20:53:24 +0800910@@ -710,6 +720,10 @@ enum offs_rev {
developere3d01472022-05-09 14:01:49 +0800911 #define MT_MCU_CMD_NORMAL_STATE BIT(5)
912 #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
913
914+#define MT_MCU_CMD_WA_WDT BIT(31)
915+#define MT_MCU_CMD_WM_WDT BIT(30)
916+#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30)
917+
918 /* TOP RGU */
919 #define MT_TOP_RGU_BASE 0x18000000
920 #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0))
developerbd398d52022-06-06 20:53:24 +0800921@@ -985,6 +999,8 @@ enum offs_rev {
developere3d01472022-05-09 14:01:49 +0800922 #define MT_CPU_UTIL_PEAK_IDLE_CNT MT_CPU_UTIL(0x0c)
923 #define MT_CPU_UTIL_CTRL MT_CPU_UTIL(0x1c)
924
925+#define MT_EXCEPTION_ADDR __REG(EXCEPTION_BASE_ADDR)
926+
927 /* LED */
928 #define MT_LED_TOP_BASE 0x18013000
929 #define MT_LED_PHYS(_n) (MT_LED_TOP_BASE + (_n))
930--
9312.18.0
932