Skip to content

Commit

Permalink
mt76: mt7921: add coredump support
Browse files Browse the repository at this point in the history
Introduce coredump support to mt7921 driver.

The coredump would be produced when MCU met the fatal error or driver
sent out the specific cmd to force trigger it.

Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
Sean Wang authored and Felix Fietkau committed Jan 29, 2021
1 parent eaafabd commit 0da3c79
Showing 10 changed files with 117 additions and 1 deletion.
9 changes: 9 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt76_connac.h
Original file line number Diff line number Diff line change
@@ -11,6 +11,9 @@
#define MT76_CONNAC_MAX_SCHED_SCAN_SSID 10
#define MT76_CONNAC_MAX_SCAN_MATCH 16

#define MT76_CONNAC_COREDUMP_TIMEOUT (HZ / 20)
#define MT76_CONNAC_COREDUMP_SZ (128 * 1024)

enum {
CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20,
CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40,
@@ -57,6 +60,12 @@ struct mt76_connac_pm {
unsigned long idle_timeout;
};

struct mt76_connac_coredump {
struct sk_buff_head msg_list;
struct delayed_work work;
unsigned long last_activity;
};

extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;

static inline bool is_mt7921(struct mt76_dev *dev)
34 changes: 34 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
Original file line number Diff line number Diff line change
@@ -1497,6 +1497,40 @@ int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable);

int mt76_connac_mcu_chip_config(struct mt76_dev *dev)
{
struct {
__le16 id;
u8 type;
u8 resp_type;
__le16 data_size;
__le16 resv;
u8 data[320];
} req = {
.resp_type = 0,
};

memcpy(req.data, "assert", 7);

return mt76_mcu_send_msg(dev, MCU_CMD_CHIP_CONFIG, &req, sizeof(req),
false);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config);

void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump)
{
spin_lock_bh(&dev->lock);
__skb_queue_tail(&coredump->msg_list, skb);
spin_unlock_bh(&dev->lock);

coredump->last_activity = jiffies;

queue_delayed_work(dev->wq, &coredump->work,
MT76_CONNAC_COREDUMP_TIMEOUT);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);

#ifdef CONFIG_PM

const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
4 changes: 4 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
Original file line number Diff line number Diff line change
@@ -561,6 +561,7 @@ enum {
MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62,
MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0,
MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0,
MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca,
MCU_CMD_FWLOG_2_HOST = MCU_CE_PREFIX | 0xc5,
MCU_CMD_GET_WTBL = MCU_CE_PREFIX | 0xcd,
};
@@ -972,4 +973,7 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend);
void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump);
#endif /* __MT76_CONNAC_MCU_H */
1 change: 1 addition & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
config MT7921E
tristate "MediaTek MT7921E (PCIe) support"
select MT76_CONNAC_LIB
select WANT_DEV_COREDUMP
depends on MAC80211
depends on PCI
help
15 changes: 15 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
Original file line number Diff line number Diff line change
@@ -213,6 +213,20 @@ mt7921_pm_idle_timeout_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
mt7921_pm_idle_timeout_set, "%lld\n");

static int mt7921_config(void *data, u64 val)
{
struct mt7921_dev *dev = data;
int ret;

mt7921_mutex_acquire(dev);
ret = mt76_connac_mcu_chip_config(&dev->mt76);
mt7921_mutex_release(dev);

return ret;
}

DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n");

int mt7921_init_debugfs(struct mt7921_dev *dev)
{
struct dentry *dir;
@@ -230,6 +244,7 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
debugfs_create_file("idle-timeout", 0600, dir, dev,
&fops_pm_idle_timeout);
debugfs_create_file("chip_config", 0600, dir, dev, &fops_config);

return 0;
}
2 changes: 2 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/init.c
Original file line number Diff line number Diff line change
@@ -226,7 +226,9 @@ int mt7921_register_device(struct mt7921_dev *dev)
INIT_LIST_HEAD(&dev->phy.stats_list);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7921_mac_work);
INIT_DELAYED_WORK(&dev->phy.scan_work, mt7921_scan_work);
INIT_DELAYED_WORK(&dev->coredump.work, mt7921_coredump_work);
skb_queue_head_init(&dev->phy.scan_event_list);
skb_queue_head_init(&dev->coredump.msg_list);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);

43 changes: 43 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/mac.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */

#include <linux/devcoredump.h>
#include <linux/etherdevice.h>
#include <linux/timekeeping.h>
#include "mt7921.h"
#include "../dma.h"
#include "mac.h"
#include "mcu.h"

#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2)

@@ -1471,3 +1473,44 @@ int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,

return 0;
}

void mt7921_coredump_work(struct work_struct *work)
{
struct mt7921_dev *dev;
char *dump, *data;

dev = (struct mt7921_dev *)container_of(work, struct mt7921_dev,
coredump.work.work);

if (time_is_after_jiffies(dev->coredump.last_activity +
4 * MT76_CONNAC_COREDUMP_TIMEOUT)) {
queue_delayed_work(dev->mt76.wq, &dev->coredump.work,
MT76_CONNAC_COREDUMP_TIMEOUT);
return;
}

dump = vzalloc(MT76_CONNAC_COREDUMP_SZ);
data = dump;

while (true) {
struct sk_buff *skb;

spin_lock_bh(&dev->mt76.lock);
skb = __skb_dequeue(&dev->coredump.msg_list);
spin_unlock_bh(&dev->mt76.lock);

if (!skb)
break;

skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
if (data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ)
break;

memcpy(data, skb->data, skb->len);
data += skb->len;

dev_kfree_skb(skb);
}
dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
GFP_KERNEL);
}
5 changes: 5 additions & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
Original file line number Diff line number Diff line change
@@ -513,6 +513,10 @@ mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
case MCU_EVENT_DBG_MSG:
mt7921_mcu_debug_msg_event(dev, skb);
break;
case MCU_EVENT_COREDUMP:
mt76_connac_mcu_coredump_event(&dev->mt76, skb,
&dev->coredump);
return;
default:
break;
}
@@ -534,6 +538,7 @@ void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
rxd->eid == MCU_EVENT_BSS_ABSENCE ||
rxd->eid == MCU_EVENT_SCAN_DONE ||
rxd->eid == MCU_EVENT_DBG_MSG ||
rxd->eid == MCU_EVENT_COREDUMP ||
!rxd->seq)
mt7921_mcu_rx_unsolicited_event(dev, skb);
else
1 change: 1 addition & 0 deletions drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
Original file line number Diff line number Diff line change
@@ -85,6 +85,7 @@ enum {
MCU_EVENT_CH_PRIVILEGE = 0x18,
MCU_EVENT_SCHED_SCAN_DONE = 0x23,
MCU_EVENT_DBG_MSG = 0x27,
MCU_EVENT_COREDUMP = 0xf0,
};

/* ext event table */
4 changes: 3 additions & 1 deletion drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@

#include <linux/interrupt.h>
#include <linux/ktime.h>
#include "../mt76_connac.h"
#include "../mt76_connac_mcu.h"
#include "regs.h"

#define MT7921_MAX_INTERFACES 4
@@ -164,6 +164,7 @@ struct mt7921_dev {
u8 fw_debug;

struct mt76_connac_pm pm;
struct mt76_connac_coredump coredump;
};

enum {
@@ -337,4 +338,5 @@ int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
struct ieee80211_vif *vif,
bool enable);
void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
void mt7921_coredump_work(struct work_struct *work);
#endif

0 comments on commit 0da3c79

Please sign in to comment.