From da1b9a55ff116cb040528ef664c70a4eec03ae99 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 16 May 2025 20:41:06 +0200 Subject: [PATCH 01/16] wifi: p54: prevent buffer-overflow in p54_rx_eeprom_readback() Robert Morris reported: |If a malicious USB device pretends to be an Intersil p54 wifi |interface and generates an eeprom_readback message with a large |eeprom->v1.len, p54_rx_eeprom_readback() will copy data from the |message beyond the end of priv->eeprom. | |static void p54_rx_eeprom_readback(struct p54_common *priv, | struct sk_buff *skb) |{ | struct p54_hdr *hdr = (struct p54_hdr *) skb->data; | struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; | | if (priv->fw_var >= 0x509) { | memcpy(priv->eeprom, eeprom->v2.data, | le16_to_cpu(eeprom->v2.len)); | } else { | memcpy(priv->eeprom, eeprom->v1.data, | le16_to_cpu(eeprom->v1.len)); | } | [...] The eeprom->v{1,2}.len is set by the driver in p54_download_eeprom(). The device is supposed to provide the same length back to the driver. But yes, it's possible (like shown in the report) to alter the value to something that causes a crash/panic due to overrun. This patch addresses the issue by adding the size to the common device context, so p54_rx_eeprom_readback no longer relies on possibly tampered values... That said, it also checks if the "firmware" altered the value and no longer copies them. The one, small saving grace is: Before the driver tries to read the eeprom, it needs to upload >a< firmware. the vendor firmware has a proprietary license and as a reason, it is not present on most distributions by default. Cc: Reported-by: Robert Morris Closes: https://lore.kernel.org/linux-wireless/28782.1747258414@localhost/ Fixes: 7cb770729ba8 ("p54: move eeprom code into common library") Signed-off-by: Christian Lamparter Link: https://patch.msgid.link/20250516184107.47794-1-chunkeey@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/intersil/p54/fwio.c | 2 ++ drivers/net/wireless/intersil/p54/p54.h | 1 + drivers/net/wireless/intersil/p54/txrx.c | 13 +++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index 772084a9bd8d..3baf8ab01e22 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -231,6 +231,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, mutex_lock(&priv->eeprom_mutex); priv->eeprom = buf; + priv->eeprom_slice_size = len; eeprom_hdr = skb_put(skb, eeprom_hdr_size + len); if (priv->fw_var < 0x509) { @@ -253,6 +254,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf, ret = -EBUSY; } priv->eeprom = NULL; + priv->eeprom_slice_size = 0; mutex_unlock(&priv->eeprom_mutex); return ret; } diff --git a/drivers/net/wireless/intersil/p54/p54.h b/drivers/net/wireless/intersil/p54/p54.h index 522656de4159..aeb5e40cc5ef 100644 --- a/drivers/net/wireless/intersil/p54/p54.h +++ b/drivers/net/wireless/intersil/p54/p54.h @@ -258,6 +258,7 @@ struct p54_common { /* eeprom handling */ void *eeprom; + size_t eeprom_slice_size; struct completion eeprom_comp; struct mutex eeprom_mutex; }; diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 8414aa208655..2deb1bb54f24 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -496,14 +496,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv, return ; if (priv->fw_var >= 0x509) { - memcpy(priv->eeprom, eeprom->v2.data, - le16_to_cpu(eeprom->v2.len)); + if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size) + return; + + memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size); } else { - memcpy(priv->eeprom, eeprom->v1.data, - le16_to_cpu(eeprom->v1.len)); + if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size) + return; + + memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size); } priv->eeprom = NULL; + priv->eeprom_slice_size = 0; tmp = p54_find_and_unlink_skb(priv, hdr->req_id); dev_kfree_skb_any(tmp); complete(&priv->eeprom_comp); -- 2.51.0 From 78a7a126dc5b8e3c5a3d4da9f513e0236d2dc1a3 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 May 2025 16:02:07 +0530 Subject: [PATCH 02/16] wifi: mac80211: validate SCAN_FLAG_AP in scan request during MLO When an AP interface is already beaconing, a subsequent scan is not allowed unless the user space explicitly sets the flag NL80211_SCAN_FLAG_AP in the scan request. If this flag is not set, the scan request will be returned with the error code -EOPNOTSUPP. However, this restriction currently applies only to non-ML interfaces. For ML interfaces, scans are allowed without this flag being explicitly set by the user space which is wrong. This is because the beaconing check currently uses only the deflink, which does not get set during MLO. Hence to fix this, during MLO, use the existing helper ieee80211_num_beaconing_links() to know if any of the link is beaconing. Signed-off-by: Aditya Kumar Singh Link: https://patch.msgid.link/20250516-bug_fix_mlo_scan-v2-1-12e59d9110ac@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 05b7296b152c..d9d88f2f2831 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2924,7 +2924,7 @@ static int ieee80211_scan(struct wiphy *wiphy, * the frames sent while scanning on other channel will be * lost) */ - if (sdata->deflink.u.ap.beacon && + if (ieee80211_num_beaconing_links(sdata) && (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || !(req->flags & NL80211_SCAN_FLAG_AP))) return -EOPNOTSUPP; -- 2.51.0 From 0b0ff976af94fc2437b62e3798f11aacc3798613 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Singh Date: Fri, 16 May 2025 16:02:08 +0530 Subject: [PATCH 03/16] wifi: mac80211: accept probe response on link address as well If a random MAC address is not requested during scan request, unicast probe response frames are only accepted if the destination address matches the interface address. This works fine for non-ML interfaces. However, with MLO, the same interface can have multiple links, and a scan on a link would be requested with the link address. In such cases, the probe response frame gets dropped which is incorrect. Therefore, add logic to check if any of the link addresses match the destination address if the interface address does not match. Signed-off-by: Aditya Kumar Singh Link: https://patch.msgid.link/20250516-bug_fix_mlo_scan-v2-2-12e59d9110ac@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index cb7079071885..7b8da40a912d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -240,6 +240,9 @@ static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *channel, u32 scan_flags, const u8 *da) { + struct ieee80211_link_data *link_sdata; + u8 link_id; + if (!sdata) return false; @@ -251,7 +254,20 @@ static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, if (scan_flags & NL80211_SCAN_FLAG_RANDOM_ADDR) return true; - return ether_addr_equal(da, sdata->vif.addr); + + if (ether_addr_equal(da, sdata->vif.addr)) + return true; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + link_sdata = rcu_dereference(sdata->link[link_id]); + if (!link_sdata) + continue; + + if (ether_addr_equal(da, link_sdata->conf->addr)) + return true; + } + + return false; } void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) -- 2.51.0 From 7014fe5358601d882b2809dea9fd1f6be409c943 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Wed, 9 Apr 2025 22:07:41 +0800 Subject: [PATCH 04/16] 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], -- 2.51.0 From a4e32b306a304dda5707281492d96b6dd7a91275 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:42 +0800 Subject: [PATCH 05/16] 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); -- 2.51.0 From 76d13deb1aa9ac93c079dc5508d924ec01585558 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:43 +0800 Subject: [PATCH 06/16] 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 @@ exit: 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, -- 2.51.0 From 9ba4a76db9eb0596c3950933ec029d6b40c39cc6 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:44 +0800 Subject: [PATCH 07/16] 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 | 192 ++++++++++++------ .../wireless/mediatek/mt76/mt7996/mt7996.h | 2 + .../net/wireless/mediatek/mt76/mt7996/regs.h | 4 +- 3 files changed, 135 insertions(+), 63 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)) { + 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, 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); - RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + 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)); - - queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA; - mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2)); - - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + 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)); + + /* 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)); + + /* 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) -- 2.51.0 From f6c87411d15fc4efadec944c7925e8f73c1972b2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:45 +0800 Subject: [PATCH 08/16] 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; + + 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, - MT_HIF_REMAP_L1_MASK, - 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 -- 2.51.0 From 7316813a9cb3a521874c56041e1a0d1e2c7f3402 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:46 +0800 Subject: [PATCH 09/16] 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, -- 2.51.0 From 6d72f267c6812abb59fec773ac74a195bca11a66 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:47 +0800 Subject: [PATCH 10/16] 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; -- 2.51.0 From b7ddeb9cc43949de58b6a422162db0a196c5d383 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Wed, 9 Apr 2025 22:07:48 +0800 Subject: [PATCH 11/16] 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; -- 2.51.0 From 14d3990eb7c37e4f3273f9130bd964a6511e4ebd Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Wed, 9 Apr 2025 22:07:49 +0800 Subject: [PATCH 12/16] 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); -- 2.51.0 From 8d63161d2e92d124bd59e1c42904b7ed256ceb94 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Wed, 9 Apr 2025 22:07:50 +0800 Subject: [PATCH 13/16] 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], -- 2.51.0 From 888208d1ccc41bebe97744445787183b17bb3ea4 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:09 +0800 Subject: [PATCH 14/16] 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); -- 2.51.0 From 758e0cc3a4928c550820171ce8bc9176ecac6386 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:18 +0800 Subject: [PATCH 15/16] 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 | 40 +++++++++---- .../net/wireless/mediatek/mt76/mt7915/mcu.h | 2 +- .../wireless/mediatek/mt76/mt7915/mt7915.h | 22 +++++-- 5 files changed, 87 insertions(+), 60 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 || val > RADAR_BACKGROUND) + return -EINVAL; - if (val > MT_RX_SEL2) + 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 ((r->band_idx && !dev->phy.mt76->band_idx) && - dev->mt76.phys[MT_BAND1]) - mphy = dev->mt76.phys[MT_BAND1]; + 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); @@ -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) { -- 2.51.0 From 1529e335f93dd72fead39bd28fab5b51b6f3ca80 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 20 Mar 2025 09:59:26 +0800 Subject: [PATCH 16/16] 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; - /* start CAC */ - err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx, - MT_RX_SEL0, 0); - if (err < 0) - return err; + rdd_idx = mt7996_get_rdd_idx(phy, false); + if (rdd_idx < 0) + return -EINVAL; - err = mt7996_dfs_start_rdd(dev, band_idx); + /* start CAC */ + err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, rdd_idx, 0); if (err < 0) return err; - 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; + err = mt7996_dfs_start_rdd(dev, rdd_idx); - 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, -- 2.51.0