summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt76/mt7921
diff options
context:
space:
mode:
authorSean Wang <sean.wang@mediatek.com>2021-01-27 22:33:56 +0300
committerFelix Fietkau <nbd@nbd.name>2021-01-29 20:10:02 +0300
commit0da3c795d07bf005d4b0be8d6cdc4714aa51a988 (patch)
tree2b34f6151eebb60b2fb7a572137e283e928cc040 /drivers/net/wireless/mediatek/mt76/mt7921
parenteaafabd2850d782366ca0558d432857d5e3d472a (diff)
downloadlinux-0da3c795d07bf005d4b0be8d6cdc4714aa51a988.tar.xz
mt76: mt7921: add coredump support
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>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7921')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/Kconfig1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c15
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.c43
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h4
7 files changed, 70 insertions, 1 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
index 92db70d11c36..001f2b9cec26 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Kconfig
@@ -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
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 390e0e49724d..0dc8e25e18e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -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;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 2a80b68a588a..89a13b4a74a4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 006cf7fe1bff..3f9097481a5e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -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);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 6ad313fd398e..db125cd22b91 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -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
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
index 52f9e5102727..2fdc62367b3f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
@@ -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 */
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index c0f26eaa269e..46e6aeec35ae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -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