summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mediatek/mt76/mt7615
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@nbd.name>2020-09-25 15:56:49 +0200
committerFelix Fietkau <nbd@nbd.name>2020-12-04 13:46:13 +0100
commitd22da02842e284eecd37dd5fdb2390206392e8b2 (patch)
tree239a0fd07eb5fbf20c4adf14d684c7467869226a /drivers/net/wireless/mediatek/mt76/mt7615
parent3298b1f866fb410710547f5dc9cfff408b9de21d (diff)
downloadlinux-d22da02842e284eecd37dd5fdb2390206392e8b2.tar.bz2
mt76: mt7615: add debugfs knob for setting extended local mac addresses
This is primarily for testing and can be used in combination with monitor mode to make the card respond to packets sent to a specific MAC address. For now this is only exposed as a debug/testing feature, later on the approach might be used to support more concurrent station interfaces Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c88
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h11
3 files changed, 101 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 00ba550fc48f..b8c31b57734d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -365,6 +365,93 @@ mt7615_rf_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_reg, mt7615_rf_reg_get, mt7615_rf_reg_set,
"0x%08llx\n");
+static ssize_t
+mt7615_ext_mac_addr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt7615_dev *dev = file->private_data;
+ char buf[32 * ((ETH_ALEN * 3) + 4) + 1];
+ u8 addr[ETH_ALEN];
+ int ofs = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (!(dev->muar_mask & BIT(i)))
+ continue;
+
+ mt76_wr(dev, MT_WF_RMAC_MAR1,
+ FIELD_PREP(MT_WF_RMAC_MAR1_IDX, i * 2) |
+ MT_WF_RMAC_MAR1_START);
+ put_unaligned_le32(mt76_rr(dev, MT_WF_RMAC_MAR0), addr);
+ put_unaligned_le16((mt76_rr(dev, MT_WF_RMAC_MAR1) &
+ MT_WF_RMAC_MAR1_ADDR), addr + 4);
+ ofs += snprintf(buf + ofs, sizeof(buf) - ofs, "%d=%pM\n", i, addr);
+ }
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ofs);
+}
+
+static ssize_t
+mt7615_ext_mac_addr_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt7615_dev *dev = file->private_data;
+ unsigned long idx = 0;
+ u8 addr[ETH_ALEN];
+ char buf[32];
+ char *p;
+
+ if (count > sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, userbuf, count))
+ return -EFAULT;
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ p = strchr(buf, '=');
+ if (p) {
+ *p = 0;
+ p++;
+
+ if (kstrtoul(buf, 0, &idx) || idx > 31)
+ return -EINVAL;
+ } else {
+ idx = 0;
+ p = buf;
+ }
+
+ if (!mac_pton(p, addr))
+ return -EINVAL;
+
+ if (is_valid_ether_addr(addr)) {
+ dev->muar_mask |= BIT(idx);
+ } else {
+ memset(addr, 0, sizeof(addr));
+ dev->muar_mask &= ~BIT(idx);
+ }
+
+ mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, 1);
+ mt76_wr(dev, MT_WF_RMAC_MAR0, get_unaligned_le32(addr));
+ mt76_wr(dev, MT_WF_RMAC_MAR1,
+ get_unaligned_le16(addr + 4) |
+ FIELD_PREP(MT_WF_RMAC_MAR1_IDX, idx * 2) |
+ MT_WF_RMAC_MAR1_START |
+ MT_WF_RMAC_MAR1_WRITE);
+
+ mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, !!dev->muar_mask);
+
+ return count;
+}
+
+static const struct file_operations fops_ext_mac_addr = {
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+ .read = mt7615_ext_mac_addr_read,
+ .write = mt7615_ext_mac_addr_write,
+ .owner = THIS_MODULE,
+};
+
int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
@@ -406,6 +493,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
&fops_reset_test);
debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
mt7615_read_temperature);
+ debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr);
debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf);
debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 716956b58c13..43d8256af66a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -295,6 +295,8 @@ struct mt7615_dev {
u32 debugfs_rf_wf;
u32 debugfs_rf_reg;
+ u32 muar_mask;
+
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 61623f480806..6e5db015b32c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -333,6 +333,9 @@ enum mt7615_reg_base {
#define MT_WF_RFCR_DROP_NDPA BIT(20)
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
+#define MT_WF_RMAC_MORE(_band) MT_WF_RMAC((_band) ? 0x124 : 0x024)
+#define MT_WF_RMAC_MORE_MUAR_MODE GENMASK(31, 30)
+
#define MT_WF_RFCR1(_band) MT_WF_RMAC((_band) ? 0x104 : 0x004)
#define MT_WF_RFCR1_DROP_ACK BIT(4)
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
@@ -342,6 +345,14 @@ enum mt7615_reg_base {
#define MT_CHFREQ(_band) MT_WF_RMAC((_band) ? 0x130 : 0x030)
+#define MT_WF_RMAC_MAR0 MT_WF_RMAC(0x025c)
+#define MT_WF_RMAC_MAR1 MT_WF_RMAC(0x0260)
+#define MT_WF_RMAC_MAR1_ADDR GENMASK(15, 0)
+#define MT_WF_RMAC_MAR1_START BIT(16)
+#define MT_WF_RMAC_MAR1_WRITE BIT(17)
+#define MT_WF_RMAC_MAR1_IDX GENMASK(29, 24)
+#define MT_WF_RMAC_MAR1_GROUP GENMASK(31, 30)
+
#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)