mt76: mt7915: add wifi subsystem reset

Reset wifi subsystem when MCU is already running.
Fixes firmware download failure after soft reboot on systems where the PCIe
reset could not be performed properly.

Signed-off-by: Ryder Lee <[email protected]>
Co-developed-by: Felix Fietkau <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
Ryder Lee
2021-04-06 17:53:30 +02:00
committed by Felix Fietkau
parent f8c6c7cbf1
commit 7d35b7a15d
3 changed files with 70 additions and 16 deletions
+56 -2
View File
@@ -4,6 +4,7 @@
#include <linux/etherdevice.h>
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "eeprom.h"
#define CCK_RATE(_idx, _rate) { \
@@ -304,9 +305,50 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_txbf_init(dev);
}
static void mt7915_wfsys_reset(struct mt7915_dev *dev)
{
u32 val = MT_TOP_PWR_KEY | MT_TOP_PWR_SW_PWR_ON | MT_TOP_PWR_PWR_ON;
u32 reg = mt7915_reg_map_l1(dev, MT_TOP_MISC);
#define MT_MCU_DUMMY_RANDOM GENMASK(15, 0)
#define MT_MCU_DUMMY_DEFAULT GENMASK(31, 16)
mt76_wr(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_RANDOM);
/* change to software control */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* reset wfsys */
val &= ~MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* release wfsys then mcu re-excutes romcode */
val |= MT_TOP_PWR_SW_RST;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* switch to hw control */
val &= ~MT_TOP_PWR_SW_RST;
val |= MT_TOP_PWR_HW_CTRL;
mt76_wr(dev, MT_TOP_PWR_CTRL, val);
/* check whether mcu resets to default */
if (!mt76_poll_msec(dev, MT_MCU_WFDMA0_DUMMY_CR, MT_MCU_DUMMY_DEFAULT,
MT_MCU_DUMMY_DEFAULT, 1000)) {
dev_err(dev->mt76.dev, "wifi subsystem reset failure\n");
return;
}
/* wfsys reset won't clear host registers */
mt76_clear(dev, reg, MT_TOP_MISC_FW_STATE);
msleep(100);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
{
int ret, idx;
u32 val;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
@@ -316,6 +358,12 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
dev->dbdc_support = !!(mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5));
val = mt76_rr(dev, mt7915_reg_map_l1(dev, MT_TOP_MISC));
/* If MCU was already running, it is likely in a bad state */
if (FIELD_GET(MT_TOP_MISC_FW_STATE, val) > FW_STATE_FW_DOWNLOAD)
mt7915_wfsys_reset(dev);
ret = mt7915_dma_init(dev);
if (ret)
return ret;
@@ -329,8 +377,14 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
if (ret) {
/* Reset and try again */
mt7915_wfsys_reset(dev);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
}
ret = mt7915_eeprom_init(dev);
if (ret < 0)