mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
mt76: mt76x2: implement full device restart on watchdog reset
Restart the firmware and re-initialize the MAC to be able to recover from more kinds of hang states Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
@@ -143,6 +143,7 @@ struct mt76_mcu_ops {
|
|||||||
const struct mt76_reg_pair *rp, int len);
|
const struct mt76_reg_pair *rp, int len);
|
||||||
int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
|
int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
|
||||||
struct mt76_reg_pair *rp, int len);
|
struct mt76_reg_pair *rp, int len);
|
||||||
|
int (*mcu_restart)(struct mt76_dev *dev);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mt76_queue_ops {
|
struct mt76_queue_ops {
|
||||||
|
|||||||
@@ -67,6 +67,32 @@ int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
|
EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
|
||||||
|
|
||||||
|
void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx,
|
||||||
|
struct ieee80211_key_conf *key)
|
||||||
|
{
|
||||||
|
enum mt76x02_cipher_type cipher;
|
||||||
|
u8 key_data[32];
|
||||||
|
u32 iv, eiv;
|
||||||
|
u64 pn;
|
||||||
|
|
||||||
|
cipher = mt76x02_mac_get_key_info(key, key_data);
|
||||||
|
iv = mt76_rr(dev, MT_WCID_IV(idx));
|
||||||
|
eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4);
|
||||||
|
|
||||||
|
pn = (u64)eiv << 16;
|
||||||
|
if (cipher == MT_CIPHER_TKIP) {
|
||||||
|
pn |= (iv >> 16) & 0xff;
|
||||||
|
pn |= (iv & 0xff) << 8;
|
||||||
|
} else if (cipher >= MT_CIPHER_AES_CCMP) {
|
||||||
|
pn |= iv & 0xffff;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic64_set(&key->tx_pn, pn);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
||||||
struct ieee80211_key_conf *key)
|
struct ieee80211_key_conf *key)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
|
|||||||
u8 key_idx, struct ieee80211_key_conf *key);
|
u8 key_idx, struct ieee80211_key_conf *key);
|
||||||
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
|
||||||
struct ieee80211_key_conf *key);
|
struct ieee80211_key_conf *key);
|
||||||
|
void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx,
|
||||||
|
struct ieee80211_key_conf *key);
|
||||||
void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, u8 vif_idx,
|
void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, u8 vif_idx,
|
||||||
u8 *mac);
|
u8 *mac);
|
||||||
void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop);
|
void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop);
|
||||||
|
|||||||
+69
-5
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
|
||||||
#include "mt76x02.h"
|
#include "mt76x02.h"
|
||||||
|
#include "mt76x02_mcu.h"
|
||||||
#include "mt76x02_trace.h"
|
#include "mt76x02_trace.h"
|
||||||
|
|
||||||
struct beacon_bc_data {
|
struct beacon_bc_data {
|
||||||
@@ -418,9 +419,63 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
|
|||||||
return i < 4;
|
return i < 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
|
struct ieee80211_sta *sta,
|
||||||
|
struct ieee80211_key_conf *key, void *data)
|
||||||
|
{
|
||||||
|
struct mt76x02_dev *dev = hw->priv;
|
||||||
|
struct mt76_wcid *wcid;
|
||||||
|
|
||||||
|
if (!sta)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wcid = (struct mt76_wcid *) sta->drv_priv;
|
||||||
|
|
||||||
|
if (wcid->hw_key_idx != key->keyidx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt76x02_reset_state(struct mt76x02_dev *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
ieee80211_iter_keys_rcu(dev->mt76.hw, NULL, mt76x02_key_sync, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(dev->mt76.wcid); i++) {
|
||||||
|
struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[i]);
|
||||||
|
struct mt76x02_sta *msta;
|
||||||
|
struct ieee80211_sta *sta;
|
||||||
|
struct ieee80211_vif *vif;
|
||||||
|
void *priv;
|
||||||
|
|
||||||
|
if (!wcid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
|
||||||
|
sta = container_of(priv, struct ieee80211_sta, drv_priv);
|
||||||
|
|
||||||
|
priv = msta->vif;
|
||||||
|
vif = container_of(priv, struct ieee80211_vif, drv_priv);
|
||||||
|
|
||||||
|
mt76_sta_state(dev->mt76.hw, vif, sta,
|
||||||
|
IEEE80211_STA_NONE, IEEE80211_STA_NOTEXIST);
|
||||||
|
memset(msta, 0, sizeof(*msta));
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
dev->vif_mask = 0;
|
||||||
|
dev->beacon_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
||||||
{
|
{
|
||||||
u32 mask = dev->mt76.mmio.irqmask;
|
u32 mask = dev->mt76.mmio.irqmask;
|
||||||
|
bool restart = dev->mt76.mcu_ops->mcu_restart;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ieee80211_stop_queues(dev->mt76.hw);
|
ieee80211_stop_queues(dev->mt76.hw);
|
||||||
@@ -432,6 +487,9 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||||||
for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++)
|
for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++)
|
||||||
napi_disable(&dev->mt76.napi[i]);
|
napi_disable(&dev->mt76.napi[i]);
|
||||||
|
|
||||||
|
if (restart)
|
||||||
|
mt76x02_reset_state(dev);
|
||||||
|
|
||||||
mutex_lock(&dev->mt76.mutex);
|
mutex_lock(&dev->mt76.mutex);
|
||||||
|
|
||||||
if (dev->beacon_mask)
|
if (dev->beacon_mask)
|
||||||
@@ -452,20 +510,21 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||||||
/* let fw reset DMA */
|
/* let fw reset DMA */
|
||||||
mt76_set(dev, 0x734, 0x3);
|
mt76_set(dev, 0x734, 0x3);
|
||||||
|
|
||||||
|
if (restart)
|
||||||
|
dev->mt76.mcu_ops->mcu_restart(&dev->mt76);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->mt76.q_tx); i++)
|
for (i = 0; i < ARRAY_SIZE(dev->mt76.q_tx); i++)
|
||||||
mt76_queue_tx_cleanup(dev, i, true);
|
mt76_queue_tx_cleanup(dev, i, true);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++)
|
for (i = 0; i < ARRAY_SIZE(dev->mt76.q_rx); i++)
|
||||||
mt76_queue_rx_reset(dev, i);
|
mt76_queue_rx_reset(dev, i);
|
||||||
|
|
||||||
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
mt76x02_mac_start(dev);
|
||||||
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
|
|
||||||
mt76_set(dev, MT_WPDMA_GLO_CFG,
|
|
||||||
MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN);
|
|
||||||
if (dev->ed_monitor)
|
if (dev->ed_monitor)
|
||||||
mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
|
mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
|
||||||
|
|
||||||
if (dev->beacon_mask)
|
if (dev->beacon_mask && !restart)
|
||||||
mt76_set(dev, MT_BEACON_TIME_CFG,
|
mt76_set(dev, MT_BEACON_TIME_CFG,
|
||||||
MT_BEACON_TIME_CFG_BEACON_TX |
|
MT_BEACON_TIME_CFG_BEACON_TX |
|
||||||
MT_BEACON_TIME_CFG_TBTT_EN);
|
MT_BEACON_TIME_CFG_TBTT_EN);
|
||||||
@@ -489,6 +548,11 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
|
|||||||
ieee80211_wake_queues(dev->mt76.hw);
|
ieee80211_wake_queues(dev->mt76.hw);
|
||||||
|
|
||||||
mt76_txq_schedule_all(&dev->mt76);
|
mt76_txq_schedule_all(&dev->mt76);
|
||||||
|
|
||||||
|
if (restart) {
|
||||||
|
mt76x02_mcu_function_select(dev, Q_SELECT, 1);
|
||||||
|
ieee80211_restart_hw(dev->mt76.hw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt76x02_check_tx_hang(struct mt76x02_dev *dev)
|
static void mt76x02_check_tx_hang(struct mt76x02_dev *dev)
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
|
|||||||
|
|
||||||
void mt76x2_cleanup(struct mt76x02_dev *dev);
|
void mt76x2_cleanup(struct mt76x02_dev *dev);
|
||||||
|
|
||||||
|
int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard);
|
||||||
void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable);
|
void mt76x2_reset_wlan(struct mt76x02_dev *dev, bool enable);
|
||||||
void mt76x2_init_txpower(struct mt76x02_dev *dev,
|
void mt76x2_init_txpower(struct mt76x02_dev *dev,
|
||||||
struct ieee80211_supported_band *sband);
|
struct ieee80211_supported_band *sband);
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
|
int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
|
||||||
{
|
{
|
||||||
const u8 *macaddr = dev->mt76.macaddr;
|
const u8 *macaddr = dev->mt76.macaddr;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|||||||
@@ -165,9 +165,30 @@ error:
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mt76pci_mcu_restart(struct mt76_dev *mdev)
|
||||||
|
{
|
||||||
|
struct mt76x02_dev *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev = container_of(mdev, struct mt76x02_dev, mt76);
|
||||||
|
|
||||||
|
mt76x02_mcu_cleanup(dev);
|
||||||
|
mt76x2_mac_reset(dev, true);
|
||||||
|
|
||||||
|
ret = mt76pci_load_firmware(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int mt76x2_mcu_init(struct mt76x02_dev *dev)
|
int mt76x2_mcu_init(struct mt76x02_dev *dev)
|
||||||
{
|
{
|
||||||
static const struct mt76_mcu_ops mt76x2_mcu_ops = {
|
static const struct mt76_mcu_ops mt76x2_mcu_ops = {
|
||||||
|
.mcu_restart = mt76pci_mcu_restart,
|
||||||
.mcu_send_msg = mt76x02_mcu_msg_send,
|
.mcu_send_msg = mt76x02_mcu_msg_send,
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user