diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7915')
19 files changed, 2700 insertions, 667 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig index f21282cea845..d710726d47bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig @@ -2,6 +2,7 @@ config MT7915E tristate "MediaTek MT7915E (PCIe) support" select MT76_CONNAC_LIB + select WANT_DEV_COREDUMP depends on MAC80211 depends on PCI select RELAY diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile index b794ceb79c37..797ae49805c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile @@ -6,4 +6,5 @@ mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \ debugfs.o mmio.o mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o -mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
\ No newline at end of file +mt7915e-$(CONFIG_MT7986_WMAC) += soc.o +mt7915e-$(CONFIG_DEV_COREDUMP) += coredump.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c new file mode 100644 index 000000000000..d097a56dd33d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2022 MediaTek Inc. */ + +#include <linux/devcoredump.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/utsname.h> +#include "coredump.h" + +static bool coredump_memdump; +module_param(coredump_memdump, bool, 0644); +MODULE_PARM_DESC(coredump_memdump, "Optional ability to dump firmware memory"); + +static const struct mt7915_mem_region mt7915_mem_regions[] = { + { + .start = 0xe003b400, + .len = 0x00003bff, + .name = "CRAM", + }, +}; + +static const struct mt7915_mem_region mt7916_mem_regions[] = { + { + .start = 0x00800000, + .len = 0x0005ffff, + .name = "ROM", + }, + { + .start = 0x00900000, + .len = 0x00013fff, + .name = "ULM1", + }, + { + .start = 0x02200000, + .len = 0x0004ffff, + .name = "ULM2", + }, + { + .start = 0x02300000, + .len = 0x0004ffff, + .name = "ULM3", + }, + { + .start = 0x00400000, + .len = 0x00027fff, + .name = "SRAM", + }, + { + .start = 0xe0000000, + .len = 0x00157fff, + .name = "CRAM", + }, +}; + +static const struct mt7915_mem_region mt7986_mem_regions[] = { + { + .start = 0x00800000, + .len = 0x0005ffff, + .name = "ROM", + }, + { + .start = 0x00900000, + .len = 0x0000ffff, + .name = "ULM1", + }, + { + .start = 0x02200000, + .len = 0x0004ffff, + .name = "ULM2", + }, + { + .start = 0x02300000, + .len = 0x0004ffff, + .name = "ULM3", + }, + { + .start = 0x00400000, + .len = 0x00017fff, + .name = "SRAM", + }, + { + .start = 0xe0000000, + .len = 0x00113fff, + .name = "CRAM", + }, +}; + +const struct mt7915_mem_region* +mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num) +{ + switch (mt76_chip(&dev->mt76)) { + case 0x7915: + *num = ARRAY_SIZE(mt7915_mem_regions); + return &mt7915_mem_regions[0]; + case 0x7986: + *num = ARRAY_SIZE(mt7986_mem_regions); + return &mt7986_mem_regions[0]; + case 0x7916: + *num = ARRAY_SIZE(mt7916_mem_regions); + return &mt7916_mem_regions[0]; + default: + return NULL; + } +} + +static int mt7915_coredump_get_mem_size(struct mt7915_dev *dev) +{ + const struct mt7915_mem_region *mem_region; + size_t size = 0; + u32 num; + int i; + + mem_region = mt7915_coredump_get_mem_layout(dev, &num); + if (!mem_region) + return 0; + + for (i = 0; i < num; i++) { + size += mem_region->len; + mem_region++; + } + + /* reserve space for the headers */ + size += num * sizeof(struct mt7915_mem_hdr); + /* make sure it is aligned 4 bytes for debug message print out */ + size = ALIGN(size, 4); + + return size; +} + +struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev) +{ + struct mt7915_crash_data *crash_data = dev->coredump.crash_data; + + lockdep_assert_held(&dev->dump_mutex); + + guid_gen(&crash_data->guid); + ktime_get_real_ts64(&crash_data->timestamp); + + return crash_data; +} + +static void +mt7915_coredump_fw_state(struct mt7915_dev *dev, struct mt7915_coredump *dump, + bool *exception) +{ + u32 state, count, type; + + type = (u32)mt76_get_field(dev, MT_FW_EXCEPT_TYPE, GENMASK(7, 0)); + state = (u32)mt76_get_field(dev, MT_FW_ASSERT_STAT, GENMASK(7, 0)); + count = is_mt7915(&dev->mt76) ? + (u32)mt76_get_field(dev, MT_FW_EXCEPT_COUNT, GENMASK(15, 8)) : + (u32)mt76_get_field(dev, MT_FW_EXCEPT_COUNT, GENMASK(7, 0)); + + /* normal mode: driver can manually trigger assertĀ for detail info */ + if (!count) + strscpy(dump->fw_state, "normal", sizeof(dump->fw_state)); + else if (state > 1 && (count == 1) && type == 5) + strscpy(dump->fw_state, "assert", sizeof(dump->fw_state)); + else if ((state > 1 && count == 1) || count > 1) + strscpy(dump->fw_state, "exception", sizeof(dump->fw_state)); + + *exception = !!count; +} + +static void +mt7915_coredump_fw_trace(struct mt7915_dev *dev, struct mt7915_coredump *dump, + bool exception) +{ + u32 n, irq, sch, base = MT_FW_EINT_INFO; + + /* trap or run? */ + dump->last_msg_id = mt76_rr(dev, MT_FW_LAST_MSG_ID); + + n = is_mt7915(&dev->mt76) ? + (u32)mt76_get_field(dev, base, GENMASK(7, 0)) : + (u32)mt76_get_field(dev, base, GENMASK(15, 8)); + dump->eint_info_idx = n; + + irq = mt76_rr(dev, base + 0x8); + n = is_mt7915(&dev->mt76) ? + FIELD_GET(GENMASK(7, 0), irq) : FIELD_GET(GENMASK(23, 16), irq); + dump->irq_info_idx = n; + + sch = mt76_rr(dev, MT_FW_SCHED_INFO); + n = is_mt7915(&dev->mt76) ? + FIELD_GET(GENMASK(7, 0), sch) : FIELD_GET(GENMASK(15, 8), sch); + dump->sched_info_idx = n; + + if (exception) { + u32 i, y; + + /* sched trace */ + n = is_mt7915(&dev->mt76) ? + FIELD_GET(GENMASK(15, 8), sch) : FIELD_GET(GENMASK(7, 0), sch); + n = n > 60 ? 60 : n; + + strscpy(dump->trace_sched, "(sched_info) id, time", + sizeof(dump->trace_sched)); + + for (y = dump->sched_info_idx, i = 0; i < n; i++, y++) { + mt7915_memcpy_fromio(dev, dump->sched, base + 0xc + y * 12, + sizeof(dump->sched)); + y = y >= n ? 0 : y; + } + + /* irq trace */ + n = is_mt7915(&dev->mt76) ? + FIELD_GET(GENMASK(15, 8), irq) : FIELD_GET(GENMASK(7, 0), irq); + n = n > 60 ? 60 : n; + + strscpy(dump->trace_irq, "(irq_info) id, time", + sizeof(dump->trace_irq)); + + for (y = dump->irq_info_idx, i = 0; i < n; i++, y++) { + mt7915_memcpy_fromio(dev, dump->irq, base + 0x4 + y * 16, + sizeof(dump->irq)); + y = y >= n ? 0 : y; + } + } +} + +static void +mt7915_coredump_fw_stack(struct mt7915_dev *dev, struct mt7915_coredump *dump, + bool exception) +{ + u32 oldest, i, idx; + + /* stop call stack record */ + if (!exception) + mt76_clear(dev, 0x89050200, BIT(0)); + + oldest = (u32)mt76_get_field(dev, 0x89050200, GENMASK(20, 16)) + 2; + for (i = 0; i < 16; i++) { + idx = ((oldest + 2 * i + 1) % 32); + dump->call_stack[i] = mt76_rr(dev, 0x89050204 + idx * 4); + } + + /* start call stack record */ + if (!exception) + mt76_set(dev, 0x89050200, BIT(0)); +} + +static void +mt7915_coredump_fw_task(struct mt7915_dev *dev, struct mt7915_coredump *dump) +{ + u32 offs = is_mt7915(&dev->mt76) ? 0xe0 : 0x170; + + strscpy(dump->task_qid, "(task queue id) read, write", + sizeof(dump->task_qid)); + + dump->taskq[0].read = mt76_rr(dev, MT_FW_TASK_QID1); + dump->taskq[0].write = mt76_rr(dev, MT_FW_TASK_QID1 - 4); + dump->taskq[1].read = mt76_rr(dev, MT_FW_TASK_QID2); + dump->taskq[1].write = mt76_rr(dev, MT_FW_TASK_QID2 - 4); + + strscpy(dump->task_info, "(task stack) start, end, size", + sizeof(dump->task_info)); + + dump->taski[0].start = mt76_rr(dev, MT_FW_TASK_START); + dump->taski[0].end = mt76_rr(dev, MT_FW_TASK_END); + dump->taski[0].size = mt76_rr(dev, MT_FW_TASK_SIZE); + dump->taski[1].start = mt76_rr(dev, MT_FW_TASK_START + offs); + dump->taski[1].end = mt76_rr(dev, MT_FW_TASK_END + offs); + dump->taski[1].size = mt76_rr(dev, MT_FW_TASK_SIZE + offs); +} + +static void +mt7915_coredump_fw_context(struct mt7915_dev *dev, struct mt7915_coredump *dump) +{ + u32 count, idx, id; + + count = mt76_rr(dev, MT_FW_CIRQ_COUNT); + + /* current context */ + if (!count) { + strscpy(dump->fw_context, "(context) interrupt", + sizeof(dump->fw_context)); + + idx = is_mt7915(&dev->mt76) ? + (u32)mt76_get_field(dev, MT_FW_CIRQ_IDX, GENMASK(31, 16)) : + (u32)mt76_get_field(dev, MT_FW_CIRQ_IDX, GENMASK(15, 0)); + dump->context.idx = idx; + dump->context.handler = mt76_rr(dev, MT_FW_CIRQ_LISR); + } else { + idx = mt76_rr(dev, MT_FW_TASK_IDX); + id = mt76_rr(dev, MT_FW_TASK_ID); + + if (!id && idx == 3) { + strscpy(dump->fw_context, "(context) idle", + sizeof(dump->fw_context)); + } else if (id && idx != 3) { + strscpy(dump->fw_context, "(context) task", + sizeof(dump->fw_context)); + + dump->context.idx = idx; + dump->context.handler = id; + } + } +} + +static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev) +{ + struct mt7915_crash_data *crash_data = dev->coredump.crash_data; + struct mt7915_coredump *dump; + struct mt7915_coredump_mem *dump_mem; + size_t len, sofar = 0, hdr_len = sizeof(*dump); + unsigned char *buf; + bool exception; + + len = hdr_len; + + if (coredump_memdump && crash_data->memdump_buf_len) + len += sizeof(*dump_mem) + crash_data->memdump_buf_len; + + sofar += hdr_len; + + /* this is going to get big when we start dumping memory and such, + * so go ahead and use vmalloc. + */ + buf = vzalloc(len); + if (!buf) + return NULL; + + mutex_lock(&dev->dump_mutex); + + dump = (struct mt7915_coredump *)(buf); + dump->len = len; + + /* plain text */ + strscpy(dump->magic, "mt76-crash-dump", sizeof(dump->magic)); + strscpy(dump->kernel, init_utsname()->release, sizeof(dump->kernel)); + strscpy(dump->fw_ver, dev->mt76.hw->wiphy->fw_version, + sizeof(dump->fw_ver)); + + guid_copy(&dump->guid, &crash_data->guid); + dump->tv_sec = crash_data->timestamp.tv_sec; + dump->tv_nsec = crash_data->timestamp.tv_nsec; + dump->device_id = mt76_chip(&dev->mt76); + + mt7915_coredump_fw_state(dev, dump, &exception); + mt7915_coredump_fw_trace(dev, dump, exception); + mt7915_coredump_fw_task(dev, dump); + mt7915_coredump_fw_context(dev, dump); + mt7915_coredump_fw_stack(dev, dump, exception); + + /* gather memory content */ + dump_mem = (struct mt7915_coredump_mem *)(buf + sofar); + dump_mem->len = crash_data->memdump_buf_len; + if (coredump_memdump && crash_data->memdump_buf_len) + memcpy(dump_mem->data, crash_data->memdump_buf, + crash_data->memdump_buf_len); + + mutex_unlock(&dev->dump_mutex); + + return dump; +} + +int mt7915_coredump_submit(struct mt7915_dev *dev) +{ + struct mt7915_coredump *dump; + + dump = mt7915_coredump_build(dev); + if (!dump) { + dev_warn(dev->mt76.dev, "no crash dump data found\n"); + return -ENODATA; + } + + dev_coredumpv(dev->mt76.dev, dump, dump->len, GFP_KERNEL); + + return 0; +} + +int mt7915_coredump_register(struct mt7915_dev *dev) +{ + struct mt7915_crash_data *crash_data; + + crash_data = vzalloc(sizeof(*dev->coredump.crash_data)); + if (!crash_data) + return -ENOMEM; + + dev->coredump.crash_data = crash_data; + + if (coredump_memdump) { + crash_data->memdump_buf_len = mt7915_coredump_get_mem_size(dev); + if (!crash_data->memdump_buf_len) + /* no memory content */ + return 0; + + crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len); + if (!crash_data->memdump_buf) { + vfree(crash_data); + return -ENOMEM; + } + } + + return 0; +} + +void mt7915_coredump_unregister(struct mt7915_dev *dev) +{ + if (dev->coredump.crash_data->memdump_buf) { + vfree(dev->coredump.crash_data->memdump_buf); + dev->coredump.crash_data->memdump_buf = NULL; + dev->coredump.crash_data->memdump_buf_len = 0; + } + + vfree(dev->coredump.crash_data); + dev->coredump.crash_data = NULL; +} + diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.h b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.h new file mode 100644 index 000000000000..709f8e9c795c --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2022 MediaTek Inc. */ + +#ifndef _COREDUMP_H_ +#define _COREDUMP_H_ + +#include "mt7915.h" + +struct trace { + u32 id; + u32 timestamp; +}; + +struct mt7915_coredump { + char magic[16]; + + u32 len; + + guid_t guid; + + /* time-of-day stamp */ + u64 tv_sec; + /* time-of-day stamp, nano-seconds */ + u64 tv_nsec; + /* kernel version */ + char kernel[64]; + /* firmware version */ + char fw_ver[ETHTOOL_FWVERS_LEN]; + + u32 device_id; + + /* exception state */ + char fw_state[12]; + + u32 last_msg_id; + u32 eint_info_idx; + u32 irq_info_idx; + u32 sched_info_idx; + + /* schedule info */ + char trace_sched[32]; + struct { + struct trace t; + u32 pc; + } sched[60]; + + /* irq info */ + char trace_irq[32]; + struct trace irq[60]; + + /* task queue status */ + char task_qid[32]; + struct { + u32 read; + u32 write; + } taskq[2]; + + /* task stack info */ + char task_info[32]; + struct { + u32 start; + u32 end; + u32 size; + } taski[2]; + + /* firmware context */ + char fw_context[24]; + struct { + u32 idx; + u32 handler; + } context; + + /* link registers calltrace */ + u32 call_stack[16]; + + /* memory content */ + u8 data[]; +} __packed; + +struct mt7915_coredump_mem { + u32 len; + u8 data[]; +} __packed; + +struct mt7915_mem_hdr { + u32 start; + u32 len; + u8 data[]; +}; + +struct mt7915_mem_region { + u32 start; + size_t len; + + const char *name; +}; + +#ifdef CONFIG_DEV_COREDUMP + +const struct mt7915_mem_region * +mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num); +struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev); +int mt7915_coredump_submit(struct mt7915_dev *dev); +int mt7915_coredump_register(struct mt7915_dev *dev); +void mt7915_coredump_unregister(struct mt7915_dev *dev); + +#else /* CONFIG_DEV_COREDUMP */ + +static inline const struct mt7915_mem_region * +mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num) +{ + return NULL; +} + +static inline int mt7915_coredump_submit(struct mt7915_dev *dev) +{ + return 0; +} + +static inline struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev) +{ + return NULL; +} + +static inline int mt7915_coredump_register(struct mt7915_dev *dev) +{ + return 0; +} + +static inline void mt7915_coredump_unregister(struct mt7915_dev *dev) +{ +} + +#endif /* CONFIG_DEV_COREDUMP */ + +#endif /* _COREDUMP_H_ */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 6ef3431cad64..fb46c2c1784f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -46,12 +46,12 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get, /* test knob of system error recovery */ static ssize_t -mt7915_fw_ser_set(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) +mt7915_sys_recovery_set(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; + bool band = phy->mt76->band_idx; char buf[16]; int ret = 0; u16 val; @@ -71,9 +71,19 @@ mt7915_fw_ser_set(struct file *file, const char __user *user_buf, return -EINVAL; switch (val) { + /* + * 0: grab firmware current SER state. + * 1: trigger & enable system error L1 recovery. + * 2: trigger & enable system error L2 recovery. + * 3: trigger & enable system error L3 rx abort. + * 4: trigger & enable system error L3 tx abort + * 5: trigger & enable system error L3 tx disable. + * 6: trigger & enable system error L3 bf recovery. + * 7: trigger & enable system error full recovery. + * 8: trigger firmware crash. + */ case SER_QUERY: - /* grab firmware SER stats */ - ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy); + ret = mt7915_mcu_set_ser(dev, 0, 0, band); break; case SER_SET_RECOVER_L1: case SER_SET_RECOVER_L2: @@ -81,11 +91,28 @@ mt7915_fw_ser_set(struct file *file, const char __user *user_buf, case SER_SET_RECOVER_L3_TX_ABORT: case SER_SET_RECOVER_L3_TX_DISABLE: case SER_SET_RECOVER_L3_BF: - ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy); + ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), band); + if (ret) + return ret; + + ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, band); + break; + + /* enable full chip reset */ + case SER_SET_RECOVER_FULL: + mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK); + ret = mt7915_mcu_set_ser(dev, 1, 3, band); if (ret) return ret; - ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy); + dev->recovery.state |= MT_MCU_CMD_WDT_MASK; + mt7915_reset(dev); + break; + + /* WARNING: trigger firmware crash */ + case SER_SET_SYSTEM_ASSERT: + mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18)); + mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18)); break; default: break; @@ -95,20 +122,45 @@ mt7915_fw_ser_set(struct file *file, const char __user *user_buf, } static ssize_t -mt7915_fw_ser_get(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +mt7915_sys_recovery_get(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; char *buff; int desc = 0; ssize_t ret; - static const size_t bufsz = 400; + static const size_t bufsz = 1024; buff = kmalloc(bufsz, GFP_KERNEL); if (!buff) return -ENOMEM; + /* HELP */ + desc += scnprintf(buff + desc, bufsz - desc, + "Please echo the correct value ...\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "0: grab firmware transient SER state\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "1: trigger system error L1 recovery\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "2: trigger system error L2 recovery\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "3: trigger system error L3 rx abort\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "4: trigger system error L3 tx abort\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "5: trigger system error L3 tx disable\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "6: trigger system error L3 bf recovery\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "7: trigger system error full recovery\n"); + desc += scnprintf(buff + desc, bufsz - desc, + "8: trigger firmware crash\n"); + + /* SER statistics */ + desc += scnprintf(buff + desc, bufsz - desc, + "\nlet's dump firmware SER statistics...\n"); desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_STATUS = 0x%08x\n", mt76_rr(dev, MT_SWDEF_SER_STATS)); @@ -139,15 +191,19 @@ mt7915_fw_ser_get(struct file *file, char __user *user_buf, desc += scnprintf(buff + desc, bufsz - desc, "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n", mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS)); + desc += scnprintf(buff + desc, bufsz - desc, + "\nSYS_RESET_COUNT: WM %d, WA %d\n", + dev->recovery.wm_reset_count, + dev->recovery.wa_reset_count); ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); return ret; } -static const struct file_operations mt7915_fw_ser_ops = { - .write = mt7915_fw_ser_set, - .read = mt7915_fw_ser_get, +static const struct file_operations mt7915_sys_recovery_ops = { + .write = mt7915_sys_recovery_set, + .read = mt7915_sys_recovery_get, .open = simple_open, .llseek = default_llseek, }; @@ -598,10 +654,6 @@ mt7915_fw_util_wm_show(struct seq_file *file, void *data) struct mt7915_dev *dev = file->private; seq_printf(file, "Program counter: 0x%x\n", mt76_rr(dev, MT_WM_MCU_PC)); - seq_printf(file, "Exception state: 0x%x\n", - is_mt7915(&dev->mt76) ? - (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(15, 8)) : - (u32)mt76_get_field(dev, MT_FW_EXCEPTION, GENMASK(7, 0))); if (dev->fw.debug_wm) { seq_printf(file, "Busy: %u%% Peak busy: %u%%\n", @@ -639,16 +691,17 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, { struct mt7915_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; - int bound[15], range[4], i, n; + int bound[15], range[4], i; + u8 band = phy->mt76->band_idx; /* Tx ampdu stat */ for (i = 0; i < ARRAY_SIZE(range); i++) - range[i] = mt76_rr(dev, MT_MIB_ARNG(phy->band_idx, i)); + range[i] = mt76_rr(dev, MT_MIB_ARNG(band, i)); for (i = 0; i < ARRAY_SIZE(bound); i++) bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i % 4) + 1; - seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, phy->band_idx); + seq_printf(file, "\nPhy %d, Phy band %d\n", ext_phy, band); seq_printf(file, "Length: %8d | ", bound[0]); for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) @@ -656,9 +709,8 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy, bound[i] + 1, bound[i + 1]); seq_puts(file, "\nCount: "); - n = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < ARRAY_SIZE(bound); i++) - seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]); + seq_printf(file, "%8d | ", phy->mt76->aggr_stats[i]); seq_puts(file, "\n"); seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt); @@ -906,35 +958,199 @@ mt7915_xmit_queues_show(struct seq_file *file, void *data) DEFINE_SHOW_ATTRIBUTE(mt7915_xmit_queues); -static int -mt7915_rate_txpower_show(struct seq_file *file, void *data) +#define mt7915_txpower_puts(prefix, rate) \ +({ \ + len += scnprintf(buf + len, sz - len, "%-16s:", #prefix " (tmac)"); \ + for (i = 0; i < mt7915_sku_group_len[rate]; i++, offs++) \ + len += scnprintf(buf + len, sz - len, " %6d", txpwr[offs]); \ + len += scnprintf(buf + len, sz - len, "\n"); \ +}) + +#define mt7915_txpower_sets(rate, pwr, flag) \ +({ \ + offs += len; \ + len = mt7915_sku_group_len[rate]; \ + if (mode == flag) { \ + for (i = 0; i < len; i++) \ + req.txpower_sku[offs + i] = pwr; \ + } \ +}) + +static ssize_t +mt7915_rate_txpower_get(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct mt7915_phy *phy = file->private_data; + struct mt7915_dev *dev = phy->dev; + s8 txpwr[MT7915_SKU_RATE_NUM]; + static const size_t sz = 2048; + u8 band = phy->mt76->band_idx; + int i, offs = 0, len = 0; + ssize_t ret; + char *buf; + u32 reg; + + buf = kzalloc(sz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = mt7915_mcu_get_txpower_sku(phy, txpwr, sizeof(txpwr)); + if (ret) + return ret; + + /* Txpower propagation path: TMAC -> TXV -> BBP */ + len += scnprintf(buf + len, sz - len, + "\nPhy%d Tx power table (channel %d)\n", + phy != &dev->phy, phy->mt76->chandef.chan->hw_value); + len += scnprintf(buf + len, sz - len, "%-16s %6s %6s %6s %6s\n", + " ", "1m", "2m", "5m", "11m"); + mt7915_txpower_puts(CCK, SKU_CCK); + + len += scnprintf(buf + len, sz - len, + "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m", + "54m"); + mt7915_txpower_puts(OFDM, SKU_OFDM); + + len += scnprintf(buf + len, sz - len, + "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", + "mcs5", "mcs6", "mcs7"); + mt7915_txpower_puts(HT20, SKU_HT_BW20); + + len += scnprintf(buf + len, sz - len, + "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7", "mcs32"); + mt7915_txpower_puts(HT40, SKU_HT_BW40); + + len += scnprintf(buf + len, sz - len, + "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n", + " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", + "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11"); + mt7915_txpower_puts(VHT20, SKU_VHT_BW20); + mt7915_txpower_puts(VHT40, SKU_VHT_BW40); + mt7915_txpower_puts(VHT80, SKU_VHT_BW80); + mt7915_txpower_puts(VHT160, SKU_VHT_BW160); + mt7915_txpower_puts(HE26, SKU_HE_RU26); + mt7915_txpower_puts(HE52, SKU_HE_RU52); + mt7915_txpower_puts(HE106, SKU_HE_RU106); + mt7915_txpower_puts(HE242, SKU_HE_RU242); + mt7915_txpower_puts(HE484, SKU_HE_RU484); + mt7915_txpower_puts(HE996, SKU_HE_RU996); + mt7915_txpower_puts(HE996x2, SKU_HE_RU2x996); + + reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_TPC_CTRL_STAT(band) : + MT_WF_PHY_TPC_CTRL_STAT_MT7916(band); + + len += scnprintf(buf + len, sz - len, "\nTx power (bbp) : %6ld\n", + mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret; +} + +static ssize_t +mt7915_rate_txpower_set(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { - static const char * const sku_group_name[] = { - "CCK", "OFDM", "HT20", "HT40", - "VHT20", "VHT40", "VHT80", "VHT160", - "RU26", "RU52", "RU106", "RU242/SU20", - "RU484/SU40", "RU996/SU80", "RU2x996/SU160" + struct mt7915_phy *phy = file->private_data; + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct mt7915_mcu_txpower_sku req = { + .format_id = TX_POWER_LIMIT_TABLE, + .band_idx = phy->mt76->band_idx, }; - struct mt7915_phy *phy = file->private; - s8 txpower[MT7915_SKU_RATE_NUM], *buf; - int i; + char buf[100]; + int i, ret, pwr160 = 0, pwr80 = 0, pwr40 = 0, pwr20 = 0; + enum mac80211_rx_encoding mode; + u32 offs = 0, len = 0; - seq_printf(file, "\nBand %d\n", phy != &phy->dev->phy); - mt7915_mcu_get_txpower_sku(phy, txpower, sizeof(txpower)); - for (i = 0, buf = txpower; i < ARRAY_SIZE(mt7915_sku_group_len); i++) { - u8 mcs_num = mt7915_sku_group_len[i]; + if (count >= sizeof(buf)) + return -EINVAL; - if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) - mcs_num = 10; + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; - mt76_seq_puts_array(file, sku_group_name[i], buf, mcs_num); - buf += mt7915_sku_group_len[i]; + if (count && buf[count - 1] == '\n') + buf[count - 1] = '\0'; + else + buf[count] = '\0'; + + if (sscanf(buf, "%u %u %u %u %u", + &mode, &pwr160, &pwr80, &pwr40, &pwr20) != 5) { + dev_warn(dev->mt76.dev, + "per bandwidth power limit: Mode BW160 BW80 BW40 BW20"); + return -EINVAL; } - return 0; + if (mode > RX_ENC_HE) + return -EINVAL; + + if (pwr160) + pwr160 = mt7915_get_power_bound(phy, pwr160); + if (pwr80) + pwr80 = mt7915_get_power_bound(phy, pwr80); + if (pwr40) + pwr40 = mt7915_get_power_bound(phy, pwr40); + if (pwr20) + pwr20 = mt7915_get_power_bound(phy, pwr20); + + if (pwr160 < 0 || pwr80 < 0 || pwr40 < 0 || pwr20 < 0) + return -EINVAL; + + mutex_lock(&dev->mt76.mutex); + ret = mt7915_mcu_get_txpower_sku(phy, req.txpower_sku, + sizeof(req.txpower_sku)); + if (ret) + goto out; + + mt7915_txpower_sets(SKU_CCK, pwr20, RX_ENC_LEGACY); + mt7915_txpower_sets(SKU_OFDM, pwr20, RX_ENC_LEGACY); + if (mode == RX_ENC_LEGACY) + goto skip; + + mt7915_txpower_sets(SKU_HT_BW20, pwr20, RX_ENC_HT); + mt7915_txpower_sets(SKU_HT_BW40, pwr40, RX_ENC_HT); + if (mode == RX_ENC_HT) + goto skip; + + mt7915_txpower_sets(SKU_VHT_BW20, pwr20, RX_ENC_VHT); + mt7915_txpower_sets(SKU_VHT_BW40, pwr40, RX_ENC_VHT); + mt7915_txpower_sets(SKU_VHT_BW80, pwr80, RX_ENC_VHT); + mt7915_txpower_sets(SKU_VHT_BW160, pwr160, RX_ENC_VHT); + if (mode == RX_ENC_VHT) + goto skip; + + mt7915_txpower_sets(SKU_HE_RU26, pwr20, RX_ENC_HE + 1); + mt7915_txpower_sets(SKU_HE_RU52, pwr20, RX_ENC_HE + 1); + mt7915_txpower_sets(SKU_HE_RU106, pwr20, RX_ENC_HE + 1); + mt7915_txpower_sets(SKU_HE_RU242, pwr20, RX_ENC_HE); + mt7915_txpower_sets(SKU_HE_RU484, pwr40, RX_ENC_HE); + mt7915_txpower_sets(SKU_HE_RU996, pwr80, RX_ENC_HE); + mt7915_txpower_sets(SKU_HE_RU2x996, pwr160, RX_ENC_HE); +skip: + ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), + &req, sizeof(req), true); + if (ret) + goto out; + + mphy->txpower_cur = max(mphy->txpower_cur, + max(pwr160, max(pwr80, max(pwr40, pwr20)))); +out: + mutex_unlock(&dev->mt76.mutex); + + return ret ? ret : count; } -DEFINE_SHOW_ATTRIBUTE(mt7915_rate_txpower); +static const struct file_operations mt7915_rate_txpower_fops = { + .write = mt7915_rate_txpower_set, + .read = mt7915_rate_txpower_get, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; static int mt7915_twt_stats(struct seq_file *s, void *data) @@ -963,7 +1179,7 @@ mt7915_twt_stats(struct seq_file *s, void *data) } /* The index of RF registers use the generic regidx, combined with two parts: - * WF selection [31:28] and offset [27:0]. + * WF selection [31:24] and offset [23:0]. */ static int mt7915_rf_regval_get(void *data, u64 *val) @@ -1010,7 +1226,8 @@ int mt7915_init_debugfs(struct mt7915_phy *phy) debugfs_create_file("xmit-queues", 0400, dir, phy, &mt7915_xmit_queues_fops); debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops); - debugfs_create_file("fw_ser", 0600, dir, phy, &mt7915_fw_ser_ops); + debugfs_create_file("sys_recovery", 0600, dir, phy, + &mt7915_sys_recovery_ops); debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); @@ -1026,7 +1243,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy) mt7915_twt_stats); debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval); - if (!dev->dbdc_support || phy->band_idx) { + if (!dev->dbdc_support || phy->mt76->band_idx) { debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); debugfs_create_file("radar_trigger", 0200, dir, dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 00aafc2422f3..e3fa064918bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -11,7 +11,11 @@ mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base struct mt7915_dev *dev = phy->dev; if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { - ring_base = MT_WED_TX_RING_BASE; + if (is_mt7986(&dev->mt76)) + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; + else + ring_base = MT_WED_TX_RING_BASE; + idx -= MT_TXQ_ID(0); } @@ -46,29 +50,65 @@ static void mt7915_dma_config(struct mt7915_dev *dev) #define TXQ_CONFIG(q, wfdma, int, id) Q_CONFIG(__TXQ(q), (wfdma), (int), (id)) if (is_mt7915(&dev->mt76)) { - RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7915_RXQ_BAND0); - RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, MT7915_RXQ_MCU_WM); - RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, MT7915_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7915_RXQ_BAND1); - RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, MT7915_RXQ_MCU_WA_EXT); - RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, MT7915_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, + MT7915_RXQ_BAND0); + RXQ_CONFIG(MT_RXQ_MCU, WFDMA1, MT_INT_RX_DONE_WM, + MT7915_RXQ_MCU_WM); + RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA1, MT_INT_RX_DONE_WA, + MT7915_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, + MT7915_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA1, MT_INT_RX_DONE_WA_EXT, + MT7915_RXQ_MCU_WA_EXT); + RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA1, MT_INT_RX_DONE_WA_MAIN, + MT7915_RXQ_MCU_WA); TXQ_CONFIG(0, WFDMA1, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); TXQ_CONFIG(1, WFDMA1, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); - MCUQ_CONFIG(MT_MCUQ_WM, WFDMA1, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); - MCUQ_CONFIG(MT_MCUQ_WA, WFDMA1, MT_INT_TX_DONE_MCU_WA, MT7915_TXQ_MCU_WA); - MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA1, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); + MCUQ_CONFIG(MT_MCUQ_WM, WFDMA1, MT_INT_TX_DONE_MCU_WM, + MT7915_TXQ_MCU_WM); + MCUQ_CONFIG(MT_MCUQ_WA, WFDMA1, MT_INT_TX_DONE_MCU_WA, + MT7915_TXQ_MCU_WA); + MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA1, MT_INT_TX_DONE_FWDL, + MT7915_TXQ_FWDL); } else { - RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, MT7916_RXQ_BAND0); - RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7916_RXQ_MCU_WM); - RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7916_RXQ_MCU_WA); - RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, MT7916_RXQ_BAND1); - RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, MT7916_RXQ_MCU_WA_EXT); - RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN_MT7916, MT7916_RXQ_MCU_WA_MAIN); - TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7915_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7915_TXQ_BAND1); - MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7915_TXQ_MCU_WM); - MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA_MT7916, MT7915_TXQ_MCU_WA); - MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7915_TXQ_FWDL); + RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, + MT7916_RXQ_MCU_WM); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT_MT7916, + MT7916_RXQ_MCU_WA_EXT); + MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, + MT7915_TXQ_MCU_WM); + MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA_MT7916, + MT7915_TXQ_MCU_WA); + MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, + MT7915_TXQ_FWDL); + + if (is_mt7916(&dev->mt76) && mtk_wed_device_active(&dev->mt76.mmio.wed)) { + RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_WED_RX_DONE_BAND0_MT7916, + MT7916_RXQ_BAND0); + RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MT7916, + MT7916_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_WED_RX_DONE_BAND1_MT7916, + MT7916_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_WED_RX_DONE_WA_MAIN_MT7916, + MT7916_RXQ_MCU_WA_MAIN); + TXQ_CONFIG(0, WFDMA0, MT_INT_WED_TX_DONE_BAND0, + MT7915_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_WED_TX_DONE_BAND1, + MT7915_TXQ_BAND1); + } else { + RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0_MT7916, + MT7916_RXQ_BAND0); + RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, + MT7916_RXQ_MCU_WA); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1_MT7916, + MT7916_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN_MT7916, + MT7916_RXQ_MCU_WA_MAIN); + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7915_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7915_TXQ_BAND1); + } } } @@ -313,17 +353,26 @@ static int mt7915_dma_enable(struct mt7915_dev *dev) MT_INT_TX_DONE_MCU | MT_INT_MCU_CMD; - if (!dev->phy.band_idx) + if (!dev->phy.mt76->band_idx) irq_mask |= MT_INT_BAND0_RX_DONE; - if (dev->dbdc_support || dev->phy.band_idx) + if (dev->dbdc_support || dev->phy.mt76->band_idx) irq_mask |= MT_INT_BAND1_RX_DONE; if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { u32 wed_irq_mask = irq_mask; + int ret; wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; - mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask); + if (!is_mt7986(&dev->mt76)) + mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask); + else + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + + ret = mt7915_mcu_wed_enable_rx_stats(dev); + if (ret) + return ret; + mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); } @@ -348,20 +397,28 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) mt7915_dma_disable(dev, true); - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { - mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED); - - mt76_wr(dev, MT_WFDMA_WED_RING_CONTROL, - FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX0, 18) | - FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX1, 19) | - FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_RX1, 1)); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + if (!is_mt7986(mdev)) { + u8 wed_control_rx1 = is_mt7915(mdev) ? 1 : 2; + + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_WED); + mt76_wr(dev, MT_WFDMA_WED_RING_CONTROL, + FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX0, 18) | + FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_TX1, 19) | + FIELD_PREP(MT_WFDMA_WED_RING_CONTROL_RX1, + wed_control_rx1)); + if (is_mt7915(mdev)) + mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP, + MT_WFDMA0_EXT0_RXWB_KEEP); + } } else { mt76_clear(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_WED); } /* init tx queue */ ret = mt7915_init_tx_queues(&dev->phy, - MT_TXQ_ID(dev->phy.band_idx), + MT_TXQ_ID(dev->phy.mt76->band_idx), MT7915_TX_RING_SIZE, MT_TXQ_RING_BASE(0)); if (ret) @@ -369,7 +426,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (phy2) { ret = mt7915_init_tx_queues(phy2, - MT_TXQ_ID(phy2->band_idx), + MT_TXQ_ID(phy2->mt76->band_idx), MT7915_TX_RING_SIZE, MT_TXQ_RING_BASE(1)); if (ret) @@ -410,7 +467,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return ret; /* event from WA */ - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; @@ -425,7 +482,14 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return ret; /* rx data queue for band0 */ - if (!dev->phy.band_idx) { + if (!dev->phy.mt76->band_idx) { + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN].flags = + MT_WED_Q_RX(MT7915_RXQ_BAND0); + dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7915_RX_RING_SIZE, @@ -437,16 +501,32 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) /* tx free notify event from WA for band0 */ if (!is_mt7915(mdev)) { + wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA); + wa_rx_idx = MT_RXQ_ID(MT_RXQ_MAIN_WA); + + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + if (is_mt7916(mdev)) { + wa_rx_base = MT_WED_RX_RING_BASE; + wa_rx_idx = MT7915_RXQ_MCU_WA; + } + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], - MT_RXQ_ID(MT_RXQ_MAIN_WA), - MT7915_RX_MCU_RING_SIZE, - MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA)); + wa_rx_idx, MT7915_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, wa_rx_base); if (ret) return ret; } - if (dev->dbdc_support || dev->phy.band_idx) { + if (dev->dbdc_support || dev->phy.mt76->band_idx) { + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) { + dev->mt76.q_rx[MT_RXQ_BAND1].flags = + MT_WED_Q_RX(MT7915_RXQ_BAND1); + dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + } + /* rx data queue for band1 */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], MT_RXQ_ID(MT_RXQ_BAND1), @@ -479,6 +559,53 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return 0; } +int mt7915_dma_reset(struct mt7915_dev *dev, bool force) +{ + struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; + int i; + + /* clean up hw queues */ + for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) { + mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); + if (mphy_ext) + mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true); + } + + for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++) + mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]); + + /* reset wfsys */ + if (force) + mt7915_wfsys_reset(dev); + + mt7915_dma_disable(dev, force); + + /* reset hw queues */ + for (i = 0; i < __MT_TXQ_MAX; i++) { + mt76_queue_reset(dev, dev->mphy.q_tx[i]); + if (mphy_ext) + mt76_queue_reset(dev, mphy_ext->q_tx[i]); + } + + for (i = 0; i < __MT_MCUQ_MAX; i++) + mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); + + mt76_tx_status_check(&dev->mt76, true); + + mt7915_dma_enable(dev); + + mt76_for_each_q_rx(&dev->mt76, i) + mt76_queue_rx_reset(dev, i); + + return 0; +} + void mt7915_dma_cleanup(struct mt7915_dev *dev) { mt7915_dma_disable(dev, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 4b1a9811646f..59069fb86414 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -131,9 +131,10 @@ static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; u8 *eeprom = dev->mt76.eeprom.data; + u8 band = phy->mt76->band_idx; u32 val; - val = eeprom[MT_EE_WIFI_CONF + phy->band_idx]; + val = eeprom[MT_EE_WIFI_CONF + band]; val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); if (!is_mt7915(&dev->mt76)) { @@ -153,7 +154,7 @@ static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) return; } } else if (val == MT_EE_BAND_SEL_DEFAULT && dev->dbdc_support) { - val = phy->band_idx ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; + val = band ? MT_EE_BAND_SEL_5GHZ : MT_EE_BAND_SEL_2GHZ; } switch (val) { @@ -173,60 +174,51 @@ static void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy) void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, struct mt7915_phy *phy) { - u8 nss, nss_band, nss_band_max, *eeprom = dev->mt76.eeprom.data; + u8 path, nss, nss_max = 4, *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; - bool ext_phy = phy != &dev->phy; + u8 band = phy->mt76->band_idx; mt7915_eeprom_parse_band_config(phy); - /* read tx/rx mask from eeprom */ + /* read tx/rx path from eeprom */ if (is_mt7915(&dev->mt76)) { - nss = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, - eeprom[MT_EE_WIFI_CONF]); + path = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, + eeprom[MT_EE_WIFI_CONF]); } else { - nss = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, - eeprom[MT_EE_WIFI_CONF + phy->band_idx]); + path = FIELD_GET(MT_EE_WIFI_CONF0_TX_PATH, + eeprom[MT_EE_WIFI_CONF + band]); } - if (!nss || nss > 4) - nss = 4; + if (!path || path > 4) + path = 4; /* read tx/rx stream */ - nss_band = nss; - + nss = path; if (dev->dbdc_support) { if (is_mt7915(&dev->mt76)) { - nss_band = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B0, - eeprom[MT_EE_WIFI_CONF + 3]); - if (phy->band_idx) - nss_band = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B1, - eeprom[MT_EE_WIFI_CONF + 3]); + path = min_t(u8, path, 2); + nss = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B0, + eeprom[MT_EE_WIFI_CONF + 3]); + if (band) + nss = FIELD_GET(MT_EE_WIFI_CONF3_TX_PATH_B1, + eeprom[MT_EE_WIFI_CONF + 3]); } else { - nss_band = FIELD_GET(MT_EE_WIFI_CONF_STREAM_NUM, - eeprom[MT_EE_WIFI_CONF + 2 + phy->band_idx]); + nss = FIELD_GET(MT_EE_WIFI_CONF_STREAM_NUM, + eeprom[MT_EE_WIFI_CONF + 2 + band]); } - nss_band_max = is_mt7986(&dev->mt76) ? - MT_EE_NSS_MAX_DBDC_MA7986 : MT_EE_NSS_MAX_DBDC_MA7915; - } else { - nss_band_max = is_mt7986(&dev->mt76) ? - MT_EE_NSS_MAX_MA7986 : MT_EE_NSS_MAX_MA7915; + if (!is_mt7986(&dev->mt76)) + nss_max = 2; } - if (!nss_band || nss_band > nss_band_max) - nss_band = nss_band_max; - - if (nss_band > nss) { - dev_warn(dev->mt76.dev, - "nss mismatch, nss(%d) nss_band(%d) band(%d) ext_phy(%d)\n", - nss, nss_band, phy->band_idx, ext_phy); - nss = nss_band; - } + if (!nss) + nss = nss_max; + nss = min_t(u8, min_t(u8, nss_max, nss), path); - mphy->chainmask = BIT(nss) - 1; - if (ext_phy) + mphy->chainmask = BIT(path) - 1; + if (band) mphy->chainmask <<= dev->chainshift; - mphy->antenna_mask = BIT(nss_band) - 1; + mphy->antenna_mask = BIT(nss) - 1; dev->chainmask |= mphy->chainmask; dev->chainshift = hweight8(dev->mphy.chainmask); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 7578ac6d0be6..f3e56817d36e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -58,11 +58,6 @@ enum mt7915_eeprom_field { #define MT_EE_RATE_DELTA_SIGN BIT(6) #define MT_EE_RATE_DELTA_EN BIT(7) -#define MT_EE_NSS_MAX_MA7915 4 -#define MT_EE_NSS_MAX_DBDC_MA7915 2 -#define MT_EE_NSS_MAX_MA7986 4 -#define MT_EE_NSS_MAX_DBDC_MA7986 4 - enum mt7915_adie_sku { MT7976_ONE_ADIE_DBDC = 0x7, MT7975_ONE_ADIE = 0x8, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index cc2aac86bcfb..c810c31fbd6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -8,6 +8,7 @@ #include "mt7915.h" #include "mac.h" #include "mcu.h" +#include "coredump.h" #include "eeprom.h" static const struct ieee80211_iface_limit if_limits[] = { @@ -262,9 +263,8 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, mt7915_led_set_config(led_cdev, 0xff, 0); } -static void -mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband) +void mt7915_init_txpower(struct mt7915_dev *dev, + struct ieee80211_supported_band *sband) { int i, n_chains = hweight8(dev->mphy.antenna_mask); int nss_delta = mt76_tx_power_nss_delta(n_chains); @@ -353,6 +353,10 @@ mt7915_init_wiphy(struct ieee80211_hw *hw) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); + + if (!is_mt7915(&dev->mt76)) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); if (!mdev->dev->of_node || !of_property_read_bool(mdev->dev->of_node, @@ -444,9 +448,32 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band) /* mt7915: disable rx rate report by default due to hw issues */ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN); + + /* clear estimated value of EIFS for Rx duration & OBSS time */ + mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR); + + /* clear backoff time for Rx duration */ + mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME1(band), + MT_WF_RMAC_MIB_NONQOSD_BACKOFF); + mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME3(band), + MT_WF_RMAC_MIB_QOS01_BACKOFF); + mt76_clear(dev, MT_WF_RMAC_MIB_AIRTIME4(band), + MT_WF_RMAC_MIB_QOS23_BACKOFF); + + /* clear backoff time and set software compensation for OBSS time */ + mask = MT_WF_RMAC_MIB_OBSS_BACKOFF | MT_WF_RMAC_MIB_ED_OFFSET; + set = FIELD_PREP(MT_WF_RMAC_MIB_OBSS_BACKOFF, 0) | + FIELD_PREP(MT_WF_RMAC_MIB_ED_OFFSET, 4); + mt76_rmw(dev, MT_WF_RMAC_MIB_AIRTIME0(band), mask, set); + + /* filter out non-resp frames and get instanstaeous signal reporting */ + mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM; + set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) | + FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3); + 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; u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680; @@ -476,7 +503,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; @@ -513,7 +540,7 @@ mt7915_alloc_ext_phy(struct mt7915_dev *dev) phy->mt76 = mphy; /* Bind main phy to band0 and ext_phy to band1 for dbdc case */ - phy->band_idx = 1; + phy->mt76->band_idx = 1; return phy; } @@ -633,7 +660,7 @@ static bool mt7915_band_config(struct mt7915_dev *dev) { bool ret = true; - dev->phy.band_idx = 0; + dev->phy.mt76->band_idx = 0; if (is_mt7986(&dev->mt76)) { u32 sku = mt7915_check_adie(dev, true); @@ -644,7 +671,7 @@ static bool mt7915_band_config(struct mt7915_dev *dev) * dbdc is disabled. */ if (sku == MT7975_ONE_ADIE || sku == MT7976_ONE_ADIE) { - dev->phy.band_idx = 1; + dev->phy.mt76->band_idx = 1; ret = false; } } else { @@ -700,45 +727,49 @@ mt7915_init_hardware(struct mt7915_dev *dev, struct mt7915_phy *phy2) void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy) { - int nss; + int sts; u32 *cap; if (!phy->mt76->cap.has_5ghz) return; - nss = hweight8(phy->mt76->chainmask); + sts = hweight8(phy->mt76->chainmask); cap = &phy->mt76->sband_5g.sband.vht_cap.cap; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | - (3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, + sts - 1); *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); - if (nss < 2) + if (sts < 2) return; *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE | FIELD_PREP(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, - nss - 1); + sts - 1); } static void -mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, - struct ieee80211_sta_he_cap *he_cap, - int vif, int nss) +mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy, + struct ieee80211_sta_he_cap *he_cap, int vif) { + struct mt7915_dev *dev = phy->dev; struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem; - u8 c, nss_160; + int sts = hweight8(phy->mt76->chainmask); + u8 c, sts_160 = sts; - /* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */ - if (is_mt7915(&dev->mt76) && !dev->dbdc_support) - nss_160 = nss / 2; - else - nss_160 = nss; + /* Can do 1/2 of STS in 160Mhz mode for mt7915 */ + if (is_mt7915(&dev->mt76)) { + if (!dev->dbdc_support) + sts_160 /= 2; + else + sts_160 = 0; + } #ifdef CONFIG_MAC80211_MESH if (vif == NL80211_IFTYPE_MESH_POINT) @@ -748,8 +779,9 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, elem->phy_cap_info[3] &= ~IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER; elem->phy_cap_info[4] &= ~IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; - c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK | - IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; + c = IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; + if (sts_160) + c |= IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; elem->phy_cap_info[5] &= ~c; c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | @@ -765,8 +797,9 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, elem->phy_cap_info[2] |= c; c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + if (sts_160) + c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; elem->phy_cap_info[4] |= c; /* do not support NG16 due to spec D4.0 changes subcarrier idx */ @@ -778,11 +811,11 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, elem->phy_cap_info[6] |= c; - if (nss < 2) + if (sts < 2) return; /* the maximum cap is 4 x 3, (Nr, Nc) = (3, 2) */ - elem->phy_cap_info[7] |= min_t(int, nss - 1, 2) << 3; + elem->phy_cap_info[7] |= min_t(int, sts - 1, 2) << 3; if (vif != NL80211_IFTYPE_AP) return; @@ -791,12 +824,13 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_dev *dev, elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; /* num_snd_dim - * for mt7915, max supported nss is 2 for bw > 80MHz + * for mt7915, max supported sts is 2 for bw > 80MHz and 0 if dbdc */ c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK, - nss - 1) | - FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, - nss_160 - 1); + sts - 1); + if (sts_160) + c |= FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, + sts_160 - 1); elem->phy_cap_info[5] |= c; c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | @@ -836,16 +870,19 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, struct ieee80211_sband_iftype_data *data) { struct mt7915_dev *dev = phy->dev; - int i, idx = 0, nss = hweight8(phy->mt76->chainmask); + int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask); u16 mcs_map = 0; u16 mcs_map_160 = 0; u8 nss_160; - /* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */ - if (is_mt7915(&dev->mt76) && !dev->dbdc_support) + if (!is_mt7915(&dev->mt76)) + nss_160 = nss; + else if (!dev->dbdc_support) + /* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */ nss_160 = nss / 2; else - nss_160 = nss; + /* Can't do 160MHz with mt7915 dbdc */ + nss_160 = 0; for (i = 0; i < 8; i++) { if (i < nss) @@ -891,11 +928,14 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; - else + else if (nss_160) he_cap_elem->phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + else + he_cap_elem->phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD; @@ -949,9 +989,11 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | - IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; + if (nss_160) + he_cap_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | @@ -969,7 +1011,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map_160); he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map_160); - mt7915_set_stream_he_txbf_caps(dev, he_cap, i, nss); + mt7915_set_stream_he_txbf_caps(phy, he_cap, i); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & @@ -1078,6 +1120,8 @@ int mt7915_register_device(struct mt7915_dev *dev) init_waitqueue_head(&dev->reset_wait); INIT_WORK(&dev->reset_work, mt7915_mac_reset_work); + INIT_WORK(&dev->dump_work, mt7915_mac_dump_work); + mutex_init(&dev->dump_mutex); dev->dbdc_support = mt7915_band_config(dev); @@ -1118,7 +1162,15 @@ int mt7915_register_device(struct mt7915_dev *dev) goto unreg_thermal; } - mt7915_init_debugfs(&dev->phy); + dev->recovery.hw_init_done = true; + + ret = mt7915_init_debugfs(&dev->phy); + if (ret) + goto unreg_thermal; + + ret = mt7915_coredump_register(dev); + if (ret) + goto unreg_thermal; return 0; @@ -1137,6 +1189,7 @@ free_phy2: void mt7915_unregister_device(struct mt7915_dev *dev) { mt7915_unregister_ext_phy(dev); + mt7915_coredump_unregister(dev); mt7915_unregister_thermal(&dev->phy); mt76_unregister_device(&dev->mt76); mt7915_stop_hardware(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index a4bcc617c1a3..f0d5a3603902 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -3,12 +3,13 @@ #include <linux/etherdevice.h> #include <linux/timekeeping.h> +#include "coredump.h" #include "mt7915.h" #include "../dma.h" #include "mac.h" #include "mcu.h" -#define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) +#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) static const struct mt7915_dfs_radar_spec etsi_radar_specs = { .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, @@ -118,6 +119,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) bool clear = false; u32 addr, val; u16 idx; + s8 rssi[4]; u8 bw; spin_lock_bh(&dev->sta_poll_lock); @@ -131,6 +133,8 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) spin_unlock_bh(&dev->sta_poll_lock); idx = msta->wcid.idx; + + /* refresh peer's airtime reporting */ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20); for (i = 0; i < IEEE80211_NUM_ACS; i++) { @@ -161,9 +165,9 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u8 q = mt76_connac_lmac_mapping(i); - u32 tx_cur = tx_time[q]; - u32 rx_cur = rx_time[q]; + u8 queue = mt76_connac_lmac_mapping(i); + u32 tx_cur = tx_time[queue]; + u32 rx_cur = rx_time[queue]; u8 tid = ac_to_tid[i]; if (!tx_cur && !rx_cur) @@ -209,13 +213,69 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) else rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; } + + /* get signal strength of resp frames (CTS/BA/ACK) */ + addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 30); + val = mt76_rr(dev, addr); + + rssi[0] = to_rssi(GENMASK(7, 0), val); + rssi[1] = to_rssi(GENMASK(15, 8), val); + rssi[2] = to_rssi(GENMASK(23, 16), val); + rssi[3] = to_rssi(GENMASK(31, 14), val); + + msta->ack_signal = + mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); + + ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal); } rcu_read_unlock(); } +void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + u32 addr; + + addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); + if (enable) + mt76_set(dev, addr, BIT(5)); + else + mt76_clear(dev, addr, BIT(5)); +} + +static void +mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, + struct mt7915_sta *msta, struct sk_buff *skb, + u32 info) +{ + struct ieee80211_vif *vif; + struct wireless_dev *wdev; + + if (!msta || !msta->vif) + return; + + if (!(q->flags & MT_QFLAG_WED) || + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) != MT76_WED_Q_RX) + return; + + if (!(info & MT_DMA_INFO_PPE_VLD)) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + wdev = ieee80211_vif_to_wdev(vif); + skb->dev = wdev->netdev; + + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), + FIELD_GET(MT_DMA_PPE_ENTRY, info)); +} + static int -mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) +mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb, + enum mt76_rxq_id q, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -242,7 +302,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) memset(status, 0, sizeof(*status)); - if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->band_idx) { + if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->mt76->band_idx) { mphy = dev->mt76.phys[MT_BAND1]; if (!mphy) return -EINVAL; @@ -482,6 +542,8 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } } else { status->flag |= RX_FLAG_8023; + mt7915_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, + *info); } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) @@ -513,7 +575,7 @@ mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb) int i; band_idx = le32_get_bits(rxv_hdr[1], MT_RXV_HDR_BAND_IDX); - if (band_idx && !phy->band_idx) { + if (band_idx && !phy->mt76->band_idx) { phy = mt7915_ext_phy(dev); if (!phy) goto out; @@ -905,17 +967,19 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT); v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4); - if (WARN_ON_ONCE((void *)&tx_info[total >> v3] > end)) - return; for (cur_info = tx_info; count < total; cur_info++) { - u32 msdu, info = le32_to_cpu(*cur_info); + u32 msdu, info; u8 i; + if (WARN_ON_ONCE((void *)cur_info >= end)) + return; + /* * 1'b1: new wcid pair. * 1'b0: msdu_id with the same 'wcid pair' as above. */ + info = le32_to_cpu(*cur_info); if (info & MT_TX_FREE_PAIR) { struct mt7915_sta *msta; struct mt76_wcid *wcid; @@ -1063,7 +1127,7 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len) } void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb) + struct sk_buff *skb, u32 *info) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); __le32 *rxd = (__le32 *)skb->data; @@ -1097,7 +1161,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: - if (!mt7915_mac_fill_rx(dev, skb)) { + if (!mt7915_mac_fill_rx(dev, skb, q, info)) { mt76_rx(&dev->mt76, q, skb); return; } @@ -1111,7 +1175,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; - u32 reg = MT_WF_PHY_RX_CTRL1(phy->band_idx); + u32 reg = MT_WF_PHY_RX_CTRL1(phy->mt76->band_idx); mt76_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN); mt76_set(dev, reg, BIT(11) | BIT(9)); @@ -1123,19 +1187,15 @@ void mt7915_mac_reset_counters(struct mt7915_phy *phy) int i; for (i = 0; i < 4; i++) { - mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i)); - mt76_rr(dev, MT_TX_AGG_CNT2(phy->band_idx, i)); + mt76_rr(dev, MT_TX_AGG_CNT(phy->mt76->band_idx, i)); + mt76_rr(dev, MT_TX_AGG_CNT2(phy->mt76->band_idx, i)); } - i = 0; phy->mt76->survey_time = ktime_get_boottime(); - if (phy->band_idx) - i = ARRAY_SIZE(dev->mt76.aggr_stats) / 2; - - memset(&dev->mt76.aggr_stats[i], 0, sizeof(dev->mt76.aggr_stats) / 2); + memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats)); /* reset airtime counters */ - mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->band_idx), + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->mt76->band_idx), MT_WF_RMAC_MIB_RXTIME_CLR); mt7915_mcu_get_chan_mib_info(phy, true); @@ -1151,7 +1211,8 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy) FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48); u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28); - int offset; + u8 band = phy->mt76->band_idx; + int eifs_ofdm = 360, sifs = 10, offset; bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ); if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) @@ -1161,7 +1222,7 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy) coverage_class = max_t(s16, dev->phy.coverage_class, ext_phy->coverage_class); - mt76_set(dev, MT_ARB_SCR(phy->band_idx), + mt76_set(dev, MT_ARB_SCR(band), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); udelay(1); @@ -1169,39 +1230,48 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy) reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) | FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset); - mt76_wr(dev, MT_TMAC_CDTR(phy->band_idx), cck + reg_offset); - mt76_wr(dev, MT_TMAC_ODTR(phy->band_idx), ofdm + reg_offset); - mt76_wr(dev, MT_TMAC_ICR0(phy->band_idx), - FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) | + if (!is_mt7915(&dev->mt76)) { + if (!a_band) { + mt76_wr(dev, MT_TMAC_ICR1(band), + FIELD_PREP(MT_IFS_EIFS_CCK, 314)); + eifs_ofdm = 78; + } else { + eifs_ofdm = 84; + } + } else if (a_band) { + sifs = 16; + } + + mt76_wr(dev, MT_TMAC_CDTR(band), cck + reg_offset); + mt76_wr(dev, MT_TMAC_ODTR(band), ofdm + reg_offset); + mt76_wr(dev, MT_TMAC_ICR0(band), + FIELD_PREP(MT_IFS_EIFS_OFDM, eifs_ofdm) | FIELD_PREP(MT_IFS_RIFS, 2) | - FIELD_PREP(MT_IFS_SIFS, 10) | + FIELD_PREP(MT_IFS_SIFS, sifs) | FIELD_PREP(MT_IFS_SLOT, phy->slottime)); - mt76_wr(dev, MT_TMAC_ICR1(phy->band_idx), - FIELD_PREP(MT_IFS_EIFS_CCK, 314)); - if (phy->slottime < 20 || a_band) val = MT7915_CFEND_RATE_DEFAULT; else val = MT7915_CFEND_RATE_11B; - mt76_rmw_field(dev, MT_AGG_ACR0(phy->band_idx), MT_AGG_ACR_CFEND_RATE, val); - mt76_clear(dev, MT_ARB_SCR(phy->band_idx), + mt76_rmw_field(dev, MT_AGG_ACR0(band), MT_AGG_ACR_CFEND_RATE, val); + mt76_clear(dev, MT_ARB_SCR(band), MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE); } -void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy) +void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool band) { u32 reg; - reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(ext_phy) : - MT_WF_PHY_RXTD12_MT7916(ext_phy); + reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(band) : + MT_WF_PHY_RXTD12_MT7916(band); mt76_set(dev, reg, MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY | MT_WF_PHY_RXTD12_IRPI_SW_CLR); - reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(ext_phy) : - MT_WF_PHY_RX_CTRL1_MT7916(ext_phy); + reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(band) : + MT_WF_PHY_RX_CTRL1_MT7916(band); mt76_set(dev, reg, FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5)); } @@ -1239,7 +1309,7 @@ void mt7915_update_channel(struct mt76_phy *mphy) mt7915_mcu_get_chan_mib_info(phy, false); - nf = mt7915_phy_get_nf(phy, phy->band_idx); + nf = mt7915_phy_get_nf(phy, phy->mt76->band_idx); if (!phy->noise) phy->noise = nf << 4; else if (nf) @@ -1254,7 +1324,7 @@ mt7915_wait_reset_state(struct mt7915_dev *dev, u32 state) bool ret; ret = wait_event_timeout(dev->reset_wait, - (READ_ONCE(dev->reset_state) & state), + (READ_ONCE(dev->recovery.state) & state), MT7915_RESET_TIMEOUT); WARN(!ret, "Timeout waiting for MCU reset state %x\n", state); @@ -1295,85 +1365,180 @@ mt7915_update_beacons(struct mt7915_dev *dev) mt7915_update_vif_beacon, mphy_ext->hw); } -static void -mt7915_dma_reset(struct mt7915_dev *dev) +void mt7915_tx_token_put(struct mt7915_dev *dev) { - struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; - u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); - int i; + struct mt76_txwi_cache *txwi; + int id; - mt76_clear(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); + spin_lock_bh(&dev->mt76.token_lock); + idr_for_each_entry(&dev->mt76.token, txwi, id) { + mt7915_txwi_free(dev, txwi, NULL, NULL); + dev->mt76.token_count--; + } + spin_unlock_bh(&dev->mt76.token_lock); + 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 (is_mt7915(&dev->mt76)) - mt76_clear(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN); if (dev->hif2) { - mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); + mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); + mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); + } - if (is_mt7915(&dev->mt76)) - mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN); + 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); } - usleep_range(1000, 2000); + /* 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); - for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true); - if (mphy_ext) - mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true); + /* 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); - for (i = 0; i < __MT_MCUQ_MAX; i++) - mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true); + /* token reinit */ + mt7915_tx_token_put(dev); + idr_init(&dev->mt76.token); - mt76_for_each_q_rx(&dev->mt76, i) - mt76_queue_rx_reset(dev, i); + mt7915_dma_reset(dev, true); - mt76_tx_status_check(&dev->mt76, 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); - /* re-init prefetch settings after reset */ - mt7915_dma_prefetch(dev); + mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask); + mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); - if (is_mt7915(&dev->mt76)) - mt76_set(dev, MT_WFDMA1_GLO_CFG, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN | - MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); if (dev->hif2) { - mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN); + 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 (is_mt7915(&dev->mt76)) - mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs, - MT_WFDMA1_GLO_CFG_TX_DMA_EN | - MT_WFDMA1_GLO_CFG_RX_DMA_EN | - MT_WFDMA1_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA1_GLO_CFG_OMIT_RX_INFO); + 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; } -void mt7915_tx_token_put(struct mt7915_dev *dev) +static void +mt7915_mac_full_reset(struct mt7915_dev *dev) { - struct mt76_txwi_cache *txwi; - int id; + struct mt76_phy *ext_phy; + int i; - spin_lock_bh(&dev->mt76.token_lock); - idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7915_txwi_free(dev, txwi, NULL, NULL); - dev->mt76.token_count--; + 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; } - spin_unlock_bh(&dev->mt76.token_lock); - idr_destroy(&dev->mt76.token); + 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 */ @@ -1388,7 +1553,33 @@ void mt7915_mac_reset_work(struct work_struct *work) ext_phy = dev->mt76.phys[MT_BAND1]; 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); + + if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT) + dev->recovery.wa_reset_count++; + else + dev->recovery.wm_reset_count++; + + 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; ieee80211_stop_queues(mt76_hw(dev)); @@ -1413,7 +1604,7 @@ void mt7915_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { - mt7915_dma_reset(dev); + mt7915_dma_reset(dev, false); mt7915_tx_token_put(dev); idr_init(&dev->mt76.token); @@ -1462,132 +1653,227 @@ void mt7915_mac_reset_work(struct work_struct *work) MT7915_WATCHDOG_TIME); } +/* firmware coredump */ +void mt7915_mac_dump_work(struct work_struct *work) +{ + const struct mt7915_mem_region *mem_region; + struct mt7915_crash_data *crash_data; + struct mt7915_dev *dev; + struct mt7915_mem_hdr *hdr; + size_t buf_len; + int i; + u32 num; + u8 *buf; + + dev = container_of(work, struct mt7915_dev, dump_work); + + mutex_lock(&dev->dump_mutex); + + crash_data = mt7915_coredump_new(dev); + if (!crash_data) { + mutex_unlock(&dev->dump_mutex); + goto skip_coredump; + } + + mem_region = mt7915_coredump_get_mem_layout(dev, &num); + if (!mem_region || !crash_data->memdump_buf_len) { + mutex_unlock(&dev->dump_mutex); + goto skip_memdump; + } + + buf = crash_data->memdump_buf; + buf_len = crash_data->memdump_buf_len; + + /* dumping memory content... */ + memset(buf, 0, buf_len); + for (i = 0; i < num; i++) { + if (mem_region->len > buf_len) { + dev_warn(dev->mt76.dev, "%s len %lu is too large\n", + mem_region->name, + (unsigned long)mem_region->len); + break; + } + + /* reserve space for the header */ + hdr = (void *)buf; + buf += sizeof(*hdr); + buf_len -= sizeof(*hdr); + + mt7915_memcpy_fromio(dev, buf, mem_region->start, + mem_region->len); + + hdr->start = mem_region->start; + hdr->len = mem_region->len; + + if (!mem_region->len) + /* note: the header remains, just with zero length */ + break; + + buf += mem_region->len; + buf_len -= mem_region->len; + + mem_region++; + } + + mutex_unlock(&dev->dump_mutex); + +skip_memdump: + mt7915_coredump_submit(dev); +skip_coredump: + queue_work(dev->mt76.wq, &dev->reset_work); +} + +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->dump_work); + return; + } + + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); +} + void mt7915_mac_update_stats(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; struct mib_stats *mib = &phy->mib; - int i, aggr0, aggr1, cnt; + int i, aggr0 = 0, aggr1, cnt; + u8 band = phy->mt76->band_idx; u32 val; - cnt = mt76_rr(dev, MT_MIB_SDR3(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR3(band)); mib->fcs_err_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR4(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR4(band)); mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR5(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR5(band)); mib->rx_mpdu_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDR6(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR6(band)); mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR7(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR7(band)); mib->rx_vector_mismatch_cnt += FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR8(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR8(band)); mib->rx_delimiter_fail_cnt += FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR10(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR10(band)); mib->rx_mrdy_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR11(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR11(band)); mib->rx_len_mismatch_cnt += FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR12(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR12(band)); mib->tx_ampdu_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDR13(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR13(band)); mib->tx_stop_q_empty_cnt += FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR14(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR14(band)); mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR15(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR15(band)); mib->tx_mpdu_success_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR16(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR16(band)); mib->primary_cca_busy_time += FIELD_GET(MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR17(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR17(band)); mib->secondary_cca_busy_time += FIELD_GET(MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR18(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR18(band)); mib->primary_energy_detect_time += FIELD_GET(MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR19(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR19(band)); mib->cck_mdrdy_time += FIELD_GET(MT_MIB_SDR19_CCK_MDRDY_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR20(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR20(band)); mib->ofdm_mdrdy_time += FIELD_GET(MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR21(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR21(band)); mib->green_mdrdy_time += FIELD_GET(MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR22(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR22(band)); mib->rx_ampdu_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDR23(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR23(band)); mib->rx_ampdu_bytes_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDR24(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR24(band)); mib->rx_ampdu_valid_subframe_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR25(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR25(band)); mib->rx_ampdu_valid_subframe_bytes_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDR27(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR27(band)); mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR28(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR28(band)); mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR29(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR29(band)); mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDRVEC(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDRVEC(band)); mib->rx_vec_queue_overflow_drop_cnt += is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt) : FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR31(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR31(band)); mib->rx_ba_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_SDRMUBF(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDRMUBF(band)); mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt); - cnt = mt76_rr(dev, MT_MIB_DR8(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_DR8(band)); mib->tx_mu_mpdu_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_DR9(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_DR9(band)); mib->tx_mu_acked_mpdu_cnt += cnt; - cnt = mt76_rr(dev, MT_MIB_DR11(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_DR11(band)); mib->tx_su_acked_mpdu_cnt += cnt; - cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(phy->band_idx)); + cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(band)); mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_PAR_RPT0_FB_BW, cnt); mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NC, cnt); mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NR, cnt); @@ -1598,44 +1884,43 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) mib->tx_amsdu_cnt += cnt; } - aggr0 = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; if (is_mt7915(&dev->mt76)) { - for (i = 0, aggr1 = aggr0 + 4; i < 4; i++) { - val = mt76_rr(dev, MT_MIB_MB_SDR1(phy->band_idx, (i << 4))); + for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) { + val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 4))); mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val); mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val); - val = mt76_rr(dev, MT_MIB_MB_SDR0(phy->band_idx, (i << 4))); + val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 4))); mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); - val = mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i)); - dev->mt76.aggr_stats[aggr0++] += val & 0xffff; - dev->mt76.aggr_stats[aggr0++] += val >> 16; + val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); + phy->mt76->aggr_stats[aggr0++] += val & 0xffff; + phy->mt76->aggr_stats[aggr0++] += val >> 16; - val = mt76_rr(dev, MT_TX_AGG_CNT2(phy->band_idx, i)); - dev->mt76.aggr_stats[aggr1++] += val & 0xffff; - dev->mt76.aggr_stats[aggr1++] += val >> 16; + val = mt76_rr(dev, MT_TX_AGG_CNT2(band, i)); + phy->mt76->aggr_stats[aggr1++] += val & 0xffff; + phy->mt76->aggr_stats[aggr1++] += val >> 16; } - cnt = mt76_rr(dev, MT_MIB_SDR32(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR32(band)); mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); - cnt = mt76_rr(dev, MT_MIB_SDR33(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR33(band)); mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT, cnt); - cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(phy->band_idx)); + cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(band)); mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt); mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt); - cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(phy->band_idx)); + cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(band)); mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt); mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt); - cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(phy->band_idx)); + cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(band)); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt); mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt); mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt); @@ -1643,51 +1928,51 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) } else { for (i = 0; i < 2; i++) { /* rts count */ - val = mt76_rr(dev, MT_MIB_MB_SDR0(phy->band_idx, (i << 2))); + val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 2))); mib->rts_cnt += FIELD_GET(GENMASK(15, 0), val); mib->rts_cnt += FIELD_GET(GENMASK(31, 16), val); /* rts retry count */ - val = mt76_rr(dev, MT_MIB_MB_SDR1(phy->band_idx, (i << 2))); + val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 2))); mib->rts_retries_cnt += FIELD_GET(GENMASK(15, 0), val); mib->rts_retries_cnt += FIELD_GET(GENMASK(31, 16), val); /* ba miss count */ - val = mt76_rr(dev, MT_MIB_MB_SDR2(phy->band_idx, (i << 2))); + val = mt76_rr(dev, MT_MIB_MB_SDR2(band, (i << 2))); mib->ba_miss_cnt += FIELD_GET(GENMASK(15, 0), val); mib->ba_miss_cnt += FIELD_GET(GENMASK(31, 16), val); /* ack fail count */ - val = mt76_rr(dev, MT_MIB_MB_BFTF(phy->band_idx, (i << 2))); + val = mt76_rr(dev, MT_MIB_MB_BFTF(band, (i << 2))); mib->ack_fail_cnt += FIELD_GET(GENMASK(15, 0), val); mib->ack_fail_cnt += FIELD_GET(GENMASK(31, 16), val); } for (i = 0; i < 8; i++) { - val = mt76_rr(dev, MT_TX_AGG_CNT(phy->band_idx, i)); - dev->mt76.aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val); - dev->mt76.aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val); + val = mt76_rr(dev, MT_TX_AGG_CNT(band, i)); + phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val); + phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val); } - cnt = mt76_rr(dev, MT_MIB_SDR32(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR32(band)); mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt); mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt); - cnt = mt76_rr(dev, MT_MIB_BFCR7(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_BFCR7(band)); mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_MIB_BFCR7_BFEE_TX_FB_CPL, cnt); - cnt = mt76_rr(dev, MT_MIB_BFCR2(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_BFCR2(band)); mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_MIB_BFCR2_BFEE_TX_FB_TRIG, cnt); - cnt = mt76_rr(dev, MT_MIB_BFCR0(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_BFCR0(band)); mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt); mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt); - cnt = mt76_rr(dev, MT_MIB_BFCR1(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_BFCR1(band)); mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt); } @@ -1696,7 +1981,6 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) static void mt7915_mac_severe_check(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; - bool ext_phy = phy != &dev->phy; u32 trb; if (!phy->omac_mask) @@ -1706,7 +1990,7 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy) * stopping Rx, so check status periodically to see if TRB hardware * requires minimal recovery. */ - trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->band_idx)); + trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->mt76->band_idx)); if ((FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, trb) != FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, trb)) && @@ -1714,7 +1998,7 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy) FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, phy->trb_ts)) && trb == phy->trb_ts) mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L3_RX_ABORT, - ext_phy); + phy->mt76->band_idx); phy->trb_ts = trb; } @@ -1816,6 +2100,13 @@ static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) if (err < 0) return err; + if (is_mt7915(&dev->mt76)) { + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, chain, + 0, dev->dbdc_support ? 2 : 0); + if (err < 0) + return err; + } + return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain, MT_RX_SEL0, 1); } @@ -1827,16 +2118,16 @@ static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) int err; /* start CAC */ - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, phy->band_idx, - MT_RX_SEL0, 0); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, + phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) return err; - err = mt7915_dfs_start_rdd(dev, phy->band_idx); + err = mt7915_dfs_start_rdd(dev, phy->mt76->band_idx); if (err < 0) return err; - phy->rdd_state |= BIT(phy->band_idx); + phy->rdd_state |= BIT(phy->mt76->band_idx); if (!is_mt7915(&dev->mt76)) return 0; @@ -1921,7 +2212,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) return 0; err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, - phy->band_idx, MT_RX_SEL0, 0); + phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; @@ -1932,10 +2223,18 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) stop: err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, - phy->band_idx, MT_RX_SEL0, 0); + phy->mt76->band_idx, MT_RX_SEL0, 0); if (err < 0) return err; + if (is_mt7915(&dev->mt76)) { + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, + phy->mt76->band_idx, 0, + dev->dbdc_support ? 2 : 0); + if (err < 0) + return err; + } + mt7915_dfs_stop_radar_detector(phy); phy->mt76->dfs_state = MT_DFS_STATE_DISABLED; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 89b519cfd14c..0511d6a505b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -20,45 +20,45 @@ static bool mt7915_dev_running(struct mt7915_dev *dev) 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_phy *phy = mt7915_hw_phy(hw); bool running; int ret; - flush_work(&dev->init_work); - - mutex_lock(&dev->mt76.mutex); - running = mt7915_dev_running(dev); if (!running) { - ret = mt76_connac_mcu_set_pm(&dev->mt76, 0, 0); + ret = mt76_connac_mcu_set_pm(&dev->mt76, + dev->phy.mt76->band_idx, 0); if (ret) goto out; - ret = mt7915_mcu_set_mac(dev, 0, true, true); + ret = mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, + true, true); if (ret) goto out; - mt7915_mac_enable_nf(dev, 0); + mt7915_mac_enable_nf(dev, dev->phy.mt76->band_idx); } - if (phy != &dev->phy || phy->band_idx) { - ret = mt76_connac_mcu_set_pm(&dev->mt76, 1, 0); + if (phy != &dev->phy) { + ret = mt76_connac_mcu_set_pm(&dev->mt76, + phy->mt76->band_idx, 0); if (ret) goto out; - ret = mt7915_mcu_set_mac(dev, 1, true, true); + ret = mt7915_mcu_set_mac(dev, phy->mt76->band_idx, + true, true); if (ret) goto out; - mt7915_mac_enable_nf(dev, 1); + mt7915_mac_enable_nf(dev, phy->mt76->band_idx); } ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, - phy != &dev->phy); + phy->mt76->band_idx); if (ret) goto out; @@ -80,6 +80,18 @@ static int mt7915_start(struct ieee80211_hw *hw) mt7915_mac_reset_counters(phy); 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); return ret; @@ -99,13 +111,13 @@ static void mt7915_stop(struct ieee80211_hw *hw) clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); if (phy != &dev->phy) { - mt76_connac_mcu_set_pm(&dev->mt76, 1, 1); - mt7915_mcu_set_mac(dev, 1, false, false); + mt76_connac_mcu_set_pm(&dev->mt76, phy->mt76->band_idx, 1); + mt7915_mcu_set_mac(dev, phy->mt76->band_idx, false, false); } if (!mt7915_dev_running(dev)) { - mt76_connac_mcu_set_pm(&dev->mt76, 0, 1); - mt7915_mcu_set_mac(dev, 0, false, false); + mt76_connac_mcu_set_pm(&dev->mt76, dev->phy.mt76->band_idx, 1); + mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, false, false); } mutex_unlock(&dev->mt76.mutex); @@ -209,7 +221,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, } mvif->mt76.omac_idx = idx; mvif->phy = phy; - mvif->mt76.band_idx = phy->band_idx; + mvif->mt76.band_idx = phy->mt76->band_idx; mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; if (ext_phy) @@ -432,7 +444,6 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - bool band = phy != &dev->phy; int ret; if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { @@ -460,6 +471,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_MONITOR) { bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); + bool band = phy->mt76->band_idx; if (!enabled) phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; @@ -498,7 +510,7 @@ static void mt7915_configure_filter(struct ieee80211_hw *hw, { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - bool band = phy != &dev->phy; + bool band = phy->mt76->band_idx; u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | MT_WF_RFCR1_DROP_BF_POLL | MT_WF_RFCR1_DROP_BA | @@ -593,10 +605,11 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, mt7915_mcu_add_sta(dev, vif, NULL, join); } - if (changed & BSS_CHANGED_ASSOC) { + if (changed & BSS_CHANGED_ASSOC) mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc); - mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable); - } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) + mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; @@ -617,7 +630,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, mt7915_mcu_set_tx(dev, vif); if (changed & BSS_CHANGED_HE_OBSS_PD) - mt7915_mcu_add_obss_spr(dev, vif, info->he_obss_pd.enable); + mt7915_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); if (changed & BSS_CHANGED_HE_BSS_COLOR) mt7915_update_bss_color(hw, vif, &info->he_bss_color); @@ -665,6 +678,8 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; msta->jiffies = jiffies; + ewma_avg_signal_init(&msta->avg_ack_signal); + mt7915_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -732,7 +747,8 @@ static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) int ret; mutex_lock(&dev->mt76.mutex); - ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, phy != &dev->phy); + ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, + phy->mt76->band_idx); mutex_unlock(&dev->mt76.mutex); return ret; @@ -835,7 +851,7 @@ u64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - bool band = phy != &dev->phy; + bool band = phy->mt76->band_idx; union { u64 t64; u32 t32[2]; @@ -880,7 +896,7 @@ mt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - bool band = phy != &dev->phy; + bool band = phy->mt76->band_idx; union { u64 t64; u32 t32[2]; @@ -911,7 +927,7 @@ mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); - bool band = phy != &dev->phy; + bool band = phy->mt76->band_idx; union { u64 t64; u32 t32[2]; @@ -953,22 +969,21 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int max_nss = hweight8(hw->wiphy->available_antennas_tx); - bool ext_phy = phy != &dev->phy; + u8 chainshift = dev->chainshift; + u8 band = phy->mt76->band_idx; if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) return -EINVAL; - if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) - tx_ant = BIT(ffs(tx_ant) - 1) - 1; - mutex_lock(&dev->mt76.mutex); phy->mt76->antenna_mask = tx_ant; - if (ext_phy) - tx_ant <<= dev->chainshift; - - phy->mt76->chainmask = tx_ant; + /* handle a variant of mt7916 which has 3T3R but nss2 on 5 GHz band */ + if (is_mt7916(&dev->mt76) && band && hweight8(tx_ant) == max_nss) + phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; + else + phy->mt76->chainmask = tx_ant << (chainshift * band); mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); @@ -1026,7 +1041,21 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw, sinfo->tx_retries = msta->wcid.stats.tx_retries; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + + if (mtk_wed_get_rx_capa(&phy->dev->mt76.mmio.wed)) { + sinfo->rx_bytes = msta->wcid.stats.rx_bytes; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); + + sinfo->rx_packets = msta->wcid.stats.rx_packets; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); + } } + + sinfo->ack_signal = (s8)msta->ack_signal; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); + + sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); } static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) @@ -1111,6 +1140,39 @@ static void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); } +static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_phy *phy = mt7915_hw_phy(hw); + struct mt7915_dev *dev = mt7915_hw_dev(hw); + s16 txpower = sta->deflink.txpwr.power; + int ret; + + if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) + txpower = 0; + + mutex_lock(&dev->mt76.mutex); + + /* NOTE: temporarily use 0 as minimum limit, which is a + * global setting and will be applied to all stations. + */ + ret = mt7915_mcu_set_txpower_frame_min(phy, 0); + if (ret) + goto out; + + /* This only applies to data frames while pushing traffic, + * whereas the management frames or other packets that are + * using fixed rate can be configured via TxD. + */ + ret = mt7915_mcu_set_txpower_frame(phy, vif, sta, txpower); + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_ampdu_cnt", "tx_stop_q_empty_cnt", @@ -1258,7 +1320,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, }; struct mib_stats *mib = &phy->mib; /* See mt7915_ampdu_stat_read_phy, etc */ - int i, n, ei = 0; + int i, ei = 0; mutex_lock(&dev->mt76.mutex); @@ -1274,9 +1336,8 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw, data[ei++] = mib->tx_pkt_ibf_cnt; /* Tx ampdu stat */ - n = phy->band_idx ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0; for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) - data[ei++] = dev->mt76.aggr_stats[i + n]; + data[ei++] = phy->mt76->aggr_stats[i]; data[ei++] = phy->mib.ba_miss_cnt; @@ -1431,7 +1492,7 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, path->dev = ctx->dev; path->mtk_wdma.wdma_idx = wed->wdma_idx; path->mtk_wdma.bss = mvif->mt76.idx; - path->mtk_wdma.wcid = msta->wcid.idx; + path->mtk_wdma.wcid = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff; path->mtk_wdma.queue = phy != &dev->phy; ctx->dev = NULL; @@ -1477,6 +1538,7 @@ const struct ieee80211_ops mt7915_ops = { .set_bitrate_mask = mt7915_set_bitrate_mask, .set_coverage_class = mt7915_set_coverage_class, .sta_statistics = mt7915_sta_statistics, + .sta_set_txpwr = mt7915_sta_set_txpwr, .sta_set_4addr = mt7915_sta_set_4addr, .sta_set_decap_offload = mt7915_sta_set_decap_offload, .add_twt_setup = mt7915_mac_add_twt_setup, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 8d297e4aa7d4..b2652de082ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -32,6 +32,10 @@ #define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p) #define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m) +static bool sr_scene_detect = true; +module_param(sr_scene_detect, bool, 0644); +MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm"); + static u8 mt7915_mcu_get_sta_nss(u16 mcs_map) { @@ -228,7 +232,8 @@ mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb) c = (struct mt7915_mcu_csa_notify *)skb->data; - if ((c->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((c->band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -247,7 +252,8 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE) return; - if ((t->ctrl.band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; phy = (struct mt7915_phy *)mphy->priv; @@ -262,7 +268,8 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) r = (struct mt7915_mcu_rdd_report *)skb->data; - if ((r->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((r->band_idx && !dev->phy.mt76->band_idx) && + dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; if (r->band_idx == MT_RX_SEL2) @@ -319,7 +326,7 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) b = (struct mt7915_mcu_bcc_notify *)skb->data; - if ((b->band_idx && !dev->phy.band_idx) && dev->mt76.phys[MT_BAND1]) + if ((b->band_idx && !dev->phy.mt76->band_idx) && dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; ieee80211_iterate_active_interfaces_atomic(mphy->hw, @@ -485,7 +492,7 @@ static void mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct mt7915_phy *phy) { - int max_nss = hweight8(phy->mt76->chainmask); + int max_nss = hweight8(phy->mt76->antenna_mask); struct bss_info_ra *ra; struct tlv *tlv; @@ -595,7 +602,7 @@ mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif, .mode = !!mask || enable, .entry_count = 1, .write = 1, - .band = phy != &dev->phy, + .band = phy->mt76->band_idx, .index = idx * 2 + bssid, }; @@ -1131,7 +1138,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - bf->ncol_bw160 = nss_mcs; + bf->ncol_gt_bw80 = nss_mcs; } if (pe->phy_cap_info[0] & @@ -1139,10 +1146,10 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80); nss_mcs = mt7915_mcu_get_sta_nss(mcs_map); - if (bf->ncol_bw160) - bf->ncol_bw160 = min_t(u8, bf->ncol_bw160, nss_mcs); + if (bf->ncol_gt_bw80) + bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs); else - bf->ncol_bw160 = nss_mcs; + bf->ncol_gt_bw80 = nss_mcs; } snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK, @@ -1150,7 +1157,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif, sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK, pe->phy_cap_info[4]); - bf->nrow_bw160 = min_t(int, snd_dim, sts); + bf->nrow_gt_bw80 = min_t(int, snd_dim, sts); } static void @@ -1306,6 +1313,9 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, case RATE_PARAM_MMPS_UPDATE: ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode); break; + case RATE_PARAM_SPE_UPDATE: + ra->spe_idx = *(u8 *)data; + break; default: break; } @@ -1349,6 +1359,18 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, } static int +mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt76_phy *mphy = mvif->phy->mt76; + u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); + + return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx, + RATE_PARAM_SPE_UPDATE); +} + +static int mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1435,7 +1457,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev, return ret; } - return 0; + return mt7915_mcu_set_spe_idx(dev, vif, sta); } static void @@ -1662,10 +1684,32 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, return ret; } out: + ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); + if (ret) + return ret; + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); } +int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct { + __le32 args[2]; + } req = { + .args[0] = cpu_to_le32(1), + .args[1] = cpu_to_le32(6), + }; + + return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL, + &req, sizeof(req)); +#else + return 0; +#endif +} + int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool enable) { @@ -1674,7 +1718,7 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, struct { struct req_hdr { u8 omac_idx; - u8 dbdc_idx; + u8 band_idx; __le16 tlv_num; u8 is_tlv_append; u8 rsv[3]; @@ -1683,13 +1727,13 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, __le16 tag; __le16 len; u8 active; - u8 dbdc_idx; + u8 band_idx; u8 omac_addr[ETH_ALEN]; } __packed tlv; } data = { .hdr = { .omac_idx = mvif->mt76.omac_idx, - .dbdc_idx = mvif->mt76.band_idx, + .band_idx = mvif->mt76.band_idx, .tlv_num = cpu_to_le16(1), .is_tlv_append = 1, }, @@ -1697,7 +1741,7 @@ int mt7915_mcu_add_dev_info(struct mt7915_phy *phy, .tag = cpu_to_le16(DEV_INFO_ACTIVE), .len = cpu_to_le16(sizeof(struct req_tlv)), .active = enable, - .dbdc_idx = mvif->mt76.band_idx, + .band_idx = mvif->mt76.band_idx, }, }; @@ -2151,7 +2195,7 @@ int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms) u8 band_idx; } req = { .cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS), - .band_idx = phy->band_idx, + .band_idx = phy->mt76->band_idx, }; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), @@ -2234,18 +2278,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev) 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; - dev->mt76.mcu_ops = &mt7915_mcu_ops; - /* force firmware operation mode into normal state, * which should be set before firmware download stage. */ @@ -2274,7 +2310,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev) if (ret) return ret; - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && is_mt7915(&dev->mt76)) mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0); ret = mt7915_mcu_set_mwds(dev, 1); @@ -2294,6 +2330,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev) 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) { __mt76_mcu_restart(&dev->mt76); @@ -2538,7 +2588,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); req.monitor_bw = mt76_connac_chan_bw(chandef); - req.band_idx = phy != &dev->phy; + req.band_idx = phy->mt76->band_idx; req.scan_mode = 1; break; } @@ -2546,7 +2596,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy, req.monitor_chan = chandef->chan->hw_value; req.monitor_central_chan = ieee80211_frequency_to_channel(chandef->center_freq1); - req.band_idx = phy != &dev->phy; + req.band_idx = phy->mt76->band_idx; req.scan_mode = 2; break; case CH_SWITCH_BACKGROUND_SCAN_STOP: @@ -2613,12 +2663,13 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) struct mt7915_dev *dev = phy->dev; struct cfg80211_chan_def *chandef = &phy->mt76->chandef; int freq1 = chandef->center_freq1; + u8 band = phy->mt76->band_idx; struct { u8 control_ch; u8 center_ch; u8 bw; - u8 tx_streams_num; - u8 rx_streams; /* mask or num */ + u8 tx_path_num; + u8 rx_path; /* mask or num */ u8 switch_reason; u8 band_idx; u8 center_ch2; /* for 80+80 only */ @@ -2634,25 +2685,23 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), - .tx_streams_num = hweight8(phy->mt76->antenna_mask), - .rx_streams = phy->mt76->antenna_mask, - .band_idx = phy->band_idx, + .tx_path_num = hweight16(phy->mt76->chainmask), + .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), + .band_idx = band, .channel_band = ch_band[chandef->chan->band], }; #ifdef CONFIG_NL80211_TESTMODE if (phy->mt76->test.tx_antenna_mask && - (phy->mt76->test.state == MT76_TM_STATE_TX_FRAMES || - phy->mt76->test.state == MT76_TM_STATE_RX_FRAMES || - phy->mt76->test.state == MT76_TM_STATE_TX_CONT)) { - req.tx_streams_num = fls(phy->mt76->test.tx_antenna_mask); - req.rx_streams = phy->mt76->test.tx_antenna_mask; - - if (phy != &dev->phy) - req.rx_streams >>= dev->chainshift; + mt76_testmode_enabled(phy->mt76)) { + req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask); + req.rx_path = phy->mt76->test.tx_antenna_mask; } #endif + if (mt76_connac_spe_idx(phy->mt76->antenna_mask)) + req.tx_path_num = fls(phy->mt76->antenna_mask); + if (cmd == MCU_EXT_CMD(SET_RX_PATH) || dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; @@ -2665,7 +2714,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) req.switch_reason = CH_SWITCH_NORMAL; if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH)) - req.rx_streams = hweight8(req.rx_streams); + req.rx_path = hweight8(req.rx_path); if (chandef->width == NL80211_CHAN_WIDTH_80P80) { int freq2 = chandef->center_freq2; @@ -2927,25 +2976,36 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) { /* strict order */ static const u32 offs[] = { - MIB_BUSY_TIME, MIB_TX_TIME, MIB_RX_TIME, MIB_OBSS_AIRTIME, - MIB_BUSY_TIME_V2, MIB_TX_TIME_V2, MIB_RX_TIME_V2, + MIB_NON_WIFI_TIME, + MIB_TX_TIME, + MIB_RX_TIME, + MIB_OBSS_AIRTIME, + MIB_TXOP_INIT_COUNT, + /* v2 */ + MIB_NON_WIFI_TIME_V2, + MIB_TX_TIME_V2, + MIB_RX_TIME_V2, MIB_OBSS_AIRTIME_V2 }; struct mt76_channel_state *state = phy->mt76->chan_state; struct mt76_channel_state *state_ts = &phy->state_ts; struct mt7915_dev *dev = phy->dev; - struct mt7915_mcu_mib *res, req[4]; + struct mt7915_mcu_mib *res, req[5]; struct sk_buff *skb; int i, ret, start = 0, ofs = 20; + u64 cc_tx; if (!is_mt7915(&dev->mt76)) { - start = 4; + start = 5; ofs = 0; } - for (i = 0; i < 4; i++) { - req[i].band = cpu_to_le32(phy != &dev->phy); + for (i = 0; i < 5; i++) { + req[i].band = cpu_to_le32(phy->mt76->band_idx); req[i].offs = cpu_to_le32(offs[i + start]); + + if (!is_mt7915(&dev->mt76) && i == 3) + break; } ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO), @@ -2955,20 +3015,24 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch) res = (struct mt7915_mcu_mib *)(skb->data + ofs); +#define __res_u64(s) le64_to_cpu(res[s].data) + /* subtract Tx backoff time from Tx duration */ + cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1); + if (chan_switch) goto out; -#define __res_u64(s) le64_to_cpu(res[s].data) - state->cc_busy += __res_u64(0) - state_ts->cc_busy; - state->cc_tx += __res_u64(1) - state_ts->cc_tx; + state->cc_tx += cc_tx - state_ts->cc_tx; state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx; state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx; + state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) - + state_ts->cc_busy; out: - state_ts->cc_busy = __res_u64(0); - state_ts->cc_tx = __res_u64(1); + state_ts->cc_tx = cc_tx; state_ts->cc_bss_rx = __res_u64(2); state_ts->cc_rx = __res_u64(2) + __res_u64(3); + state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3); #undef __res_u64 dev_kfree_skb(skb); @@ -2982,11 +3046,11 @@ int mt7915_mcu_get_temperature(struct mt7915_phy *phy) struct { u8 ctrl_id; u8 action; - u8 dbdc_idx; + u8 band_idx; u8 rsv[5]; } req = { .ctrl_id = THERMAL_SENSOR_TEMP_QUERY, - .dbdc_idx = phy != &dev->phy, + .band_idx = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req, @@ -3005,7 +3069,7 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state) u8 rsv[2]; } __packed req = { .ctrl = { - .band_idx = phy->band_idx, + .band_idx = phy->mt76->band_idx, }, }; int level; @@ -3045,28 +3109,103 @@ out: &req, sizeof(req), false); } -int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) +int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower) { struct mt7915_dev *dev = phy->dev; + struct { + u8 format_id; + u8 rsv; + u8 band_idx; + s8 txpower_min; + } __packed req = { + .format_id = TX_POWER_LIMIT_FRAME_MIN, + .band_idx = phy->mt76->band_idx, + .txpower_min = txpower * 2, /* 0.5db */ + }; + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + +int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, s8 txpower) +{ + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct mt7915_dev *dev = phy->dev; struct mt76_phy *mphy = phy->mt76; - struct ieee80211_hw *hw = mphy->hw; - struct mt7915_sku_val { + struct { u8 format_id; - u8 limit_type; - u8 dbdc_idx; - s8 val[MT7915_SKU_RATE_NUM]; + u8 rsv[3]; + u8 band_idx; + s8 txpower_max; + __le16 wcid; + s8 txpower_offs[48]; } __packed req = { - .format_id = 4, - .dbdc_idx = phy != &dev->phy, + .format_id = TX_POWER_LIMIT_FRAME, + .band_idx = phy->mt76->band_idx, + .txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2), + .wcid = cpu_to_le16(msta->wcid.idx), + }; + int ret; + s8 txpower_sku[MT7915_SKU_RATE_NUM]; + + ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku)); + if (ret) + return ret; + + txpower = mt7915_get_power_bound(phy, txpower); + if (txpower > mphy->txpower_cur || txpower < 0) + return -EINVAL; + + if (txpower) { + u32 offs, len, i; + + if (sta->deflink.ht_cap.ht_supported) { + const u8 *sku_len = mt7915_sku_group_len; + + offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM]; + len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40]; + + if (sta->deflink.vht_cap.vht_supported) { + offs += len; + len = sku_len[SKU_VHT_BW20] * 4; + + if (sta->deflink.he_cap.has_he) { + offs += len + sku_len[SKU_HE_RU26] * 3; + len = sku_len[SKU_HE_RU242] * 4; + } + } + } else { + return -EINVAL; + } + + for (i = 0; i < len; i++, offs++) + req.txpower_offs[i] = + DIV_ROUND_UP(txpower - txpower_sku[offs], 2); + } + + return mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req, + sizeof(req), true); +} + +int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct mt7915_mcu_txpower_sku req = { + .format_id = TX_POWER_LIMIT_TABLE, + .band_idx = phy->mt76->band_idx, }; struct mt76_power_limits limits_array; s8 *la = (s8 *)&limits_array; - int i, idx, n_chains = hweight8(mphy->antenna_mask); - int tx_power = hw->conf.power_level * 2; + int i, idx; + int tx_power; - tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, - tx_power); - tx_power -= mt76_tx_power_nss_delta(n_chains); + tx_power = mt7915_get_power_bound(phy, hw->conf.power_level); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits_array, tx_power); mphy->txpower_cur = tx_power; @@ -3085,7 +3224,7 @@ int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy) } for (j = 0; j < min_t(u8, mcs_num, len); j++) - req.val[idx + j] = la[j]; + req.txpower_sku[idx + j] = la[j]; la += mcs_num; idx += len; @@ -3103,14 +3242,14 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) struct { u8 format_id; u8 category; - u8 band; + u8 band_idx; u8 _rsv; } __packed req = { - .format_id = 7, + .format_id = TX_POWER_LIMIT_INFO, .category = RATE_POWER_INFO, - .band = phy != &dev->phy, + .band_idx = phy->mt76->band_idx, }; - s8 res[MT7915_SKU_RATE_NUM][2]; + s8 txpower_sku[MT7915_SKU_RATE_NUM][2]; struct sk_buff *skb; int ret, i; @@ -3120,9 +3259,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len) if (ret) return ret; - memcpy(res, skb->data + 4, sizeof(res)); + memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku)); for (i = 0; i < len; i++) - txpower[i] = res[i][req.band]; + txpower[i] = txpower_sku[i][req.band_idx]; dev_kfree_skb(skb); @@ -3157,11 +3296,11 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable) struct mt7915_sku { u8 format_id; u8 sku_enable; - u8 dbdc_idx; + u8 band_idx; u8 rsv; } __packed req = { - .format_id = 0, - .dbdc_idx = phy != &dev->phy, + .format_id = TX_POWER_LIMIT_ENABLE, + .band_idx = phy->mt76->band_idx, .sku_enable = enable, }; @@ -3236,31 +3375,193 @@ int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action) sizeof(req), true); } -int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, - bool enable) +static int +mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val) +{ + struct mt7915_dev *dev = phy->dev; + struct mt7915_mcu_sr_ctrl req = { + .action = action, + .argnum = 1, + .band_idx = phy->mt76->band_idx, + .val = cpu_to_le32(val), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_sr_ctrl ctrl; + struct { + u8 pd_th_non_srg; + u8 pd_th_srg; + u8 period_offs; + u8 rcpi_src; + __le16 obss_pd_min; + __le16 obss_pd_min_srg; + u8 resp_txpwr_mode; + u8 txpwr_restrict_mode; + u8 txpwr_ref; + u8 rsv[3]; + } __packed param; + } __packed req = { + .ctrl = { + .action = SPR_SET_PARAM, + .argnum = 9, + .band_idx = phy->mt76->band_idx, + }, + }; + int ret; + u8 max_th = 82, non_srg_max_th = 62; + + /* disable firmware dynamical PD asjustment */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false); + if (ret) + return ret; + + if (he_obss_pd->sr_ctrl & + IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED) + req.param.pd_th_non_srg = max_th; + else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT) + req.param.pd_th_non_srg = max_th - he_obss_pd->non_srg_max_offset; + else + req.param.pd_th_non_srg = non_srg_max_th; + + if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) + req.param.pd_th_srg = max_th - he_obss_pd->max_offset; + + req.param.obss_pd_min = cpu_to_le16(82); + req.param.obss_pd_min_srg = cpu_to_le16(82); + req.param.txpwr_restrict_mode = 2; + req.param.txpwr_ref = 21; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd) { -#define MT_SPR_ENABLE 1 struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_dev *dev = phy->dev; + u8 omac = mvif->mt76.omac_idx; struct { - u8 action; - u8 arg_num; - u8 band_idx; - u8 status; - u8 drop_tx_idx; - u8 sta_idx; /* 256 sta */ - u8 rsv[2]; - __le32 val; + struct mt7915_mcu_sr_ctrl ctrl; + struct { + u8 omac; + u8 rsv[3]; + u8 flag[20]; + } __packed siga; + } __packed req = { + .ctrl = { + .action = SPR_SET_SIGA, + .argnum = 1, + .band_idx = phy->mt76->band_idx, + }, + .siga = { + .omac = omac > HW_BSSID_MAX ? omac - 12 : omac, + }, + }; + int ret; + + if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED) + req.siga.flag[req.siga.omac] = 0xf; + else + return 0; + + /* switch to normal AP mode */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0); + if (ret) + return ret; + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, + sizeof(req), true); +} + +static int +mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + struct mt7915_dev *dev = phy->dev; + struct { + struct mt7915_mcu_sr_ctrl ctrl; + struct { + __le32 color_l[2]; + __le32 color_h[2]; + __le32 bssid_l[2]; + __le32 bssid_h[2]; + } __packed bitmap; } __packed req = { - .action = MT_SPR_ENABLE, - .arg_num = 1, - .band_idx = mvif->mt76.band_idx, - .val = cpu_to_le32(enable), + .ctrl = { + .action = SPR_SET_SRG_BITMAP, + .argnum = 4, + .band_idx = phy->mt76->band_idx, + }, }; + u32 bitmap; + + memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap)); + req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap)); + req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap)); + req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap); + + memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap)); + req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap); return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req, sizeof(req), true); } +int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd) +{ + int ret; + + /* enable firmware scene detection algorithms */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect); + if (ret) + return ret; + + /* firmware dynamically adjusts PD threshold so skip manual control */ + if (sr_scene_detect && !he_obss_pd->enable) + return 0; + + /* enable spatial reuse */ + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable); + if (ret) + return ret; + + if (sr_scene_detect || !he_obss_pd->enable) + return 0; + + ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true); + if (ret) + return ret; + + /* set SRG/non-SRG OBSS PD threshold */ + ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd); + if (ret) + return ret; + + /* Set SR prohibit */ + ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd); + if (ret) + return ret; + + /* set SRG BSS color/BSSID bitmap */ + return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd); +} + int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct rate_info *rate) { @@ -3447,8 +3748,8 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set) __le32 ofs; __le32 data; } __packed req = { - .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 28))), - .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(27, 0))), + .idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))), + .ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))), .data = set ? cpu_to_le32(*val) : 0, }; struct sk_buff *skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index cd1edf553fc1..29b5434bfdb8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -129,6 +129,17 @@ struct mt7915_mcu_background_chain_ctrl { u8 rsv[2]; } __packed; +struct mt7915_mcu_sr_ctrl { + u8 action; + u8 argnum; + u8 band_idx; + u8 status; + u8 drop_ta_idx; + u8 sta_idx; /* 256 sta */ + u8 rsv[2]; + __le32 val; +} __packed; + struct mt7915_mcu_eeprom { u8 buffer_mode; u8 format; @@ -160,17 +171,26 @@ struct mt7915_mcu_mib { enum mt7915_chan_mib_offs { /* mt7915 */ - MIB_BUSY_TIME = 14, MIB_TX_TIME = 81, MIB_RX_TIME, MIB_OBSS_AIRTIME = 86, + MIB_NON_WIFI_TIME, + MIB_TXOP_INIT_COUNT, + /* mt7916 */ - MIB_BUSY_TIME_V2 = 0, MIB_TX_TIME_V2 = 6, MIB_RX_TIME_V2 = 8, - MIB_OBSS_AIRTIME_V2 = 490 + MIB_OBSS_AIRTIME_V2 = 490, + MIB_NON_WIFI_TIME_V2 }; +struct mt7915_mcu_txpower_sku { + u8 format_id; + u8 limit_type; + u8 band_idx; + s8 txpower_sku[MT7915_SKU_RATE_NUM]; +} __packed; + struct edca { u8 queue; u8 set; @@ -394,6 +414,7 @@ enum { RATE_PARAM_FIXED_MCS, RATE_PARAM_FIXED_GI = 11, RATE_PARAM_AUTO = 20, + RATE_PARAM_SPE_UPDATE = 22, }; #define RATE_CFG_MCS GENMASK(3, 0) @@ -406,6 +427,25 @@ enum { #define RATE_CFG_HE_LTF GENMASK(31, 28) enum { + TX_POWER_LIMIT_ENABLE, + TX_POWER_LIMIT_TABLE = 0x4, + TX_POWER_LIMIT_INFO = 0x7, + TX_POWER_LIMIT_FRAME = 0x11, + TX_POWER_LIMIT_FRAME_MIN = 0x12, +}; + +enum { + SPR_ENABLE = 0x1, + SPR_ENABLE_SD = 0x3, + SPR_ENABLE_MODE = 0x5, + SPR_ENABLE_DPD = 0x23, + SPR_ENABLE_TX = 0x25, + SPR_SET_SRG_BITMAP = 0x80, + SPR_SET_PARAM = 0xc2, + SPR_SET_SIGA = 0xdc, +}; + +enum { THERMAL_PROTECT_PARAMETER_CTRL, THERMAL_PROTECT_BASIC_INFO, THERMAL_PROTECT_ENABLE, @@ -447,6 +487,8 @@ enum { SER_SET_RECOVER_L3_TX_ABORT, SER_SET_RECOVER_L3_TX_DISABLE, SER_SET_RECOVER_L3_BF, + SER_SET_RECOVER_FULL, + SER_SET_SYSTEM_ASSERT, /* action */ SER_ENABLE = 2, SER_RECOVER @@ -474,4 +516,16 @@ enum { sizeof(struct bss_info_bcn_cont) + \ sizeof(struct bss_info_inband_discovery)) +static inline s8 +mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower) +{ + struct mt76_phy *mphy = phy->mt76; + int n_chains = hweight8(mphy->antenna_mask); + + txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); + txpower -= mt76_tx_power_nss_delta(n_chains); + + return txpower; +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 7bd5f6725d7b..0a95c3da241b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -9,53 +9,112 @@ #include "mt7915.h" #include "mac.h" #include "../trace.h" +#include "../dma.h" + +static bool wed_enable; +module_param(wed_enable, bool, 0644); +MODULE_PARM_DESC(wed_enable, "Enable Wireless Ethernet Dispatch support"); static const u32 mt7915_reg[] = { - [INT_SOURCE_CSR] = 0xd7010, - [INT_MASK_CSR] = 0xd7014, - [INT1_SOURCE_CSR] = 0xd7088, - [INT1_MASK_CSR] = 0xd708c, - [INT_MCU_CMD_SOURCE] = 0xd51f0, - [INT_MCU_CMD_EVENT] = 0x3108, - [WFDMA0_ADDR] = 0xd4000, - [WFDMA0_PCIE1_ADDR] = 0xd8000, - [WFDMA_EXT_CSR_ADDR] = 0xd7000, - [CBTOP1_PHY_END] = 0x77ffffff, - [INFRA_MCU_ADDR_END] = 0x7c3fffff, - [FW_EXCEPTION_ADDR] = 0x219848, - [SWDEF_BASE_ADDR] = 0x41f200, + [INT_SOURCE_CSR] = 0xd7010, + [INT_MASK_CSR] = 0xd7014, + [INT1_SOURCE_CSR] = 0xd7088, + [INT1_MASK_CSR] = 0xd708c, + [INT_MCU_CMD_SOURCE] = 0xd51f0, + [INT_MCU_CMD_EVENT] = 0x3108, + [WFDMA0_ADDR] = 0xd4000, + [WFDMA0_PCIE1_ADDR] = 0xd8000, + [WFDMA_EXT_CSR_ADDR] = 0xd7000, + [CBTOP1_PHY_END] = 0x77ffffff, + [INFRA_MCU_ADDR_END] = 0x7c3fffff, + [FW_ASSERT_STAT_ADDR] = 0x219848, + [FW_EXCEPT_TYPE_ADDR] = 0x21987c, + [FW_EXCEPT_COUNT_ADDR] = 0x219848, + [FW_CIRQ_COUNT_ADDR] = 0x216f94, + [FW_CIRQ_IDX_ADDR] = 0x216ef8, + [FW_CIRQ_LISR_ADDR] = 0x2170ac, + [FW_TASK_ID_ADDR] = 0x216f90, + [FW_TASK_IDX_ADDR] = 0x216f9c, + [FW_TASK_QID1_ADDR] = 0x219680, + [FW_TASK_QID2_ADDR] = 0x219760, + [FW_TASK_START_ADDR] = 0x219558, + [FW_TASK_END_ADDR] = 0x219554, + [FW_TASK_SIZE_ADDR] = 0x219560, + [FW_LAST_MSG_ID_ADDR] = 0x216f70, + [FW_EINT_INFO_ADDR] = 0x219818, + [FW_SCHED_INFO_ADDR] = 0x219828, + [SWDEF_BASE_ADDR] = 0x41f200, + [TXQ_WED_RING_BASE] = 0xd7300, + [RXQ_WED_RING_BASE] = 0xd7410, + [RXQ_WED_DATA_RING_BASE] = 0xd4500, }; static const u32 mt7916_reg[] = { - [INT_SOURCE_CSR] = 0xd4200, - [INT_MASK_CSR] = 0xd4204, - [INT1_SOURCE_CSR] = 0xd8200, - [INT1_MASK_CSR] = 0xd8204, - [INT_MCU_CMD_SOURCE] = 0xd41f0, - [INT_MCU_CMD_EVENT] = 0x2108, - [WFDMA0_ADDR] = 0xd4000, - [WFDMA0_PCIE1_ADDR] = 0xd8000, - [WFDMA_EXT_CSR_ADDR] = 0xd7000, - [CBTOP1_PHY_END] = 0x7fffffff, - [INFRA_MCU_ADDR_END] = 0x7c085fff, - [FW_EXCEPTION_ADDR] = 0x022050bc, - [SWDEF_BASE_ADDR] = 0x411400, + [INT_SOURCE_CSR] = 0xd4200, + [INT_MASK_CSR] = 0xd4204, + [INT1_SOURCE_CSR] = 0xd8200, + [INT1_MASK_CSR] = 0xd8204, + [INT_MCU_CMD_SOURCE] = 0xd41f0, + [INT_MCU_CMD_EVENT] = 0x2108, + [WFDMA0_ADDR] = 0xd4000, + [WFDMA0_PCIE1_ADDR] = 0xd8000, + [WFDMA_EXT_CSR_ADDR] = 0xd7000, + [CBTOP1_PHY_END] = 0x7fffffff, + [INFRA_MCU_ADDR_END] = 0x7c085fff, + [FW_ASSERT_STAT_ADDR] = 0x02204c14, + [FW_EXCEPT_TYPE_ADDR] = 0x022051a4, + [FW_EXCEPT_COUNT_ADDR] = 0x022050bc, + [FW_CIRQ_COUNT_ADDR] = 0x022001ac, + [FW_CIRQ_IDX_ADDR] = 0x02204f84, + [FW_CIRQ_LISR_ADDR] = 0x022050d0, + [FW_TASK_ID_ADDR] = 0x0220406c, + [FW_TASK_IDX_ADDR] = 0x0220500c, + [FW_TASK_QID1_ADDR] = 0x022028c8, + [FW_TASK_QID2_ADDR] = 0x02202a38, + [FW_TASK_START_ADDR] = 0x0220286c, + [FW_TASK_END_ADDR] = 0x02202870, + [FW_TASK_SIZE_ADDR] = 0x02202878, + [FW_LAST_MSG_ID_ADDR] = 0x02204fe8, + [FW_EINT_INFO_ADDR] = 0x0220525c, + [FW_SCHED_INFO_ADDR] = 0x0220516c, + [SWDEF_BASE_ADDR] = 0x411400, + [TXQ_WED_RING_BASE] = 0xd7300, + [RXQ_WED_RING_BASE] = 0xd7410, + [RXQ_WED_DATA_RING_BASE] = 0xd4540, }; static const u32 mt7986_reg[] = { - [INT_SOURCE_CSR] = 0x24200, - [INT_MASK_CSR] = 0x24204, - [INT1_SOURCE_CSR] = 0x28200, - [INT1_MASK_CSR] = 0x28204, - [INT_MCU_CMD_SOURCE] = 0x241f0, - [INT_MCU_CMD_EVENT] = 0x54000108, - [WFDMA0_ADDR] = 0x24000, - [WFDMA0_PCIE1_ADDR] = 0x28000, - [WFDMA_EXT_CSR_ADDR] = 0x27000, - [CBTOP1_PHY_END] = 0x7fffffff, - [INFRA_MCU_ADDR_END] = 0x7c085fff, - [FW_EXCEPTION_ADDR] = 0x02204ffc, - [SWDEF_BASE_ADDR] = 0x411400, + [INT_SOURCE_CSR] = 0x24200, + [INT_MASK_CSR] = 0x24204, + [INT1_SOURCE_CSR] = 0x28200, + [INT1_MASK_CSR] = 0x28204, + [INT_MCU_CMD_SOURCE] = 0x241f0, + [INT_MCU_CMD_EVENT] = 0x54000108, + [WFDMA0_ADDR] = 0x24000, + [WFDMA0_PCIE1_ADDR] = 0x28000, + [WFDMA_EXT_CSR_ADDR] = 0x27000, + [CBTOP1_PHY_END] = 0x7fffffff, + [INFRA_MCU_ADDR_END] = 0x7c085fff, + [FW_ASSERT_STAT_ADDR] = 0x02204b54, + [FW_EXCEPT_TYPE_ADDR] = 0x022050dc, + [FW_EXCEPT_COUNT_ADDR] = 0x02204ffc, + [FW_CIRQ_COUNT_ADDR] = 0x022001ac, + [FW_CIRQ_IDX_ADDR] = 0x02204ec4, + [FW_CIRQ_LISR_ADDR] = 0x02205010, + [FW_TASK_ID_ADDR] = 0x02204fac, + [FW_TASK_IDX_ADDR] = 0x02204f4c, + [FW_TASK_QID1_ADDR] = 0x02202814, + [FW_TASK_QID2_ADDR] = 0x02202984, + [FW_TASK_START_ADDR] = 0x022027b8, + [FW_TASK_END_ADDR] = 0x022027bc, + [FW_TASK_SIZE_ADDR] = 0x022027c4, + [FW_LAST_MSG_ID_ADDR] = 0x02204f28, + [FW_EINT_INFO_ADDR] = 0x02205194, + [FW_SCHED_INFO_ADDR] = 0x022051a4, + [SWDEF_BASE_ADDR] = 0x411400, + [TXQ_WED_RING_BASE] = 0x24420, + [RXQ_WED_RING_BASE] = 0x24520, + [RXQ_WED_DATA_RING_BASE] = 0x24540, }; static const u32 mt7915_offs[] = { @@ -448,6 +507,14 @@ static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr) return mt7915_reg_map_l2(dev, addr); } +void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, + size_t len) +{ + u32 addr = __mt7915_reg_addr(dev, offset); + + memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); +} + static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset) { struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); @@ -472,6 +539,257 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, addr, mask, val); } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt7915_dev *dev; + struct mt7915_phy *phy; + int ret; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + + spin_lock_bh(&dev->mt76.token_lock); + dev->mt76.token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->mt76.token_lock); + + ret = wait_event_timeout(dev->mt76.tx_wait, + !dev->mt76.wed_token_count, HZ); + if (!ret) + return -EAGAIN; + + phy = &dev->phy; + mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H); + + phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; + if (phy) + mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), + MT_AGG_ACR_PPDU_TXS2H); + + return 0; +} + +static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt7915_dev *dev; + struct mt7915_phy *phy; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + + spin_lock_bh(&dev->mt76.token_lock); + dev->mt76.token_size = MT7915_TOKEN_SIZE; + spin_unlock_bh(&dev->mt76.token_lock); + + /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than + * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. + */ + phy = &dev->phy; + mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H); + + phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; + if (phy) + mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), + MT_AGG_ACR_PPDU_TXS2H); +} + +static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt7915_dev *dev; + struct page *page; + int i; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + for (i = 0; i < dev->mt76.rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(&dev->mt76, i); + if (!t || !t->ptr) + continue; + + dma_unmap_single(dev->mt76.dma_dev, t->dma_addr, + wed->wlan.rx_size, DMA_FROM_DEVICE); + skb_free_frag(t->ptr); + t->ptr = NULL; + + mt76_put_rxwi(&dev->mt76, t); + } + + if (!wed->rx_buf_ring.rx_page.va) + return; + + page = virt_to_page(wed->rx_buf_ring.rx_page.va); + __page_frag_cache_drain(page, wed->rx_buf_ring.rx_page.pagecnt_bias); + memset(&wed->rx_buf_ring.rx_page, 0, sizeof(wed->rx_buf_ring.rx_page)); +} + +static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc; + struct mt7915_dev *dev; + u32 length; + int i; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size + + sizeof(struct skb_shared_info)); + + for (i = 0; i < size; i++) { + struct mt76_txwi_cache *t = mt76_get_rxwi(&dev->mt76); + dma_addr_t phy_addr; + int token; + void *ptr; + + ptr = page_frag_alloc(&wed->rx_buf_ring.rx_page, length, + GFP_KERNEL); + if (!ptr) + goto unmap; + + phy_addr = dma_map_single(dev->mt76.dma_dev, ptr, + wed->wlan.rx_size, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) { + skb_free_frag(ptr); + goto unmap; + } + + desc->buf0 = cpu_to_le32(phy_addr); + token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr); + desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, + token)); + desc++; + } + + return 0; + +unmap: + mt7915_mmio_wed_release_rx_buf(wed); + return -ENOMEM; +} + +static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, + struct mtk_wed_wo_rx_stats *stats) +{ + int idx = le16_to_cpu(stats->wlan_idx); + struct mt7915_dev *dev; + struct mt76_wcid *wcid; + + dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); + + if (idx >= mt7915_wtbl_size(dev)) + return; + + rcu_read_lock(); + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (wcid) { + wcid->stats.rx_bytes += le32_to_cpu(stats->rx_byte_cnt); + wcid->stats.rx_packets += le32_to_cpu(stats->rx_pkt_cnt); + wcid->stats.rx_errors += le32_to_cpu(stats->rx_err_cnt); + wcid->stats.rx_drops += le32_to_cpu(stats->rx_drop_cnt); + } + + rcu_read_unlock(); +} +#endif + +int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, + bool pci, int *irq) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + int ret; + + if (!wed_enable) + return 0; + + if (pci) { + struct pci_dev *pci_dev = pdev_ptr; + + wed->wlan.pci_dev = pci_dev; + wed->wlan.bus_type = MTK_WED_BUS_PCIE; + wed->wlan.base = devm_ioremap(dev->mt76.dev, + pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); + wed->wlan.wpdma_int = pci_resource_start(pci_dev, 0) + + MT_INT_WED_SOURCE_CSR; + wed->wlan.wpdma_mask = pci_resource_start(pci_dev, 0) + + MT_INT_WED_MASK_CSR; + wed->wlan.wpdma_phys = pci_resource_start(pci_dev, 0) + + MT_WFDMA_EXT_CSR_BASE; + wed->wlan.wpdma_tx = pci_resource_start(pci_dev, 0) + + MT_TXQ_WED_RING_BASE; + wed->wlan.wpdma_txfree = pci_resource_start(pci_dev, 0) + + MT_RXQ_WED_RING_BASE; + wed->wlan.wpdma_rx_glo = pci_resource_start(pci_dev, 0) + + MT_WPDMA_GLO_CFG; + wed->wlan.wpdma_rx = pci_resource_start(pci_dev, 0) + + MT_RXQ_WED_DATA_RING_BASE; + } else { + struct platform_device *plat_dev = pdev_ptr; + struct resource *res; + + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); + if (!res) + return -ENOMEM; + + wed->wlan.platform_dev = plat_dev; + wed->wlan.bus_type = MTK_WED_BUS_AXI; + wed->wlan.base = devm_ioremap(dev->mt76.dev, res->start, + resource_size(res)); + wed->wlan.phy_base = res->start; + wed->wlan.wpdma_int = res->start + MT_INT_SOURCE_CSR; + wed->wlan.wpdma_mask = res->start + MT_INT_MASK_CSR; + wed->wlan.wpdma_tx = res->start + MT_TXQ_WED_RING_BASE; + wed->wlan.wpdma_txfree = res->start + MT_RXQ_WED_RING_BASE; + wed->wlan.wpdma_rx_glo = res->start + MT_WPDMA_GLO_CFG; + wed->wlan.wpdma_rx = res->start + MT_RXQ_WED_DATA_RING_BASE; + } + wed->wlan.nbuf = 4096; + wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30; + wed->wlan.tx_tbit[1] = is_mt7915(&dev->mt76) ? 5 : 31; + wed->wlan.txfree_tbit = is_mt7986(&dev->mt76) ? 2 : 1; + wed->wlan.token_start = MT7915_TOKEN_SIZE - wed->wlan.nbuf; + wed->wlan.wcid_512 = !is_mt7915(&dev->mt76); + + wed->wlan.rx_nbuf = 65536; + wed->wlan.rx_npkt = MT7915_WED_RX_TOKEN_SIZE; + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); + if (is_mt7915(&dev->mt76)) { + wed->wlan.rx_tbit[0] = 16; + wed->wlan.rx_tbit[1] = 17; + } else if (is_mt7986(&dev->mt76)) { + wed->wlan.rx_tbit[0] = 22; + wed->wlan.rx_tbit[1] = 23; + } else { + wed->wlan.rx_tbit[0] = 18; + wed->wlan.rx_tbit[1] = 19; + } + + wed->wlan.init_buf = mt7915_wed_init_buf; + wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; + wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; + wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; + + dev->mt76.rx_token_size = wed->wlan.rx_npkt; + + if (mtk_wed_device_attach(wed)) + return 0; + + *irq = wed->irq; + dev->mt76.dma_dev = wed->dev; + + ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + return 1; +#else + return 0; +#endif +} + static int mt7915_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, u32 device_id) @@ -536,7 +854,11 @@ void mt7915_dual_hif_set_irq_mask(struct mt7915_dev *dev, mdev->mmio.irqmask |= set; if (write_reg) { - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed)) + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + else + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); } @@ -560,6 +882,8 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) if (mtk_wed_device_active(wed)) { mtk_wed_device_irq_set_mask(wed, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); } else { mt76_wr(dev, MT_INT_MASK_CSR, 0); @@ -613,10 +937,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t) u32 val = mt76_rr(dev, MT_MCU_CMD); mt76_wr(dev, MT_MCU_CMD, val); - if (val & MT_MCU_CMD_ERROR_MASK) { - dev->reset_state = val; - queue_work(dev->mt76.wq, &dev->reset_work); - wake_up(&dev->reset_wait); + if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) { + dev->recovery.state = val; + mt7915_reset(dev); } } } @@ -648,7 +971,8 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), - .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | + MT_DRV_AMSDU_OFFLOAD, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 1eb11617a625..6351feba6bdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -68,6 +68,8 @@ #define MT7915_MIN_TWT_DUR 64 #define MT7915_MAX_QUEUE (MT_RXQ_BAND2 + __MT_MCUQ_MAX + 2) +#define MT7915_WED_RX_TOKEN_SIZE 12288 + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -114,6 +116,8 @@ struct mt7915_twt_flow { u8 sched:1; }; +DECLARE_EWMA(avg_signal, 10, 8) + struct mt7915_sta { struct mt76_wcid wcid; /* must be first */ @@ -123,10 +127,12 @@ struct mt7915_sta { struct list_head rc_list; u32 airtime_ac[8]; + int ack_signal; + struct ewma_avg_signal avg_ack_signal; + unsigned long changed; unsigned long jiffies; unsigned long ampdu_state; - struct mt76_connac_sta_key_conf bip; struct { @@ -220,6 +226,15 @@ struct mib_stats { u32 tx_amsdu_cnt; }; +/* crash-dump */ +struct mt7915_crash_data { + guid_t guid; + struct timespec64 timestamp; + + u8 *memdump_buf; + size_t memdump_buf_len; +}; + struct mt7915_hif { struct list_head list; @@ -243,7 +258,6 @@ struct mt7915_phy { u32 rxfilter; u64 omac_mask; - u8 band_idx; u16 noise; @@ -301,9 +315,26 @@ struct mt7915_dev { struct work_struct init_work; struct work_struct rc_work; + struct work_struct dump_work; struct work_struct reset_work; wait_queue_head_t reset_wait; - u32 reset_state; + + struct { + u32 state; + u32 wa_reset_count; + u32 wm_reset_count; + bool hw_full_reset:1; + bool hw_init_done:1; + bool restart:1; + } recovery; + + /* protects coredump data */ + struct mutex dump_mutex; +#ifdef CONFIG_DEV_COREDUMP + struct { + struct mt7915_crash_data *crash_data; + } coredump; +#endif struct list_head sta_rc_list; struct list_head sta_poll_list; @@ -357,6 +388,7 @@ enum mt7915_rdd_cmd { RDD_DET_MODE, RDD_RADAR_EMULATE, RDD_START_TXQ = 20, + RDD_SET_WF_ANT = 30, RDD_CAC_START = 50, RDD_CAC_END, RDD_NORMAL_START, @@ -442,7 +474,14 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band); int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2); void mt7915_dma_prefetch(struct mt7915_dev *dev); void mt7915_dma_cleanup(struct mt7915_dev *dev); +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_firmware(struct mt7915_dev *dev); int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev, struct mt7915_vif *mvif, struct mt7915_twt_flow *flow, @@ -463,8 +502,8 @@ int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vi struct cfg80211_he_bss_color *he_bss_color); int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable, u32 changed); -int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif, - bool enable); +int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_he_obss_pd *he_obss_pd); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool changed); int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif, @@ -488,6 +527,10 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band); int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable); int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy); int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len); +int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower); +int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, s8 txpower); int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action); int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val); int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev, @@ -542,11 +585,17 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +void mt7915_memcpy_fromio(struct mt7915_dev *dev, void *buf, u32 offset, + size_t len); + +void mt7915_mac_init(struct mt7915_dev *dev); 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); void mt7915_mac_reset_counters(struct mt7915_phy *phy); void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy); void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy); +void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, + struct ieee80211_vif *vif, bool enable); void mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, int pid, struct ieee80211_key_conf *key, @@ -558,6 +607,7 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt7915_mac_work(struct work_struct *work); void mt7915_mac_reset_work(struct work_struct *work); +void mt7915_mac_dump_work(struct work_struct *work); void mt7915_mac_sta_rc_work(struct work_struct *work); void mt7915_mac_update_stats(struct mt7915_phy *phy); void mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev, @@ -572,7 +622,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct mt76_tx_info *tx_info); void mt7915_tx_token_put(struct mt7915_dev *dev); void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, - struct sk_buff *skb); + struct sk_buff *skb, u32 *info); bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps); void mt7915_stats_work(struct work_struct *work); @@ -583,6 +633,7 @@ void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy); void mt7915_update_channel(struct mt76_phy *mphy); int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enable); int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms); +int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev); int mt7915_init_debugfs(struct mt7915_phy *phy); void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len); bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len); @@ -590,5 +641,7 @@ bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len); void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif +int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, + bool pci, int *irq); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 728a879c3b00..39132894e8ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -12,9 +12,6 @@ #include "mac.h" #include "../trace.h" -static bool wed_enable = false; -module_param(wed_enable, bool, 0644); - static LIST_HEAD(hif_list); static DEFINE_SPINLOCK(hif_lock); static u32 hif_idx; @@ -65,10 +62,17 @@ static void mt7915_put_hif2(struct mt7915_hif *hif) static struct mt7915_hif *mt7915_pci_init_hif2(struct pci_dev *pdev) { + struct pci_dev *tmp_pdev; + hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL)) - return NULL; + + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7916, NULL); + if (!tmp_pdev) { + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x790a, NULL); + if (!tmp_pdev) + return NULL; + } + pci_dev_put(tmp_pdev); writel(hif_idx | MT_PCIE_RECOG_ID_SEM, pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); @@ -95,94 +99,6 @@ static int mt7915_pci_hif2_probe(struct pci_dev *pdev) return 0; } -#ifdef CONFIG_NET_MEDIATEK_SOC_WED -static int mt7915_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - struct mt7915_phy *phy; - int ret; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->mt76.token_lock); - - ret = wait_event_timeout(dev->mt76.tx_wait, - !dev->mt76.wed_token_count, HZ); - if (!ret) - return -EAGAIN; - - phy = &dev->phy; - mt76_set(dev, MT_AGG_ACR4(phy->band_idx), MT_AGG_ACR_PPDU_TXS2H); - - phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; - if (phy) - mt76_set(dev, MT_AGG_ACR4(phy->band_idx), - MT_AGG_ACR_PPDU_TXS2H); - - return 0; -} - -static void mt7915_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - struct mt7915_phy *phy; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = MT7915_TOKEN_SIZE; - spin_unlock_bh(&dev->mt76.token_lock); - - /* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than - * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. - */ - phy = &dev->phy; - mt76_clear(dev, MT_AGG_ACR4(phy->band_idx), MT_AGG_ACR_PPDU_TXS2H); - - phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL; - if (phy) - mt76_clear(dev, MT_AGG_ACR4(phy->band_idx), - MT_AGG_ACR_PPDU_TXS2H); -} -#endif - -static int -mt7915_pci_wed_init(struct mt7915_dev *dev, struct pci_dev *pdev, int *irq) -{ -#ifdef CONFIG_NET_MEDIATEK_SOC_WED - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - int ret; - - if (!wed_enable) - return 0; - - wed->wlan.pci_dev = pdev; - wed->wlan.wpdma_phys = pci_resource_start(pdev, 0) + - MT_WFDMA_EXT_CSR_BASE; - wed->wlan.nbuf = 4096; - wed->wlan.token_start = MT7915_TOKEN_SIZE - wed->wlan.nbuf; - wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt7915_wed_offload_enable; - wed->wlan.offload_disable = mt7915_wed_offload_disable; - - if (mtk_wed_device_attach(wed) != 0) - return 0; - - *irq = wed->irq; - dev->mt76.dma_dev = wed->dev; - - ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - return 1; -#else - return 0; -#endif -} - static int mt7915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -220,7 +136,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev, mt7915_wfsys_reset(dev); hif2 = mt7915_pci_init_hif2(pdev); - ret = mt7915_pci_wed_init(dev, pdev, &irq); + ret = mt7915_mmio_wed_init(dev, pdev, true, &irq); if (ret < 0) goto free_wed_or_irq_vector; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 5920e705835a..aca1b2f1e9e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -24,8 +24,26 @@ enum reg_rev { WFDMA_EXT_CSR_ADDR, CBTOP1_PHY_END, INFRA_MCU_ADDR_END, - FW_EXCEPTION_ADDR, + FW_ASSERT_STAT_ADDR, + FW_EXCEPT_TYPE_ADDR, + FW_EXCEPT_COUNT_ADDR, + FW_CIRQ_COUNT_ADDR, + FW_CIRQ_IDX_ADDR, + FW_CIRQ_LISR_ADDR, + FW_TASK_ID_ADDR, + FW_TASK_IDX_ADDR, + FW_TASK_QID1_ADDR, + FW_TASK_QID2_ADDR, + FW_TASK_START_ADDR, + FW_TASK_END_ADDR, + FW_TASK_SIZE_ADDR, + FW_LAST_MSG_ID_ADDR, + FW_EINT_INFO_ADDR, + FW_SCHED_INFO_ADDR, SWDEF_BASE_ADDR, + TXQ_WED_RING_BASE, + RXQ_WED_RING_BASE, + RXQ_WED_DATA_RING_BASE, __MT_REG_MAX, }; @@ -224,6 +242,14 @@ enum offs_rev { #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3) #define MT_DMA_DCR0_RXD_G5_EN BIT(23) +/* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */ +#define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000) +#define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs)) + +#define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008) +#define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30) +#define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24) + /* ETBF: band 0(0x820ea000), band 1(0x820fa000) */ #define MT_WF_ETBF_BASE(_band) ((_band) ? 0x820fa000 : 0x820ea000) #define MT_WF_ETBF(_band, ofs) (MT_WF_ETBF_BASE(_band) + (ofs)) @@ -523,8 +549,22 @@ enum offs_rev { #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) +#define MT_WF_RMAC_RSVD0(_band) MT_WF_RMAC(_band, 0x02e0) +#define MT_WF_RMAC_RSVD0_EIFS_CLR BIT(21) + #define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380) #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_OBSS_BACKOFF GENMASK(15, 0) +#define MT_WF_RMAC_MIB_ED_OFFSET GENMASK(20, 16) + +#define MT_WF_RMAC_MIB_AIRTIME1(_band) MT_WF_RMAC(_band, 0x0384) +#define MT_WF_RMAC_MIB_NONQOSD_BACKOFF GENMASK(31, 16) + +#define MT_WF_RMAC_MIB_AIRTIME3(_band) MT_WF_RMAC(_band, 0x038c) +#define MT_WF_RMAC_MIB_QOS01_BACKOFF GENMASK(31, 0) + +#define MT_WF_RMAC_MIB_AIRTIME4(_band) MT_WF_RMAC(_band, 0x0390) +#define MT_WF_RMAC_MIB_QOS23_BACKOFF GENMASK(31, 0) /* WFDMA0 */ #define MT_WFDMA0_BASE __REG(WFDMA0_ADDR) @@ -539,6 +579,8 @@ enum offs_rev { #define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1) #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_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) @@ -547,9 +589,14 @@ enum offs_rev { #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) + +#define MT_WFDMA0_EXT0_CFG MT_WFDMA0(0x2b0) +#define MT_WFDMA0_EXT0_RXWB_KEEP BIT(10) + #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) #define MT_WFDMA0_PRI_DLY_INT_CFG1 MT_WFDMA0(0x2f4) #define MT_WFDMA0_PRI_DLY_INT_CFG2 MT_WFDMA0(0x2f8) +#define MT_WPDMA_GLO_CFG MT_WFDMA0(0x208) /* WFDMA1 */ #define MT_WFDMA1_BASE 0xd5000 @@ -596,6 +643,7 @@ enum offs_rev { #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) +#define MT_INT_WED_SOURCE_CSR MT_WFDMA_EXT_CSR(0x200) #define MT_INT_WED_MASK_CSR MT_WFDMA_EXT_CSR(0x204) #define MT_WED_TX_RING_BASE MT_WFDMA_EXT_CSR(0x300) @@ -642,6 +690,10 @@ enum offs_rev { #define MT_TXQ_EXT_CTRL(q) (MT_Q_BASE(__TXQ(q)) + 0x600 + \ MT_TXQ_ID(q)* 0x4) +#define MT_TXQ_WED_RING_BASE __REG(TXQ_WED_RING_BASE) +#define MT_RXQ_WED_RING_BASE __REG(RXQ_WED_RING_BASE) +#define MT_RXQ_WED_DATA_RING_BASE __REG(RXQ_WED_DATA_RING_BASE) + #define MT_INT_SOURCE_CSR __REG(INT_SOURCE_CSR) #define MT_INT_MASK_CSR __REG(INT_MASK_CSR) @@ -660,6 +712,11 @@ enum offs_rev { #define MT_INT_RX_DONE_WA_MAIN_MT7916 BIT(2) #define MT_INT_RX_DONE_WA_EXT_MT7916 BIT(3) +#define MT_INT_WED_RX_DONE_BAND0_MT7916 BIT(18) +#define MT_INT_WED_RX_DONE_BAND1_MT7916 BIT(19) +#define MT_INT_WED_RX_DONE_WA_MAIN_MT7916 BIT(1) +#define MT_INT_WED_RX_DONE_WA_MT7916 BIT(17) + #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) @@ -683,6 +740,8 @@ enum offs_rev { #define MT_INT_TX_DONE_BAND0 BIT(30) #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_MCU_WA_MT7916 BIT(25) +#define MT_INT_WED_TX_DONE_BAND0 BIT(4) +#define MT_INT_WED_TX_DONE_BAND1 BIT(5) #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ @@ -696,6 +755,10 @@ enum offs_rev { #define MT_MCU_CMD_NORMAL_STATE BIT(5) #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1) +#define MT_MCU_CMD_WA_WDT BIT(31) +#define MT_MCU_CMD_WM_WDT BIT(30) +#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) + /* TOP RGU */ #define MT_TOP_RGU_BASE 0x18000000 #define MT_TOP_PWR_CTRL (MT_TOP_RGU_BASE + (0x0)) @@ -938,7 +1001,22 @@ enum offs_rev { #define MT_ADIE_TYPE_MASK BIT(1) /* FW MODE SYNC */ -#define MT_FW_EXCEPTION __REG(FW_EXCEPTION_ADDR) +#define MT_FW_ASSERT_STAT __REG(FW_ASSERT_STAT_ADDR) +#define MT_FW_EXCEPT_TYPE __REG(FW_EXCEPT_TYPE_ADDR) +#define MT_FW_EXCEPT_COUNT __REG(FW_EXCEPT_COUNT_ADDR) +#define MT_FW_CIRQ_COUNT __REG(FW_CIRQ_COUNT_ADDR) +#define MT_FW_CIRQ_IDX __REG(FW_CIRQ_IDX_ADDR) +#define MT_FW_CIRQ_LISR __REG(FW_CIRQ_LISR_ADDR) +#define MT_FW_TASK_ID __REG(FW_TASK_ID_ADDR) +#define MT_FW_TASK_IDX __REG(FW_TASK_IDX_ADDR) +#define MT_FW_TASK_QID1 __REG(FW_TASK_QID1_ADDR) +#define MT_FW_TASK_QID2 __REG(FW_TASK_QID2_ADDR) +#define MT_FW_TASK_START __REG(FW_TASK_START_ADDR) +#define MT_FW_TASK_END __REG(FW_TASK_END_ADDR) +#define MT_FW_TASK_SIZE __REG(FW_TASK_SIZE_ADDR) +#define MT_FW_LAST_MSG_ID __REG(FW_LAST_MSG_ID_ADDR) +#define MT_FW_EINT_INFO __REG(FW_EINT_INFO_ADDR) +#define MT_FW_SCHED_INFO __REG(FW_SCHED_INFO_ADDR) #define MT_SWDEF_BASE __REG(SWDEF_BASE_ADDR) @@ -1108,9 +1186,15 @@ enum offs_rev { #define MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY BIT(18) #define MT_WF_PHY_RXTD12_IRPI_SW_CLR BIT(29) +#define MT_WF_PHY_TPC_CTRL_STAT(_phy) MT_WF_PHY(0xe7a0 + ((_phy) << 16)) +#define MT_WF_PHY_TPC_CTRL_STAT_MT7916(_phy) MT_WF_PHY(0xe7a0 + ((_phy) << 20)) +#define MT_WF_PHY_TPC_POWER GENMASK(15, 8) + #define MT_MCU_WM_CIRQ_BASE 0x89010000 #define MT_MCU_WM_CIRQ(ofs) (MT_MCU_WM_CIRQ_BASE + (ofs)) #define MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x80) #define MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR MT_MCU_WM_CIRQ(0xc0) +#define MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x108) +#define MT_MCU_WM_CIRQ_EINT_SOFT_ADDR MT_MCU_WM_CIRQ(0x118) #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index c74afa746251..c06c56a0270d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1172,10 +1172,6 @@ static int mt7986_wmac_probe(struct platform_device *pdev) chip_id = (uintptr_t)of_device_get_match_data(&pdev->dev); - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - mem_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem_base)) { dev_err(&pdev->dev, "Failed to get memory resource\n"); @@ -1187,6 +1183,18 @@ static int mt7986_wmac_probe(struct platform_device *pdev) return PTR_ERR(dev); mdev = &dev->mt76; + ret = mt7915_mmio_wed_init(dev, pdev, false, &irq); + if (ret < 0) + goto free_device; + + if (!ret) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto free_device; + } + } + ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) @@ -1206,9 +1214,10 @@ static int mt7986_wmac_probe(struct platform_device *pdev) free_irq: devm_free_irq(mdev->dev, irq, dev); - free_device: - mt76_free_device(&dev->mt76); + if (mtk_wed_device_active(&mdev->mmio.wed)) + mtk_wed_device_detach(&mdev->mmio.wed); + mt76_free_device(mdev); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index efb9bb8231e2..0d76ae31b376 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -44,14 +44,14 @@ mt7915_tm_set_tx_power(struct mt7915_phy *phy) int ret; struct { u8 format_id; - u8 dbdc_idx; + u8 band_idx; s8 tx_power; u8 ant_idx; /* Only 0 is valid */ u8 center_chan; u8 rsv[3]; } __packed req = { .format_id = 0xf, - .dbdc_idx = phy != &dev->phy, + .band_idx = phy->mt76->band_idx, .center_chan = ieee80211_frequency_to_channel(freq), }; u8 *tx_power = NULL; @@ -77,7 +77,7 @@ mt7915_tm_set_freq_offset(struct mt7915_phy *phy, bool en, u32 val) struct mt7915_tm_cmd req = { .testmode_en = en, .param_idx = MCU_ATE_SET_FREQ_OFFSET, - .param.freq.band = phy != &dev->phy, + .param.freq.band = phy->mt76->band_idx, .param.freq.freq_offset = cpu_to_le32(val), }; @@ -111,7 +111,7 @@ mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en) .param_idx = MCU_ATE_SET_TRX, .param.trx.type = type, .param.trx.enable = en, - .param.trx.band = phy != &dev->phy, + .param.trx.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, @@ -126,7 +126,7 @@ mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid) .testmode_en = 1, .param_idx = MCU_ATE_CLEAN_TXQUEUE, .param.clean.wcid = wcid, - .param.clean.band = phy != &dev->phy, + .param.clean.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, @@ -144,7 +144,7 @@ mt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) .param.slot.sifs = sifs, .param.slot.rifs = 2, .param.slot.eifs = cpu_to_le16(60), - .param.slot.band = phy != &dev->phy, + .param.slot.band = phy->mt76->band_idx, }; return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, @@ -198,6 +198,7 @@ mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode) u8 sig_ext = (mode == MT76_TM_TX_MODE_CCK) ? 0 : 6; u8 slot_time = 9, sifs = TM_DEFAULT_SIFS; u8 aifsn = TM_MIN_AIFSN; + u8 band = phy->mt76->band_idx; u32 i2t_time, tr2t_time, txv_time; u16 cw = 0; @@ -232,14 +233,14 @@ mt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode) sifs = min_t(u32, ipg, TM_MAX_SIFS); } done: - txv_time = mt76_get_field(dev, MT_TMAC_ATCR(phy->band_idx), + txv_time = mt76_get_field(dev, MT_TMAC_ATCR(band), MT_TMAC_ATCR_TXV_TOUT); txv_time *= 50; /* normal clock time */ i2t_time = (slot_time * 1000 - txv_time - BBP_PROC_TIME) / 50; tr2t_time = (sifs * 1000 - txv_time - BBP_PROC_TIME) / 50; - mt76_set(dev, MT_TMAC_TRCR0(phy->band_idx), + mt76_set(dev, MT_TMAC_TRCR0(band), FIELD_PREP(MT_TMAC_TRCR0_TR2T_CHK, tr2t_time) | FIELD_PREP(MT_TMAC_TRCR0_I2T_CHK, i2t_time)); @@ -336,6 +337,7 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) int n_regs = ARRAY_SIZE(reg_backup_list); struct mt7915_dev *dev = phy->dev; u32 *b = phy->test.reg_backup; + u8 band = phy->mt76->band_idx; int i; REG_BAND_IDX(reg_backup_list[0], AGG_PCR0, 0); @@ -358,7 +360,7 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) if (phy->mt76->test.state == MT76_TM_STATE_OFF) { for (i = 0; i < n_regs; i++) - mt76_wr(dev, reg_backup_list[i].band[phy->band_idx], b[i]); + mt76_wr(dev, reg_backup_list[i].band[band], b[i]); return; } @@ -369,33 +371,33 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) phy->test.reg_backup = b; for (i = 0; i < n_regs; i++) - b[i] = mt76_rr(dev, reg_backup_list[i].band[phy->band_idx]); + b[i] = mt76_rr(dev, reg_backup_list[i].band[band]); } - mt76_clear(dev, MT_AGG_PCR0(phy->band_idx, 0), MT_AGG_PCR0_MM_PROT | + mt76_clear(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_MM_PROT | MT_AGG_PCR0_GF_PROT | MT_AGG_PCR0_ERP_PROT | MT_AGG_PCR0_VHT_PROT | MT_AGG_PCR0_BW20_PROT | MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT); - mt76_set(dev, MT_AGG_PCR0(phy->band_idx, 0), MT_AGG_PCR0_PTA_WIN_DIS); + mt76_set(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_PTA_WIN_DIS); - mt76_wr(dev, MT_AGG_PCR0(phy->band_idx, 1), MT_AGG_PCR1_RTS0_NUM_THRES | + mt76_wr(dev, MT_AGG_PCR0(band, 1), MT_AGG_PCR1_RTS0_NUM_THRES | MT_AGG_PCR1_RTS0_LEN_THRES); - mt76_clear(dev, MT_AGG_MRCR(phy->band_idx), MT_AGG_MRCR_BAR_CNT_LIMIT | + mt76_clear(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_BAR_CNT_LIMIT | MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT | MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT); - mt76_rmw(dev, MT_AGG_MRCR(phy->band_idx), MT_AGG_MRCR_RTS_FAIL_LIMIT | + mt76_rmw(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_RTS_FAIL_LIMIT | MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, FIELD_PREP(MT_AGG_MRCR_RTS_FAIL_LIMIT, 1) | FIELD_PREP(MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 1)); - mt76_wr(dev, MT_TMAC_TFCR0(phy->band_idx), 0); - mt76_clear(dev, MT_TMAC_TCR0(phy->band_idx), MT_TMAC_TCR0_TBTT_STOP_CTRL); + mt76_wr(dev, MT_TMAC_TFCR0(band), 0); + mt76_clear(dev, MT_TMAC_TCR0(band), MT_TMAC_TCR0_TBTT_STOP_CTRL); /* config rx filter for testmode rx */ - mt76_wr(dev, MT_WF_RFCR(phy->band_idx), 0xcf70a); - mt76_wr(dev, MT_WF_RFCR1(phy->band_idx), 0); + mt76_wr(dev, MT_WF_RFCR(band), 0xcf70a); + mt76_wr(dev, MT_WF_RFCR1(band), 0); } static void @@ -432,8 +434,6 @@ mt7915_tm_update_channel(struct mt7915_phy *phy) static void mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) { - static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0, - 9, 8, 6, 10, 16, 12, 18, 0}; struct mt76_testmode_data *td = &phy->mt76->test; struct mt7915_dev *dev = phy->dev; struct ieee80211_tx_info *info; @@ -447,15 +447,10 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) if (en) { mt7915_tm_update_channel(phy); - if (td->tx_spe_idx) { + if (td->tx_spe_idx) phy->test.spe_idx = td->tx_spe_idx; - } else { - u8 tx_ant = td->tx_antenna_mask; - - if (phy != &dev->phy) - tx_ant >>= dev->chainshift; - phy->test.spe_idx = spe_idx_map[tx_ant]; - } + else + phy->test.spe_idx = mt76_connac_spe_idx(td->tx_antenna_mask); } mt7915_tm_set_tam_arb(phy, en, @@ -495,7 +490,7 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) mt7915_tm_update_channel(phy); /* read-clear */ - mt76_rr(dev, MT_MIB_SDR3(phy != &dev->phy)); + mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); } } @@ -522,6 +517,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) struct mt76_testmode_data *td = &phy->mt76->test; u32 func_idx = en ? TX_CONT_START : TX_CONT_STOP; u8 rate_idx = td->tx_rate_idx, mode; + u8 band = phy->mt76->band_idx; u16 rateval; struct mt7915_tm_rf_test req = { .action = 1, @@ -533,7 +529,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) tx_cont->control_ch = chandef->chan->hw_value; tx_cont->center_ch = freq1; tx_cont->tx_ant = td->tx_antenna_mask; - tx_cont->band = phy != &dev->phy; + tx_cont->band = band; switch (chandef->width) { case NL80211_CHAN_WIDTH_40: @@ -565,7 +561,7 @@ mt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) } if (!en) { - req.op.rf.param.func_data = cpu_to_le32(phy != &dev->phy); + req.op.rf.param.func_data = cpu_to_le32(band); goto out; } @@ -696,7 +692,9 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, { struct mt76_testmode_data *td = &mphy->test; struct mt7915_phy *phy = mphy->priv; - u32 changed = 0; + struct mt7915_dev *dev = phy->dev; + u32 chainmask = mphy->chainmask, changed = 0; + bool ext_phy = phy != &dev->phy; int i; BUILD_BUG_ON(NUM_TM_CHANGED >= 32); @@ -705,7 +703,8 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, td->state == MT76_TM_STATE_OFF) return 0; - if (td->tx_antenna_mask & ~mphy->chainmask) + chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask; + if (td->tx_antenna_mask > chainmask) return -EINVAL; for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { @@ -771,11 +770,11 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) nla_nest_end(msg, rx); - cnt = mt76_rr(dev, MT_MIB_SDR3(phy->band_idx)); + cnt = mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); fcs_err = is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); - q = phy->band_idx ? MT_RXQ_BAND1 : MT_RXQ_MAIN; + q = phy->mt76->band_idx ? MT_RXQ_BAND1 : MT_RXQ_MAIN; mphy->test.rx_stats.packets[q] += fcs_err; mphy->test.rx_stats.fcs_error[q] += fcs_err; |