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