Commit 8a55712d authored by Bo Jiao's avatar Bo Jiao Committed by Felix Fietkau

wifi: mt76: mt7915: enable full system reset support

Add mt7915_reset() and refactor mt7915_mac_reset_work() to support
full system recovery.
Co-developed-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Signed-off-by: default avatarBo Jiao <bo.jiao@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent d493bb5b
...@@ -262,9 +262,8 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, ...@@ -262,9 +262,8 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
mt7915_led_set_config(led_cdev, 0xff, 0); mt7915_led_set_config(led_cdev, 0xff, 0);
} }
static void void mt7915_init_txpower(struct mt7915_dev *dev,
mt7915_init_txpower(struct mt7915_dev *dev, struct ieee80211_supported_band *sband)
struct ieee80211_supported_band *sband)
{ {
int i, n_chains = hweight8(dev->mphy.antenna_mask); int i, n_chains = hweight8(dev->mphy.antenna_mask);
int nss_delta = mt76_tx_power_nss_delta(n_chains); int nss_delta = mt76_tx_power_nss_delta(n_chains);
...@@ -470,7 +469,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) ...@@ -470,7 +469,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set); mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
} }
static void mt7915_mac_init(struct mt7915_dev *dev) void mt7915_mac_init(struct mt7915_dev *dev)
{ {
int i; int i;
u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
...@@ -500,7 +499,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev) ...@@ -500,7 +499,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
} }
} }
static int mt7915_txbf_init(struct mt7915_dev *dev) int mt7915_txbf_init(struct mt7915_dev *dev)
{ {
int ret; int ret;
...@@ -1141,6 +1140,8 @@ int mt7915_register_device(struct mt7915_dev *dev) ...@@ -1141,6 +1140,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
goto unreg_thermal; goto unreg_thermal;
} }
dev->recovery.hw_init_done = true;
mt7915_init_debugfs(&dev->phy); mt7915_init_debugfs(&dev->phy);
return 0; return 0;
......
...@@ -1291,7 +1291,7 @@ mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) ...@@ -1291,7 +1291,7 @@ mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state)
bool ret; bool ret;
ret = wait_event_timeout(dev->reset_wait, ret = wait_event_timeout(dev->reset_wait,
(READ_ONCE(dev->reset_state) & state), (READ_ONCE(dev->recovery.state) & state),
MT7915_RESET_TIMEOUT); MT7915_RESET_TIMEOUT);
WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
...@@ -1346,6 +1346,168 @@ void mt7915_tx_token_put(struct mt7915_dev *dev) ...@@ -1346,6 +1346,168 @@ void mt7915_tx_token_put(struct mt7915_dev *dev)
idr_destroy(&dev->mt76.token); idr_destroy(&dev->mt76.token);
} }
static int
mt7915_mac_restart(struct mt7915_dev *dev)
{
struct mt7915_phy *phy2;
struct mt76_phy *ext_phy;
struct mt76_dev *mdev = &dev->mt76;
int i, ret;
ext_phy = dev->mt76.phys[MT_BAND1];
phy2 = ext_phy ? ext_phy->priv : NULL;
if (dev->hif2) {
mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
}
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
if (dev->hif2)
mt76_wr(dev, MT_PCIE1_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);
if (ext_phy) {
set_bit(MT76_RESET, &ext_phy->state);
set_bit(MT76_MCU_RESET, &ext_phy->state);
}
/* lock/unlock all queues to ensure that no tx is pending */
mt76_txq_schedule_all(&dev->mphy);
if (ext_phy)
mt76_txq_schedule_all(ext_phy);
/* disable all tx/rx napi */
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(mdev, i) {
if (mdev->q_rx[i].ndesc)
napi_disable(&dev->mt76.napi[i]);
}
napi_disable(&dev->mt76.tx_napi);
/* token reinit */
mt7915_tx_token_put(dev);
idr_init(&dev->mt76.token);
mt7915_dma_reset(dev, true);
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
if (mdev->q_rx[i].ndesc) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
}
local_bh_enable();
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
if (dev->hif2) {
mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
}
if (dev_is_pci(mdev->dev)) {
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
if (dev->hif2)
mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
}
/* load firmware */
ret = mt7915_mcu_init_firmware(dev);
if (ret)
goto out;
/* set the necessary init items */
ret = mt7915_mcu_set_eeprom(dev);
if (ret)
goto out;
mt7915_mac_init(dev);
mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
ret = mt7915_txbf_init(dev);
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
ret = mt7915_run(dev->mphy.hw);
if (ret)
goto out;
}
if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) {
ret = mt7915_run(ext_phy->hw);
if (ret)
goto out;
}
out:
/* reset done */
clear_bit(MT76_RESET, &dev->mphy.state);
if (phy2)
clear_bit(MT76_RESET, &phy2->mt76->state);
local_bh_disable();
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
local_bh_enable();
mt76_worker_enable(&dev->mt76.tx_worker);
return ret;
}
static void
mt7915_mac_full_reset(struct mt7915_dev *dev)
{
struct mt76_phy *ext_phy;
int i;
ext_phy = dev->mt76.phys[MT_BAND1];
dev->recovery.hw_full_reset = true;
wake_up(&dev->mt76.mcu.wait);
ieee80211_stop_queues(mt76_hw(dev));
if (ext_phy)
ieee80211_stop_queues(ext_phy->hw);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (ext_phy)
cancel_delayed_work_sync(&ext_phy->mac_work);
mutex_lock(&dev->mt76.mutex);
for (i = 0; i < 10; i++) {
if (!mt7915_mac_restart(dev))
break;
}
mutex_unlock(&dev->mt76.mutex);
if (i == 10)
dev_err(dev->mt76.dev, "chip full reset failed\n");
ieee80211_restart_hw(mt76_hw(dev));
if (ext_phy)
ieee80211_restart_hw(ext_phy->hw);
ieee80211_wake_queues(mt76_hw(dev));
if (ext_phy)
ieee80211_wake_queues(ext_phy->hw);
dev->recovery.hw_full_reset = false;
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
MT7915_WATCHDOG_TIME);
if (ext_phy)
ieee80211_queue_delayed_work(ext_phy->hw,
&ext_phy->mac_work,
MT7915_WATCHDOG_TIME);
}
/* system error recovery */ /* system error recovery */
void mt7915_mac_reset_work(struct work_struct *work) void mt7915_mac_reset_work(struct work_struct *work)
{ {
...@@ -1358,7 +1520,28 @@ void mt7915_mac_reset_work(struct work_struct *work) ...@@ -1358,7 +1520,28 @@ void mt7915_mac_reset_work(struct work_struct *work)
ext_phy = dev->mt76.phys[MT_BAND1]; ext_phy = dev->mt76.phys[MT_BAND1];
phy2 = ext_phy ? ext_phy->priv : NULL; phy2 = ext_phy ? ext_phy->priv : NULL;
if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA)) /* chip full reset */
if (dev->recovery.restart) {
/* disable WA/WM WDT */
mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
MT_MCU_CMD_WDT_MASK);
mt7915_mac_full_reset(dev);
/* enable mcu irq */
mt7915_irq_enable(dev, MT_INT_MCU_CMD);
mt7915_irq_disable(dev, 0);
/* enable WA/WM WDT */
mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
dev->recovery.restart = false;
return;
}
/* chip partial reset */
if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
return; return;
ieee80211_stop_queues(mt76_hw(dev)); ieee80211_stop_queues(mt76_hw(dev));
...@@ -1432,6 +1615,30 @@ void mt7915_mac_reset_work(struct work_struct *work) ...@@ -1432,6 +1615,30 @@ void mt7915_mac_reset_work(struct work_struct *work)
MT7915_WATCHDOG_TIME); MT7915_WATCHDOG_TIME);
} }
void mt7915_reset(struct mt7915_dev *dev)
{
if (!dev->recovery.hw_init_done)
return;
if (dev->recovery.hw_full_reset)
return;
/* wm/wa exception: do full recovery */
if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
dev->recovery.restart = true;
dev_info(dev->mt76.dev,
"%s indicated firmware crash, attempting recovery\n",
wiphy_name(dev->mt76.hw->wiphy));
mt7915_irq_disable(dev, MT_INT_MCU_CMD);
queue_work(dev->mt76.wq, &dev->reset_work);
return;
}
queue_work(dev->mt76.wq, &dev->reset_work);
wake_up(&dev->reset_wait);
}
void mt7915_mac_update_stats(struct mt7915_phy *phy) void mt7915_mac_update_stats(struct mt7915_phy *phy)
{ {
struct mt7915_dev *dev = phy->dev; struct mt7915_dev *dev = phy->dev;
......
...@@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev) ...@@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev)
return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
} }
static int mt7915_start(struct ieee80211_hw *hw) int mt7915_run(struct ieee80211_hw *hw)
{ {
struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw);
bool running; bool running;
int ret; int ret;
flush_work(&dev->init_work);
mutex_lock(&dev->mt76.mutex);
running = mt7915_dev_running(dev); running = mt7915_dev_running(dev);
if (!running) { if (!running) {
...@@ -80,6 +76,18 @@ static int mt7915_start(struct ieee80211_hw *hw) ...@@ -80,6 +76,18 @@ static int mt7915_start(struct ieee80211_hw *hw)
mt7915_mac_reset_counters(phy); mt7915_mac_reset_counters(phy);
out: out:
return ret;
}
static int mt7915_start(struct ieee80211_hw *hw)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
int ret;
flush_work(&dev->init_work);
mutex_lock(&dev->mt76.mutex);
ret = mt7915_run(hw);
mutex_unlock(&dev->mt76.mutex); mutex_unlock(&dev->mt76.mutex);
return ret; return ret;
......
...@@ -2249,18 +2249,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) ...@@ -2249,18 +2249,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
sizeof(req), true); sizeof(req), true);
} }
int mt7915_mcu_init(struct mt7915_dev *dev) int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
{ {
static const struct mt76_mcu_ops mt7915_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd),
.mcu_skb_send_msg = mt7915_mcu_send_message,
.mcu_parse_response = mt7915_mcu_parse_response,
.mcu_restart = mt76_connac_mcu_restart,
};
int ret; int ret;
dev->mt76.mcu_ops = &mt7915_mcu_ops;
/* force firmware operation mode into normal state, /* force firmware operation mode into normal state,
* which should be set before firmware download stage. * which should be set before firmware download stage.
*/ */
...@@ -2309,6 +2301,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev) ...@@ -2309,6 +2301,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
MCU_WA_PARAM_RED, 0, 0); MCU_WA_PARAM_RED, 0, 0);
} }
int mt7915_mcu_init(struct mt7915_dev *dev)
{
static const struct mt76_mcu_ops mt7915_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd),
.mcu_skb_send_msg = mt7915_mcu_send_message,
.mcu_parse_response = mt7915_mcu_parse_response,
.mcu_restart = mt76_connac_mcu_restart,
};
dev->mt76.mcu_ops = &mt7915_mcu_ops;
return mt7915_mcu_init_firmware(dev);
}
void mt7915_mcu_exit(struct mt7915_dev *dev) void mt7915_mcu_exit(struct mt7915_dev *dev)
{ {
__mt76_mcu_restart(&dev->mt76); __mt76_mcu_restart(&dev->mt76);
......
...@@ -746,10 +746,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) ...@@ -746,10 +746,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
u32 val = mt76_rr(dev, MT_MCU_CMD); u32 val = mt76_rr(dev, MT_MCU_CMD);
mt76_wr(dev, MT_MCU_CMD, val); mt76_wr(dev, MT_MCU_CMD, val);
if (val & MT_MCU_CMD_ERROR_MASK) { if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
dev->reset_state = val; dev->recovery.state = val;
queue_work(dev->mt76.wq, &dev->reset_work); mt7915_reset(dev);
wake_up(&dev->reset_wait);
} }
} }
} }
......
...@@ -307,7 +307,13 @@ struct mt7915_dev { ...@@ -307,7 +307,13 @@ struct mt7915_dev {
struct work_struct rc_work; struct work_struct rc_work;
struct work_struct reset_work; struct work_struct reset_work;
wait_queue_head_t reset_wait; wait_queue_head_t reset_wait;
u32 reset_state;
struct {
u32 state;
bool hw_full_reset:1;
bool hw_init_done:1;
bool restart:1;
} recovery;
struct list_head sta_rc_list; struct list_head sta_rc_list;
struct list_head sta_poll_list; struct list_head sta_poll_list;
...@@ -448,7 +454,13 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); ...@@ -448,7 +454,13 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2);
void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
int mt7915_txbf_init(struct mt7915_dev *dev);
void mt7915_init_txpower(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband);
void mt7915_reset(struct mt7915_dev *dev);
int mt7915_run(struct ieee80211_hw *hw);
int mt7915_mcu_init(struct mt7915_dev *dev); int mt7915_mcu_init(struct mt7915_dev *dev);
int mt7915_mcu_init_firmware(struct mt7915_dev *dev);
int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
struct mt7915_vif *mvif, struct mt7915_vif *mvif,
struct mt7915_twt_flow *flow, struct mt7915_twt_flow *flow,
...@@ -548,6 +560,7 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) ...@@ -548,6 +560,7 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
} }
void mt7915_mac_init(struct mt7915_dev *dev);
u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw); u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw);
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask); bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_reset_counters(struct mt7915_phy *phy);
......
...@@ -563,6 +563,8 @@ enum offs_rev { ...@@ -563,6 +563,8 @@ enum offs_rev {
#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2) #define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)
#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
...@@ -731,6 +733,8 @@ enum offs_rev { ...@@ -731,6 +733,8 @@ enum offs_rev {
#define MT_MCU_CMD_NORMAL_STATE BIT(5) #define MT_MCU_CMD_NORMAL_STATE BIT(5)
#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30)
/* TOP RGU */ /* TOP RGU */
#define MT_TOP_RGU_BASE 0x18000000 #define MT_TOP_RGU_BASE 0x18000000
#define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0)) #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment