From 7014fe5358601d882b2809dea9fd1f6be409c943 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Wed, 9 Apr 2025 22:07:41 +0800 Subject: [PATCH 01/48] wifi: mt76: mt7996: add macros for pci device ids The chipset name (i.e., brand name) used by the driver may cause confusion with the PCI device ID when adding support for new chipsets. | Chipset name | PCI device id | |--------------|----------------| | 7996 | 0x7990, 0x7991 | | 7992 | 0x7992, 0x799a | | 7990 | 0x7993, 0x799b | To prevent confusion, replace the code that directly uses the device ID with macros. This is a preliminary patch to support mt7990 chipset. Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-2-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/coredump.c | 4 ++-- .../net/wireless/mediatek/mt76/mt7996/eeprom.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 6 +++--- .../net/wireless/mediatek/mt76/mt7996/mt7996.h | 9 +++++++-- drivers/net/wireless/mediatek/mt76/mt7996/pci.c | 15 ++++++++------- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c b/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c index ccab0d7b9be4..303d6e80a666 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c @@ -48,8 +48,8 @@ const struct mt7996_mem_region* mt7996_coredump_get_mem_layout(struct mt7996_dev *dev, u32 *num) { switch (mt76_chip(&dev->mt76)) { - case 0x7990: - case 0x7991: + case MT7996_DEVICE_ID: + case MT7996_DEVICE_ID_2: *num = ARRAY_SIZE(mt7996_mem_regions); return &mt7996_mem_regions[0]; default: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 53dfac02f8af..51b09956486b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -13,9 +13,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) u16 val = get_unaligned_le16(eeprom); switch (val) { - case 0x7990: + case MT7996_DEVICE_ID: return is_mt7996(&dev->mt76) ? 0 : -EINVAL; - case 0x7992: + case MT7992_DEVICE_ID: return is_mt7992(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; @@ -25,7 +25,7 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) static char *mt7996_eeprom_name(struct mt7996_dev *dev) { switch (mt76_chip(&dev->mt76)) { - case 0x7992: + case MT7992_DEVICE_ID: switch (dev->var.type) { case MT7992_VAR_TYPE_23: if (dev->var.fem == MT7996_FEM_INT) @@ -39,7 +39,7 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) return MT7992_EEPROM_DEFAULT_MIX; return MT7992_EEPROM_DEFAULT; } - case 0x7990: + case MT7996_DEVICE_ID: default: switch (dev->var.type) { case MT7996_VAR_TYPE_233: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 6b660424aedc..f017d30e1c49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -929,13 +929,13 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev) u8 var_type; switch (mt76_chip(&dev->mt76)) { - case 0x7990: + case MT7996_DEVICE_ID: if (val & MT_PAD_GPIO_2ADIE_TBTC) var_type = MT7996_VAR_TYPE_233; else var_type = MT7996_VAR_TYPE_444; break; - case 0x7992: + case MT7992_DEVICE_ID: if (val & MT_PAD_GPIO_ADIE_SINGLE) var_type = MT7992_VAR_TYPE_23; else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index ddd555942c73..81cc50ae55b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -13,7 +13,7 @@ #define fw_name(_dev, name, ...) ({ \ char *_fw; \ switch (mt76_chip(&(_dev)->mt76)) { \ - case 0x7992: \ + case MT7992_DEVICE_ID: \ switch ((_dev)->var.type) { \ case MT7992_VAR_TYPE_23: \ _fw = MT7992_##name##_23; \ @@ -22,7 +22,7 @@ _fw = MT7992_##name; \ } \ break; \ - case 0x7990: \ + case MT7996_DEVICE_ID: \ default: \ switch ((_dev)->var.type) { \ case MT7996_VAR_TYPE_233: \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 13b188e281bd..8b07883f45cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -350,7 +350,7 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + MT7996_RXQ_BAND0 * MT_RING_SIZE; - wed->wlan.id = 0x7991; + wed->wlan.id = MT7996_DEVICE_ID_2; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; } else { wed->wlan.hw_rro = dev->has_rro; /* default on */ @@ -443,13 +443,13 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, spin_lock_init(&dev->reg_lock); switch (device_id) { - case 0x7990: + case MT7996_DEVICE_ID: dev->reg.base = mt7996_reg_base; dev->reg.offs_rev = mt7996_offs; dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; - case 0x7992: + case MT7992_DEVICE_ID: dev->reg.base = mt7996_reg_base; dev->reg.offs_rev = mt7992_offs; dev->reg.map = mt7996_reg_map; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 43e646ed6094..bc22c3e12d94 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -30,6 +30,11 @@ #define MT7996_RX_MCU_RING_SIZE 512 #define MT7996_RX_MCU_RING_SIZE_WA 1024 +#define MT7996_DEVICE_ID 0x7990 +#define MT7996_DEVICE_ID_2 0x7991 +#define MT7992_DEVICE_ID 0x7992 +#define MT7992_DEVICE_ID_2 0x799a + #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin" #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin" #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" @@ -471,11 +476,11 @@ static inline bool mt7996_has_background_radar(struct mt7996_dev *dev) { switch (mt76_chip(&dev->mt76)) { - case 0x7990: + case MT7996_DEVICE_ID: if (dev->var.type == MT7996_VAR_TYPE_233) return false; break; - case 0x7992: + case MT7992_DEVICE_ID: if (dev->var.type == MT7992_VAR_TYPE_23) return false; break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 04056181368a..a4338367aaa1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -16,14 +16,14 @@ static DEFINE_SPINLOCK(hif_lock); static u32 hif_idx; static const struct pci_device_id mt7996_pci_device_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7992) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID) }, { }, }; static const struct pci_device_id mt7996_hif_device_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2) }, { }, }; @@ -63,8 +63,8 @@ static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) + if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL) && + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL)) return NULL; writel(hif_idx | MT_PCIE_RECOG_ID_SEM, @@ -121,7 +121,8 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt76_pci_disable_aspm(pdev); - if (id->device == 0x7991 || id->device == 0x799a) + if (id->device == MT7996_DEVICE_ID_2 || + id->device == MT7992_DEVICE_ID_2) return mt7996_pci_hif2_probe(pdev); dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], From a4e32b306a304dda5707281492d96b6dd7a91275 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:42 +0800 Subject: [PATCH 02/48] wifi: mt76: connac: add support to load firmware for mt7990 Add firmware download support. Note that mt7990 does not have WA and DSP firmwares. This is a preliminary patch to support mt7990 chipset. Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-3-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac.h | 7 +++++- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 3 +-- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 23 ++++++++++++------- .../wireless/mediatek/mt76/mt7996/mt7996.h | 12 ++++++++++ .../net/wireless/mediatek/mt76/mt7996/pci.c | 2 ++ 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 455979476d11..192dcc374a64 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -232,9 +232,14 @@ static inline bool is_mt7992(struct mt76_dev *dev) return mt76_chip(dev) == 0x7992; } +static inline bool is_mt7990(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7993; +} + static inline bool is_mt799x(struct mt76_dev *dev) { - return is_mt7996(dev) || is_mt7992(dev); + return is_mt7996(dev) || is_mt7992(dev) || is_mt7990(dev); } static inline bool is_mt7622(struct mt76_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index bafcf5a279e2..185ba57d416d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -67,8 +67,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_mt7921(dev) && addr == 0x900000) || (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || - (is_mt7996(dev) && addr == 0x900000) || - (is_mt7992(dev) && addr == 0x900000)) + (is_mt799x(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); else cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 81cc50ae55b0..1d12ccbacbcf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -22,6 +22,9 @@ _fw = MT7992_##name; \ } \ break; \ + case MT7990_DEVICE_ID: \ + _fw = MT7990_##name; \ + break; \ case MT7996_DEVICE_ID: \ default: \ switch ((_dev)->var.type) { \ @@ -265,7 +268,7 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd); txd = (__le32 *)skb_push(skb, txd_len); - if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state) && mt7996_has_wa(dev)) qid = MT_MCUQ_WA; else qid = MT_MCUQ_WM; @@ -3011,6 +3014,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev) if (ret) return ret; + if (!mt7996_has_wa(dev)) + return 0; + ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP), MT7996_RAM_TYPE_DSP); if (ret) @@ -3021,10 +3027,9 @@ static int mt7996_load_ram(struct mt7996_dev *dev) } static int -mt7996_firmware_state(struct mt7996_dev *dev, bool wa) +mt7996_firmware_state(struct mt7996_dev *dev, u8 fw_state) { - u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, - wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD); + u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE, fw_state); if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE, state, 1000)) { @@ -3056,13 +3061,14 @@ mt7996_mcu_restart(struct mt76_dev *dev) static int mt7996_load_firmware(struct mt7996_dev *dev) { + u8 fw_state; int ret; /* make sure fw is download state */ - if (mt7996_firmware_state(dev, false)) { + if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) { /* restart firmware once */ mt7996_mcu_restart(&dev->mt76); - ret = mt7996_firmware_state(dev, false); + ret = mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD); if (ret) { dev_err(dev->mt76.dev, "Firmware is not ready for download\n"); @@ -3078,7 +3084,8 @@ static int mt7996_load_firmware(struct mt7996_dev *dev) if (ret) return ret; - ret = mt7996_firmware_state(dev, true); + fw_state = mt7996_has_wa(dev) ? FW_STATE_RDY : FW_STATE_NORMAL_TRX; + ret = mt7996_firmware_state(dev, fw_state); if (ret) return ret; @@ -3248,7 +3255,7 @@ int mt7996_mcu_init(struct mt7996_dev *dev) void mt7996_mcu_exit(struct mt7996_dev *dev) { mt7996_mcu_restart(&dev->mt76); - if (mt7996_firmware_state(dev, false)) { + if (mt7996_firmware_state(dev, FW_STATE_FW_DOWNLOAD)) { dev_err(dev->mt76.dev, "Failed to exit mcu\n"); goto out; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index bc22c3e12d94..c03747ed6c70 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -34,6 +34,8 @@ #define MT7996_DEVICE_ID_2 0x7991 #define MT7992_DEVICE_ID 0x7992 #define MT7992_DEVICE_ID_2 0x799a +#define MT7990_DEVICE_ID 0x7993 +#define MT7990_DEVICE_ID_2 0x799b #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin" #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin" @@ -55,6 +57,11 @@ #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" +#define MT7990_FIRMWARE_WA "" +#define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" +#define MT7990_FIRMWARE_DSP "" +#define MT7990_ROM_PATCH "mediatek/mt7996/mt7990_rom_patch.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" #define MT7996_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7996_eeprom_2i5i6i.bin" #define MT7996_EEPROM_DEFAULT_233 "mediatek/mt7996/mt7996_eeprom_233.bin" @@ -709,6 +716,11 @@ static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); } +static inline bool mt7996_has_wa(struct mt7996_dev *dev) +{ + return !is_mt7990(&dev->mt76); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index a4338367aaa1..05248339a17b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -257,3 +257,5 @@ MODULE_FIRMWARE(MT7992_FIRMWARE_WA); MODULE_FIRMWARE(MT7992_FIRMWARE_WM); MODULE_FIRMWARE(MT7992_FIRMWARE_DSP); MODULE_FIRMWARE(MT7992_ROM_PATCH); +MODULE_FIRMWARE(MT7990_FIRMWARE_WM); +MODULE_FIRMWARE(MT7990_ROM_PATCH); From 76d13deb1aa9ac93c079dc5508d924ec01585558 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:43 +0800 Subject: [PATCH 03/48] wifi: mt76: mt7996: rework WA mcu command for mt7990 Since mt7990 lacks WA firmware, some WA commands are not supported or need to be refactored to use the SDO command. This is a preliminary patch to support mt7990 chipset. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-4-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 2 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 50 ++++++++++++++++--- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 6 +++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 43237e518373..8226b975f7e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1065,6 +1065,7 @@ enum { MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, + MCU_UNI_EVENT_SDO = 0x83, }; #define MCU_UNI_CMD_EVENT BIT(1) @@ -1297,6 +1298,7 @@ enum { MCU_UNI_CMD_PER_STA_INFO = 0x6d, MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, + MCU_UNI_CMD_SDO = 0x88, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 1d12ccbacbcf..a99e290faf1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -338,8 +338,12 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) { struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; __le32 args[3]; - } req = { + } __packed req = { .args = { cpu_to_le32(a1), cpu_to_le32(a2), @@ -347,7 +351,16 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) }, }; - return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false); + if (mt7996_has_wa(dev)) + return mt76_mcu_send_msg(&dev->mt76, cmd, &req.args, + sizeof(req.args), false); + + req.tag = cpu_to_le16(cmd == MCU_WA_PARAM_CMD(QUERY) ? UNI_CMD_SDO_QUERY : + UNI_CMD_SDO_SET); + req.len = cpu_to_le16(sizeof(req) - 4); + + return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO), &req, + sizeof(req), false); } static void @@ -3223,13 +3236,15 @@ int mt7996_mcu_init_firmware(struct mt7996_dev *dev) if (ret) return ret; - ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); - if (ret) - return ret; + if (mt7996_has_wa(dev)) { + ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0); + if (ret) + return ret; - ret = mt7996_mcu_set_mwds(dev, 1); - if (ret) - return ret; + ret = mt7996_mcu_set_mwds(dev, 1); + if (ret) + return ret; + } ret = mt7996_mcu_init_rx_airtime(dev); if (ret) @@ -4749,7 +4764,26 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode) mode > mt76_connac_lmac_mapping(IEEE80211_AC_VO)) return -EINVAL; + if (!mt7996_has_wa(dev)) { + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + u8 cp_mode; + u8 rsv[3]; + } __packed req = { + .tag = cpu_to_le16(UNI_CMD_SDO_CP_MODE), + .len = cpu_to_le16(sizeof(req) - 4), + .cp_mode = mode, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(SDO), + &req, sizeof(req), false); + } + cp_mode = cpu_to_le32(mode); + return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), &cp_mode, sizeof(cp_mode), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 2ab6a53bee86..8ef7d4baee90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -937,6 +937,12 @@ enum { UNI_CMD_SER_TRIGGER }; +enum { + UNI_CMD_SDO_SET = 1, + UNI_CMD_SDO_QUERY, + UNI_CMD_SDO_CP_MODE = 6, +}; + enum { MT7996_SEC_MODE_PLAIN, MT7996_SEC_MODE_AES, From 9ba4a76db9eb0596c3950933ec029d6b40c39cc6 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:44 +0800 Subject: [PATCH 04/48] wifi: mt76: mt7996: rework DMA configuration for mt7990 Modify DMA ring setting for mt7990. This is a preliminary patch to support mt7990 chipset. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-5-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 190 ++++++++++++------ .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 + .../net/wireless/mediatek/mt76/mt7996/regs.h | 4 +- 3 files changed, 134 insertions(+), 62 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 69a7d9b2e38b..fe8cc1d3f738 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -55,20 +55,32 @@ static void mt7996_dma_config(struct mt7996_dev *dev) /* rx queue */ RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM); + /* for mt7990, RX ring 1 is for SDO instead */ RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA); - - /* mt7996: band0 and band1, mt7992: band0 */ RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0); - RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN); + if (mt7996_has_wa(dev)) + RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, + MT7996_RXQ_MCU_WA_MAIN); - if (is_mt7996(&dev->mt76)) { - /* mt7996 band2 */ - RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); - RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); - } else { - /* mt7992 band1 */ - RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + switch (mt76_chip(&dev->mt76)) { + case MT7992_DEVICE_ID: RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + break; + case MT7990_DEVICE_ID: + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, + MT_INT_RX_TXFREE_BAND0_MT7990, MT7990_RXQ_TXFREE0); + if (dev->hif2) + RXQ_CONFIG(MT_RXQ_TXFREE_BAND1, WFDMA0, + MT_INT_RX_TXFREE_BAND1_MT7990, MT7990_RXQ_TXFREE1); + break; + case MT7996_DEVICE_ID: + default: + /* mt7996 band2 */ + RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); + break; } if (dev->has_rro) { @@ -104,9 +116,11 @@ static void mt7996_dma_config(struct mt7996_dev *dev) } /* mcu tx queue */ - MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); - MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA, MT7996_TXQ_MCU_WA); MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL); + MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); + if (mt7996_has_wa(dev)) + MCUQ_CONFIG(MT_MCUQ_WA, WFDMA0, MT_INT_TX_DONE_MCU_WA, + MT7996_TXQ_MCU_WA); } static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) @@ -121,43 +135,62 @@ static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { u16 base = 0; - u8 queue; + u8 queue, val; #define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2)); + /* Tx Command Rings */ + val = is_mt7996(&dev->mt76) ? 2 : 4; + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(val)); + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(val)); + if (mt7996_has_wa(dev)) + mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(val)); + + /* Tx Data Rings */ mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2)); + if (!is_mt7996(&dev->mt76) || dev->hif2) + mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8)); + if (is_mt7996(&dev->mt76)) + mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8)); - queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; - mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2)); + /* Rx Event Rings */ + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(val)); + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(val)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + /* Rx TxFreeDone From WA Rings */ + if (mt7996_has_wa(dev)) { + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(val)); + queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; + mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(val)); + } + /* Rx TxFreeDone From MAC Rings */ + val = is_mt7996(&dev->mt76) ? 4 : 8; + if (is_mt7990(&dev->mt76) || (is_mt7996(&dev->mt76) && dev->has_rro)) + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, PREFETCH(val)); + if (is_mt7990(&dev->mt76) && dev->hif2) + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND1) + ofs, PREFETCH(val)); + else if (is_mt7996(&dev->mt76) && dev->has_rro) + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, PREFETCH(val)); + + /* Rx Data Rings */ + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1; - mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10)); + /* Rx RRO Rings */ if (dev->has_rro) { - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, - PREFETCH(0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, - PREFETCH(0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, - PREFETCH(0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, - PREFETCH(0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, - PREFETCH(0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, - PREFETCH(0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, - PREFETCH(0x4)); + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_RRO_BAND0) + ofs, PREFETCH(0x10)); + queue = is_mt7996(&dev->mt76) ? MT_RXQ_RRO_BAND2 : MT_RXQ_RRO_BAND1; + mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10)); + + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, PREFETCH(val)); + if (is_mt7996(&dev->mt76)) { + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, + PREFETCH(val)); + mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, + PREFETCH(val)); + } } #undef PREFETCH @@ -269,6 +302,9 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) mtk_wed_device_start(wed, wed_irq_mask); } + if (!mt7996_has_wa(dev)) + irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) | + MT_INT_RX(MT_RXQ_BAND1_WA)); irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; mt7996_irq_enable(dev, irq_mask); @@ -474,12 +510,14 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* command to WA */ - ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, - MT_MCUQ_ID(MT_MCUQ_WA), - MT7996_TX_MCU_RING_SIZE, - MT_MCUQ_RING_BASE(MT_MCUQ_WA)); - if (ret) - return ret; + if (mt7996_has_wa(dev)) { + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, + MT_MCUQ_ID(MT_MCUQ_WA), + MT7996_TX_MCU_RING_SIZE, + MT_MCUQ_RING_BASE(MT_MCUQ_WA)); + if (ret) + return ret; + } /* firmware download */ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, @@ -498,7 +536,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* event from WA */ + /* event from WA, or SDO event for mt7990 */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT_RXQ_ID(MT_RXQ_MCU_WA), MT7996_RX_MCU_RING_SIZE_WA, @@ -527,13 +565,41 @@ int mt7996_dma_init(struct mt7996_dev *dev) dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; } - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], - MT_RXQ_ID(MT_RXQ_MAIN_WA), - MT7996_RX_MCU_RING_SIZE, - MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA)); - if (ret) - return ret; + if (mt7996_has_wa(dev)) { + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], + MT_RXQ_ID(MT_RXQ_MAIN_WA), + MT7996_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA)); + if (ret) + return ret; + } else { + if (mtk_wed_device_active(wed)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); + if (ret) + return ret; + } + + if (!mt7996_has_wa(dev) && dev->hif2) { + if (mtk_wed_device_active(wed)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND1].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND1].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND1], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND1), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND1)); + if (ret) + return ret; + } if (mt7996_band_valid(dev, MT_BAND2)) { /* rx data queue for mt7996 band2 */ @@ -573,14 +639,16 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for mt7992 band1 */ - rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], - MT_RXQ_ID(MT_RXQ_BAND1_WA), - MT7996_RX_MCU_RING_SIZE, - MT_RX_BUF_SIZE, - rx_base); - if (ret) - return ret; + if (mt7996_has_wa(dev)) { + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], + MT_RXQ_ID(MT_RXQ_BAND1_WA), + MT7996_RX_MCU_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + return ret; + } } if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index c03747ed6c70..148271fcd88f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -177,6 +177,8 @@ enum mt7996_rxq_id { MT7996_RXQ_TXFREE1 = 9, MT7996_RXQ_TXFREE2 = 7, MT7996_RXQ_RRO_IND = 0, + MT7990_RXQ_TXFREE0 = 6, + MT7990_RXQ_TXFREE1 = 7, }; struct mt7996_twt_flow { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 1876a968c92d..1981b6250f45 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -483,7 +483,7 @@ enum offs_rev { #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) -#define MT_RXQ_BAND1_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ +#define MT_RXQ_EXT_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ MT_RXQ_ID(q) * 0x4) #define MT_TXQ_EXT_CTRL(q) (MT_Q_BASE(__TXQ(q)) + 0x600 + \ MT_TXQ_ID(q) * 0x4) @@ -504,6 +504,8 @@ enum offs_rev { #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) +#define MT_INT_RX_TXFREE_BAND0_MT7990 BIT(14) +#define MT_INT_RX_TXFREE_BAND1_MT7990 BIT(15) #define MT_INT_RX_DONE_BAND2_EXT BIT(23) #define MT_INT_RX_TXFREE_EXT BIT(26) #define MT_INT_MCU_CMD BIT(29) From f6c87411d15fc4efadec944c7925e8f73c1972b2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:45 +0800 Subject: [PATCH 05/48] wifi: mt76: mt7996: rework register mapping for mt7990 Rework register offset and l1/l2/cbtop mapping for mt7990. This is a preliminary patch to support mt7990 chipset. Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: StanleyYP Wang Link: https://patch.msgid.link/20250409140750.724437-6-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 186 ++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7996/regs.h | 47 +++-- 2 files changed, 208 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 8b07883f45cc..51dd9a5f83cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -54,6 +54,17 @@ static const u32 mt7996_offs[] = { [MIB_BSCR7] = 0x9e8, [MIB_BSCR17] = 0xa10, [MIB_TRDR1] = 0xa28, + [HIF_REMAP_L1] = 0x24, + [HIF_REMAP_BASE_L1] = 0x130000, + [HIF_REMAP_L2] = 0x1b4, + [HIF_REMAP_BASE_L2] = 0x1000, + [CBTOP1_PHY_END] = 0x77ffffff, + [INFRA_MCU_END] = 0x7c3fffff, + [WTBLON_WDUCR] = 0x370, + [WTBL_UPDATE] = 0x380, + [WTBL_ITCR] = 0x3b0, + [WTBL_ITCR0] = 0x3b8, + [WTBL_ITCR1] = 0x3bc, }; static const u32 mt7992_offs[] = { @@ -80,6 +91,54 @@ static const u32 mt7992_offs[] = { [MIB_BSCR7] = 0xae4, [MIB_BSCR17] = 0xb0c, [MIB_TRDR1] = 0xb24, + [HIF_REMAP_L1] = 0x8, + [HIF_REMAP_BASE_L1] = 0x40000, + [HIF_REMAP_L2] = 0x1b4, + [HIF_REMAP_BASE_L2] = 0x1000, + [CBTOP1_PHY_END] = 0x77ffffff, + [INFRA_MCU_END] = 0x7c3fffff, + [WTBLON_WDUCR] = 0x370, + [WTBL_UPDATE] = 0x380, + [WTBL_ITCR] = 0x3b0, + [WTBL_ITCR0] = 0x3b8, + [WTBL_ITCR1] = 0x3bc, +}; + +static const u32 mt7990_offs[] = { + [MIB_RVSR0] = 0x800, + [MIB_RVSR1] = 0x804, + [MIB_BTSCR5] = 0x868, + [MIB_BTSCR6] = 0x878, + [MIB_RSCR1] = 0x890, + [MIB_RSCR27] = 0xa38, + [MIB_RSCR28] = 0xa3c, + [MIB_RSCR29] = 0xa40, + [MIB_RSCR30] = 0xa44, + [MIB_RSCR31] = 0xa48, + [MIB_RSCR33] = 0xa50, + [MIB_RSCR35] = 0xa58, + [MIB_RSCR36] = 0xa5c, + [MIB_BSCR0] = 0xbb8, + [MIB_BSCR1] = 0xbbc, + [MIB_BSCR2] = 0xbc0, + [MIB_BSCR3] = 0xbc4, + [MIB_BSCR4] = 0xbc8, + [MIB_BSCR5] = 0xbcc, + [MIB_BSCR6] = 0xbd0, + [MIB_BSCR7] = 0xbd4, + [MIB_BSCR17] = 0xbfc, + [MIB_TRDR1] = 0xc14, + [HIF_REMAP_L1] = 0x8, + [HIF_REMAP_BASE_L1] = 0x40000, + [HIF_REMAP_L2] = 0x1b8, + [HIF_REMAP_BASE_L2] = 0x110000, + [CBTOP1_PHY_END] = 0x7fffffff, + [INFRA_MCU_END] = 0x7cffffff, + [WTBLON_WDUCR] = 0x400, + [WTBL_UPDATE] = 0x410, + [WTBL_ITCR] = 0x440, + [WTBL_ITCR0] = 0x448, + [WTBL_ITCR1] = 0x44c, }; static const struct __map mt7996_reg_map[] = { @@ -135,14 +194,83 @@ static const struct __map mt7996_reg_map[] = { { 0x0, 0x0, 0x0 }, /* imply end of search */ }; +static const struct __map mt7990_reg_map[] = { + {0x54000000, 0x02000, 0x1000}, /* WFDMA_0 (PCIE0 MCU DMA0) */ + {0x55000000, 0x03000, 0x1000}, /* WFDMA_1 (PCIE0 MCU DMA1) */ + {0x56000000, 0x04000, 0x1000}, /* WFDMA_2 (Reserved) */ + {0x57000000, 0x05000, 0x1000}, /* WFDMA_3 (MCU wrap CR) */ + {0x58000000, 0x06000, 0x1000}, /* WFDMA_4 (PCIE1 MCU DMA0 (MEM_DMA)) */ + {0x59000000, 0x07000, 0x1000}, /* WFDMA_5 (PCIE1 MCU DMA1) */ + {0x820c0000, 0x08000, 0x4000}, /* WF_UMAC_TOP (PLE) */ + {0x820c8000, 0x0c000, 0x2000}, /* WF_UMAC_TOP (PSE) */ + {0x820cc000, 0x0e000, 0x2000}, /* WF_UMAC_TOP (PP) */ + {0x820e0000, 0x20000, 0x0400}, /* WF_LMAC_TOP BN0 (WF_CFG) */ + {0x820e1000, 0x20400, 0x0200}, /* WF_LMAC_TOP BN0 (WF_TRB) */ + {0x820e2000, 0x20800, 0x0400}, /* WF_LMAC_TOP BN0 (WF_AGG) */ + {0x820e3000, 0x20c00, 0x0400}, /* WF_LMAC_TOP BN0 (WF_ARB) */ + {0x820e4000, 0x21000, 0x0400}, /* WF_LMAC_TOP BN0 (WF_TMAC) */ + {0x820e5000, 0x21400, 0x0800}, /* WF_LMAC_TOP BN0 (WF_RMAC) */ + {0x820ce000, 0x21c00, 0x0200}, /* WF_LMAC_TOP (WF_SEC) */ + {0x820e7000, 0x21e00, 0x0200}, /* WF_LMAC_TOP BN0 (WF_DMA) */ + {0x820cf000, 0x22000, 0x1000}, /* WF_LMAC_TOP (WF_PF) */ + {0x820e9000, 0x23400, 0x0200}, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */ + {0x820ea000, 0x24000, 0x0200}, /* WF_LMAC_TOP BN0 (WF_ETBF) */ + {0x820eb000, 0x24200, 0x0400}, /* WF_LMAC_TOP BN0 (WF_LPON) */ + {0x820ec000, 0x24600, 0x0200}, /* WF_LMAC_TOP BN0 (WF_INT) */ + {0x820ed000, 0x24800, 0x0800}, /* WF_LMAC_TOP BN0 (WF_MIB) */ + {0x820ca000, 0x26000, 0x2000}, /* WF_LMAC_TOP BN0 (WF_MUCOP) */ + {0x820d0000, 0x30000, 0x10000}, /* WF_LMAC_TOP (WF_WTBLON) */ + {0x00400000, 0x80000, 0x10000}, /* WF_MCU_SYSRAM */ + {0x820f0000, 0xa0000, 0x0400}, /* WF_LMAC_TOP BN1 (WF_CFG) */ + {0x820f1000, 0xa0600, 0x0200}, /* WF_LMAC_TOP BN1 (WF_TRB) */ + {0x820f2000, 0xa0800, 0x0400}, /* WF_LMAC_TOP BN1 (WF_AGG) */ + {0x820f3000, 0xa0c00, 0x0400}, /* WF_LMAC_TOP BN1 (WF_ARB) */ + {0x820f4000, 0xa1000, 0x0400}, /* WF_LMAC_TOP BN1 (WF_TMAC) */ + {0x820f5000, 0xa1400, 0x0800}, /* WF_LMAC_TOP BN1 (WF_RMAC) */ + {0x820f7000, 0xa1e00, 0x0200}, /* WF_LMAC_TOP BN1 (WF_DMA) */ + {0x820f9000, 0xa3400, 0x0200}, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */ + {0x820fa000, 0xa4000, 0x0200}, /* WF_LMAC_TOP BN1 (WF_ETBF) */ + {0x820fb000, 0xa4200, 0x0400}, /* WF_LMAC_TOP BN1 (WF_LPON) */ + {0x820fc000, 0xa4600, 0x0200}, /* WF_LMAC_TOP BN1 (WF_INT) */ + {0x820fd000, 0xa4800, 0x0800}, /* WF_LMAC_TOP BN1 (WF_MIB) */ + {0x820cc000, 0xa5000, 0x2000}, /* WF_LMAC_TOP BN1 (WF_MUCOP) */ + {0x820c4000, 0xa8000, 0x4000}, /* WF_LMAC_TOP (WF_UWTBL) */ + {0x81030000, 0xae000, 0x100}, /* WFSYS_AON part 1 */ + {0x81031000, 0xae100, 0x100}, /* WFSYS_AON part 2 */ + {0x81032000, 0xae200, 0x100}, /* WFSYS_AON part 3 */ + {0x81033000, 0xae300, 0x100}, /* WFSYS_AON part 4 */ + {0x81034000, 0xae400, 0x100}, /* WFSYS_AON part 5 */ + {0x80020000, 0xb0000, 0x10000}, /* WF_TOP_MISC_OFF */ + {0x81020000, 0xc0000, 0x10000}, /* WF_TOP_MISC_ON */ + {0x81040000, 0x120000, 0x1000}, /* WF_MCU_CFG_ON */ + {0x81050000, 0x121000, 0x1000}, /* WF_MCU_EINT */ + {0x81060000, 0x122000, 0x1000}, /* WF_MCU_GPT */ + {0x81070000, 0x123000, 0x1000}, /* WF_MCU_WDT */ + {0x80010000, 0x124000, 0x1000}, /* WF_AXIDMA */ + {0x7c020000, 0xd0000, 0x10000}, /* CONN_INFRA, wfdma for from CODA flow use */ + {0x7c060000, 0xe0000, 0x10000}, /* CONN_INFRA, conn_host_csr_top for from CODA flow use */ + {0x20020000, 0xd0000, 0x10000}, /* CONN_INFRA, wfdma */ + {0x20060000, 0xe0000, 0x10000}, /* CONN_INFRA, conn_host_csr_top */ + {0x7c000000, 0xf0000, 0x10000}, /* CONN_INFRA */ + {0x70020000, 0x1f0000, 0x9000}, /* PCIE remapping (AP2CONN) */ + {0x0, 0x0, 0x0}, /* imply end of search */ +}; + static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) { u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr); u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr); + u32 l1_mask, val; - dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, - MT_HIF_REMAP_L1_MASK, - FIELD_PREP(MT_HIF_REMAP_L1_MASK, base)); + if (is_mt7996(&dev->mt76)) { + l1_mask = MT_HIF_REMAP_L1_MASK_7996; + val = FIELD_PREP(MT_HIF_REMAP_L1_MASK_7996, base); + } else { + l1_mask = MT_HIF_REMAP_L1_MASK; + val = FIELD_PREP(MT_HIF_REMAP_L1_MASK, base); + } + + dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1, l1_mask, val); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1); @@ -151,18 +279,41 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr) static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr) { - u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); - u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); + u32 offset, base, l2_mask, val; - dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, - MT_HIF_REMAP_L2_MASK, - FIELD_PREP(MT_HIF_REMAP_L2_MASK, base)); + if (is_mt7990(&dev->mt76)) { + offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET_7990, addr); + base = FIELD_GET(MT_HIF_REMAP_L2_BASE_7990, addr); + l2_mask = MT_HIF_REMAP_L2_MASK_7990; + val = FIELD_PREP(MT_HIF_REMAP_L2_MASK_7990, base); + } else { + offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr); + base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr); + l2_mask = MT_HIF_REMAP_L2_MASK; + val = FIELD_PREP(MT_HIF_REMAP_L2_MASK, base); + } + + dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2, l2_mask, val); /* use read to push write */ dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2); return MT_HIF_REMAP_BASE_L2 + offset; } +static u32 mt7996_reg_map_cbtop(struct mt7996_dev *dev, u32 addr) +{ + u32 offset = FIELD_GET(MT_HIF_REMAP_CBTOP_OFFSET, addr); + u32 base = FIELD_GET(MT_HIF_REMAP_CBTOP_BASE, addr); + + dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_CBTOP, + MT_HIF_REMAP_CBTOP_MASK, + FIELD_PREP(MT_HIF_REMAP_CBTOP_MASK, base)); + /* use read to push write */ + dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_CBTOP); + + return MT_HIF_REMAP_BASE_CBTOP + offset; +} + static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) { int i; @@ -193,17 +344,20 @@ static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) (addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END)) return mt7996_reg_map_l1(dev, addr); - if (dev_is_pci(dev->mt76.dev) && - ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || - addr >= MT_CBTOP2_PHY_START)) - return mt7996_reg_map_l1(dev, addr); - /* CONN_INFRA: covert to phyiscal addr and use layer 1 remap */ if (addr >= MT_INFRA_MCU_START && addr <= MT_INFRA_MCU_END) { addr = addr - MT_INFRA_MCU_START + MT_INFRA_BASE; return mt7996_reg_map_l1(dev, addr); } + if (dev_is_pci(dev->mt76.dev) && + ((addr >= MT_CBTOP1_PHY_START && addr <= MT_CBTOP1_PHY_END) || + addr >= MT_CBTOP2_PHY_START)) { + if (is_mt7990(&dev->mt76)) + return mt7996_reg_map_cbtop(dev, addr); + return mt7996_reg_map_l1(dev, addr); + } + return mt7996_reg_map_l2(dev, addr); } @@ -455,6 +609,12 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; + case MT7990_DEVICE_ID: + dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7990_offs; + dev->reg.map = mt7990_reg_map; + dev->reg.map_size = ARRAY_SIZE(mt7990_reg_map); + break; default: return -EINVAL; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 1981b6250f45..e942c0058731 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -64,6 +64,17 @@ enum offs_rev { MIB_BSCR7, MIB_BSCR17, MIB_TRDR1, + HIF_REMAP_L1, + HIF_REMAP_BASE_L1, + HIF_REMAP_L2, + HIF_REMAP_BASE_L2, + CBTOP1_PHY_END, + INFRA_MCU_END, + WTBLON_WDUCR, + WTBL_UPDATE, + WTBL_ITCR, + WTBL_ITCR0, + WTBL_ITCR1, __MT_OFFS_MAX, }; @@ -291,19 +302,19 @@ enum offs_rev { /* WTBLON TOP */ #define MT_WTBLON_TOP_BASE 0x820d4000 #define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs)) -#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x370) +#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(__OFFS(WTBLON_WDUCR)) #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(4, 0) -#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x380) +#define MT_WTBL_UPDATE MT_WTBLON_TOP(__OFFS(WTBL_UPDATE)) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(11, 0) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(14) #define MT_WTBL_UPDATE_BUSY BIT(31) -#define MT_WTBL_ITCR MT_WTBLON_TOP(0x3b0) +#define MT_WTBL_ITCR MT_WTBLON_TOP(__OFFS(WTBL_ITCR)) #define MT_WTBL_ITCR_WR BIT(16) #define MT_WTBL_ITCR_EXEC BIT(31) -#define MT_WTBL_ITDR0 MT_WTBLON_TOP(0x3b8) -#define MT_WTBL_ITDR1 MT_WTBLON_TOP(0x3bc) +#define MT_WTBL_ITDR0 MT_WTBLON_TOP(__OFFS(WTBL_ITCR0)) +#define MT_WTBL_ITDR1 MT_WTBLON_TOP(__OFFS(WTBL_ITCR1)) #define MT_WTBL_SPE_IDX_SEL BIT(6) /* WTBL */ @@ -578,27 +589,39 @@ enum offs_rev { #define MT_MCU_CMD_WDT_MASK GENMASK(31, 30) /* l1/l2 remap */ -#define MT_HIF_REMAP_L1 0x155024 -#define MT_HIF_REMAP_L1_MASK GENMASK(31, 16) +#define CONN_BUS_CR_VON_BASE 0x155000 +#define MT_HIF_REMAP_L1 (CONN_BUS_CR_VON_BASE + __OFFS(HIF_REMAP_L1)) +#define MT_HIF_REMAP_L1_MASK_7996 GENMASK(31, 16) +#define MT_HIF_REMAP_L1_MASK GENMASK(15, 0) #define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0) #define MT_HIF_REMAP_L1_BASE GENMASK(31, 16) -#define MT_HIF_REMAP_BASE_L1 0x130000 +#define MT_HIF_REMAP_BASE_L1 __OFFS(HIF_REMAP_BASE_L1) -#define MT_HIF_REMAP_L2 0x1b4 +#define MT_HIF_REMAP_L2 __OFFS(HIF_REMAP_L2) #define MT_HIF_REMAP_L2_MASK GENMASK(19, 0) #define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0) #define MT_HIF_REMAP_L2_BASE GENMASK(31, 12) -#define MT_HIF_REMAP_BASE_L2 0x1000 +#define MT_HIF_REMAP_L2_MASK_7990 GENMASK(15, 0) +#define MT_HIF_REMAP_L2_OFFSET_7990 GENMASK(15, 0) +#define MT_HIF_REMAP_L2_BASE_7990 GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_L2 __OFFS(HIF_REMAP_BASE_L2) + +/* for mt7990 only */ +#define MT_HIF_REMAP_CBTOP 0x1f6554 +#define MT_HIF_REMAP_CBTOP_MASK GENMASK(15, 0) +#define MT_HIF_REMAP_CBTOP_OFFSET GENMASK(15, 0) +#define MT_HIF_REMAP_CBTOP_BASE GENMASK(31, 16) +#define MT_HIF_REMAP_BASE_CBTOP 0x1c0000 #define MT_INFRA_BASE 0x18000000 #define MT_WFSYS0_PHY_START 0x18400000 #define MT_WFSYS1_PHY_START 0x18800000 #define MT_WFSYS1_PHY_END 0x18bfffff #define MT_CBTOP1_PHY_START 0x70000000 -#define MT_CBTOP1_PHY_END 0x77ffffff +#define MT_CBTOP1_PHY_END __OFFS(CBTOP1_PHY_END) #define MT_CBTOP2_PHY_START 0xf0000000 #define MT_INFRA_MCU_START 0x7c000000 -#define MT_INFRA_MCU_END 0x7c3fffff +#define MT_INFRA_MCU_END __OFFS(INFRA_MCU_END) /* FW MODE SYNC */ #define MT_FW_ASSERT_CNT 0x02208274 From 7316813a9cb3a521874c56041e1a0d1e2c7f3402 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:46 +0800 Subject: [PATCH 06/48] wifi: mt76: mt7996: add eeprom support for mt7990 Add eeprom definition and default bin file for mt7990. This is a preliminary patch to support mt7990 chipset. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-7-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 51b09956486b..6f3eb053ef02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -17,6 +17,8 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) return is_mt7996(&dev->mt76) ? 0 : -EINVAL; case MT7992_DEVICE_ID: return is_mt7992(&dev->mt76) ? 0 : -EINVAL; + case MT7990_DEVICE_ID: + return is_mt7990(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; } @@ -39,6 +41,10 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) return MT7992_EEPROM_DEFAULT_MIX; return MT7992_EEPROM_DEFAULT; } + case MT7990_DEVICE_ID: + if (dev->var.fem == MT7996_FEM_INT) + return MT7990_EEPROM_DEFAULT_INT; + return MT7990_EEPROM_DEFAULT; case MT7996_DEVICE_ID: default: switch (dev->var.type) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index f017d30e1c49..a4c2986fcffd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -943,6 +943,9 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev) else return -EINVAL; break; + case MT7990_DEVICE_ID: + var_type = MT7990_VAR_TYPE_23; + break; default: return -EINVAL; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 148271fcd88f..2dd33f303a06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -73,6 +73,9 @@ #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" #define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" +#define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" +#define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" + #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 @@ -143,6 +146,10 @@ enum mt7992_var_type { MT7992_VAR_TYPE_23, }; +enum mt7990_var_type { + MT7990_VAR_TYPE_23, +}; + enum mt7996_fem_type { MT7996_FEM_EXT, MT7996_FEM_INT, From 6d72f267c6812abb59fec773ac74a195bca11a66 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:47 +0800 Subject: [PATCH 07/48] wifi: mt76: mt7996: adjust HW capabilities for mt7990 This is a preliminary patch to support mt7990 chipset. Co-developed-by: Howard Hsu Signed-off-by: Howard Hsu Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Peter Chiu Link: https://patch.msgid.link/20250409140750.724437-8-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 9 ++++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index a4c2986fcffd..9a8b10c50f72 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -440,6 +440,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) hw->queues = 4; hw->max_rx_aggregation_subframes = max_subframes; hw->max_tx_aggregation_subframes = max_subframes; + if (is_mt7990(mdev) && dev->has_eht) + hw->max_tx_aggregation_subframes = 512; + hw->netdev_features = NETIF_F_RXCSUM; if (mtk_wed_device_active(wed)) hw->netdev_features |= NETIF_F_HW_TC; @@ -1064,10 +1067,10 @@ void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy) *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; - if (is_mt7996(phy->mt76->dev)) - *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 3); - else + if (is_mt7992(phy->mt76->dev)) *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 4); + else + *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 3); *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK | IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 2dd33f303a06..92b01ed82e7e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -14,7 +14,7 @@ #define MT7996_MAX_RADIOS 3 #define MT7996_MAX_INTERFACES 19 /* per-band */ #define MT7996_MAX_WMM_SETS 4 -#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64) +#define MT7996_WTBL_BMC_SIZE (is_mt7996(&dev->mt76) ? 64 : 32) #define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1) #define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \ mt7996_max_interface_num(dev)) @@ -482,7 +482,7 @@ mt7996_phy3(struct mt7996_dev *dev) static inline bool mt7996_band_valid(struct mt7996_dev *dev, u8 band) { - if (is_mt7992(&dev->mt76)) + if (!is_mt7996(&dev->mt76)) return band <= MT_BAND1; return band <= MT_BAND2; From b7ddeb9cc43949de58b6a422162db0a196c5d383 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Wed, 9 Apr 2025 22:07:48 +0800 Subject: [PATCH 08/48] wifi: mt76: connac: rework TX descriptor and TX free for mt7990 Adjust the TX descriptor and TX free for updated hardware fields. This is a preliminary patch to support mt7990 chipset. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Co-developed-by: Benjamin Lin Signed-off-by: Benjamin Lin Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-9-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac3_mac.h | 1 + .../net/wireless/mediatek/mt76/mt7996/mac.c | 42 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 487ad716f872..1013cad57a7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -273,6 +273,7 @@ enum tx_frag_idx { #define MT_TXD6_TX_RATE GENMASK(21, 16) #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) +#define MT_TXD6_TID_ADDBA GENMASK(10, 8) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) #define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index d89c06f47997..ab9ab4887818 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -789,10 +789,13 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, if (ieee80211_is_action(fc) && mgmt->u.action.category == WLAN_CATEGORY_BACK && - mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) + mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { + if (is_mt7990(&dev->mt76)) + txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TID_ADDBA, tid)); tid = MT_TX_ADDBA; - else if (ieee80211_is_mgmt(hdr->frame_control)) + } else if (ieee80211_is_mgmt(hdr->frame_control)) { tid = MT_TX_NORMAL; + } val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) | FIELD_PREP(MT_TXD1_HDR_INFO, @@ -987,12 +990,32 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, } } +static bool +mt7996_tx_use_mgmt(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (ieee80211_is_mgmt(hdr->frame_control)) + return true; + + /* for SDO to bypass specific data frame */ + if (!mt7996_has_wa(dev)) { + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return true; + + if (ieee80211_has_a4(hdr->frame_control) && + !ieee80211_is_data_present(hdr->frame_control)) + return true; + } + + return false; +} + int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data; struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; @@ -1041,7 +1064,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!key) txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); - if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control)) + if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb)) txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); if (vif) { @@ -1179,6 +1202,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) void *end = data + len; bool wake = false; u16 total, count = 0; + u8 ver; /* clean DMA queues and unmap buffers first */ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false); @@ -1192,7 +1216,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false); } - if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 5)) + ver = le32_get_bits(tx_free[1], MT_TXFREE1_VER); + if (WARN_ON_ONCE(ver < 5)) return; total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT); @@ -1214,11 +1239,16 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) wcid = rcu_dereference(dev->mt76.wcid[idx]); sta = wcid_to_sta(wcid); if (!sta) - continue; + goto next; msta_link = container_of(wcid, struct mt7996_sta_link, wcid); mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid); +next: + /* ver 7 has a new DW with pair = 1, skip it */ + if (ver == 7 && ((void *)(cur_info + 1) < end) && + (le32_to_cpu(*(cur_info + 1)) & MT_TXFREE_INFO_PAIR)) + cur_info++; continue; } else if (info & MT_TXFREE_INFO_HEADER) { u32 tx_retries = 0, tx_failed = 0; From 14d3990eb7c37e4f3273f9130bd964a6511e4ebd Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:49 +0800 Subject: [PATCH 09/48] wifi: mt76: mt7996: rework background radar check for mt7990 The MT7990 comes in 2T2R and 3T3R variants, with only the 2T2R supporting background radar. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-10-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/eeprom.c | 27 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/init.c | 2 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 20 +------------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 6f3eb053ef02..7bfd19ed9594 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -376,3 +376,30 @@ s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band) return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta; } + +bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev) +{ + switch (mt76_chip(&dev->mt76)) { + case MT7996_DEVICE_ID: + if (dev->var.type == MT7996_VAR_TYPE_233) + return false; + break; + case MT7992_DEVICE_ID: + if (dev->var.type == MT7992_VAR_TYPE_23) + return false; + break; + case MT7990_DEVICE_ID: { + u8 path, rx_path, nss, *eeprom = dev->mt76.eeprom.data; + + mt7996_eeprom_parse_stream(eeprom, MT_BAND1, &path, &rx_path, &nss); + /* Disable background radar capability in 3T3R */ + if (path == 3 || rx_path == 3) + return false; + break; + } + default: + return false; + } + + return true; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 9a8b10c50f72..e26451add9a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -475,7 +475,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); - if (mt7996_has_background_radar(dev) && + if (mt7996_eeprom_has_background_radar(dev) && (!mdev->dev->of_node || !of_property_read_bool(mdev->dev->of_node, "mediatek,disable-radar-background"))) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 92b01ed82e7e..a45cd3ff61a0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -488,25 +488,6 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band) return band <= MT_BAND2; } -static inline bool -mt7996_has_background_radar(struct mt7996_dev *dev) -{ - switch (mt76_chip(&dev->mt76)) { - case MT7996_DEVICE_ID: - if (dev->var.type == MT7996_VAR_TYPE_233) - return false; - break; - case MT7992_DEVICE_ID: - if (dev->var.type == MT7992_VAR_TYPE_23) - return false; - break; - default: - return false; - } - - return true; -} - static inline struct mt7996_phy * mt7996_band_phy(struct mt7996_dev *dev, enum nl80211_band band) { @@ -570,6 +551,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy); int mt7996_eeprom_get_target_power(struct mt7996_dev *dev, struct ieee80211_channel *chan); s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band); +bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev); int mt7996_dma_init(struct mt7996_dev *dev); void mt7996_dma_reset(struct mt7996_dev *dev, bool force); void mt7996_dma_prefetch(struct mt7996_dev *dev); From 8d63161d2e92d124bd59e1c42904b7ed256ceb94 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:50 +0800 Subject: [PATCH 10/48] wifi: mt76: mt7996: add PCI device id for mt7990 Add PCI device IDs to enable support for mt7990 chipsets. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250409140750.724437-11-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/pci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 05248339a17b..19e99bc1c6c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -18,12 +18,14 @@ static u32 hif_idx; static const struct pci_device_id mt7996_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID) }, { }, }; static const struct pci_device_id mt7996_hif_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2) }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2) }, { }, }; @@ -64,7 +66,8 @@ static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) hif_idx++; if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL)) + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL) && + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL)) return NULL; writel(hif_idx | MT_PCIE_RECOG_ID_SEM, @@ -122,7 +125,8 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt76_pci_disable_aspm(pdev); if (id->device == MT7996_DEVICE_ID_2 || - id->device == MT7992_DEVICE_ID_2) + id->device == MT7992_DEVICE_ID_2 || + id->device == MT7990_DEVICE_ID_2) return mt7996_pci_hif2_probe(pdev); dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], From 888208d1ccc41bebe97744445787183b17bb3ea4 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:09 +0800 Subject: [PATCH 11/48] wifi: mt76: mt7915: set correct background radar capability Some of the variants do not support background radar, so add a helper to report background radar capability. For mt7916, only the variant of 5G 2T2R + 1R supports background radar. Signed-off-by: StanleyYP Wang Reviewed-by: Shayne Chen Link: https://patch.msgid.link/20250320015909.3948612-1-StanleyYP.Wang@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 5 +++ .../wireless/mediatek/mt76/mt7915/eeprom.c | 33 ++++++++++++++++++- .../wireless/mediatek/mt76/mt7915/eeprom.h | 1 + .../net/wireless/mediatek/mt76/mt7915/init.c | 7 ++-- .../net/wireless/mediatek/mt76/mt7915/mcu.c | 8 +++-- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 +- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 192e8eff970b..0384e9f519fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -445,6 +445,11 @@ mt7915_rdd_monitor(struct seq_file *s, void *data) mutex_lock(&dev->mt76.mutex); + if (!mt7915_eeprom_has_background_radar(dev)) { + seq_puts(s, "no background radar capability\n"); + goto out; + } + if (!cfg80211_chandef_valid(chandef)) { ret = -EINVAL; goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 928e0b07a9bf..c0f3402d30bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -147,7 +147,7 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev) /* read eeprom data from efuse */ block_num = DIV_ROUND_UP(eeprom_size, eeprom_blk_size); for (i = 0; i < block_num; i++) { - ret = mt7915_mcu_get_eeprom(dev, i * eeprom_blk_size); + ret = mt7915_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL); if (ret < 0) return ret; } @@ -361,6 +361,37 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band) return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta; } +bool +mt7915_eeprom_has_background_radar(struct mt7915_dev *dev) +{ + u8 val, buf[MT7915_EEPROM_BLOCK_SIZE]; + u8 band_sel, tx_path, rx_path; + int offs = MT_EE_WIFI_CONF + 1; + + switch (mt76_chip(&dev->mt76)) { + case 0x7915: + return true; + case 0x7906: + /* read efuse to check background radar capability */ + if (mt7915_mcu_get_eeprom(dev, offs, buf)) + break; + + val = buf[offs % MT7915_EEPROM_BLOCK_SIZE]; + band_sel = u8_get_bits(val, MT_EE_WIFI_CONF0_BAND_SEL); + tx_path = u8_get_bits(val, MT_EE_WIFI_CONF0_TX_PATH); + rx_path = u8_get_bits(val, MT_EE_WIFI_CONF0_RX_PATH); + + return (band_sel == MT_EE_V2_BAND_SEL_5GHZ && + tx_path == rx_path && rx_path == 2); + case 0x7981: + case 0x7986: + default: + break; + } + + return false; +} + const u8 mt7915_sku_group_len[] = { [SKU_CCK] = 4, [SKU_OFDM] = 8, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 509fb43d8a68..31aec0f40232 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -55,6 +55,7 @@ enum mt7915_eeprom_field { #define MT_EE_CAL_DPD_SIZE_V2_7981 (102 * MT_EE_CAL_UNIT) /* no 6g dpd data */ #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) +#define MT_EE_WIFI_CONF0_RX_PATH GENMASK(5, 3) #define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6) #define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6) #define MT_EE_WIFI_CONF_STREAM_NUM GENMASK(7, 5) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index bee4beabc4eb..57d5be94624b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -392,9 +392,10 @@ mt7915_init_wiphy(struct mt7915_phy *phy) 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, - "mediatek,disable-radar-background")) + if (mt7915_eeprom_has_background_radar(phy->dev) && + (!mdev->dev->of_node || + !of_property_read_bool(mdev->dev->of_node, + "mediatek,disable-radar-background"))) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RADAR_BACKGROUND); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 3643c72bb68d..c9a4c35001dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -2859,7 +2859,7 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) &req, sizeof(req), true); } -int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf) { struct mt7915_mcu_eeprom_info req = { .addr = cpu_to_le32(round_down(offset, @@ -2867,8 +2867,8 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) }; struct mt7915_mcu_eeprom_info *res; struct sk_buff *skb; + u8 *buf = read_buf; int ret; - u8 *buf; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS), @@ -2877,8 +2877,10 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset) return ret; res = (struct mt7915_mcu_eeprom_info *)skb->data; - buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); + if (!buf) + buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); + dev_kfree_skb(skb); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 533939f2b7ed..66bb94192297 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -425,6 +425,7 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, struct ieee80211_channel *chan, u8 chain_idx); s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band); +bool mt7915_eeprom_has_background_radar(struct mt7915_dev *dev); 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); @@ -473,7 +474,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_sta *sta, void *data, u32 field); int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); -int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); +int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf); int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num); int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, bool hdr_trans); From 758e0cc3a4928c550820171ce8bc9176ecac6386 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:18 +0800 Subject: [PATCH 12/48] wifi: mt76: mt7915: rework radar HWRDD idx The definition of MT_RX_SEL (for rdd_rx_sel) is mixed with the definition of HWRDD idx. For example, MT_RX_SEL2 is for background HWRDD idx, not an option of rdd_rx_sel. Therefore, add mt7915_get_rdd_idx as a helper function to get the HWRDD idx for each variants. Additionally, remove some parts of the code inherited from the legacy chips. For instance, 1. rdd_state is used for single-band-dual-HWRDD chips (for 80+80), especially the 76xx series. 2. rdd_rx_sel is also used for single-band-dual-HWRDD chips rx_sel = 0 => RDD0 for WF0, RDD1 for WF2 rx_sel = 1 => RDD0 for WF1, RDD1 for WF3 Chip Variants | 5G rdd idx(=bandidx)| Background rdd idx -------------------------------|---------------------|------------------- MT7915A | 0 | 2 MT7915D | 1 | 2 MT7916 2G + 5G (2T2R+1R) | 1 | 2 MT7916 2G + 5G (3T3R) | 1 | N/A MT7981 2G + 5G | 1 | N/A MT7986 2G + 5G (one adie DBDC) | 1 | N/A MT7986 5G (one adie) | 1 (bandidx=MT_BAND1)| N/A MT7986 2G + 5G (dual adie) | 1 | N/A Signed-off-by: StanleyYP Wang Reviewed-by: Shayne Chen Link: https://patch.msgid.link/20250320015918.3948643-1-StanleyYP.Wang@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7915/debugfs.c | 23 +++++-- .../net/wireless/mediatek/mt76/mt7915/mac.c | 60 +++++++------------ .../net/wireless/mediatek/mt76/mt7915/mcu.c | 42 +++++++++---- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 2 +- .../wireless/mediatek/mt76/mt7915/mt7915.h | 22 +++++-- 5 files changed, 88 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 0384e9f519fb..b287b7d9394e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -211,13 +211,28 @@ static const struct file_operations mt7915_sys_recovery_ops = { static int mt7915_radar_trigger(void *data, u64 val) { - struct mt7915_dev *dev = data; +#define RADAR_MAIN_CHAIN 1 +#define RADAR_BACKGROUND 2 + struct mt7915_phy *phy = data; + struct mt7915_dev *dev = phy->dev; + int rdd_idx; - if (val > MT_RX_SEL2) + if (!val || val > RADAR_BACKGROUND) return -EINVAL; + if (val == RADAR_BACKGROUND && !dev->rdd2_phy) { + dev_err(dev->mt76.dev, "Background radar is not enabled\n"); + return -EINVAL; + } + + rdd_idx = mt7915_get_rdd_idx(phy, val == RADAR_BACKGROUND); + if (rdd_idx < 0) { + dev_err(dev->mt76.dev, "No RDD found\n"); + return -EINVAL; + } + return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE, - val, 0, 0); + rdd_idx, 0, 0); } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, @@ -1247,7 +1262,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy) 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, + debugfs_create_file("radar_trigger", 0200, dir, phy, &fops_radar_trigger); debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir, mt7915_rdd_monitor); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2ba6eb3038ce..9400e4af2a04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -2035,16 +2035,15 @@ void mt7915_mac_work(struct work_struct *work) static void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; + int rdd_idx = mt7915_get_rdd_idx(phy, false); - if (phy->rdd_state & BIT(0)) - mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0, - MT_RX_SEL0, 0); - if (phy->rdd_state & BIT(1)) - mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1, - MT_RX_SEL0, 0); + if (rdd_idx < 0) + return; + + mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, rdd_idx, 0, 0); } -static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) +static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int rdd_idx) { int err, region; @@ -2061,52 +2060,38 @@ static int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain) break; } - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain, - MT_RX_SEL0, region); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, rdd_idx, 0, region); if (err < 0) return err; if (is_mt7915(&dev->mt76)) { - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, chain, + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, rdd_idx, 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); + return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, rdd_idx, 0, 1); } static int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy) { - struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7915_dev *dev = phy->dev; - int err; + int err, rdd_idx; + + rdd_idx = mt7915_get_rdd_idx(phy, false); + if (rdd_idx < 0) + return -EINVAL; /* start CAC */ - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, - phy->mt76->band_idx, MT_RX_SEL0, 0); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, rdd_idx, 0, 0); if (err < 0) return err; - err = mt7915_dfs_start_rdd(dev, phy->mt76->band_idx); + err = mt7915_dfs_start_rdd(dev, rdd_idx); if (err < 0) return err; - phy->rdd_state |= BIT(phy->mt76->band_idx); - - if (!is_mt7915(&dev->mt76)) - return 0; - - if (chandef->width == NL80211_CHAN_WIDTH_160 || - chandef->width == NL80211_CHAN_WIDTH_80P80) { - err = mt7915_dfs_start_rdd(dev, 1); - if (err < 0) - return err; - - phy->rdd_state |= BIT(1); - } - return 0; } @@ -2148,12 +2133,12 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; enum mt76_dfs_state dfs_state, prev_state; - int err; + int err, rdd_idx = mt7915_get_rdd_idx(phy, false); prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); - if (prev_state == dfs_state) + if (prev_state == dfs_state || rdd_idx < 0) return 0; if (prev_state == MT_DFS_STATE_UNKNOWN) @@ -2177,8 +2162,7 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) if (dfs_state == MT_DFS_STATE_CAC) return 0; - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, - phy->mt76->band_idx, MT_RX_SEL0, 0); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END, rdd_idx, 0, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; @@ -2188,15 +2172,13 @@ int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy) return 0; stop: - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, - phy->mt76->band_idx, MT_RX_SEL0, 0); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, rdd_idx, 0, 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); + rdd_idx, 0, dev->dbdc_support ? 2 : 0); if (err < 0) return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c9a4c35001dd..427542777abc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -303,17 +303,35 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; struct mt7915_mcu_rdd_report *r; + u32 sku; r = (struct mt7915_mcu_rdd_report *)skb->data; - if (r->band_idx > MT_RX_SEL2) + switch (r->rdd_idx) { + case MT_RDD_IDX_BAND0: + break; + case MT_RDD_IDX_BAND1: + sku = mt7915_check_adie(dev, true); + /* the main phy is bound to band 1 for this sku */ + if (is_mt7986(&dev->mt76) && + (sku == MT7975_ONE_ADIE || sku == MT7976_ONE_ADIE)) + break; + mphy = dev->mt76.phys[MT_BAND1]; + break; + case MT_RDD_IDX_BACKGROUND: + if (!dev->rdd2_phy) + return; + mphy = dev->rdd2_phy->mt76; + break; + default: + dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); + return; + } + + if (!mphy) return; - 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) + if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) cfg80211_background_radar_event(mphy->hw->wiphy, &dev->rdd2_chandef, GFP_ATOMIC); @@ -2697,11 +2715,14 @@ int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy, struct cfg80211_chan_def *chandef) { struct mt7915_dev *dev = phy->dev; - int err, region; + int err, region, rdd_idx; + + rdd_idx = mt7915_get_rdd_idx(phy, true); + if (rdd_idx < 0) + return -EINVAL; if (!chandef) { /* disable offchain */ - err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2, - 0, 0); + err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, rdd_idx, 0, 0); if (err) return err; @@ -2727,8 +2748,7 @@ int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy, break; } - return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2, - 0, region); + return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, rdd_idx, 0, region); } int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 092ed504a8f2..086ad89ecd91 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -57,7 +57,7 @@ struct mt7915_mcu_bcc_notify { struct mt7915_mcu_rdd_report { struct mt76_connac2_mcu_rxd_hdr rxd; - u8 band_idx; + u8 rdd_idx; u8 long_detected; u8 constant_prf_detected; u8 staggered_prf_detected; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 66bb94192297..2e94347c46d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -215,8 +215,6 @@ struct mt7915_phy { s16 coverage_class; u8 slottime; - u8 rdd_state; - u32 trb_ts; u32 rx_ampdu_ts; @@ -331,10 +329,10 @@ enum { __MT_WFDMA_MAX, }; -enum { - MT_RX_SEL0, - MT_RX_SEL1, - MT_RX_SEL2, /* monitor chain */ +enum rdd_idx { + MT_RDD_IDX_BAND0, /* RDD idx for band idx 0 (single-band) */ + MT_RDD_IDX_BAND1, /* RDD idx for band idx 1 */ + MT_RDD_IDX_BACKGROUND, /* RDD idx for background chain */ }; enum mt7915_rdd_cmd { @@ -354,6 +352,18 @@ enum mt7915_rdd_cmd { RDD_IRQ_OFF, }; +static inline int +mt7915_get_rdd_idx(struct mt7915_phy *phy, bool is_background) +{ + if (!phy->mt76->cap.has_5ghz) + return -1; + + if (is_background) + return MT_RDD_IDX_BACKGROUND; + + return phy->mt76->band_idx; +} + static inline struct mt7915_phy * mt7915_hw_phy(struct ieee80211_hw *hw) { From 1529e335f93dd72fead39bd28fab5b51b6f3ca80 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:26 +0800 Subject: [PATCH 13/48] wifi: mt76: mt7996: rework radar HWRDD idx The definition of MT_RX_SEL (for rdd_rx_sel) is mixed with the definition of HWRDD idx. For example, MT_RX_SEL2 is for background HWRDD idx, not an option of rdd_rx_sel. Additionally, HWRDD idx does not exactly map to band idx for Connac 3 chips. So, add mt7996_get_rdd_idx as a helper function. Finally, remove some parts of the code inherited from the legacy chips. For instance, 1. rdd_state is used for single-band-dual-HWRDD chips (for 80+80), especially the 76xx series. 2. rdd_rx_sel is also used for single-band-dual-HWRDD chips rx_sel = 0 => RDD0 for WF0, RDD1 for WF2 rx_sel = 1 => RDD0 for WF1, RDD1 for WF3 Chip Variants | 5G rdd idx | Background rdd idx ---------------------------|----------------|------------------- MT7996 (except 205/255) | 1 | 2 MT7992 | 1 | 2 MT7990 | 1 | 2 Signed-off-by: StanleyYP Wang Reviewed-by: Shayne Chen Reviewed-by: Money Wang Link: https://patch.msgid.link/20250320015926.3948672-1-StanleyYP.Wang@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/debugfs.c | 17 ++++-- .../net/wireless/mediatek/mt76/mt7996/mac.c | 57 +++++++------------ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 40 ++++++------- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 28 ++++++--- 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 4a28db17a287..0ab827f52fd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -222,18 +222,27 @@ static const struct file_operations mt7996_sys_recovery_ops = { static int mt7996_radar_trigger(void *data, u64 val) { +#define RADAR_MAIN_CHAIN 1 +#define RADAR_BACKGROUND 2 struct mt7996_dev *dev = data; + struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ); + int rdd_idx; - if (val > MT_RX_SEL2) + if (!phy || !val || val > RADAR_BACKGROUND) return -EINVAL; - if (val == MT_RX_SEL2 && !dev->rdd2_phy) { + if (val == RADAR_BACKGROUND && !dev->rdd2_phy) { dev_err(dev->mt76.dev, "Background radar is not enabled\n"); return -EINVAL; } - return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, - val, 0, 0); + rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND); + if (rdd_idx < 0) { + dev_err(dev->mt76.dev, "No RDD found\n"); + return -EINVAL; + } + + return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0); } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index ab9ab4887818..8c3523662426 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2441,16 +2441,15 @@ void mt7996_mac_work(struct work_struct *work) static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; + int rdd_idx = mt7996_get_rdd_idx(phy, false); - if (phy->rdd_state & BIT(0)) - mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0, - MT_RX_SEL0, 0); - if (phy->rdd_state & BIT(1)) - mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1, - MT_RX_SEL0, 0); + if (rdd_idx < 0) + return; + + mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0); } -static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain) +static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) { int err, region; @@ -2467,44 +2466,30 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain) break; } - err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain, - MT_RX_SEL0, region); + err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); if (err < 0) return err; - return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, - MT_RX_SEL0, 1); + return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1); } static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) { - struct cfg80211_chan_def *chandef = &phy->mt76->chandef; struct mt7996_dev *dev = phy->dev; - u8 band_idx = phy->mt76->band_idx; - int err; + int err, rdd_idx; + + rdd_idx = mt7996_get_rdd_idx(phy, false); + if (rdd_idx < 0) + return -EINVAL; /* start CAC */ - err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx, - MT_RX_SEL0, 0); + err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, rdd_idx, 0); if (err < 0) return err; - err = mt7996_dfs_start_rdd(dev, band_idx); - if (err < 0) - return err; + err = mt7996_dfs_start_rdd(dev, rdd_idx); - phy->rdd_state |= BIT(band_idx); - - if (chandef->width == NL80211_CHAN_WIDTH_160 || - chandef->width == NL80211_CHAN_WIDTH_80P80) { - err = mt7996_dfs_start_rdd(dev, 1); - if (err < 0) - return err; - - phy->rdd_state |= BIT(1); - } - - return 0; + return err; } static int @@ -2545,12 +2530,12 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; enum mt76_dfs_state dfs_state, prev_state; - int err; + int err, rdd_idx = mt7996_get_rdd_idx(phy, false); prev_state = phy->mt76->dfs_state; dfs_state = mt76_phy_dfs_state(phy->mt76); - if (prev_state == dfs_state) + if (prev_state == dfs_state || rdd_idx < 0) return 0; if (prev_state == MT_DFS_STATE_UNKNOWN) @@ -2574,8 +2559,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) if (dfs_state == MT_DFS_STATE_CAC) return 0; - err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, - phy->mt76->band_idx, MT_RX_SEL0, 0); + err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END, rdd_idx, 0); if (err < 0) { phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; return err; @@ -2585,8 +2569,7 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) return 0; stop: - err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, - phy->mt76->band_idx, MT_RX_SEL0, 0); + err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START, rdd_idx, 0); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index a99e290faf1f..fdc517873fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -380,21 +380,27 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) r = (struct mt7996_mcu_rdd_report *)skb->data; - if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys)) - return; - - if (r->band_idx == MT_RX_SEL2 && !dev->rdd2_phy) - return; - - if (r->band_idx == MT_RX_SEL2) + switch (r->rdd_idx) { + case MT_RDD_IDX_BAND2: + mphy = dev->mt76.phys[MT_BAND2]; + break; + case MT_RDD_IDX_BAND1: + mphy = dev->mt76.phys[MT_BAND1]; + break; + case MT_RDD_IDX_BACKGROUND: + if (!dev->rdd2_phy) + return; mphy = dev->rdd2_phy->mt76; - else - mphy = dev->mt76.phys[r->band_idx]; + break; + default: + dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); + return; + } if (!mphy) return; - if (r->band_idx == MT_RX_SEL2) + if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) cfg80211_background_radar_event(mphy->hw->wiphy, &dev->rdd2_chandef, GFP_ATOMIC); @@ -3557,11 +3563,10 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef) { struct mt7996_dev *dev = phy->dev; - int err, region; + int err, region, rdd_idx = mt7996_get_rdd_idx(phy, true); if (!chandef) { /* disable offchain */ - err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2, - 0, 0); + err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0); if (err) return err; @@ -3587,8 +3592,7 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, break; } - return mt7996_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2, - 0, region); + return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); } int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) @@ -4455,8 +4459,7 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) &req, sizeof(req), true); } -int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, - u8 rx_sel, u8 val) +int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) { struct { u8 _rsv[4]; @@ -4473,8 +4476,7 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, .tag = cpu_to_le16(UNI_RDD_CTRL_PARM), .len = cpu_to_le16(sizeof(req) - 4), .ctrl = cmd, - .rdd_idx = index, - .rdd_rx_sel = rx_sel, + .rdd_idx = rdd_idx, .val = val, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 8ef7d4baee90..fd660e913b82 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -69,7 +69,7 @@ struct mt7996_mcu_rdd_report { __le16 tag; __le16 len; - u8 band_idx; + u8 rdd_idx; u8 long_detected; u8 constant_prf_detected; u8 staggered_prf_detected; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index a45cd3ff61a0..7c334e319547 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -302,8 +302,6 @@ struct mt7996_phy { s16 coverage_class; u8 slottime; - u8 rdd_state; - u16 beacon_rate; u32 rx_ampdu_ts; @@ -426,10 +424,10 @@ enum { __MT_WFDMA_MAX, }; -enum { - MT_RX_SEL0, - MT_RX_SEL1, - MT_RX_SEL2, /* monitor chain */ +enum rdd_idx { + MT_RDD_IDX_BAND2, /* RDD idx for band idx 2 */ + MT_RDD_IDX_BAND1, /* RDD idx for band idx 1 */ + MT_RDD_IDX_BACKGROUND, /* RDD idx for background chain */ }; enum mt7996_rdd_cmd { @@ -448,6 +446,21 @@ enum mt7996_rdd_cmd { RDD_IRQ_OFF, }; +static inline int +mt7996_get_rdd_idx(struct mt7996_phy *phy, bool is_background) +{ + if (!phy->mt76->cap.has_5ghz) + return -1; + + if (is_background) + return MT_RDD_IDX_BACKGROUND; + + if (phy->mt76->band_idx == MT_BAND2) + return MT_RDD_IDX_BAND2; + + return MT_RDD_IDX_BAND1; +} + static inline struct mt7996_dev * mt7996_hw_dev(struct ieee80211_hw *hw) { @@ -640,8 +653,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); -int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, - u8 rx_sel, u8 val); +int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, From 88224119863c39fa67581874e1ba218fa56113b4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Mar 2025 17:35:40 +0300 Subject: [PATCH 14/48] wifi: mt76: mt7925: Fix logical vs bitwise typo This was supposed to be & instead of &&. Fixes: f0317215b367 ("wifi: mt76: mt7925: add EHT control support based on the CLC data") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/d323a443-4e81-4064-8563-b62274b53ef4@stanley.mountain Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 63cb08f4d87c..79639be0d29a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -89,7 +89,7 @@ void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2) } /* Check the last one */ - if (rule->flag && BIT(0)) + if (rule->flag & BIT(0)) break; pos += sizeof(*rule); From cadebdad959bf25edd544da6dd1a9750e876deb6 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Tue, 1 Apr 2025 16:35:25 +0800 Subject: [PATCH 15/48] wifi: mt76: mt7925: add EHT preamble puncturing Add mt7925 EHT preamble puncturing. Signed-off-by: Allan Wang Link: https://patch.msgid.link/20250401083525.2734333-1-allan.wang@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7925/main.c | 10 ++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 34 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.h | 16 +++++++++ 4 files changed, 61 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 8226b975f7e6..478cd1886736 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1371,6 +1371,7 @@ enum { UNI_BSS_INFO_OFFLOAD = 25, UNI_BSS_INFO_MLD = 26, UNI_BSS_INFO_PM_DISABLE = 27, + UNI_BSS_INFO_EHT = 30, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 66f327781947..128a742ca631 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1865,6 +1865,10 @@ mt7925_change_chanctx(struct ieee80211_hw *hw, link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, link_conf, ctx); + + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, + link_conf, ctx); } } @@ -1954,8 +1958,10 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_bss_conf *mconf; + struct ieee80211_bss_conf *link_conf; mconf = mt792x_vif_to_link(mvif, info->link_id); + link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); mt792x_mutex_acquire(dev); @@ -1997,6 +2003,10 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; } + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, + link_conf, NULL); + mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index e61da76b2097..286f602623c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2298,6 +2298,40 @@ __mt7925_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif_link *mvif, int return skb; } +static +void mt7925_mcu_bss_eht_tlv(struct sk_buff *skb, struct mt76_phy *phy, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct cfg80211_chan_def *chandef = ctx ? &ctx->def : + &link_conf->chanreq.oper; + + struct bss_eht_tlv *req; + struct tlv *tlv; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_EHT, sizeof(*req)); + req = (struct bss_eht_tlv *)tlv; + req->is_eth_dscb_present = chandef->punctured ? 1 : 0; + req->eht_dis_sub_chan_bitmap = cpu_to_le16(chandef->punctured); +} + +int mt7925_mcu_set_eht_pp(struct mt76_phy *phy, struct mt76_vif_link *mvif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx) +{ + struct sk_buff *skb; + + skb = __mt7925_mcu_alloc_bss_req(phy->dev, mvif, + MT7925_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7925_mcu_bss_eht_tlv(skb, phy, link_conf, ctx); + + return mt76_mcu_skb_send_msg(phy->dev, skb, + MCU_UNI_CMD(BSS_INFO_UPDATE), true); +} + int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index 8ac43feb26d6..d55ea59bda7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -372,6 +372,19 @@ struct bss_mld_tlv { u8 __rsv[3]; } __packed; +struct bss_eht_tlv { + __le16 tag; + __le16 len; + u8 is_eht_op_present; + u8 is_eth_dscb_present; + u8 eht_ctrl; + u8 eht_ccfs0; + u8 eht_ccfs1; + u8 pad1; + __le16 eht_dis_sub_chan_bitmap; + u8 pad2[4]; +} __packed; + struct sta_rec_ba_uni { __le16 tag; __le16 len; @@ -642,6 +655,9 @@ int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx); +int mt7925_mcu_set_eht_pp(struct mt76_phy *phy, struct mt76_vif_link *mvif, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_chanctx_conf *ctx); int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy); int mt7925_mcu_update_arp_filter(struct mt76_dev *dev, struct ieee80211_bss_conf *link_conf); From caf4b347c5dc40fdd125793b5e82ba9fc4de5275 Mon Sep 17 00:00:00 2001 From: Charles Han Date: Mon, 7 Apr 2025 17:55:51 +0800 Subject: [PATCH 16/48] wifi: mt76: mt7996: Add NULL check in mt7996_thermal_init devm_kasprintf() can return a NULL pointer on failure,but this returned value in mt7996_thermal_init() is not checked. Add NULL check in mt7996_thermal_init(), to handle kernel NULL pointer dereference error. Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: Charles Han Link: https://patch.msgid.link/20250407095551.32127-1-hanchunchao@inspur.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index e26451add9a3..ff835a6f77ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -217,6 +217,9 @@ static int mt7996_thermal_init(struct mt7996_phy *phy) name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s.%d", wiphy_name(wiphy), phy->mt76->band_idx); + if (!name) + return -ENOMEM; + snprintf(cname, sizeof(cname), "cooling_device%d", phy->mt76->band_idx); cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); From 3dbfb8abe3fd3fff81a95bd8ac2a48741f63e872 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Fri, 28 Mar 2025 10:28:47 +0800 Subject: [PATCH 17/48] Revert "wifi: mt76: mt7996: fill txd by host driver" This reverts commit 3b522cadedfe6e9e0e8193d7d4ab5aa8d0c73209. The MTK connac3 has introduced new hardware, SDO (Software Defined Offload), to offload the process of filling the TX descriptor. Initially, there were some issues, but after several fixes, it should now be stable, allowing us to revert this commit. Additionally, activating SDO is essential for the proper functioning of features like TX checksum offload. Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250328022847.1612082-1-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 8c3523662426..771c16e8d10c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1040,8 +1040,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return id; pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); - mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, - pid, qid, 0); + memset(txwi_ptr, 0, MT_TXD_SIZE); + /* Transmit non qos data by 802.11 header and need to fill txd by host*/ + if (!is_8023 || pid >= MT_PACKET_ID_FIRST) + mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, + pid, qid, 0); txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { @@ -1058,8 +1061,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, } txp->fw.nbuf = nbuf; - txp->fw.flags = - cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD); + txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST); + + if (!is_8023 || pid >= MT_PACKET_ID_FIRST) + txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD); if (!key) txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); From d9bc625861d490cb76ae8af86fac6f8ab0655a18 Mon Sep 17 00:00:00 2001 From: Qasim Ijaz Date: Mon, 21 Apr 2025 12:05:50 +0100 Subject: [PATCH 18/48] wifi: mt76: mt7996: prevent uninit return in mt7996_mac_sta_add_links If link_conf_dereference_protected() or mt7996_vif_link() or link_sta_dereference_protected() fail the code jumps to the error_unlink label and returns ret which is uninitialised. Fix this by setting err before jumping to error_unlink. Fixes: c7e4fc362443 ("wifi: mt76: mt7996: Update mt7996_mcu_add_sta to MLO support") Fixes: dd82a9e02c05 ("wifi: mt76: mt7996: Rely on mt7996_sta_link in sta_add/sta_remove callbacks") Signed-off-by: Qasim Ijaz Link: https://patch.msgid.link/20250421110550.9839-1-qasdev00@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 91c64e3a0860..70823bbb165c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -998,16 +998,22 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, continue; link_conf = link_conf_dereference_protected(vif, link_id); - if (!link_conf) + if (!link_conf) { + err = -EINVAL; goto error_unlink; + } link = mt7996_vif_link(dev, vif, link_id); - if (!link) + if (!link) { + err = -EINVAL; goto error_unlink; + } link_sta = link_sta_dereference_protected(sta, link_id); - if (!link_sta) + if (!link_sta) { + err = -EINVAL; goto error_unlink; + } err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link, link_id); From 939481cd87bda817ba5fe9d36267017cabe936e3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 18 Apr 2025 00:28:01 +0200 Subject: [PATCH 19/48] wifi: mt76: Remove an unneeded local variable in mt76x02_dma_init() Remove 't' which is unneeded since commit f3950a414143 ("mt76: set txwi_size according to the driver value") This slightly simplifies the code. Signed-off-by: Christophe JAILLET Link: https://patch.msgid.link/e86d5602bdd8b6bd22258ee69536992f39470bf5.1744928865.git.christophe.jaillet@wanadoo.fr Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index a82c75ba26e6..a683d53c7ceb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -174,7 +174,6 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget) int mt76x02_dma_init(struct mt76x02_dev *dev) { - struct mt76_txwi_cache __maybe_unused *t; int i, ret, fifo_size; struct mt76_queue *q; void *status_fifo; From 3c0e4f606d8693795a2c965d6f4987b1bfc31097 Mon Sep 17 00:00:00 2001 From: Henk Vergonet Date: Fri, 18 Apr 2025 16:39:14 +0200 Subject: [PATCH 20/48] wifi: mt76: mt76x2: Add support for LiteOn WN4516R,WN4519R Adds support for: - LiteOn WN4516R - LiteOn WN4519R Both use: - A nonstandard USB connector - Mediatek chipset MT7600U - ASIC revision: 76320044 Disabled VHT support on ASIC revision 76320044: This fixes the 5G connectibity issue on LiteOn WN4519R module see https://github.com/openwrt/mt76/issues/971 And may also fix the 5G issues on the XBox One Wireless Adapter see https://github.com/openwrt/mt76/issues/200 I have looked at the FCC info related to the MT7632U chip as mentioned in here: https://github.com/openwrt/mt76/issues/459 These confirm the chipset does not support 'ac' mode and hence VHT should be turned of. Signed-off-by: Henk Vergonet Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250418143914.31384-1-henk.vergonet@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 2 ++ .../net/wireless/mediatek/mt76/mt76x2/usb_init.c | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 84ef80ab4afb..96cecc576a98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -17,6 +17,8 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ + { USB_DEVICE(0x0471, 0x2126) }, /* LiteOn WN4516R module, nonstandard USB connector */ + { USB_DEVICE(0x0471, 0x7600) }, /* LiteOn WN4519R module, nonstandard USB connector */ { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ { USB_DEVICE(0x0846, 0x9014) }, /* Netgear WNDA3100v3 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 33a14365ec9b..3b5562811511 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -191,6 +191,7 @@ int mt76x2u_register_device(struct mt76x02_dev *dev) { struct ieee80211_hw *hw = mt76_hw(dev); struct mt76_usb *usb = &dev->mt76.usb; + bool vht; int err; INIT_DELAYED_WORK(&dev->cal_work, mt76x2u_phy_calibrate); @@ -217,7 +218,17 @@ int mt76x2u_register_device(struct mt76x02_dev *dev) /* check hw sg support in order to enable AMSDU */ hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_TX_SG_MAX_SIZE : 1; - err = mt76_register_device(&dev->mt76, true, mt76x02_rates, + switch (dev->mt76.rev) { + case 0x76320044: + /* these ASIC revisions do not support VHT */ + vht = false; + break; + default: + vht = true; + break; + } + + err = mt76_register_device(&dev->mt76, vht, mt76x02_rates, ARRAY_SIZE(mt76x02_rates)); if (err) goto fail; From 1d81e893b422a6f0ae70f8648867c2e73edfb413 Mon Sep 17 00:00:00 2001 From: Leon Yen Date: Fri, 9 May 2025 16:21:17 +0800 Subject: [PATCH 21/48] wifi: mt76: mt7925: introduce thermal protection Add thermal protection to prevent the chip from possible overheating due to prolonged high traffic and adverse operating conditions. Signed-off-by: Leon Yen Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250509082117.453819-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/init.c | 6 ++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 20 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 79639be0d29a..2a83ff59a968 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -322,6 +322,12 @@ static void mt7925_init_work(struct work_struct *work) return; } + ret = mt7925_mcu_set_thermal_protect(dev); + if (ret) { + dev_err(dev->mt76.dev, "thermal protection enable failed\n"); + return; + } + /* we support chip reset now */ dev->hw_init_done = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 286f602623c0..63076171df3b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -974,6 +974,23 @@ int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable) } EXPORT_SYMBOL_GPL(mt7925_mcu_set_deep_sleep); +int mt7925_mcu_set_thermal_protect(struct mt792x_dev *dev) +{ + char cmd[64]; + int ret = 0; + + snprintf(cmd, sizeof(cmd), "ThermalProtGband %d %d %d %d %d %d %d %d %d %d", + 0, 100, 90, 80, 30, 1, 1, 115, 105, 5); + ret = mt7925_mcu_chip_config(dev, cmd); + + snprintf(cmd, sizeof(cmd), "ThermalProtAband %d %d %d %d %d %d %d %d %d %d", + 1, 100, 90, 80, 30, 1, 1, 115, 105, 5); + ret |= mt7925_mcu_chip_config(dev, cmd); + + return ret; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_set_thermal_protect); + int mt7925_run_firmware(struct mt792x_dev *dev) { int err; @@ -3339,7 +3356,8 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, else uni_txd->option = MCU_CMD_UNI_EXT_ACK; - if (cmd == MCU_UNI_CMD(HIF_CTRL)) + if (cmd == MCU_UNI_CMD(HIF_CTRL) || + cmd == MCU_UNI_CMD(CHIP_CONFIG)) uni_txd->option &= ~MCU_CMD_ACK; goto exit; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index d55ea59bda7d..b1882944807e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -650,6 +650,7 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, int mt7925_mcu_set_timing(struct mt792x_phy *phy, struct ieee80211_bss_conf *link_conf); int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); +int mt7925_mcu_set_thermal_protect(struct mt792x_dev *dev); int mt7925_mcu_set_channel_domain(struct mt76_phy *phy); int mt7925_mcu_set_radio_en(struct mt792x_phy *phy, bool enable); int mt7925_mcu_set_chctx(struct mt76_phy *phy, struct mt76_vif_link *mvif, From ca872e0ad97159375da8f3d05cac1f48239e01d7 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Fri, 9 May 2025 16:35:12 +0800 Subject: [PATCH 22/48] wifi: mt76: mt7925: fix host interrupt register initialization ensure proper interrupt handling and aligns with the hardware spec by updating the register offset for MT_WFDMA0_HOST_INT_ENA. Cc: stable@vger.kernel.org Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Michael Lo Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250509083512.455095-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 3 --- drivers/net/wireless/mediatek/mt76/mt7925/regs.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index c7b5dc1dbb34..2e20ecc71207 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -490,9 +490,6 @@ static int mt7925_pci_suspend(struct device *device) /* disable interrupt */ mt76_wr(dev, dev->irq_map->host_irq_enable, 0); - mt76_wr(dev, MT_WFDMA0_HOST_INT_DIS, - dev->irq_map->tx.all_complete_mask | - MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h index 985794a40c1a..547489092c29 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h @@ -28,7 +28,7 @@ #define MT_MDP_TO_HIF 0 #define MT_MDP_TO_WM 1 -#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x228) +#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x204) #define MT_WFDMA0_HOST_INT_DIS MT_WFDMA0(0x22c) #define HOST_RX_DONE_INT_ENA4 BIT(12) #define HOST_RX_DONE_INT_ENA5 BIT(13) From 7011faebe543f8f094fdb3281d0ec9e1eab81309 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sat, 10 May 2025 19:53:09 -0500 Subject: [PATCH 23/48] wifi: mt76: mt7921: add 160 MHz AP for mt7922 device This allows mt7922 in hostapd mode to transmit up to 1.4 Gbps. Signed-off-by: Samuel Williams Link: https://patch.msgid.link/20250511005316.1118961-1-sam8641@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 826c48a2ee69..1fffa43379b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -83,6 +83,11 @@ mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; + + if (is_mt7922(phy->mt76->dev)) { + he_cap_elem->phy_cap_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + } break; case NL80211_IFTYPE_STATION: he_cap_elem->mac_cap_info[1] |= From cb423ddad0f6e6f55b1700422ab777b25597cc83 Mon Sep 17 00:00:00 2001 From: Qasim Ijaz Date: Mon, 21 Apr 2025 12:25:44 +0100 Subject: [PATCH 24/48] wifi: mt76: mt7996: avoid NULL pointer dereference in mt7996_set_monitor() The function mt7996_set_monitor() dereferences phy before the NULL sanity check. Fix this to avoid NULL pointer dereference by moving the dereference after the check. Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: Qasim Ijaz Link: https://patch.msgid.link/20250421112544.13430-1-qasdev00@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 70823bbb165c..5ec4f9793286 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -414,11 +414,13 @@ static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) { - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev; if (!phy) return; + dev = phy->dev; + if (enabled == !(phy->rxfilter & MT_WF_RFCR_DROP_OTHER_UC)) return; From a0bdd3d1b94d22dd9d255fd148eb9183ea0a822f Mon Sep 17 00:00:00 2001 From: Qasim Ijaz Date: Mon, 21 Apr 2025 12:13:44 +0100 Subject: [PATCH 25/48] wifi: mt76: mt7996: avoid null deref in mt7996_stop_phy() In mt7996_stop_phy() the mt7996_phy structure is dereferenced before the null sanity check which could lead to a null deref. Fix by moving the dereference operation after the sanity check. Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: Qasim Ijaz Link: https://patch.msgid.link/20250421111344.11484-1-qasdev00@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 5ec4f9793286..8698c4345af0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -68,11 +68,13 @@ static int mt7996_start(struct ieee80211_hw *hw) static void mt7996_stop_phy(struct mt7996_phy *phy) { - struct mt7996_dev *dev = phy->dev; + struct mt7996_dev *dev; if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) return; + dev = phy->dev; + cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); From 187de25110c8ac8d52e24f8c596ebdcbcd55bbbf Mon Sep 17 00:00:00 2001 From: sunliming Date: Sat, 19 Apr 2025 11:15:28 +0800 Subject: [PATCH 26/48] wifi: mt76: mt7996: fix uninitialized symbol warning Fix below smatch warnings: drivers/net/wireless/mediatek/mt76/mt7996/main.c:952 mt7996_mac_sta_add_links() error: uninitialized symbol 'err'. drivers/net/wireless/mediatek/mt76/mt7996/main.c:1133 mt7996_set_rts_threshold() error: uninitialized symbol 'ret'. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202504101051.1ya4Z4va-lkp@intel.com/ Signed-off-by: sunliming Link: https://patch.msgid.link/20250419031528.2073892-1-sunliming@linux.dev Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 8698c4345af0..b77e1721c7b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -991,7 +991,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; unsigned int link_id; - int err; + int err = 0; for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf; @@ -1254,7 +1254,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - int i, ret; + int i, ret = 0; mutex_lock(&dev->mt76.mutex); From f22037407cb40a4e7bfa4b5d1853fa6c2f3bef6f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 25 Mar 2025 17:12:05 +0100 Subject: [PATCH 27/48] Revert "wifi: mt76: Check link_conf pointer in mt76_connac_mcu_sta_basic_tlv()" In mt76_connac_mcu_sta_basic_tlv() link_conf is always not NULL. Revert the commit '9890624c1b39 ("wifi: mt76: Check link_conf pointer in mt76_connac_mcu_sta_basic_tlv()")' in order to fix the following warning: drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c:394 mt76_connac_mcu_sta_basic_tlv() warn: variable dereferenced before check 'link_conf' This reverts commit 9890624c1b3948c1c7f1d0e19ef0bb7680b8c80d. Signed-off-by: Lorenzo Bianconi Link: https://patch.msgid.link/20250325-mt76_connac_mcu_sta_basic_tlv-link_conf-revert-v1-1-b84efefb74ee@kernel.org Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 185ba57d416d..5f79a7f083d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -390,7 +390,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC); if (vif->type == NL80211_IFTYPE_STATION && - link_conf && !is_zero_ether_addr(link_conf->bssid)) { + !is_zero_ether_addr(link_conf->bssid)) { memcpy(basic->peer_addr, link_conf->bssid, ETH_ALEN); basic->aid = cpu_to_le16(vif->cfg.aid); } else { From c29f2c773afc2b56edffa9b4372d07322018a689 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Mar 2025 17:35:35 +0300 Subject: [PATCH 28/48] wifi: mt76: mt7996: remove duplicate check in mt7996_mcu_sta_mld_setup_tlv() The "msta_link" pointer has two NULL checks. Delete the second check. Signed-off-by: Dan Carpenter Acked-by: Lorenzo Bianconi Link: https://patch.msgid.link/fde7246b-08a2-4c2f-b2dc-c3fd0e6b300b@stanley.mountain Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index fdc517873fa6..f0adc0b4b8b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2264,9 +2264,6 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, if (!link) continue; - if (!msta_link) - continue; - mld_setup_link->wcid = cpu_to_le16(msta_link->wcid.idx); mld_setup_link->bss_idx = link->mt76.idx; mld_setup_link++; From 7e1fcf687c2fb22ad25cf3fae322a37452f5f560 Mon Sep 17 00:00:00 2001 From: Feng Jiang Date: Wed, 2 Apr 2025 14:24:15 +0800 Subject: [PATCH 29/48] wifi: mt76: scan: Fix 'mlink' dereferenced before IS_ERR_OR_NULL check Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202504011739.HvUKtUUe-lkp@intel.com/ Fixes: 3ba20af886d1 ("wifi: mt76: scan: set vif offchannel link for scanning/roc") Signed-off-by: Feng Jiang Link: https://patch.msgid.link/20250402062415.25434-1-jiangfeng@kylinos.cn Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/channel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index e7b839e74290..cc2d888e3f17 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -302,11 +302,13 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_vif_link *mlink) { struct mt76_dev *dev = phy->dev; - struct mt76_vif_data *mvif = mlink->mvif; + struct mt76_vif_data *mvif; if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel) return; + mvif = mlink->mvif; + rcu_assign_pointer(mvif->offchannel_link, NULL); dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink); kfree(mlink); From 913a61826787669471b5b27b304dd2d0deedd7c8 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 21 Mar 2025 09:38:28 +0800 Subject: [PATCH 30/48] wifi: mt76: add mt76_connac_mcu_build_rnr_scan_param routine Introduce mt76_connac_mcu_build_rnr_scan_param routine for handling RNR scan. This is a preliminary patch to enable RNR scan in mt7921 and mt7925 driver. Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250321013829.3598-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 12 ++++++ .../wireless/mediatek/mt76/mt76_connac_mcu.c | 38 +++++++++++++++++++ .../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 ++ 3 files changed, 53 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d7cd467b812f..ee6ed89fe496 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -162,6 +162,16 @@ enum mt76_dfs_state { MT_DFS_STATE_ACTIVE, }; +#define MT76_RNR_SCAN_MAX_BSSIDS 16 +struct mt76_scan_rnr_param { + u8 bssid[MT76_RNR_SCAN_MAX_BSSIDS][ETH_ALEN]; + u8 channel[MT76_RNR_SCAN_MAX_BSSIDS]; + u8 random_mac[ETH_ALEN]; + u8 seq_num; + u8 bssid_num; + u32 sreq_flag; +}; + struct mt76_queue_buf { dma_addr_t addr; u16 len:15, @@ -941,6 +951,8 @@ struct mt76_dev { char alpha2[3]; enum nl80211_dfs_regions region; + struct mt76_scan_rnr_param rnr; + u32 debugfs_reg; u8 csa_complete; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 5f79a7f083d2..cb13d0a76878 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1666,6 +1666,44 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss); +void mt76_connac_mcu_build_rnr_scan_param(struct mt76_dev *mdev, + struct cfg80211_scan_request *sreq) +{ + struct ieee80211_channel **scan_list = sreq->channels; + int i, bssid_index = 0; + + /* clear 6G active Scan BSSID table */ + memset(&mdev->rnr, 0, sizeof(mdev->rnr)); + + for (i = 0; i < sreq->n_6ghz_params; i++) { + u8 ch_idx = sreq->scan_6ghz_params[i].channel_idx; + int k = 0; + + /* Remove the duplicated BSSID */ + for (k = 0; k < bssid_index; k++) { + if (!memcmp(&mdev->rnr.bssid[k], + sreq->scan_6ghz_params[i].bssid, + ETH_ALEN)) + break; + } + + if (k == bssid_index && + bssid_index < MT76_RNR_SCAN_MAX_BSSIDS) { + memcpy(&mdev->rnr.bssid[bssid_index++], + sreq->scan_6ghz_params[i].bssid, ETH_ALEN); + mdev->rnr.channel[k] = scan_list[ch_idx]->hw_value; + } + } + + mdev->rnr.bssid_num = bssid_index; + + if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { + memcpy(mdev->rnr.random_mac, sreq->mac_addr, ETH_ALEN); + mdev->rnr.sreq_flag = sreq->flags; + } +} +EXPORT_SYMBOL_GPL(mt76_connac_mcu_build_rnr_scan_param); + #define MT76_CONNAC_SCAN_CHANNEL_TIME 60 int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 478cd1886736..5f1ae9617aa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -869,6 +869,7 @@ enum { #define NETWORK_WDS BIT(21) #define SCAN_FUNC_RANDOM_MAC BIT(0) +#define SCAN_FUNC_RNR_SCAN BIT(3) #define SCAN_FUNC_SPLIT_SCAN BIT(5) #define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) @@ -1972,6 +1973,8 @@ int mt76_connac_mcu_start_patch(struct mt76_dev *dev); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); +void mt76_connac_mcu_build_rnr_scan_param(struct mt76_dev *mdev, + struct cfg80211_scan_request *sreq); int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); int mt76_connac_mcu_cancel_hw_scan(struct mt76_phy *phy, From 8284815ca161e0fa0861cc4085f1c0141e10a34d Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Fri, 21 Mar 2025 09:38:29 +0800 Subject: [PATCH 31/48] wifi: mt76: mt7925: add RNR scan support for 6GHz Enhance the mt7925 to include RNR scan support. It adds the necessary RNR information to the scan command. Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250321013829.3598-2-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 34 +++++++++++++++---- .../net/wireless/mediatek/mt76/mt7925/mcu.h | 17 ++++++---- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 63076171df3b..eed2dd56b5d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2830,7 +2830,6 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_dev *mdev = phy->dev; struct mt76_connac_mcu_scan_channel *chan; struct sk_buff *skb; - struct scan_hdr_tlv *hdr; struct scan_req_tlv *req; struct scan_ssid_tlv *ssid; @@ -2842,8 +2841,8 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, int max_len; max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) + - sizeof(*bssid) + sizeof(*chan_info) + - sizeof(*misc) + sizeof(*ie); + sizeof(*bssid) * MT7925_RNR_SCAN_MAX_BSSIDS + + sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie); skb = mt76_mcu_msg_alloc(mdev, NULL, max_len); if (!skb) @@ -2866,6 +2865,8 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, for (i = 0; i < sreq->n_ssids; i++) { if (!sreq->ssids[i].ssid_len) continue; + if (i > MT7925_RNR_SCAN_MAX_BSSIDS) + break; ssid->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); memcpy(ssid->ssids[i].ssid, sreq->ssids[i].ssid, @@ -2875,10 +2876,31 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, ssid->ssid_type = n_ssids ? BIT(2) : BIT(0); ssid->ssids_num = n_ssids; - tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, sizeof(*bssid)); - bssid = (struct scan_bssid_tlv *)tlv; + if (sreq->n_6ghz_params) { + u8 j; - memcpy(bssid->bssid, sreq->bssid, ETH_ALEN); + mt76_connac_mcu_build_rnr_scan_param(mdev, sreq); + + for (j = 0; j < mdev->rnr.bssid_num; j++) { + if (j > MT7925_RNR_SCAN_MAX_BSSIDS) + break; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, + sizeof(*bssid)); + bssid = (struct scan_bssid_tlv *)tlv; + + ether_addr_copy(bssid->bssid, mdev->rnr.bssid[j]); + bssid->match_ch = mdev->rnr.channel[j]; + bssid->match_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS; + bssid->match_short_ssid_ind = MT7925_RNR_SCAN_MAX_BSSIDS; + } + req->scan_func |= SCAN_FUNC_RNR_SCAN; + } else { + tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, sizeof(*bssid)); + bssid = (struct scan_bssid_tlv *)tlv; + + ether_addr_copy(bssid->bssid, sreq->bssid); + } tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_CHANNEL, sizeof(*chan_info)); chan_info = (struct scan_chan_info_tlv *)tlv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index b1882944807e..c569f02da8f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -196,6 +196,7 @@ enum { UNI_SNIFFER_CONFIG, }; +#define MT7925_RNR_SCAN_MAX_BSSIDS 10 struct scan_hdr_tlv { /* fixed field */ u8 seq_num; @@ -223,7 +224,7 @@ struct scan_req_tlv { __le16 timeout_value; __le16 probe_delay_time; __le32 func_mask_ext; -}; +} __packed; struct scan_ssid_tlv { __le16 tag; @@ -235,9 +236,10 @@ struct scan_ssid_tlv { * BIT(2) + ssid_type_ext BIT(0) specified SSID only */ u8 ssids_num; - u8 pad[2]; - struct mt76_connac_mcu_scan_ssid ssids[4]; -}; + u8 is_short_ssid; + u8 pad; + struct mt76_connac_mcu_scan_ssid ssids[MT7925_RNR_SCAN_MAX_BSSIDS]; +} __packed; struct scan_bssid_tlv { __le16 tag; @@ -247,8 +249,9 @@ struct scan_bssid_tlv { u8 match_ch; u8 match_ssid_ind; u8 rcpi; - u8 pad[3]; -}; + u8 match_short_ssid_ind; + u8 pad[2]; +} __packed; struct scan_chan_info_tlv { __le16 tag; @@ -264,7 +267,7 @@ struct scan_chan_info_tlv { u8 channels_num; /* valid when channel_type is 4 */ u8 pad[2]; struct mt76_connac_mcu_scan_channel channels[64]; -}; +} __packed; struct scan_ie_tlv { __le16 tag; From 8f30e2b059757d8711a823e4c9c023db62a1d171 Mon Sep 17 00:00:00 2001 From: Henry Martin Date: Mon, 7 Apr 2025 11:23:49 +0800 Subject: [PATCH 32/48] wifi: mt76: mt7996: Fix null-ptr-deref in mt7996_mmio_wed_init() devm_ioremap() returns NULL on error. Currently, mt7996_mmio_wed_init() does not check for this case, which results in a NULL pointer dereference. Prevent null pointer dereference in mt7996_mmio_wed_init() Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support") Signed-off-by: Henry Martin Link: https://patch.msgid.link/20250407032349.83360-1-bsdhenrymartin@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 51dd9a5f83cc..30b40f4a91be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -477,6 +477,9 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.base = devm_ioremap(dev->mt76.dev, pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); + if (!wed->wlan.base) + return -ENOMEM; + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); if (hif2) { From efb95439c1477bbc955cacd0179c35e7861b437c Mon Sep 17 00:00:00 2001 From: Henry Martin Date: Mon, 7 Apr 2025 14:19:00 +0800 Subject: [PATCH 33/48] wifi: mt76: mt7915: Fix null-ptr-deref in mt7915_mmio_wed_init() devm_ioremap() returns NULL on error. Currently, mt7915_mmio_wed_init() does not check for this case, which results in a NULL pointer dereference. Prevent null pointer dereference in mt7915_mmio_wed_init(). Fixes: 4f831d18d12d ("wifi: mt76: mt7915: enable WED RX support") Signed-off-by: Henry Martin Link: https://patch.msgid.link/20250407061900.85317-1-bsdhenrymartin@gmail.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 876f0692850a..9c4d5cea0c42 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -651,6 +651,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.base = devm_ioremap(dev->mt76.dev, pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); + if (!wed->wlan.base) + return -ENOMEM; + 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; @@ -678,6 +681,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.bus_type = MTK_WED_BUS_AXI; wed->wlan.base = devm_ioremap(dev->mt76.dev, res->start, resource_size(res)); + if (!wed->wlan.base) + return -ENOMEM; + 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; From 122f270aca2c86d7de264ab67161c845e0691d73 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Mon, 14 Apr 2025 09:39:52 +0800 Subject: [PATCH 34/48] wifi: mt76: mt7925: prevent multiple scan commands Add a check to ensure only one scan command is active at a time by testing the MT76_HW_SCANNING state. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250414013954.1151774-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index eed2dd56b5d0..c45eec44d859 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2840,6 +2840,9 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct tlv *tlv; int max_len; + if (test_bit(MT76_HW_SCANNING, &phy->state)) + return -EBUSY; + max_len = sizeof(*hdr) + sizeof(*req) + sizeof(*ssid) + sizeof(*bssid) * MT7925_RNR_SCAN_MAX_BSSIDS + sizeof(*chan_info) + sizeof(*misc) + sizeof(*ie); From bd02eebfc0b3502fe8322cf229b4c801416d1007 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Mon, 14 Apr 2025 09:39:53 +0800 Subject: [PATCH 35/48] wifi: mt76: mt7925: refine the sniffer commnad Remove a duplicate call to `mt76_mcu_send_msg` to fix redundant operations in the sniffer command handling. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250414013954.1151774-2-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index c45eec44d859..b19898aee64c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2063,8 +2063,6 @@ int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, }, }; - mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); - return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); } From aa97ff5782cf01cf2163593e1f57bbde63a06047 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Mon, 14 Apr 2025 09:39:54 +0800 Subject: [PATCH 36/48] wifi: mt76: mt7925: ensure all MCU commands wait for response Modify MCU command sending functions to wait for a response, ensuring consistent behavior across all commands and improves reliability by confirming that each command is processed successfully. Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips") Signed-off-by: Michael Lo Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20250414013954.1151774-3-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index b19898aee64c..0a1a8dff3f9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -783,7 +783,7 @@ int mt7925_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl) int ret; ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(WSYS_CONFIG), - &req, sizeof(req), false, NULL); + &req, sizeof(req), true, NULL); return ret; } @@ -1441,7 +1441,7 @@ int mt7925_mcu_set_eeprom(struct mt792x_dev *dev) }; return mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(EFUSE_CTRL), - &req, sizeof(req), false, NULL); + &req, sizeof(req), true, NULL); } EXPORT_SYMBOL_GPL(mt7925_mcu_set_eeprom); @@ -2813,7 +2813,7 @@ int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) conf->band = 0; /* unused */ err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SET_DBDC_PARMS), - false); + true); return err; } @@ -2943,7 +2943,7 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, } err = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), - false); + true); if (err < 0) clear_bit(MT76_HW_SCANNING, &phy->state); @@ -3049,7 +3049,7 @@ int mt7925_mcu_sched_scan_req(struct mt76_phy *phy, } return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), - false); + true); } EXPORT_SYMBOL_GPL(mt7925_mcu_sched_scan_req); @@ -3085,7 +3085,7 @@ mt7925_mcu_sched_scan_enable(struct mt76_phy *phy, clear_bit(MT76_HW_SCHED_SCANNING, &phy->state); return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(SCAN_REQ), - false); + true); } int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy, @@ -3124,7 +3124,7 @@ int mt7925_mcu_cancel_hw_scan(struct mt76_phy *phy, } return mt76_mcu_send_msg(phy->dev, MCU_UNI_CMD(SCAN_REQ), - &req, sizeof(req), false); + &req, sizeof(req), true); } EXPORT_SYMBOL_GPL(mt7925_mcu_cancel_hw_scan); @@ -3229,7 +3229,7 @@ int mt7925_mcu_set_channel_domain(struct mt76_phy *phy) memcpy(__skb_push(skb, sizeof(req)), &req, sizeof(req)); return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD(SET_DOMAIN_INFO), - false); + true); } EXPORT_SYMBOL_GPL(mt7925_mcu_set_channel_domain); From ba7fe3b064639e3e2687b68e5fb2223380114794 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Mon, 5 May 2025 16:36:17 -0700 Subject: [PATCH 37/48] wifi: mt76: mt7925: extend MCU support for testmode Add MCU command and its handling needed for testmode support on MT7925. This enables low-level chip testing features such as continuous TX/RX.. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Michael Lo Link: https://patch.msgid.link/20250505233618.1951021-1-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 7 +++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 8 ++++ .../net/wireless/mediatek/mt76/mt7925/mcu.h | 48 ++++++++++++++++--- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 5f1ae9617aa6..97f9d6da39bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1184,6 +1184,11 @@ enum { #define MCU_UNI_CMD(_t) (__MCU_CMD_FIELD_UNI | \ FIELD_PREP(__MCU_CMD_FIELD_ID, \ MCU_UNI_CMD_##_t)) + +#define MCU_UNI_QUERY(_t) (__MCU_CMD_FIELD_UNI | __MCU_CMD_FIELD_QUERY | \ + FIELD_PREP(__MCU_CMD_FIELD_ID, \ + MCU_UNI_CMD_##_t)) + #define MCU_CE_CMD(_t) (__MCU_CMD_FIELD_CE | \ FIELD_PREP(__MCU_CMD_FIELD_ID, \ MCU_CE_CMD_##_t)) @@ -1289,11 +1294,13 @@ enum { MCU_UNI_CMD_EFUSE_CTRL = 0x2d, MCU_UNI_CMD_RA = 0x2f, MCU_UNI_CMD_MURU = 0x31, + MCU_UNI_CMD_TESTMODE_RX_STAT = 0x32, MCU_UNI_CMD_BF = 0x33, MCU_UNI_CMD_CHANNEL_SWITCH = 0x34, MCU_UNI_CMD_THERMAL = 0x35, MCU_UNI_CMD_VOW = 0x37, MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, + MCU_UNI_CMD_TESTMODE_CTRL = 0x46, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, MCU_UNI_CMD_PER_STA_INFO = 0x6d, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 0a1a8dff3f9c..708be543954c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -3383,6 +3383,14 @@ int mt7925_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, cmd == MCU_UNI_CMD(CHIP_CONFIG)) uni_txd->option &= ~MCU_CMD_ACK; + if (mcu_cmd == MCU_UNI_CMD_TESTMODE_CTRL || + mcu_cmd == MCU_UNI_CMD_TESTMODE_RX_STAT) { + if (cmd & __MCU_CMD_FIELD_QUERY) + uni_txd->option = 0x2; + else + uni_txd->option = 0x6; + } + goto exit; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index c569f02da8f5..ee6fb16e83c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -104,13 +104,6 @@ enum { MT7925_TM_WIFISPECTRUM, }; -struct mt7925_rftest_cmd { - u8 action; - u8 rsv[3]; - __le32 param0; - __le32 param1; -} __packed; - struct mt7925_rftest_evt { __le32 param0; __le32 param1; @@ -605,6 +598,47 @@ struct roc_acquire_tlv { u8 rsv[3]; } __packed; +enum ENUM_CMD_TEST_CTRL_ACT { + CMD_TEST_CTRL_ACT_SWITCH_MODE = 0, + CMD_TEST_CTRL_ACT_SET_AT = 1, + CMD_TEST_CTRL_ACT_GET_AT = 2, + CMD_TEST_CTRL_ACT_SET_AT_ENG = 3, + CMD_TEST_CTRL_ACT_GET_AT_ENG = 4, + CMD_TEST_CTRL_ACT_NUM +}; + +enum ENUM_CMD_TEST_CTRL_ACT_SWITCH_MODE_OP { + CMD_TEST_CTRL_ACT_SWITCH_MODE_NORMAL = 0, + CMD_TEST_CTRL_ACT_SWITCH_MODE_RF_TEST = 1, + CMD_TEST_CTRL_ACT_SWITCH_MODE_ICAP = 2, + CMD_TEST_CTRL_ACT_SWITCH_MODE_NUM +}; + +union testmode_data { + __le32 op_mode; + __le32 channel_freq; + u8 rf_at_info[84]; +}; + +union testmode_evt { + __le32 op_mode; + __le32 channel_freq; + u8 rf_at_info[1024]; +}; + +struct uni_cmd_testmode_ctrl { + u16 tag; + u16 length; + u8 action; + u8 reserved[3]; + union testmode_data data; +} __packed; + +struct mt7925_rftest_cmd { + u8 padding[4]; + struct uni_cmd_testmode_ctrl ctrl; +} __packed; + static inline enum connac3_mcu_cipher_type mt7925_mcu_get_cipher(int cipher) { From 0a41b6751e4fe5094f17e5e14908cf3713d58d60 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Mon, 5 May 2025 16:36:18 -0700 Subject: [PATCH 38/48] wifi: mt76: mt7925: add test mode support The test mode interface allows controlled execution of chip-level operations such as continuous transmission, reception tests, and register access, which are essential during bring-up, diagnostics, and factory testing. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Michael Lo Link: https://patch.msgid.link/20250505233618.1951021-2-sean.wang@kernel.org Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7925/Makefile | 1 + .../net/wireless/mediatek/mt76/mt7925/main.c | 2 + .../wireless/mediatek/mt76/mt7925/mt7925.h | 5 + .../wireless/mediatek/mt76/mt7925/testmode.c | 201 ++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7925/testmode.c diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile index d321e4ed732f..ade5e647c941 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_MT7925E) += mt7925e.o obj-$(CONFIG_MT7925U) += mt7925u.o mt7925-common-y := mac.o mcu.o main.o init.o debugfs.o +mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7925e-y := pci.o pci_mac.o pci_mcu.o mt7925u-y := usb.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 128a742ca631..f1d0e29ebd55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -2244,6 +2244,8 @@ const struct ieee80211_ops mt7925_ops = { .sta_statistics = mt792x_sta_statistics, .sched_scan_start = mt7925_start_sched_scan, .sched_scan_stop = mt7925_stop_sched_scan, + CFG80211_TESTMODE_CMD(mt7925_testmode_cmd) + CFG80211_TESTMODE_DUMP(mt7925_testmode_dump) #ifdef CONFIG_PM .suspend = mt7925_suspend, .resume = mt7925_resume, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 4e50f2597ccd..c507dcae07d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -366,4 +366,9 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_sta *sta, int link_id); +int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); +int mt7925_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len); + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c new file mode 100644 index 000000000000..a3c97164ba21 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: ISC + +#include "mt7925.h" +#include "mcu.h" + +#define MT7925_EVT_RSP_LEN 512 + +enum mt7925_testmode_attr { + MT7925_TM_ATTR_UNSPEC, + MT7925_TM_ATTR_SET, + MT7925_TM_ATTR_QUERY, + MT7925_TM_ATTR_RSP, + + /* keep last */ + NUM_MT7925_TM_ATTRS, + MT7925_TM_ATTR_MAX = NUM_MT7925_TM_ATTRS - 1, +}; + +struct mt7925_tm_cmd { + u8 padding[4]; + struct uni_cmd_testmode_ctrl c; +} __packed; + +struct mt7925_tm_evt { + u32 param0; + u32 param1; +} __packed; + +static const struct nla_policy mt7925_tm_policy[NUM_MT7925_TM_ATTRS] = { + [MT7925_TM_ATTR_SET] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7925_tm_cmd)), + [MT7925_TM_ATTR_QUERY] = NLA_POLICY_EXACT_LEN(sizeof(struct mt7925_tm_cmd)), +}; + +static int +mt7925_tm_set(struct mt792x_dev *dev, struct mt7925_tm_cmd *req) +{ + struct mt7925_rftest_cmd cmd; + struct mt7925_rftest_cmd *pcmd = &cmd; + bool testmode = false, normal = false; + struct mt76_connac_pm *pm = &dev->pm; + struct mt76_phy *phy = &dev->mphy; + int ret = -ENOTCONN; + + memset(pcmd, 0, sizeof(*pcmd)); + memcpy(pcmd, req, sizeof(struct mt7925_tm_cmd)); + + mutex_lock(&dev->mt76.mutex); + + if (pcmd->ctrl.action == CMD_TEST_CTRL_ACT_SWITCH_MODE) { + if (pcmd->ctrl.data.op_mode == CMD_TEST_CTRL_ACT_SWITCH_MODE_NORMAL) + normal = true; + else + testmode = true; + } + + if (testmode) { + /* Make sure testmode running on full power mode */ + pm->enable = false; + cancel_delayed_work_sync(&pm->ps_work); + cancel_work_sync(&pm->wake_work); + __mt792x_mcu_drv_pmctrl(dev); + + phy->test.state = MT76_TM_STATE_ON; + } + + if (!mt76_testmode_enabled(phy)) + goto out; + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(TESTMODE_CTRL), &cmd, + sizeof(cmd), false); + + if (ret) + goto out; + + if (normal) { + /* Switch back to the normal world */ + phy->test.state = MT76_TM_STATE_OFF; + pm->enable = true; + } +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static int +mt7925_tm_query(struct mt792x_dev *dev, struct mt7925_tm_cmd *req, + char *evt_resp) +{ + struct mt7925_rftest_cmd cmd; + char *pcmd = (char *)&cmd; + struct sk_buff *skb = NULL; + int ret = 1; + + memset(pcmd, 0, sizeof(*pcmd)); + memcpy(pcmd + 4, (char *)&req->c, sizeof(struct uni_cmd_testmode_ctrl)); + + if (*((uint16_t *)req->padding) == MCU_UNI_CMD_TESTMODE_CTRL) + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_QUERY(TESTMODE_CTRL), + &cmd, sizeof(cmd), true, &skb); + else if (*((uint16_t *)req->padding) == MCU_UNI_CMD_TESTMODE_RX_STAT) + ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_QUERY(TESTMODE_RX_STAT), + &cmd, sizeof(cmd), true, &skb); + + if (ret) + goto out; + + memcpy((char *)evt_resp, (char *)skb->data + 8, MT7925_EVT_RSP_LEN); + +out: + dev_kfree_skb(skb); + + return ret; +} + +int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + struct mt76_phy *mphy = hw->priv; + struct mt792x_phy *phy = mphy->priv; + int err; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR)) + return -ENOTCONN; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + if (tb[MT76_TM_ATTR_DRV_DATA]) { + struct nlattr *drv_tb[NUM_MT7925_TM_ATTRS], *data; + int ret; + + data = tb[MT76_TM_ATTR_DRV_DATA]; + ret = nla_parse_nested_deprecated(drv_tb, + MT7925_TM_ATTR_MAX, + data, mt7925_tm_policy, + NULL); + if (ret) + return ret; + + data = drv_tb[MT7925_TM_ATTR_SET]; + if (data) + return mt7925_tm_set(phy->dev, nla_data(data)); + } + + return -EINVAL; +} + +int mt7925_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len) +{ + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + struct mt76_phy *mphy = hw->priv; + struct mt792x_phy *phy = mphy->priv; + int err; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR) || + !mt76_testmode_enabled(mphy)) + return -ENOTCONN; + + if (cb->args[2]++ > 0) + return -ENOENT; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + if (tb[MT76_TM_ATTR_DRV_DATA]) { + struct nlattr *drv_tb[NUM_MT7925_TM_ATTRS], *data; + int ret; + + data = tb[MT76_TM_ATTR_DRV_DATA]; + ret = nla_parse_nested_deprecated(drv_tb, + MT7925_TM_ATTR_MAX, + data, mt7925_tm_policy, + NULL); + if (ret) + return ret; + + data = drv_tb[MT7925_TM_ATTR_QUERY]; + if (data) { + char evt_resp[MT7925_EVT_RSP_LEN]; + + err = mt7925_tm_query(phy->dev, nla_data(data), + evt_resp); + if (err) + return err; + + return nla_put(msg, MT7925_TM_ATTR_RSP, + sizeof(evt_resp), evt_resp); + } + } + + return -EINVAL; +} From 08419f9e9bbb58f6eeb61990797e6084db6500ec Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Thu, 15 May 2025 11:29:44 +0800 Subject: [PATCH 39/48] wifi: mt76: remove capability of partial bandwidth UL MU-MIMO The firmware only supports full bandwidth UL MU-MIMO, so remove the partial bandwidth capability from HE PHY CAP. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-1-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 57d5be94624b..be9527dd0269 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -925,8 +925,7 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy, c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US; if (!is_mt7915(&dev->mt76)) - c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | - IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + c |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; elem->phy_cap_info[2] |= c; c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index ff835a6f77ce..b77fa94df8c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1116,8 +1116,7 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy, elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; c = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | - IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | - IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; elem->phy_cap_info[2] |= c; c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; From 5c78949fc7cd772d483a8abe126fe90937c0f002 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Thu, 15 May 2025 11:29:45 +0800 Subject: [PATCH 40/48] wifi: mt76: mt7996: fix beamformee SS field Fix the beamformee SS field for the mt7996, mt7992 and mt7990 chipsets. For the mt7992, this value shall be set to 0x4, while the others shall be set to 0x3. Fixes: 5b20557593d4 ("wifi: mt76: connac: adjust phy capabilities based on band constraints") Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-2-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index b77fa94df8c7..5c545293f294 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1121,12 +1121,12 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy, c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE; - if (is_mt7996(phy->mt76->dev)) - c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | - (IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 * non_2g); - else + if (is_mt7992(phy->mt76->dev)) c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 | (IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5 * non_2g); + else + c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 | + (IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4 * non_2g); elem->phy_cap_info[4] |= c; From 8b2f574845e33d02e7fbad2d3192a8b717567afa Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 15 May 2025 11:29:46 +0800 Subject: [PATCH 41/48] wifi: mt76: mt7996: set EHT max ampdu length capability Set the max AMPDU length in the EHT MAC CAP. Without this patch, the peer station cannot obtain the correct capability, which prevents achieving peak throughput on the 2 GHz band. Fixes: 1816ad9381e0 ("wifi: mt76: mt7996: add max mpdu len capability") Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-3-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 5c545293f294..213c7bcd4ade 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -1326,6 +1326,9 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); + eht_cap_elem->mac_cap_info[1] |= + IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK; + eht_cap_elem->phy_cap_info[0] = IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER | From 80fda1cd7b0a1edd0849dc71403a070d0922118d Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Thu, 15 May 2025 11:29:47 +0800 Subject: [PATCH 42/48] wifi: mt76: mt7996: drop fragments with multicast or broadcast RA IEEE 802.11 fragmentation can only be applied to unicast frames. Therefore, drop fragments with multicast or broadcast RA. This patch addresses vulnerabilities such as CVE-2020-26145. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-4-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 771c16e8d10c..0dbd4662bc84 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -647,6 +647,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME; } + /* IEEE 802.11 fragmentation can only be applied to unicast frames. + * Hence, drop fragments with multicast/broadcast RA. + * This check fixes vulnerabilities, like CVE-2020-26145. + */ + if ((ieee80211_has_morefrags(fc) || seq_ctrl & IEEE80211_SCTL_FRAG) && + FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) != MT_RXD3_NORMAL_U2M) + return -EINVAL; + hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad; if (hdr_trans && ieee80211_has_morefrags(fc)) { if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap)) From d5012734fc4bd5371e2e8dea8c2f3d28287573b8 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 15 May 2025 11:29:48 +0800 Subject: [PATCH 43/48] wifi: mt76: mt7996: fix invalid NSS setting when TX path differs from NSS The maximum TX path and NSS may differ on a band. For example, one variant of the MT7992 has 5 TX paths and 4 NSS on the 5 GHz band. To address this, add orig_antenna_mask to record the maximum NSS and prevent setting an invalid NSS in mt7996_set_antenna(). Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-5-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 1 + drivers/net/wireless/mediatek/mt76/mt7996/main.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 7bfd19ed9594..87c6192b6384 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -310,6 +310,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) phy->has_aux_rx = true; mphy->antenna_mask = BIT(nss) - 1; + phy->orig_antenna_mask = mphy->antenna_mask; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; phy->orig_chainmask = mphy->chainmask; dev->chainmask |= mphy->chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index b77e1721c7b8..b11dd3dd5c46 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1528,7 +1528,8 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) u8 shift = dev->chainshift[band_idx]; phy->mt76->chainmask = tx_ant & phy->orig_chainmask; - phy->mt76->antenna_mask = phy->mt76->chainmask >> shift; + phy->mt76->antenna_mask = (phy->mt76->chainmask >> shift) & + phy->orig_antenna_mask; mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 7c334e319547..c75189a02316 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -312,6 +312,7 @@ struct mt7996_phy { struct mt76_channel_state state_ts; u16 orig_chainmask; + u16 orig_antenna_mask; bool has_aux_rx; bool counter_reset; From 79e788fcb2043eabf99e73f6af35a79ccca365c4 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 15 May 2025 11:29:49 +0800 Subject: [PATCH 44/48] wifi: mt76: mt7996: change max beacon size According to hardware capability, the maximum beacon size is 2048 bytes minus the size of TLV headers. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-6-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index fd660e913b82..130ea95626d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -832,13 +832,13 @@ enum { sizeof(struct sta_rec_eht_mld) + \ sizeof(struct tlv)) -#define MT7996_MAX_BEACON_SIZE 1338 #define MT7996_BEACON_UPDATE_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct bss_bcn_content_tlv) + \ 4 + MT_TXD_SIZE + \ sizeof(struct bss_bcn_cntdwn_tlv) + \ sizeof(struct bss_bcn_mbss_tlv)) -#define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ +#define MT7996_MAX_BSS_OFFLOAD_SIZE 2048 +#define MT7996_MAX_BEACON_SIZE (MT7996_MAX_BSS_OFFLOAD_SIZE - \ MT7996_BEACON_UPDATE_SIZE) enum { From 42cb27af34de4acf680606fad2c1f2932110591f Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 15 May 2025 11:29:50 +0800 Subject: [PATCH 45/48] wifi: mt76: mt7996: fix RX buffer size of MCU event Some management frames are first processed by the firmware and then passed to the driver through the MCU event rings. In CONNAC3, event rings do not support scatter-gather and have a size limitation of 2048 bytes. If a packet sized between 1728 and 2048 bytes arrives from an event ring, the ring will hang because the driver attempts to use scatter-gather to process it. To fix this, include the size of struct skb_shared_info in the MCU RX buffer size to prevent scatter-gather from being used for event skb in mt76_dma_rx_fill_buf(). Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Co-developed-by: Peter Chiu Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-7-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/dma.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index fe8cc1d3f738..c8bef0b2a144 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -531,7 +531,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT_RXQ_ID(MT_RXQ_MCU), MT7996_RX_MCU_RING_SIZE, - MT_RX_BUF_SIZE, + MT7996_RX_MCU_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MCU)); if (ret) return ret; @@ -540,7 +540,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT_RXQ_ID(MT_RXQ_MCU_WA), MT7996_RX_MCU_RING_SIZE_WA, - MT_RX_BUF_SIZE, + MT7996_RX_MCU_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MCU_WA)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index c75189a02316..1ad6bc046f7c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -29,6 +29,9 @@ #define MT7996_RX_RING_SIZE 1536 #define MT7996_RX_MCU_RING_SIZE 512 #define MT7996_RX_MCU_RING_SIZE_WA 1024 +/* scatter-gather of mcu event is not supported in connac3 */ +#define MT7996_RX_MCU_BUF_SIZE (2048 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) #define MT7996_DEVICE_ID 0x7990 #define MT7996_DEVICE_ID_2 0x7991 From 249173e94dd5edef9e704f89513de7d9715ddf22 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 15 May 2025 11:29:51 +0800 Subject: [PATCH 46/48] wifi: mt76: fix available_antennas setting Check if available_antennas_tx and available_antennas_rx are already set during the per-chip initialization phase; otherwise, they could be overwritten with incorrect values. Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy") Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-8-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index b88d7e10742e..e9605dc22291 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -449,8 +449,10 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); - wiphy->available_antennas_tx = phy->antenna_mask; - wiphy->available_antennas_rx = phy->antenna_mask; + if (!wiphy->available_antennas_tx) + wiphy->available_antennas_tx = phy->antenna_mask; + if (!wiphy->available_antennas_rx) + wiphy->available_antennas_rx = phy->antenna_mask; wiphy->sar_capa = &mt76_sar_capa; phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, From 56e38675c5bdd185e52387bf75de8237d4cda106 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 15 May 2025 11:29:52 +0800 Subject: [PATCH 47/48] wifi: mt76: support power delta calculation for 5 TX paths One variant of MT7992 has 5 TX paths, so extend the power delta function to support it. Also, rename nss_delta to path_delta since the value is based on the number of TX paths rather tha the number of spatial streams. (path delta [0.5 dBm] = 10 * log(path number) [dBm] * 2) Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Link: https://patch.msgid.link/20250515032952.1653494-9-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7996/init.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7996/main.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index e9605dc22291..45c8db939d55 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1705,7 +1705,7 @@ s8 mt76_get_power_bound(struct mt76_phy *phy, s8 txpower) int n_chains = hweight16(phy->chainmask); txpower = mt76_get_sar_power(phy, phy->chandef.chan, txpower * 2); - txpower -= mt76_tx_power_nss_delta(n_chains); + txpower -= mt76_tx_power_path_delta(n_chains); return txpower; } @@ -1721,7 +1721,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return -EINVAL; n_chains = hweight16(phy->chainmask); - delta = mt76_tx_power_nss_delta(n_chains); + delta = mt76_tx_power_path_delta(n_chains); *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ee6ed89fe496..5f8d81cda6cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1398,12 +1398,12 @@ static inline bool mt76_is_skb_pktid(u8 pktid) return pktid >= MT_PACKET_ID_FIRST; } -static inline u8 mt76_tx_power_nss_delta(u8 nss) +static inline u8 mt76_tx_power_path_delta(u8 path) { - static const u8 nss_delta[4] = { 0, 6, 9, 12 }; - u8 idx = nss - 1; + static const u8 path_delta[5] = { 0, 6, 9, 12, 14 }; + u8 idx = path - 1; - return (idx < ARRAY_SIZE(nss_delta)) ? nss_delta[idx] : 0; + return (idx < ARRAY_SIZE(path_delta)) ? path_delta[idx] : 0; } static inline bool mt76_testmode_enabled(struct mt76_phy *phy) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 66ba3be27343..aae80005a3c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -273,7 +273,7 @@ void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband) { int i, n_chains = hweight8(dev->mphy.antenna_mask), target_chains; - int delta_idx, delta = mt76_tx_power_nss_delta(n_chains); + int delta_idx, delta = mt76_tx_power_path_delta(n_chains); u8 *eep = (u8 *)dev->mt76.eeprom.data; enum nl80211_band band = sband->band; struct mt76_power_limits limits; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index b8fcd4eb3fbb..4064e193d4de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2067,7 +2067,7 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku) }; tx_power = mt76_get_sar_power(mphy, mphy->chandef.chan, tx_power); - tx_power -= mt76_tx_power_nss_delta(n_chains); + tx_power -= mt76_tx_power_path_delta(n_chains); tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, &limits, tx_power); mphy->txpower_cur = tx_power; @@ -2084,8 +2084,8 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku) int delta = 0; if (i < n_chains - 1) - delta = mt76_tx_power_nss_delta(n_chains) - - mt76_tx_power_nss_delta(i + 1); + delta = mt76_tx_power_path_delta(n_chains) - + mt76_tx_power_path_delta(i + 1); sku[MT_SKU_1SS_DELTA + i] = delta; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index be9527dd0269..3e30ca5155d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -285,7 +285,7 @@ static void __mt7915_init_txpower(struct mt7915_phy *phy, { struct mt7915_dev *dev = phy->dev; int i, n_chains = hweight16(phy->mt76->chainmask); - int nss_delta = mt76_tx_power_nss_delta(n_chains); + int path_delta = mt76_tx_power_path_delta(n_chains); int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -305,7 +305,7 @@ static void __mt7915_init_txpower(struct mt7915_phy *phy, target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); - target_power += nss_delta; + target_power += path_delta; target_power = DIV_ROUND_UP(target_power, 2); chan->max_power = min_t(int, chan->max_reg_power, target_power); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 213c7bcd4ade..a9599c286328 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -317,8 +317,8 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy, struct ieee80211_supported_band *sband) { struct mt7996_dev *dev = phy->dev; - int i, nss = hweight16(phy->mt76->chainmask); - int nss_delta = mt76_tx_power_nss_delta(nss); + int i, n_chains = hweight16(phy->mt76->chainmask); + int path_delta = mt76_tx_power_path_delta(n_chains); int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -330,7 +330,7 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy, target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); - target_power += nss_delta; + target_power += path_delta; target_power = DIV_ROUND_UP(target_power, 2); chan->max_power = min_t(int, chan->max_reg_power, target_power); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index b11dd3dd5c46..78ae9f5cb176 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -688,7 +688,7 @@ mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } n_chains = hweight16(phy->mt76->chainmask); - delta = mt76_tx_power_nss_delta(n_chains); + delta = mt76_tx_power_path_delta(n_chains); *dbm = DIV_ROUND_UP(phy->mt76->txpower_cur + delta, 2); return 0; From e54b870212c079bef4ff61238f8c1278a14d1863 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Wed, 7 May 2025 13:31:31 +0800 Subject: [PATCH 48/48] wifi: mt76: mt7925: add rfkill_poll for hardware rfkill Add mac80211 rfkill_poll ops to monitor hardware rfkill state and state change will be updated. Signed-off-by: Allan Wang Link: https://patch.msgid.link/20250507053131.4173691-1-allan.wang@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7925/main.c | 16 ++++++++ .../net/wireless/mediatek/mt76/mt7925/mcu.c | 37 +++++++++++++++++++ .../wireless/mediatek/mt76/mt7925/mt7925.h | 1 + .../net/wireless/mediatek/mt76/mt7925/pci.c | 4 ++ 5 files changed, 59 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 97f9d6da39bd..27daf419560a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1306,6 +1306,7 @@ enum { MCU_UNI_CMD_PER_STA_INFO = 0x6d, MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, + MCU_UNI_CMD_RADIO_STATUS = 0x80, MCU_UNI_CMD_SDO = 0x88, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index f1d0e29ebd55..94b0099dcd41 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -334,6 +334,9 @@ int __mt7925_start(struct mt792x_phy *phy) ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, MT792x_WATCHDOG_TIME); + if (phy->chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) + wiphy_rfkill_start_polling(mphy->hw->wiphy); + return 0; } EXPORT_SYMBOL_GPL(__mt7925_start); @@ -2205,6 +2208,18 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_unlock(&dev->mt76.mutex); } +static void mt7925_rfkill_poll(struct ieee80211_hw *hw) +{ + struct mt792x_phy *phy = mt792x_hw_phy(hw); + int ret; + + mt792x_mutex_acquire(phy->dev); + ret = mt7925_mcu_wf_rf_pin_ctrl(phy); + mt792x_mutex_release(phy->dev); + + wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0); +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -2267,6 +2282,7 @@ const struct ieee80211_ops mt7925_ops = { .link_info_changed = mt7925_link_info_changed, .change_vif_links = mt7925_change_vif_links, .change_sta_links = mt7925_change_sta_links, + .rfkill_poll = mt7925_rfkill_poll, }; EXPORT_SYMBOL_GPL(mt7925_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 708be543954c..9d6e7f328b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -3682,6 +3682,43 @@ int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy) return 0; } +int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy) +{ +#define UNI_CMD_RADIO_STATUS_GET 0 + struct mt792x_dev *dev = phy->dev; + struct sk_buff *skb; + int ret; + struct { + __le16 tag; + __le16 len; + u8 rsv[4]; + } __packed req = { + .tag = UNI_CMD_RADIO_STATUS_GET, + .len = cpu_to_le16(sizeof(req)), + }; + struct mt7925_radio_status_event { + __le16 tag; + __le16 len; + + u8 data; + u8 rsv[3]; + } __packed *status; + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_UNI_CMD(RADIO_STATUS), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + skb_pull(skb, sizeof(struct tlv)); + status = (struct mt7925_radio_status_event *)skb->data; + ret = status->data; + + dev_kfree_skb(skb); + + return ret; +} + int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, u8 bit_op, u32 bit_map) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index c507dcae07d4..1b165d0d8bd3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -365,6 +365,7 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, int link_id); +int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy); int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 2e20ecc71207..89dc30f7c6b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -31,6 +31,10 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev) { int i; struct mt76_connac_pm *pm = &dev->pm; + struct ieee80211_hw *hw = mt76_hw(dev); + + if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) + wiphy_rfkill_stop_polling(hw->wiphy); cancel_work_sync(&dev->init_work); mt76_unregister_device(&dev->mt76);