From 14cdeaf9504cd37589e8acfedf644d32fb29a429 Mon Sep 17 00:00:00 2001 From: Ryder Lee Date: Fri, 25 Aug 2023 01:08:37 +0800 Subject: [PATCH 01/62] wifi: mt76: add ability to explicitly forbid LED registration with DT Add ability to explicitly forbid LED registration using DT led\status = "disabled". Tested-by: Alexey D. Filimonov Signed-off-by: Alexey D. Filimonov Signed-off-by: Ryder Lee Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 51a767121b0d..81746d4cd4c8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -197,10 +197,33 @@ static int mt76_led_init(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; struct ieee80211_hw *hw = phy->hw; + struct device_node *np = dev->dev->of_node; if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) return 0; + np = of_get_child_by_name(np, "led"); + if (np) { + if (!of_device_is_available(np)) { + of_node_put(np); + dev_info(dev->dev, + "led registration was explicitly disabled by dts\n"); + return 0; + } + + if (phy == &dev->phy) { + int led_pin; + + if (!of_property_read_u32(np, "led-sources", &led_pin)) + phy->leds.pin = led_pin; + + phy->leds.al = + of_property_read_bool(np, "led-active-low"); + } + + of_node_put(np); + } + snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", wiphy_name(hw->wiphy)); @@ -211,20 +234,8 @@ static int mt76_led_init(struct mt76_phy *phy) mt76_tpt_blink, ARRAY_SIZE(mt76_tpt_blink)); - if (phy == &dev->phy) { - struct device_node *np = dev->dev->of_node; - - np = of_get_child_by_name(np, "led"); - if (np) { - int led_pin; - - if (!of_property_read_u32(np, "led-sources", &led_pin)) - phy->leds.pin = led_pin; - phy->leds.al = of_property_read_bool(np, - "led-active-low"); - of_node_put(np); - } - } + dev_info(dev->dev, + "registering led '%s'\n", phy->leds.name); return led_classdev_register(dev->dev, &phy->leds.cdev); } From ce18572b7b5933ae3f97ea201d03463c320f0956 Mon Sep 17 00:00:00 2001 From: Rong Yan Date: Sun, 1 Oct 2023 23:02:05 +0800 Subject: [PATCH 02/62] wifi: mt76: mt7921: support 5.9/6GHz channel config in acpi The mtcl table, configured by platform vendor, provides regulatory information for 5.9/6 GHz channels. mt792x should work on corresponding channels supported by mtcl. This patch would parse the settings in mtcl table and apply the result into chip side. Signed-off-by: Rong Yan Co-developed-by: Deren Wu Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 4 +- drivers/net/wireless/mediatek/mt76/mt792x.h | 6 +++ .../wireless/mediatek/mt76/mt792x_acpi_sar.c | 53 +++++++++++++++++++ .../wireless/mediatek/mt76/mt792x_acpi_sar.h | 2 + 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 63f3d4a5c9aa..94fc3eb40234 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1260,12 +1260,14 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u8 alpha2[2]; u8 type[2]; u8 env_6g; - u8 rsvd[63]; + u8 mtcl_conf; + u8 rsvd[62]; } __packed req = { .idx = idx, .env = env_cap, .env_6g = dev->phy.power_type, .acpi_conf = mt792x_acpi_get_flags(&dev->phy), + .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; u8 i, *pos; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 36fae736dd19..3c897b34aaa7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -382,6 +382,7 @@ int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev); int mt792x_init_acpi_sar(struct mt792x_dev *dev); int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default); u8 mt792x_acpi_get_flags(struct mt792x_phy *phy); +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2); #else static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev) { @@ -398,6 +399,11 @@ static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) { return 0; } + +static inline u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + return 0xf; +} #endif #endif /* __MT7925_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index 303c0f5c9c66..e7afea87e82e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -348,3 +348,56 @@ u8 mt792x_acpi_get_flags(struct mt792x_phy *phy) return flags; } EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags); + +static u8 +mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl) +{ + u8 config = 0; + + if (cl->cl6g[row] & BIT(column)) + config |= (cl->mode_6g & 0x3) << 2; + if (cl->version > 1 && cl->cl5g9[row] & BIT(column)) + config |= (cl->mode_5g9 & 0x3); + + return config; +} + +u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2) +{ + static const char * const cc_list_all[] = { + "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR", + "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME", + "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR", + "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY", + }; + static const char * const cc_list_eu[] = { + "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE", + "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", + "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL", + "PT", "RO", "MT", "SK", "SI", "ES", "CH", + }; + struct mt792x_acpi_sar *sar = phy->acpisar; + struct mt792x_asar_cl *cl; + int col, row, i; + + if (!sar) + return 0xf; + + cl = sar->countrylist; + if (!cl) + return 0xc; + + for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) { + col = 7 - i % 8; + row = i / 8; + if (!memcmp(cc_list_all[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(row, col, cl); + } + + for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++) + if (!memcmp(cc_list_eu[i], alpha2, 2)) + return mt792x_acpi_get_mtcl_map(0, 6, cl); + + return mt792x_acpi_get_mtcl_map(0, 7, cl); +} +EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h index d6d332e863ba..2298983b6342 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h @@ -77,6 +77,8 @@ struct mt792x_asar_cl { u8 version; u8 mode_6g; u8 cl6g[6]; + u8 mode_5g9; + u8 cl5g9[6]; } __packed; struct mt792x_asar_fg { From 706e83b33103fc5dc945765ddbf6a3e879d21275 Mon Sep 17 00:00:00 2001 From: Yi-Chia Hsieh Date: Thu, 12 Oct 2023 15:00:26 -0700 Subject: [PATCH 03/62] wifi: mt76: mt7996: fix uninitialized variable in parsing txfree Fix the uninitialized variable warning in mt7996_mac_tx_free. Fixes: 2461599f835e ("wifi: mt76: mt7996: get tx_retries and tx_failed from txfree") Signed-off-by: Yi-Chia Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 04540833485f..59ab07b89087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1074,7 +1074,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; struct mt76_txwi_cache *txwi; struct ieee80211_sta *sta = NULL; - struct mt76_wcid *wcid; + struct mt76_wcid *wcid = NULL; LIST_HEAD(free_list); struct sk_buff *skb, *tmp; void *end = data + len; From e874a79250b39447765ac13272b67ac36ccf2a75 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:37 +0200 Subject: [PATCH 04/62] wifi: mt76: fix broken precal loading from MTD for mt7915 Commit 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") was fundamentally broken and never worked. The idea (before NVMEM support) was to expand the MTD function and pass an additional offset. For normal EEPROM load the offset would always be 0. For the purpose of precal loading, an offset was passed that was internally the size of EEPROM, since precal data is right after the EEPROM. Problem is that the offset value passed is never handled and is actually overwrite by offset = be32_to_cpup(list); ret = mtd_read(mtd, offset, len, &retlen, eep); resulting in the passed offset value always ingnored. (and even passing garbage data as precal as the start of the EEPROM is getting read) Fix this by adding to the current offset value, the offset from DT to correctly read the piece of data at the requested location. Cc: stable@vger.kernel.org Fixes: 495184ac91bb ("mt76: mt7915: add support for applying pre-calibration data") Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 7725dd6763ef..7936ac8aa9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -67,7 +67,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs goto out_put_node; } - offset = be32_to_cpup(list); + offset += be32_to_cpup(list); ret = mtd_read(mtd, offset, len, &retlen, eep); put_mtd_device(mtd); if (mtd_is_bitflip(ret)) From c33e5f4cbb9f961e66473a9ace077c4d1f29a5bb Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:38 +0200 Subject: [PATCH 05/62] wifi: mt76: fix typo in mt76_get_of_eeprom_from_nvmem function Fix typo in mt76_get_of_eeprom_from_nvmem where eeprom was misspelled as epprom. Fixes: 5bef3a406c6e ("wifi: mt76: add support for providing eeprom in nvmem cells") Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 7936ac8aa9c0..50820fe00b8b 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -106,7 +106,7 @@ out_put_node: #endif } -static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; @@ -153,7 +153,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - return mt76_get_of_epprom_from_nvmem(dev, eep, len); + return mt76_get_of_eeprom_from_nvmem(dev, eep, len); } EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); From a6342c31ab3b2cfae92298ff91635e8b82fed792 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:39 +0200 Subject: [PATCH 06/62] wifi: mt76: limit support of precal loading for mt7915 to MTD only Limit support for precal loading for mt7915 only to MTD. Passing data from DT doesn't support offset and NVMEM require a different cell name and doesn't support offset hence only MTD way is actually supported. Rename mt76_get_of_eeprom_from_mtd to mt76_get_of_data_from_mtd as it is now used for a more generic purpose and export it. Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 50820fe00b8b..d924338e1a3e 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -28,7 +28,7 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) return 0; } -static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len) { #ifdef CONFIG_MTD struct device_node *np = dev->dev->of_node; @@ -105,6 +105,7 @@ out_put_node: return -ENOENT; #endif } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) { @@ -149,7 +150,7 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, offset, len); if (!ret) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ea828ba0b83a..82a2b293a0fe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1102,6 +1102,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); +int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); struct mt76_queue * diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 76be7308460b..5228f710b3da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -25,7 +25,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_eeprom(mdev, dev->cal, offs, val); + return mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); } static int mt7915_check_eeprom(struct mt7915_dev *dev) From 3d96764e6a22296392866e9fc6318ae912151380 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:40 +0200 Subject: [PATCH 07/62] wifi: mt76: make mt76_get_of_eeprom static again Since mt76_get_of_eeprom is not used by mt7915 anymore, unexport it and make it static again. Also drop offset arg as it's only supported for MTD and was always set to 0, hardcode the MTD functio instead. Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 7 +++---- drivers/net/wireless/mediatek/mt76/mt76.h | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index d924338e1a3e..e193ca8629f8 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -138,7 +138,7 @@ exit: return ret; } -int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) +static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { struct device_node *np = dev->dev->of_node; int ret; @@ -150,13 +150,12 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len) if (!ret) return 0; - ret = mt76_get_of_data_from_mtd(dev, eep, offset, len); + ret = mt76_get_of_data_from_mtd(dev, eep, 0, len); if (!ret) return 0; return mt76_get_of_eeprom_from_nvmem(dev, eep, len); } -EXPORT_SYMBOL_GPL(mt76_get_of_eeprom); void mt76_eeprom_override(struct mt76_phy *phy) @@ -413,6 +412,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len) if (!dev->eeprom.data) return -ENOMEM; - return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len); + return !mt76_get_of_eeprom(dev, dev->eeprom.data, len); } EXPORT_SYMBOL_GPL(mt76_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 82a2b293a0fe..89250801c079 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1103,7 +1103,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); -int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, From a1f57685fe851677d62d3551aa2de674c25120cf Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:41 +0200 Subject: [PATCH 08/62] wifi: mt76: permit to use alternative cell name to eeprom NVMEM load Generilize mt76_get_of_eeprom_from_nvmem to use alternative cell name by passing the cell name as an arg and expose it. Rename it to mt76_get_of_data_from_nvmem to better reflect the now more generic usage. This is to permit driver to load additional cell, like precal cell. Tested-by: Shiji Yang Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index e193ca8629f8..59586fa134e3 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -107,7 +107,8 @@ out_put_node: } EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd); -static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len) +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len) { struct device_node *np = dev->dev->of_node; struct nvmem_cell *cell; @@ -115,7 +116,7 @@ static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int le size_t retlen; int ret = 0; - cell = of_nvmem_cell_get(np, "eeprom"); + cell = of_nvmem_cell_get(np, cell_name); if (IS_ERR(cell)) return PTR_ERR(cell); @@ -137,6 +138,7 @@ exit: return ret; } +EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem); static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) { @@ -154,7 +156,7 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) if (!ret) return 0; - return mt76_get_of_eeprom_from_nvmem(dev, eep, len); + return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len); } void diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 89250801c079..f7979fba2fd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1103,6 +1103,8 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, int mt76_eeprom_init(struct mt76_dev *dev, int len); void mt76_eeprom_override(struct mt76_phy *phy); int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); +int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, + const char *cell_name, int len); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, From fdddaa52641e222ef6149d2faa7c10afe02f647e Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 18 Oct 2023 15:09:42 +0200 Subject: [PATCH 09/62] wifi: mt76: permit to load precal from NVMEM cell for mt7915 Permit to load precal from NVMEM cell for mt7915. The NVMEM cell must be named "precal" to be correctly loaded. NVMEM cell must already account the correct offset and be placed after the EEPROM as the function expect the data right from the start. Tested-by: Shiji Yang Signed-off-by: Christian Marangi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index 5228f710b3da..3bb2643d1b26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -11,6 +11,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) u8 *eeprom = mdev->eeprom.data; u32 val = eeprom[MT_EE_DO_PRE_CAL]; u32 offs; + int ret; if (!dev->flash_mode) return 0; @@ -25,7 +26,11 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev) offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2; - return mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); + ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val); + if (!ret) + return ret; + + return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", val); } static int mt7915_check_eeprom(struct mt7915_dev *dev) From 2fac91f2a1db221b070ea0fda1e2392c92386975 Mon Sep 17 00:00:00 2001 From: Wu Yunchuan Date: Fri, 20 Oct 2023 17:34:32 +0800 Subject: [PATCH 10/62] wifi: mt76: Remove unnecessary (void*) conversions No need cast (void *) to (struct mt7615_phy *). Signed-off-by: Wu Yunchuan Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt792x_mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 955974a82180..ae34d019e588 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -453,7 +453,7 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb) else mphy = &dev->mt76.phy; - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); @@ -481,7 +481,7 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb) ieee80211_ready_on_channel(mphy->hw); - phy = (struct mt7615_phy *)mphy->priv; + phy = mphy->priv; phy->roc_grant = true; wake_up(&phy->roc_wait); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 2222fb9aa103..f12008244db3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1247,7 +1247,7 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx) void mt7915_update_channel(struct mt76_phy *mphy) { - struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv; + struct mt7915_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index b22f06d4411a..c67c4f6ca2aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -269,7 +269,7 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb) dev->mt76.phys[MT_BAND1]) mphy = dev->mt76.phys[MT_BAND1]; - phy = (struct mt7915_phy *)mphy->priv; + phy = mphy->priv; phy->throttle_state = t->ctrl.duty.duty_cycle; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 94fc3eb40234..a9056b55b0a4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -160,7 +160,7 @@ static void mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 9c0e397537ac..c5fd7116929b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -345,7 +345,7 @@ static void mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_phy *mphy = &dev->mt76.phy; - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; spin_lock_bh(&dev->mt76.lock); __skb_queue_tail(&phy->scan_event_list, skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 5d1f8229fdc1..eb29434abee1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -223,7 +223,7 @@ static void mt792x_phy_update_channel(struct mt76_phy *mphy, int idx) { struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76); - struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv; + struct mt792x_phy *phy = mphy->priv; struct mt76_channel_state *state; u64 busy_time, tx_time, rx_time, obss_time; int nf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 59ab07b89087..53a78d971326 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1525,7 +1525,7 @@ mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx) void mt7996_update_channel(struct mt76_phy *mphy) { - struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv; + struct mt7996_phy *phy = mphy->priv; struct mt76_channel_state *state = mphy->chan_state; int nf; From b92158a8dc413d0facaf0d807c66f76a6865c93c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:48 +0200 Subject: [PATCH 11/62] wifi: mt76: mmio: move mt76_mmio_wed_{init,release}_rx_buf in common code Move mt76_mmio_wed_init_rx_buf and mt76_mmio_wed_release_rx_buf routines in common code. This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 75 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 5 ++ .../net/wireless/mediatek/mt76/mt7915/mmio.c | 78 +------------------ 3 files changed, 82 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 86e3d2ac4d0d..350650a0fce2 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -4,6 +4,7 @@ */ #include "mt76.h" +#include "dma.h" #include "trace.h" static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) @@ -84,6 +85,80 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, } EXPORT_SYMBOL_GPL(mt76_set_irq_mask); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + int i; + + for (i = 0; i < dev->rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(dev, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->ptr = NULL; + + mt76_put_rxwi(dev, t); + } + + mt76_free_pending_rxwi(dev); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf); + +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; + int i, len = SKB_WITH_OVERHEAD(q->buf_size); + struct mt76_txwi_cache *t = NULL; + + for (i = 0; i < size; i++) { + enum dma_data_direction dir; + dma_addr_t addr; + u32 offset; + int token; + void *buf; + + t = mt76_get_rxwi(dev); + if (!t) + goto unmap; + + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); + if (!buf) + goto unmap; + + addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; + dir = page_pool_get_dma_dir(q->page_pool); + dma_sync_single_for_device(dev->dma_dev, addr, len, dir); + + desc->buf0 = cpu_to_le32(addr); + token = mt76_rx_token_consume(dev, buf, t, addr); + if (token < 0) { + mt76_put_page_pool_buf(buf, false); + goto unmap; + } + + desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, + token)); + desc++; + } + + return 0; + +unmap: + if (t) + mt76_put_rxwi(dev, t); + mt76_mmio_wed_release_rx_buf(wed); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) { static const struct mt76_bus_ops mt76_mmio_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f7979fba2fd7..5dd6b99afeca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1057,6 +1057,11 @@ static inline u16 mt76_rev(struct mt76_dev *dev) return dev->rev & 0xffff; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index e7d8e03f826f..1621a8150798 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -567,80 +567,6 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) spin_unlock_bh(&dev->mt76.token_lock); } -static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - int i; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - for (i = 0; i < dev->mt76.rx_token_size; i++) { - struct mt76_txwi_cache *t; - - t = mt76_rx_token_release(&dev->mt76, i); - if (!t || !t->ptr) - continue; - - mt76_put_page_pool_buf(t->ptr, false); - t->ptr = NULL; - - mt76_put_rxwi(&dev->mt76, t); - } - - mt76_free_pending_rxwi(&dev->mt76); -} - -static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) -{ - struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; - struct mt76_txwi_cache *t = NULL; - struct mt7915_dev *dev; - struct mt76_queue *q; - int i, len; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; - len = SKB_WITH_OVERHEAD(q->buf_size); - - for (i = 0; i < size; i++) { - enum dma_data_direction dir; - dma_addr_t addr; - u32 offset; - int token; - void *buf; - - t = mt76_get_rxwi(&dev->mt76); - if (!t) - goto unmap; - - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); - if (!buf) - goto unmap; - - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir); - - desc->buf0 = cpu_to_le32(addr); - token = mt76_rx_token_consume(&dev->mt76, buf, t, addr); - if (token < 0) { - mt76_put_page_pool_buf(buf, false); - goto unmap; - } - - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, - token)); - desc++; - } - - return 0; - -unmap: - if (t) - mt76_put_rxwi(&dev->mt76, t); - mt7915_mmio_wed_release_rx_buf(wed); - return -ENOMEM; -} - static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { @@ -780,8 +706,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.init_buf = mt7915_wed_init_buf; wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; - wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; - wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; From 5f60735c08ce3dd368d30bb3b1addf7149cb664c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:49 +0200 Subject: [PATCH 12/62] wifi: mt76: move mt76_mmio_wed_offload_{enable,disable} in common code mt76_mmio_wed_offload_enable and mt76_mmio_wed_offload_disable routines will be reused by mt7996 driver for wed support. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mmio.c | 22 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ .../net/wireless/mediatek/mt76/mt7915/mmio.c | 29 ++----------------- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 350650a0fce2..c34624978a14 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -157,6 +157,28 @@ unmap: return -ENOMEM; } EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); + +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = wed->wlan.token_start; + spin_unlock_bh(&dev->token_lock); + + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable); + +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + spin_lock_bh(&dev->token_lock); + dev->token_size = dev->drv->token_size; + spin_unlock_bh(&dev->token_lock); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 5dd6b99afeca..a1809a6ea8da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1060,6 +1060,8 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #ifdef CONFIG_NET_MEDIATEK_SOC_WED u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 1621a8150798..85cb3fed9505 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -542,31 +542,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) } #ifdef CONFIG_NET_MEDIATEK_SOC_WED -static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = wed->wlan.token_start; - spin_unlock_bh(&dev->mt76.token_lock); - - return !wait_event_timeout(dev->mt76.tx_wait, - !dev->mt76.wed_token_count, HZ); -} - -static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) -{ - struct mt7915_dev *dev; - - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); - - spin_lock_bh(&dev->mt76.token_lock); - dev->mt76.token_size = MT7915_TOKEN_SIZE; - spin_unlock_bh(&dev->mt76.token_lock); -} - static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, struct mtk_wed_wo_rx_stats *stats) { @@ -704,8 +679,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, } wed->wlan.init_buf = mt7915_wed_init_buf; - wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; - wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; From ac4659856c22440e2ad208928a3c5911ac364a54 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:50 +0200 Subject: [PATCH 13/62] wifi: mt76: move mt76_net_setup_tc in common code This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/main.c | 16 +--------------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 81746d4cd4c8..b0dbea964c29 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1853,3 +1853,19 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) return MT_DFS_STATE_ACTIVE; } EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct mt76_phy *phy = hw->priv; + struct mtk_wed_device *wed = &phy->dev->mmio.wed; + + if (!mtk_wed_device_active(wed)) + return -EOPNOTSUPP; + + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); +} +EXPORT_SYMBOL_GPL(mt76_net_setup_tc); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a1809a6ea8da..9035db4129a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1047,6 +1047,12 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); void mt76_pci_disable_aspm(struct pci_dev *pdev); +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data); +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ + static inline u16 mt76_chip(struct mt76_dev *dev) { return dev->rev >> 16; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index a3fd54cc1911..ba34c8e19aab 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1653,20 +1653,6 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, return 0; } - -static int -mt7915_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct net_device *netdev, enum tc_setup_type type, - void *type_data) -{ - struct mt7915_dev *dev = mt7915_hw_dev(hw); - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - - if (!mtk_wed_device_active(wed)) - return -EOPNOTSUPP; - - return mtk_wed_device_setup_tc(wed, netdev, type, type_data); -} #endif const struct ieee80211_ops mt7915_ops = { @@ -1721,6 +1707,6 @@ const struct ieee80211_ops mt7915_ops = { .set_radar_background = mt7915_set_radar_background, #ifdef CONFIG_NET_MEDIATEK_SOC_WED .net_fill_forward_path = mt7915_net_fill_forward_path, - .net_setup_tc = mt7915_net_setup_tc, + .net_setup_tc = mt76_net_setup_tc, #endif }; From 132d74d31e86130b4e8b8c5d7bfe05c227d989d6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:51 +0200 Subject: [PATCH 14/62] wifi: mt76: introduce mt76_queue_is_wed_tx_free utility routine This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt76.h | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7915/dma.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 511fe7e6e744..d9e11817a563 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -724,7 +724,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - if (q->flags != MT_WED_Q_TXFREE) + if (!mt76_queue_is_wed_tx_free(q)) mt76_dma_queue_reset(dev, q); return 0; @@ -775,7 +775,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) /* reset WED rx queues */ mt76_dma_wed_setup(dev, q, true); - if (q->flags != MT_WED_Q_TXFREE) { + if (!mt76_queue_is_wed_tx_free(q)) { mt76_dma_sync_idx(dev, q); mt76_dma_rx_fill(dev, q, false); } @@ -818,7 +818,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) bool more; if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && - q->flags == MT_WED_Q_TXFREE) { + mt76_queue_is_wed_tx_free(q)) { dma_idx = Q_READ(dev, q, dma_idx); check_ddone = true; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 9035db4129a9..e32d9c7089f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1562,6 +1562,12 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct mt76_power_limits *dest, s8 target_power); +static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) +{ + return (q->flags & MT_QFLAG_WED) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; +} + static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) { return (q->flags & MT_QFLAG_WED) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 59a44d79aaed..96b2c3802ac1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -643,7 +643,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { - if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE) + if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) continue; mt76_queue_reset(dev, &dev->mt76.q_rx[i]); From 2e420b88ca86e3322b36793f12d8fd2bff5ed57d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:52 +0200 Subject: [PATCH 15/62] wifi: mt76: introduce wed pointer in mt76_queue Introduce mtk_wed_device pointer in mt76_queue structure in order to configure WED chip. Get rid of dev parameter in Q_READ and Q_WRITE macros. Introduce wed parameter to the following routine signatures: - mt76_init_queue - mt76_init_tx_queue This is a preliminary patch to introduce WED support for mt7996 since mt7996 runs two separate WED chips. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 49 ++++++++++--------- drivers/net/wireless/mediatek/mt76/mac80211.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76.h | 10 ++-- .../net/wireless/mediatek/mt76/mt7603/dma.c | 9 ++-- .../net/wireless/mediatek/mt76/mt7615/dma.c | 6 +-- .../net/wireless/mediatek/mt76/mt76_connac.h | 3 +- .../wireless/mediatek/mt76/mt76_connac_mac.c | 5 +- .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +- .../net/wireless/mediatek/mt76/mt7915/dma.c | 16 ++++-- .../net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7925/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/dma.c | 2 +- .../net/wireless/mediatek/mt76/mt7996/init.c | 3 +- 13 files changed, 65 insertions(+), 50 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index d9e11817a563..3453b4c7b0e1 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -9,11 +9,11 @@ #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) -#define Q_READ(_dev, _q, _field) ({ \ +#define Q_READ(_q, _field) ({ \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ u32 _val; \ if ((_q)->flags & MT_QFLAG_WED) \ - _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \ + _val = mtk_wed_device_reg_read((_q)->wed, \ ((_q)->wed_regs + \ _offset)); \ else \ @@ -21,10 +21,10 @@ _val; \ }) -#define Q_WRITE(_dev, _q, _field, _val) do { \ +#define Q_WRITE(_q, _field, _val) do { \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ if ((_q)->flags & MT_QFLAG_WED) \ - mtk_wed_device_reg_write(&(_dev)->mmio.wed, \ + mtk_wed_device_reg_write((_q)->wed, \ ((_q)->wed_regs + _offset), \ _val); \ else \ @@ -33,8 +33,8 @@ #else -#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field) -#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field) +#define Q_READ(_q, _field) readl(&(_q)->regs->_field) +#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) #endif @@ -188,9 +188,9 @@ EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { - Q_WRITE(dev, q, desc_base, q->desc_dma); - Q_WRITE(dev, q, ring_size, q->ndesc); - q->head = Q_READ(dev, q, dma_idx); + Q_WRITE(q, desc_base, q->desc_dma); + Q_WRITE(q, ring_size, q->ndesc); + q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -206,8 +206,8 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) for (i = 0; i < q->ndesc; i++) q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); - Q_WRITE(dev, q, cpu_idx, 0); - Q_WRITE(dev, q, dma_idx, 0); + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); mt76_dma_sync_idx(dev, q); } @@ -343,7 +343,7 @@ static void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) { wmb(); - Q_WRITE(dev, q, cpu_idx, q->head); + Q_WRITE(q, cpu_idx, q->head); } static void @@ -359,7 +359,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) if (flush) last = -1; else - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); @@ -371,7 +371,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) } if (!flush && q->tail == last) - last = Q_READ(dev, q, dma_idx); + last = Q_READ(q, dma_idx); } spin_unlock_bh(&q->cleanup_lock); @@ -641,7 +641,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED - struct mtk_wed_device *wed = &dev->mmio.wed; int ret, type, ring; u8 flags; @@ -649,7 +648,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) return -EINVAL; flags = q->flags; - if (!mtk_wed_device_active(wed)) + if (!q->wed || !mtk_wed_device_active(q->wed)) q->flags &= ~MT_QFLAG_WED; if (!(q->flags & MT_QFLAG_WED)) @@ -660,9 +659,10 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) switch (type) { case MT76_WED_Q_TX: - ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->tx_ring[ring].reg_base; + q->wed_regs = q->wed->tx_ring[ring].reg_base; break; case MT76_WED_Q_TXFREE: /* WED txfree queue needs ring to be initialized before setup */ @@ -671,14 +671,15 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) mt76_dma_rx_fill(dev, q, false); q->flags = flags; - ret = mtk_wed_device_txfree_ring_setup(wed, q->regs); + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); if (!ret) - q->wed_regs = wed->txfree_ring.reg_base; + q->wed_regs = q->wed->txfree_ring.reg_base; break; case MT76_WED_Q_RX: - ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset); + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, + reset); if (!ret) - q->wed_regs = wed->rx_ring[ring].reg_base; + q->wed_regs = q->wed->rx_ring[ring].reg_base; break; default: ret = -EINVAL; @@ -819,7 +820,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && mt76_queue_is_wed_tx_free(q)) { - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); check_ddone = true; } @@ -829,7 +830,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (check_ddone) { if (q->tail == dma_idx) - dma_idx = Q_READ(dev, q, dma_idx); + dma_idx = Q_READ(q, dma_idx); if (q->tail == dma_idx) break; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index b0dbea964c29..d4004a62af1d 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1736,7 +1736,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna); struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { struct mt76_queue *hwq; int err; @@ -1746,6 +1746,7 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, return ERR_PTR(-ENOMEM); hwq->flags = flags; + hwq->wed = wed; err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); if (err < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index e32d9c7089f7..afcc98dd128f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -199,6 +199,7 @@ struct mt76_queue { u8 hw_idx; u8 flags; + struct mtk_wed_device *wed; u32 wed_regs; dma_addr_t desc_dma; @@ -1121,15 +1122,16 @@ int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, struct mt76_queue * mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); u16 mt76_calculate_default_rate(struct mt76_phy *phy, struct ieee80211_vif *vif, int rateidx); static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, - int n_desc, int ring_base, u32 flags) + int n_desc, int ring_base, void *wed, + u32 flags) { struct mt76_queue *q; - q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags); + q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags); if (IS_ERR(q)) return PTR_ERR(q); @@ -1143,7 +1145,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, { struct mt76_queue *q; - q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0); + q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0); if (IS_ERR(q)) return PTR_ERR(q); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 03ba11a61c90..7a2f5d38562b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -173,13 +173,14 @@ int mt7603_dma_init(struct mt7603_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], - MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_TX_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -189,12 +190,12 @@ int mt7603_dma_init(struct mt7603_dev *dev) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC, - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 0ce01ccc5dce..e7135b2f1742 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev) for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], MT7615_TX_RING_SIZE / 2, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; @@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) return mt7622_init_tx_queues_multi(dev); ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 1f29d8cd900c..e5ebde19af8f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -391,7 +391,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags); + int ring_base, void *wed, u32 flags); + void mt76_connac_write_hw_txp(struct mt76_dev *dev, struct mt76_tx_info *tx_info, void *txp_ptr, u32 id); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 93402d2c2538..c7914643e9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -256,11 +256,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, - int ring_base, u32 flags) + int ring_base, void *wed, u32 flags) { int i, err; - err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, + wed, flags); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 9b5e3fb7b0df..e5ad635d3c56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -199,13 +199,14 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) for (i = 0; i < IEEE80211_NUM_ACS; i++) { ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), MT76x02_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; } ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, - MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0); + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, + NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 96b2c3802ac1..1bceeb5227b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -9,18 +9,20 @@ static int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) { struct mt7915_dev *dev = phy->dev; + struct mtk_wed_device *wed = NULL; - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { if (is_mt798x(&dev->mt76)) ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; else ring_base = MT_WED_TX_RING_BASE; idx -= MT_TXQ_ID(0); + wed = &dev->mt76.mmio.wed; } return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, - MT_WED_Q_TX(idx)); + wed, MT_WED_Q_TX(idx)); } static int mt7915_poll_tx(struct napi_struct *napi, int budget) @@ -492,7 +494,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; - dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed; } else { wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA); wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA); @@ -507,9 +510,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (!dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_MAIN].flags = + mdev->q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(MT7915_RXQ_BAND0); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed; } ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], @@ -528,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (mtk_wed_device_active(&mdev->mmio.wed)) { mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed; if (is_mt7916(mdev)) { wa_rx_base = MT_WED_RX_RING_BASE; wa_rx_idx = MT7915_RXQ_MCU_WA; @@ -544,9 +549,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) if (dev->dbdc_support || dev->phy.mt76->band_idx) { if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) { - dev->mt76.q_rx[MT_RXQ_BAND1].flags = + mdev->q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(MT7915_RXQ_BAND1); dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; + mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed; } /* rx data queue for band1 */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index f04e7095e181..6f83c4c5fce2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -171,7 +171,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, MT7921_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 08ef75e24e1c..734f31ee40d3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -218,7 +218,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev) /* init tx queue */ ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0, MT7925_TX_RING_SIZE, - MT_TX_RING_BASE, 0); + MT_TX_RING_BASE, NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 586e247a1e06..b33346360075 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -268,7 +268,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT_TXQ_ID(dev->mphy.band_idx), MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), 0); + MT_TXQ_RING_BASE(0), NULL, 0); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 55cb1770fa34..b09ae6cc6eb4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -405,7 +405,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, ret = mt76_connac_init_tx_queues(phy->mt76, MT_TXQ_ID(band), MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, 0); + MT_TXQ_RING_BASE(band) + hif1_ofs, + NULL, 0); if (ret) goto error; From af8d2af57584762ef2727831ffca01036ca5bd40 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:53 +0200 Subject: [PATCH 16/62] wifi: mt76: increase MT_QFLAG_WED_TYPE size This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index afcc98dd128f..3fc38f00d0a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -29,8 +29,8 @@ #define MT76_TOKEN_FREE_THR 64 #define MT_QFLAG_WED_RING GENMASK(1, 0) -#define MT_QFLAG_WED_TYPE GENMASK(3, 2) -#define MT_QFLAG_WED BIT(4) +#define MT_QFLAG_WED_TYPE GENMASK(4, 2) +#define MT_QFLAG_WED BIT(5) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ From 83eafc9251d6d30574b629ac637c56d168fcbdd9 Mon Sep 17 00:00:00 2001 From: Sujuan Chen Date: Fri, 20 Oct 2023 12:30:54 +0200 Subject: [PATCH 17/62] wifi: mt76: mt7996: add wed tx support Similar to MT7915, enable Wireless Ethernet Ditpatcher for MT7996 to offload traffic received from the LAN nic and transmitted on the WLAN one Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Sujuan Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 9 +- drivers/net/wireless/mediatek/mt76/mt76.h | 11 ++ .../net/wireless/mediatek/mt76/mt7996/dma.c | 76 ++++++-- .../net/wireless/mediatek/mt76/mt7996/init.c | 30 +++- .../net/wireless/mediatek/mt76/mt7996/mac.c | 31 +++- .../net/wireless/mediatek/mt76/mt7996/main.c | 42 +++++ .../net/wireless/mediatek/mt76/mt7996/mmio.c | 170 ++++++++++++++++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 12 +- .../net/wireless/mediatek/mt76/mt7996/pci.c | 63 ++++--- .../net/wireless/mediatek/mt76/mt7996/regs.h | 5 + 10 files changed, 383 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 3453b4c7b0e1..a7a045488cb2 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -988,10 +988,13 @@ void mt76_dma_cleanup(struct mt76_dev *dev) page_pool_destroy(q->page_pool); } - mt76_free_pending_txwi(dev); - mt76_free_pending_rxwi(dev); - if (mtk_wed_device_active(&dev->mmio.wed)) mtk_wed_device_detach(&dev->mmio.wed); + + if (mtk_wed_device_active(&dev->mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mmio.wed_hif2); + + mt76_free_pending_txwi(dev); + mt76_free_pending_rxwi(dev); } EXPORT_SYMBOL_GPL(mt76_dma_cleanup); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3fc38f00d0a5..8389b493759c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -107,6 +107,16 @@ enum mt76_rxq_id { MT_RXQ_MAIN_WA, MT_RXQ_BAND2, MT_RXQ_BAND2_WA, + MT_RXQ_RRO_BAND0, + MT_RXQ_RRO_BAND1, + MT_RXQ_RRO_BAND2, + MT_RXQ_MSDU_PAGE_BAND0, + MT_RXQ_MSDU_PAGE_BAND1, + MT_RXQ_MSDU_PAGE_BAND2, + MT_RXQ_TXFREE_BAND0, + MT_RXQ_TXFREE_BAND1, + MT_RXQ_TXFREE_BAND2, + MT_RXQ_RRO_IND, __MT_RXQ_MAX }; @@ -604,6 +614,7 @@ struct mt76_mmio { u32 irqmask; struct mtk_wed_device wed; + struct mtk_wed_device wed_hif2; struct completion wed_reset; struct completion wed_reset_complete; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index b33346360075..72912f376bc9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -7,6 +7,26 @@ #include "../dma.h" #include "mac.h" +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, + int ring_base, struct mtk_wed_device *wed) +{ + struct mt7996_dev *dev = phy->dev; + u32 flags = 0; + + if (mtk_wed_device_active(wed)) { + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; + idx -= MT_TXQ_ID(0); + + if (phy->mt76->band_idx == MT_BAND2) + flags = MT_WED_Q_TX(0); + else + flags = MT_WED_Q_TX(idx); + } + + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, + ring_base, wed, flags); +} + static int mt7996_poll_tx(struct napi_struct *napi, int budget) { struct mt7996_dev *dev; @@ -128,7 +148,7 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) } } -void mt7996_dma_start(struct mt7996_dev *dev, bool reset) +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { u32 hif1_ofs = 0; u32 irq_mask; @@ -153,11 +173,7 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) } /* enable interrupts for TX/RX rings */ - irq_mask = MT_INT_MCU_CMD; - if (reset) - goto done; - - irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; + irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; if (!dev->mphy.band_idx) irq_mask |= MT_INT_BAND0_RX_DONE; @@ -168,7 +184,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) if (dev->tbtc_support) irq_mask |= MT_INT_BAND2_RX_DONE; -done: + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) { + u32 wed_irq_mask = irq_mask; + + wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); + } + + irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; + mt7996_irq_enable(dev, irq_mask); mt7996_irq_disable(dev, 0); } @@ -243,15 +268,16 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) */ mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, MT_WFDMA0_RX_INT_SEL_RING3); - - /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */ } - mt7996_dma_start(dev, reset); + mt7996_dma_start(dev, reset, true); } int mt7996_dma_init(struct mt7996_dev *dev) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; + u32 rx_base; u32 hif1_ofs = 0; int ret; @@ -265,10 +291,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) mt7996_dma_disable(dev, true); /* init tx queue */ - ret = mt76_connac_init_tx_queues(dev->phy.mt76, - MT_TXQ_ID(dev->mphy.band_idx), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), NULL, 0); + ret = mt7996_init_tx_queues(&dev->phy, + MT_TXQ_ID(dev->mphy.band_idx), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(0), + wed); if (ret) return ret; @@ -315,6 +342,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* rx data queue for band0 and band1 */ + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); + dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], MT_RXQ_ID(MT_RXQ_MAIN), MT7996_RX_RING_SIZE, @@ -324,6 +356,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ + if (mtk_wed_device_active(wed)) { + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; + 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, @@ -334,17 +371,26 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { /* rx data queue for band2 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; + if (mtk_wed_device_active(wed)) + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2); + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, MT_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs); + rx_base); if (ret) return ret; /* tx free notify event from WA for band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA], MT_RXQ_ID(MT_RXQ_BAND2_WA), MT7996_RX_MCU_RING_SIZE, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index b09ae6cc6eb4..e19c8fb71609 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -156,7 +156,7 @@ mt7996_regd_notifier(struct wiphy *wiphy, } static void -mt7996_init_wiphy(struct ieee80211_hw *hw) +mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) { struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt76_dev *mdev = &phy->dev->mt76; @@ -168,6 +168,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw) hw->max_rx_aggregation_subframes = max_subframes; hw->max_tx_aggregation_subframes = max_subframes; hw->netdev_features = NETIF_F_RXCSUM; + if (mtk_wed_device_active(wed)) + hw->netdev_features |= NETIF_F_HW_TC; hw->radiotap_timestamp.units_pos = IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; @@ -356,6 +358,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, struct mt76_phy *mphy; u32 mac_ofs, hif1_ofs = 0; int ret; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; if (band != MT_BAND1 && band != MT_BAND2) return 0; @@ -367,8 +370,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (phy) return 0; - if (band == MT_BAND2 && dev->hif2) + if (band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + wed = &dev->mt76.mmio.wed_hif2; + } mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); if (!mphy) @@ -401,12 +406,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, mt76_eeprom_override(mphy); /* init wiphy according to mphy and phy */ - mt7996_init_wiphy(mphy->hw); - ret = mt76_connac_init_tx_queues(phy->mt76, - MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, - NULL, 0); + mt7996_init_wiphy(mphy->hw, wed); + ret = mt7996_init_tx_queues(mphy->priv, + MT_TXQ_ID(band), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(band) + hif1_ofs, + wed); if (ret) goto error; @@ -419,6 +424,13 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; + if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { + u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; + + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); + } + return 0; error: @@ -890,7 +902,7 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; - mt7996_init_wiphy(hw); + mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 53a78d971326..6095ce72ab1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -996,6 +996,29 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, return 0; } +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) +{ + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; + __le32 *txwi = ptr; + u32 val; + + memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); + + val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); + txwi[0] = cpu_to_le32(val); + + val = BIT(31) | + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); + txwi[1] = cpu_to_le32(val); + + txp->token = cpu_to_le16(token_id); + txp->nbuf = 1; + txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); + + return MT_TXD_SIZE + sizeof(*txp); +} + static void mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) { @@ -1403,6 +1426,12 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, switch (type) { case PKT_TYPE_TXRX_NOTIFY: + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) && + q == MT_RXQ_TXFREE_BAND2) { + dev_kfree_skb(skb); + break; + } + mt7996_mac_tx_free(dev, skb->data, skb->len); napi_consume_skb(skb, 1); break; @@ -1877,7 +1906,7 @@ void mt7996_mac_reset_work(struct work_struct *work) mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); /* enable DMA Tx/Tx and interrupt */ - mt7996_dma_start(dev, false); + mt7996_dma_start(dev, false, false); clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 09c7a28a3d51..f074616c7007 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1388,6 +1388,44 @@ out: return ret; } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int +mt7996_net_fill_forward_path(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct net_device_path_ctx *ctx, + struct net_device_path *path) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_hw_phy(hw); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + + if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) + wed = &dev->mt76.mmio.wed_hif2; + + if (!mtk_wed_device_active(wed)) + return -ENODEV; + + if (msta->wcid.idx > MT7996_WTBL_STA) + return -EIO; + + path->type = DEV_PATH_MTK_WDMA; + path->dev = ctx->dev; + path->mtk_wdma.wdma_idx = wed->wdma_idx; + path->mtk_wdma.bss = mvif->mt76.idx; + path->mtk_wdma.queue = 0; + path->mtk_wdma.wcid = msta->wcid.idx; + + path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); + ctx->dev = NULL; + + return 0; +} + +#endif + const struct ieee80211_ops mt7996_ops = { .tx = mt7996_tx, .start = mt7996_start, @@ -1432,4 +1470,8 @@ const struct ieee80211_ops mt7996_ops = { .sta_add_debugfs = mt7996_sta_add_debugfs, #endif .set_radar_background = mt7996_set_radar_background, +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + .net_fill_forward_path = mt7996_net_fill_forward_path, + .net_setup_tc = mt76_net_setup_tc, +#endif }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 3a591a7b47ae..ae029ae9969d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -10,6 +10,10 @@ #include "mt7996.h" #include "mac.h" #include "../trace.h" +#include "../dma.h" + +static bool wed_enable; +module_param(wed_enable, bool, 0644); static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, @@ -191,6 +195,106 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); } +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct pci_dev *pci_dev = pdev_ptr; + u32 hif1_ofs = 0; + int ret; + + if (!wed_enable) + return 0; + + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + + if (hif2) + wed = &dev->mt76.mmio.wed_hif2; + + wed->wlan.pci_dev = pci_dev; + wed->wlan.bus_type = MTK_WED_BUS_PCIE; + + wed->wlan.base = devm_ioremap(dev->mt76.dev, + pci_resource_start(pci_dev, 0), + pci_resource_len(pci_dev, 0)); + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); + + if (hif2) { + wed->wlan.wpdma_int = wed->wlan.phy_base + + MT_INT_PCIE1_SOURCE_CSR_EXT; + wed->wlan.wpdma_mask = wed->wlan.phy_base + + MT_INT_PCIE1_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + + wed->wlan.id = 0x7991; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; + } else { + wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; + wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; + wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + + MT7996_TXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; + + wed->wlan.wpdma_rx = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; + + wed->wlan.rx_nbuf = 65536; + wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); + + wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; + wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + + wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; + wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; + + wed->wlan.amsdu_max_subframes = 8; + wed->wlan.amsdu_max_len = 1536; + + wed->wlan.init_buf = mt7996_wed_init_buf; + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + + dev->mt76.rx_token_size += wed->wlan.rx_npkt; + + if (mtk_wed_device_attach(wed)) + return 0; + + *irq = wed->irq; + dev->mt76.dma_dev = wed->dev; + + ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + ret = dma_set_coherent_mask(wed->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + return 1; +#else + return 0; +#endif +} + static int mt7996_mmio_init(struct mt76_dev *mdev, void __iomem *mem_base, u32 device_id) @@ -241,8 +345,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, mdev->mmio.irqmask |= set; if (write_reg) { - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); - mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, + mdev->mmio.irqmask); + if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) { + mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2, + mdev->mmio.irqmask); + } + } else { + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); + } } spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); @@ -260,22 +373,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev, static void mt7996_irq_tasklet(struct tasklet_struct *t) { struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; u32 i, intr, mask, intr1; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (dev->hif2 && mtk_wed_device_active(wed_hif2)) { + mtk_wed_device_irq_set_mask(wed_hif2, 0); + intr1 = mtk_wed_device_irq_get(wed_hif2, + dev->mt76.mmio.irqmask); + if (intr1 & MT_INT_RX_TXFREE_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); + } - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); - intr &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (mtk_wed_device_active(wed)) { + mtk_wed_device_irq_set_mask(wed, 0); + intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); + intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); + } else { + mt76_wr(dev, MT_INT_MASK_CSR, 0); + if (dev->hif2) + mt76_wr(dev, MT_INT1_MASK_CSR, 0); - if (dev->hif2) { - intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); - intr1 &= dev->mt76.mmio.irqmask; - mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); - - intr |= intr1; + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); + intr &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); + if (dev->hif2) { + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); + intr1 &= dev->mt76.mmio.irqmask; + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); + intr |= intr1; + } } trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); @@ -307,10 +434,19 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t) irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - mt76_wr(dev, MT_INT_MASK_CSR, 0); - if (dev->hif2) - mt76_wr(dev, MT_INT1_MASK_CSR, 0); + if (mtk_wed_device_active(wed)) + mtk_wed_device_irq_set_mask(wed, 0); + else + mt76_wr(dev, MT_INT_MASK_CSR, 0); + + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0); + else + mt76_wr(dev, MT_INT1_MASK_CSR, 0); + } if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) return IRQ_NONE; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index e53cf6a3704c..ccb6c5763956 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -37,6 +37,7 @@ #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 +#define MT7996_HW_TOKEN_SIZE 8192 #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ @@ -334,7 +335,9 @@ 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); void mt7996_dma_cleanup(struct mt7996_dev *dev); -void mt7996_dma_start(struct mt7996_dev *dev, bool reset); +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, + int n_desc, int ring_base, struct mtk_wed_device *wed); void mt7996_init_txpower(struct mt7996_dev *dev, struct ieee80211_supported_band *sband); int mt7996_txbf_init(struct mt7996_dev *dev); @@ -495,5 +498,12 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); #endif +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, + bool hif2, int *irq); +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); + +#ifdef CONFIG_MTK_DEBUG +int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); +#endif #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index c5301050ff8b..93ecc9a8dde0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -92,10 +92,10 @@ static int mt7996_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pci_dev *hif2_dev; - struct mt7996_dev *dev; - struct mt76_dev *mdev; struct mt7996_hif *hif2; - int irq, ret; + struct mt7996_dev *dev; + int irq, hif2_irq, ret; + struct mt76_dev *mdev; ret = pcim_enable_device(pdev); if (ret) @@ -125,15 +125,22 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt7996_wfsys_reset(dev); hif2 = mt7996_pci_init_hif2(pdev); - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) - goto free_device; + goto free_wed_or_irq_vector; + + if (!ret) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_device; + + irq = pdev->irq; + } - irq = pdev->irq; ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) - goto free_irq_vector; + goto free_wed_or_irq_vector; mt76_wr(dev, MT_INT_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -143,16 +150,25 @@ static int mt7996_pci_probe(struct pci_dev *pdev, hif2_dev = container_of(hif2->dev, struct pci_dev, dev); dev->hif2 = hif2; - ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); + ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq); if (ret < 0) - goto free_hif2; + goto free_hif2_wed_irq_vector; - dev->hif2->irq = hif2_dev->irq; - ret = devm_request_irq(mdev->dev, dev->hif2->irq, - mt7996_irq_handler, IRQF_SHARED, - KBUILD_MODNAME "-hif", dev); + if (!ret) { + ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, + PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto free_hif2; + + dev->hif2->irq = hif2_dev->irq; + hif2_irq = dev->hif2->irq; + } + + ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler, + IRQF_SHARED, KBUILD_MODNAME "-hif", + dev); if (ret) - goto free_hif2_irq_vector; + goto free_hif2_wed_irq_vector; mt76_wr(dev, MT_INT1_MASK_CSR, 0); /* master switch of PCIe tnterrupt enable */ @@ -167,16 +183,23 @@ static int mt7996_pci_probe(struct pci_dev *pdev, free_hif2_irq: if (dev->hif2) - devm_free_irq(mdev->dev, dev->hif2->irq, dev); -free_hif2_irq_vector: - if (dev->hif2) - pci_free_irq_vectors(hif2_dev); + devm_free_irq(mdev->dev, hif2_irq, dev); +free_hif2_wed_irq_vector: + if (dev->hif2) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2); + else + pci_free_irq_vectors(hif2_dev); + } free_hif2: if (dev->hif2) put_device(dev->hif2->dev); devm_free_irq(mdev->dev, irq, dev); -free_irq_vector: - pci_free_irq_vectors(pdev); +free_wed_or_irq_vector: + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_detach(&dev->mt76.mmio.wed); + else + pci_free_irq_vectors(pdev); free_device: mt76_free_device(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 0086a7866657..b7d78adce11a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -330,6 +330,7 @@ enum base_rev { #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) +#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) @@ -374,6 +375,9 @@ enum base_rev { #define MT_WFDMA0_PCIE1_BASE 0xd8000 #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) +#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118) +#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c) + #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) @@ -419,6 +423,7 @@ enum base_rev { #define MT_INT_RX_TXFREE_MAIN BIT(17) #define MT_INT_RX_TXFREE_TRI BIT(15) #define MT_INT_MCU_CMD BIT(29) +#define MT_INT_RX_TXFREE_EXT BIT(26) #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) From 5bb7a655045ebc023f421c13c2156fcd478185bc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:55 +0200 Subject: [PATCH 18/62] wifi: mt76: dma: introduce __mt76_dma_queue_reset utility routine This is a preliminary patch to introduce WED support for mt7996 Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index a7a045488cb2..12615b49c0d7 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -195,7 +195,8 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) } static void -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { int i; @@ -206,11 +207,19 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) for (i = 0; i < q->ndesc; i++) q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); - Q_WRITE(q, cpu_idx, 0); - Q_WRITE(q, dma_idx, 0); + if (reset_idx) { + Q_WRITE(q, cpu_idx, 0); + Q_WRITE(q, dma_idx, 0); + } mt76_dma_sync_idx(dev, q); } +static void +mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) +{ + __mt76_dma_queue_reset(dev, q, true); +} + static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) From b8b36f47070f47dbfd3dc8eb0b674d6103306935 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:56 +0200 Subject: [PATCH 19/62] wifi: mt76: mt7996: use u16 for val field in mt7996_mcu_set_rro signature This is a preliminary patch to introduce WED rx support for mt7996 driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index bf917beb9439..3ecdc09323c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4019,7 +4019,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev) &req, sizeof(req), false); } -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val) +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ccb6c5763956..d4425c133ced 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -397,7 +397,7 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); -int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val); +int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl); int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); From 950d0abb5cd94f2b0710c5c42ac4398c91a7ff22 Mon Sep 17 00:00:00 2001 From: Bo Jiao Date: Fri, 20 Oct 2023 12:30:57 +0200 Subject: [PATCH 20/62] wifi: mt76: mt7996: add wed rx support Similar to MT7915, enable Wireless Ethernet Ditpatcher for MT7996 to offload traffic received from the WLAN nic and transmitted on the LAN one Co-developed-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Signed-off-by: Bo Jiao Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 149 +++++++++---- drivers/net/wireless/mediatek/mt76/dma.h | 43 ++++ drivers/net/wireless/mediatek/mt76/mt76.h | 50 ++++- .../net/wireless/mediatek/mt76/mt7996/dma.c | 198 ++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7996/init.c | 175 +++++++++++++++- .../net/wireless/mediatek/mt76/mt7996/mac.c | 41 +++- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 24 ++- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 2 + .../net/wireless/mediatek/mt76/mt7996/mmio.c | 60 ++++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 55 +++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 62 +++++- 11 files changed, 772 insertions(+), 87 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 12615b49c0d7..7c76afdaef68 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -189,7 +189,10 @@ static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { Q_WRITE(q, desc_base, q->desc_dma); - Q_WRITE(q, ring_size, q->ndesc); + if (q->flags & MT_QFLAG_WED_RRO_EN) + Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); + else + Q_WRITE(q, ring_size, q->ndesc); q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -198,14 +201,16 @@ static void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, bool reset_idx) { - int i; - if (!q || !q->ndesc) return; - /* clear descriptors */ - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + /* clear descriptors */ + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } if (reset_idx) { Q_WRITE(q, cpu_idx, 0); @@ -224,13 +229,22 @@ static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) { - struct mt76_desc *desc = &q->desc[q->head]; struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; + struct mt76_desc *desc; u32 buf1 = 0, ctrl; int idx = q->head; int rx_token; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + data = &rro_desc[q->head]; + goto done; + } + + desc = &q->desc[q->head]; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); if (mt76_queue_is_wed_rx(q)) { @@ -253,6 +267,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); WRITE_ONCE(desc->info, 0); +done: entry->dma_addr[0] = buf->addr; entry->dma_len[0] = buf->len; entry->txwi = txwi; @@ -401,19 +416,26 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, { struct mt76_queue_entry *e = &q->entry[idx]; struct mt76_desc *desc = &q->desc[idx]; - void *buf; + u32 ctrl, desc_info, buf1; + void *buf = e->buf; + if (mt76_queue_is_wed_rro_ind(q)) + goto done; + + ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); if (len) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); *more = !(ctrl & MT_DMA_CTL_LAST_SEC0); } + desc_info = le32_to_cpu(desc->info); if (info) - *info = le32_to_cpu(desc->info); + *info = desc_info; + + buf1 = le32_to_cpu(desc->buf1); + mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info); if (mt76_queue_is_wed_rx(q)) { - u32 buf1 = le32_to_cpu(desc->buf1); u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1); struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token); @@ -429,23 +451,16 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, t->ptr = NULL; mt76_put_rxwi(dev, t); - - if (drop) { - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); - - *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | - MT_DMA_CTL_DROP)); - + if (drop) *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); - } } else { - buf = e->buf; - e->buf = NULL; dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size), page_pool_get_dma_dir(q->page_pool)); } +done: + e->buf = NULL; return buf; } @@ -459,11 +474,16 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, if (!q->queued) return NULL; - if (flush) - q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); - else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + if (mt76_queue_is_wed_rro_data(q)) return NULL; + if (!mt76_queue_is_wed_rro_ind(q)) { + if (flush) + q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); + else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) + return NULL; + } + q->tail = (q->tail + 1) % q->ndesc; q->queued--; @@ -615,11 +635,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, spin_lock_bh(&q->lock); while (q->queued < q->ndesc - 1) { + struct mt76_queue_buf qbuf = {}; enum dma_data_direction dir; - struct mt76_queue_buf qbuf; dma_addr_t addr; int offset; - void *buf; + void *buf = NULL; + + if (mt76_queue_is_wed_rro_ind(q)) + goto done; buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); if (!buf) @@ -630,6 +653,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, dma_sync_single_for_device(dev->dma_dev, addr, len, dir); qbuf.addr = addr + q->buf_offset; +done: qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false; if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { @@ -639,7 +663,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, frames++; } - if (frames) + if (frames || mt76_queue_is_wed_rx(q)) mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); @@ -650,8 +674,8 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) { #ifdef CONFIG_NET_MEDIATEK_SOC_WED - int ret, type, ring; - u8 flags; + int ret = 0, type, ring; + u16 flags; if (!q || !q->ndesc) return -EINVAL; @@ -678,7 +702,6 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) q->flags = 0; mt76_dma_queue_reset(dev, q); mt76_dma_rx_fill(dev, q, false); - q->flags = flags; ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); if (!ret) @@ -690,9 +713,31 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) if (!ret) q->wed_regs = q->wed->rx_ring[ring].reg_base; break; + case MT76_WED_RRO_Q_DATA: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_MSDU_PG: + q->flags &= ~MT_QFLAG_WED; + __mt76_dma_queue_reset(dev, q, false); + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); + q->head = q->ndesc - 1; + q->queued = q->head; + break; + case MT76_WED_RRO_Q_IND: + q->flags &= ~MT_QFLAG_WED; + mt76_dma_queue_reset(dev, q); + mt76_dma_rx_fill(dev, q, false); + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); + break; default: ret = -EINVAL; + break; } + q->flags = flags; return ret; #else @@ -716,11 +761,26 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, q->buf_size = bufsize; q->hw_idx = idx; - size = q->ndesc * sizeof(struct mt76_desc); - q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL); + size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) + : sizeof(struct mt76_desc); + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, + &q->desc_dma, GFP_KERNEL); if (!q->desc) return -ENOMEM; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + int i; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + for (i = 0; i < q->ndesc; i++) { + struct mt76_wed_rro_ind *cmd; + + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; + cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; + } + } + size = q->ndesc * sizeof(*q->entry); q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (!q->entry) @@ -734,8 +794,13 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (ret) return ret; - if (!mt76_queue_is_wed_tx_free(q)) - mt76_dma_queue_reset(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) { + if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) || + mt76_queue_is_wed_tx_free(q)) + return 0; + } + + mt76_dma_queue_reset(dev, q); return 0; } @@ -757,7 +822,8 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) if (!buf) break; - mt76_put_page_pool_buf(buf, false); + if (!mt76_queue_is_wed_rro(q)) + mt76_put_page_pool_buf(buf, false); } while (1); spin_lock_bh(&q->lock); @@ -773,13 +839,16 @@ static void mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) { struct mt76_queue *q = &dev->q_rx[qid]; - int i; if (!q->ndesc) return; - for (i = 0; i < q->ndesc; i++) - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + if (!mt76_queue_is_wed_rro_ind(q)) { + int i; + + for (i = 0; i < q->ndesc; i++) + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); + } mt76_dma_rx_cleanup(dev, q); @@ -991,6 +1060,10 @@ void mt76_dma_cleanup(struct mt76_dev *dev) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + continue; + netif_napi_del(&dev->napi[i]); mt76_dma_rx_cleanup(dev, q); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 1b090d78cd05..e549e678b69f 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -23,8 +23,17 @@ #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11) #define MT_DMA_PPE_ENTRY GENMASK(30, 16) +#define MT_DMA_INFO_DMA_FRAG BIT(9) #define MT_DMA_INFO_PPE_VLD BIT(31) +#define MT_DMA_CTL_PN_CHK_FAIL BIT(13) +#define MT_DMA_CTL_VER_MASK BIT(7) + +#define MT_DMA_RRO_EN BIT(13) + +#define MT_DMA_WED_IND_CMD_CNT 8 +#define MT_DMA_WED_IND_REASON GENMASK(15, 12) + #define MT_DMA_HDR_LEN 4 #define MT_RX_INFO_LEN 4 #define MT_FCE_INFO_LEN 4 @@ -37,6 +46,11 @@ struct mt76_desc { __le32 info; } __packed __aligned(4); +struct mt76_wed_rro_desc { + __le32 buf0; + __le32 buf1; +} __packed __aligned(4); + enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, @@ -54,9 +68,38 @@ enum mt76_mcu_evt_type { EVT_EVENT_DFS_DETECT_RSP, }; +enum mt76_dma_wed_ind_reason { + MT_DMA_WED_IND_REASON_NORMAL, + MT_DMA_WED_IND_REASON_REPEAT, + MT_DMA_WED_IND_REASON_OLDPKT, +}; + int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +static inline void +mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) +{ + if (!drop) + return; + + *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP)); + if (!(ctrl & MT_DMA_CTL_VER_MASK)) + return; + + switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) { + case MT_DMA_WED_IND_REASON_REPEAT: + *drop = true; + break; + case MT_DMA_WED_IND_REASON_OLDPKT: + *drop = !(info & MT_DMA_INFO_DMA_FRAG); + break; + default: + *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL); + break; + } +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8389b493759c..7aac973723bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -31,13 +31,20 @@ #define MT_QFLAG_WED_RING GENMASK(1, 0) #define MT_QFLAG_WED_TYPE GENMASK(4, 2) #define MT_QFLAG_WED BIT(5) +#define MT_QFLAG_WED_RRO BIT(6) +#define MT_QFLAG_WED_RRO_EN BIT(7) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ FIELD_PREP(MT_QFLAG_WED_RING, _n)) +#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n)) + #define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n) #define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n) #define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0) +#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) +#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) +#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) struct mt76_dev; struct mt76_phy; @@ -59,6 +66,9 @@ enum mt76_wed_type { MT76_WED_Q_TX, MT76_WED_Q_TXFREE, MT76_WED_Q_RX, + MT76_WED_RRO_Q_DATA, + MT76_WED_RRO_Q_MSDU_PG, + MT76_WED_RRO_Q_IND, }; struct mt76_bus_ops { @@ -194,6 +204,7 @@ struct mt76_queue { spinlock_t lock; spinlock_t cleanup_lock; struct mt76_queue_entry *entry; + struct mt76_rro_desc *rro_desc; struct mt76_desc *desc; u16 first; @@ -207,7 +218,7 @@ struct mt76_queue { u8 buf_offset; u8 hw_idx; - u8 flags; + u16 flags; struct mtk_wed_device *wed; u32 wed_regs; @@ -364,6 +375,17 @@ struct mt76_txq { bool aggr; }; +struct mt76_wed_rro_ind { + u32 se_id : 12; + u32 rsv : 4; + u32 start_sn : 12; + u32 ind_reason : 4; + u32 ind_cnt : 13; + u32 win_sz : 3; + u32 rsv2 : 13; + u32 magic_cnt : 3; +}; + struct mt76_txwi_cache { struct list_head list; dma_addr_t dma_addr; @@ -1581,10 +1603,32 @@ static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; } +static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_WED_RRO; +} + +static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; +} + +static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); +} + static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) { - return (q->flags & MT_QFLAG_WED) && - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; + if (!(q->flags & MT_QFLAG_WED)) + return false; + + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || + mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); + } struct mt76_txwi_cache * diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 72912f376bc9..2221d22ccffb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -65,6 +65,29 @@ static void mt7996_dma_config(struct mt7996_dev *dev) 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); + if (dev->has_rro) { + /* band0 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, + MT7996_RXQ_RRO_BAND0); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, + MT7996_RXQ_MSDU_PG_BAND0); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, + MT7996_RXQ_TXFREE0); + /* band1 */ + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, + MT7996_RXQ_MSDU_PG_BAND1); + /* band2 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, + MT7996_RXQ_RRO_BAND2); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, + MT7996_RXQ_MSDU_PG_BAND2); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, + MT7996_RXQ_TXFREE2); + + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, + MT7996_RXQ_RRO_IND); + } + /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); @@ -93,6 +116,24 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + if (dev->has_rro) { + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, + PREFETCH(0x3a0, 0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, + PREFETCH(0x4a0, 0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, + PREFETCH(0x5a0, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, + PREFETCH(0x5e0, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, + PREFETCH(0x620, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, + PREFETCH(0x660, 0x4)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, + PREFETCH(0x6a0, 0x4)); + } +#undef PREFETCH + mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE); } @@ -150,6 +191,7 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; u32 hif1_ofs = 0; u32 irq_mask; @@ -158,11 +200,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) /* enable WFDMA Tx/Rx */ if (!reset) { - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_RX_DMA_EN | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO); + else + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_DMA_EN | + MT_WFDMA0_GLO_CFG_RX_DMA_EN | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); if (dev->hif2) mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, @@ -184,12 +231,12 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) if (dev->tbtc_support) irq_mask |= MT_INT_BAND2_RX_DONE; - if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) { + if (mtk_wed_device_active(wed) && wed_reset) { u32 wed_irq_mask = irq_mask; wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); - mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask); + mtk_wed_device_start(wed, wed_irq_mask); } irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; @@ -266,13 +313,85 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) /* fix hardware limitation, pcie1's rx ring3 is not available * so, redirect pcie0 rx ring3 interrupt to pcie1 */ - mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, - MT_WFDMA0_RX_INT_SEL_RING3); + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + dev->has_rro) + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, + MT_WFDMA0_RX_INT_SEL_RING6); + else + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, + MT_WFDMA0_RX_INT_SEL_RING3); } mt7996_dma_start(dev, reset, true); } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + u32 irq_mask; + int ret; + + /* ind cmd */ + mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], + MT_RXQ_ID(MT_RXQ_RRO_IND), + MT7996_RX_RING_SIZE, + 0, MT_RXQ_RRO_IND_RING_BASE); + if (ret) + return ret; + + /* rx msdu page queue for band0 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = + MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); + if (ret) + return ret; + + if (dev->dbdc_support) { + /* rx msdu page queue for band1 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = + MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); + if (ret) + return ret; + } + + if (dev->tbtc_support) { + /* rx msdu page queue for band2 */ + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = + MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_MSDU_PAGE_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); + if (ret) + return ret; + } + + irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | + MT_INT_TX_DONE_BAND2; + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mt7996_irq_enable(dev, irq_mask); + + return 0; +} +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + int mt7996_dma_init(struct mt7996_dev *dev) { struct mtk_wed_device *wed = &dev->mt76.mmio.wed; @@ -356,7 +475,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ - if (mtk_wed_device_active(wed)) { + if (mtk_wed_device_active(wed) && !dev->has_rro) { dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; } @@ -372,9 +491,6 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { /* rx data queue for band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; - if (mtk_wed_device_active(wed)) - rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2); - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), MT7996_RX_RING_SIZE, @@ -386,7 +502,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) /* tx free notify event from WA for band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ - if (mtk_wed_device_active(wed_hif2)) { + if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; } @@ -400,6 +516,60 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; } + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && + dev->has_rro) { + /* rx rro data queue for band0 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = + MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], + MT_RXQ_ID(MT_RXQ_RRO_BAND0), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0)); + if (ret) + return ret; + + /* tx free notify event from WA for band0 */ + 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 (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + /* rx rro data queue for band2 */ + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], + MT_RXQ_ID(MT_RXQ_RRO_BAND2), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); + if (ret) + return ret; + + /* tx free notify event from MAC for band2 */ + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND2), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs); + if (ret) + return ret; + } + } + ret = mt76_init_queues(dev, mt76_dma_rx_poll); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index e19c8fb71609..a1adbc65ae00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -320,8 +320,17 @@ void mt7996_mac_init(struct mt7996_dev *dev) /* rro module init */ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + if (dev->has_rro) { + u16 timeout; + + timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; + mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); + } else { + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); + } mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), MCU_WA_PARAM_HW_PATH_HIF_VER, @@ -475,6 +484,163 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev) msleep(20); } +static int mt7996_wed_rro_init(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; + struct mt7996_wed_rro_addr *addr; + void *ptr; + int i; + + if (!dev->has_rro) + return 0; + + if (!mtk_wed_device_active(wed)) + return 0; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + &dev->wed_rro.ba_bitmap[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.ba_bitmap[i].ptr = ptr; + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + int j; + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr), + &dev->wed_rro.addr_elem[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.addr_elem[i].ptr = ptr; + memset(dev->wed_rro.addr_elem[i].ptr, 0, + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr)); + + addr = dev->wed_rro.addr_elem[i].ptr; + for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { + addr->signature = 0xff; + addr++; + } + + wed->wlan.ind_cmd.addr_elem_phys[i] = + dev->wed_rro.addr_elem[i].phy_addr; + } + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), + &dev->wed_rro.session.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.session.ptr = ptr; + addr = dev->wed_rro.session.ptr; + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + addr->signature = 0xff; + addr++; + } + + /* rro hw init */ + /* TODO: remove line after WM has set */ + mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); + + /* setup BA bitmap cache address */ + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, + dev->wed_rro.ba_bitmap[0].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, + dev->wed_rro.ba_bitmap[1].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); + + /* setup Address element address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); + reg += 4; + } + + /* setup Address element address - separate address segment mode */ + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); + + wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; + wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; + wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; + + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); + + /* particular session configure */ + /* use max session idx + 1 as particular session id */ + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, + MT_RRO_PARTICULAR_CONFG_EN | + FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); + + /* interrupt enable */ + mt76_wr(dev, MT_RRO_HOST_INT_ENA, + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); + + /* rro ind cmd queue init */ + return mt7996_dma_rro_init(dev); +#else + return 0; +#endif +} + +static void mt7996_wed_rro_free(struct mt7996_dev *dev) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + int i; + + if (!dev->has_rro) + return; + + if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) + return; + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + if (!dev->wed_rro.ba_bitmap[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + dev->wed_rro.ba_bitmap[i].ptr, + dev->wed_rro.ba_bitmap[i].phy_addr); + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + if (!dev->wed_rro.addr_elem[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_SIZE * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.addr_elem[i].ptr, + dev->wed_rro.addr_elem[i].phy_addr); + } + + if (!dev->wed_rro.session.ptr) + return; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_WINDOW_MAX_LEN * + sizeof(struct mt7996_wed_rro_addr), + dev->wed_rro.session.ptr, + dev->wed_rro.session.phy_addr); +#endif +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; @@ -496,6 +662,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_wed_rro_init(dev); + if (ret) + return ret; + ret = mt7996_eeprom_init(dev); if (ret < 0) return ret; @@ -934,6 +1104,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev) mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); + mt7996_wed_rro_free(dev); mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 6095ce72ab1f..e5d3b7569163 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -449,8 +449,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, return 0; } +static void +mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q, + struct mt7996_sta *msta, struct sk_buff *skb, + u32 info) +{ + struct ieee80211_vif *vif; + struct wireless_dev *wdev; + + if (!msta || !msta->vif) + return; + + if (!mt76_queue_is_wed_rx(q)) + return; + + if (!(info & MT_DMA_INFO_PPE_VLD)) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, + drv_priv); + wdev = ieee80211_vif_to_wdev(vif); + skb->dev = wdev->netdev; + + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), + FIELD_GET(MT_DMA_PPE_ENTRY, info)); +} + static int -mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) +mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, + struct sk_buff *skb, u32 *info) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_phy *mphy = &dev->mt76.phy; @@ -475,7 +503,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) u16 seq_ctrl = 0; __le16 fc = 0; int idx; + u8 hw_aggr = false; + struct mt7996_sta *msta = NULL; + hw_aggr = status->aggr; memset(status, 0, sizeof(*status)); band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); @@ -502,8 +533,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); if (status->wcid) { - struct mt7996_sta *msta; - msta = container_of(status->wcid, struct mt7996_sta, wcid); spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&msta->wcid.poll_list)) @@ -708,12 +737,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) } } else { status->flag |= RX_FLAG_8023; + mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, + *info); } if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); - if (!status->wcid || !ieee80211_is_data_qos(fc)) + if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) return 0; status->aggr = unicast && @@ -1448,7 +1479,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, dev_kfree_skb(skb); break; case PKT_TYPE_NORMAL: - if (!mt7996_mac_fill_rx(dev, skb)) { + if (!mt7996_mac_fill_rx(dev, q, skb, info)) { mt76_rx(&dev->mt76, q, skb); return; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 3ecdc09323c5..5369f0a7800c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -963,7 +963,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) } static int -mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, +mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif, struct ieee80211_ampdu_params *params, bool enable, bool tx) { @@ -972,7 +972,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, struct sk_buff *skb; struct tlv *tlv; - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid, MT7996_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -986,8 +986,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; + ba->ba_rdd_rro = !tx && enable && dev->has_rro; - return mt76_mcu_skb_send_msg(dev, skb, + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } @@ -1002,8 +1003,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, if (enable && !params->amsdu) msta->wcid.amsdu = false; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, true); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true); } int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, @@ -1013,8 +1013,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; struct mt7996_vif *mvif = msta->vif; - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, - enable, false); + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false); } static void @@ -4023,10 +4022,8 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) { struct { u8 __rsv1[4]; - __le16 tag; __le16 len; - union { struct { u8 type; @@ -4041,6 +4038,11 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) u8 path; u8 __rsv2[3]; } __packed txfree_path; + struct { + __le16 flush_one; + __le16 flush_all; + u8 __rsv2[4]; + } __packed timeout; }; } __packed req = { .tag = cpu_to_le16(tag), @@ -4057,6 +4059,10 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val) case UNI_RRO_SET_TXFREE_PATH: req.txfree_path.path = val; break; + case UNI_RRO_SET_FLUSH_TIMEOUT: + req.timeout.flush_one = cpu_to_le16(val); + req.timeout.flush_all = cpu_to_le16(2 * val); + break; default: return -EINVAL; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a88f6af323da..a4715b8e005b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -669,6 +669,8 @@ enum { UNI_RRO_GET_BA_SESSION_TABLE, UNI_RRO_SET_BYPASS_MODE, UNI_RRO_SET_TXFREE_PATH, + UNI_RRO_DEL_BA_SESSION, + UNI_RRO_SET_FLUSH_TIMEOUT }; enum{ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index ae029ae9969d..c7b6d4bd2ded 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -207,6 +207,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, if (!wed_enable) return 0; + dev->has_rro = true; + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); if (hif2) @@ -228,14 +230,27 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + MT_TXQ_RING_BASE(0) + MT7996_TXQ_BAND2 * MT_RING_SIZE; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + } else { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + } + + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; + wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; wed->wlan.id = 0x7991; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; } else { + wed->wlan.hw_rro = dev->has_rro; /* default on */ wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + @@ -247,6 +262,16 @@ 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.wpdma_rx_rro[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; + wed->wlan.rx_nbuf = 65536; wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); @@ -254,11 +279,25 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + + wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; + wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; + wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1; + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + if (dev->has_rro) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + } + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; } wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; @@ -273,8 +312,6 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; - dev->mt76.rx_token_size += wed->wlan.rx_npkt; - if (mtk_wed_device_attach(wed)) return 0; @@ -434,10 +471,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t) irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) { struct mt7996_dev *dev = dev_instance; - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (mtk_wed_device_active(wed)) - mtk_wed_device_irq_set_mask(wed, 0); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0); else mt76_wr(dev, MT_INT_MASK_CSR, 0); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index d4425c133ced..f7b6945b7acc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -50,6 +50,22 @@ #define MT7996_BASIC_RATES_TBL 11 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_RRO_MAX_SESSION 1024 +#define MT7996_RRO_WINDOW_MAX_LEN 1024 +#define MT7996_RRO_ADDR_ELEM_LEN 128 +#define MT7996_RRO_BA_BITMAP_LEN 2 +#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \ + MT7996_RRO_BA_BITMAP_LEN) +#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \ + MT7996_RRO_ADDR_ELEM_LEN) +#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \ + MT7996_RRO_BA_BITMAP_SESSION_SIZE) + +#define MT7996_RX_BUF_SIZE (1800 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) + struct mt7996_vif; struct mt7996_sta; struct mt7996_dfs_pulse; @@ -79,6 +95,16 @@ enum mt7996_rxq_id { MT7996_RXQ_BAND0 = 4, MT7996_RXQ_BAND1 = 4,/* unused */ MT7996_RXQ_BAND2 = 5, + MT7996_RXQ_RRO_BAND0 = 8, + MT7996_RXQ_RRO_BAND1 = 8,/* unused */ + MT7996_RXQ_RRO_BAND2 = 6, + MT7996_RXQ_MSDU_PG_BAND0 = 10, + MT7996_RXQ_MSDU_PG_BAND1 = 11, + MT7996_RXQ_MSDU_PG_BAND2 = 12, + MT7996_RXQ_TXFREE0 = 9, + MT7996_RXQ_TXFREE1 = 9, + MT7996_RXQ_TXFREE2 = 7, + MT7996_RXQ_RRO_IND = 0, }; struct mt7996_twt_flow { @@ -147,6 +173,15 @@ struct mt7996_hif { int irq; }; +struct mt7996_wed_rro_addr { + u32 head_low; + u32 head_high : 4; + u32 count: 11; + u32 oor: 1; + u32 rsv : 8; + u32 signature : 8; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -226,6 +261,22 @@ struct mt7996_dev { bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; + bool has_rro:1; + + struct { + struct { + void *ptr; + dma_addr_t phy_addr; + } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } addr_elem[MT7996_RRO_ADDR_ELEM_LEN]; + struct { + void *ptr; + dma_addr_t phy_addr; + } session; + } wed_rro; bool ibf; u8 fw_debug_wm; @@ -506,4 +557,8 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); #endif +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +int mt7996_dma_rro_init(struct mt7996_dev *dev); +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index b7d78adce11a..7cefe8985590 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -39,6 +39,38 @@ enum base_rev { #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +/* RRO TOP */ +#define MT_RRO_TOP_BASE 0xA000 +#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) + +#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8) +#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) +#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) +#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) +#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) +#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) + +#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C) +#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40) +#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31) + +#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C) +#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60) +#define MT_RRO_PARTICULAR_CONFG_EN BIT(31) +#define MT_RRO_PARTICULAR_SID GENMASK(30, 16) + +#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70) +#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74) +#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204) +#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0) + +#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) + +#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) +#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) +#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) @@ -398,6 +430,7 @@ enum base_rev { #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) +#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) @@ -425,6 +458,14 @@ enum base_rev { #define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_TXFREE_EXT BIT(26) +#define MT_INT_RX_DONE_RRO_BAND0 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND2 BIT(14) +#define MT_INT_RX_DONE_RRO_IND BIT(11) +#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) +#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) +#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) + #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) @@ -432,20 +473,31 @@ enum base_rev { MT_INT_RX(MT_RXQ_MCU_WA)) #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ MT_INT_RX(MT_RXQ_BAND1_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) #define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \ MT_INT_RX(MT_RXQ_BAND2_WA) | \ - MT_INT_RX(MT_RXQ_MAIN_WA)) + MT_INT_RX(MT_RXQ_MAIN_WA) | \ + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) + +#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ + MT_INT_RX(MT_RXQ_RRO_BAND1) | \ + MT_INT_RX(MT_RXQ_RRO_BAND2) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ MT_INT_BAND0_RX_DONE | \ MT_INT_BAND1_RX_DONE | \ - MT_INT_BAND2_RX_DONE) + MT_INT_BAND2_RX_DONE | \ + MT_INT_RRO_RX_DONE) #define MT_INT_TX_DONE_FWDL BIT(26) #define MT_INT_TX_DONE_MCU_WM BIT(27) @@ -558,6 +610,8 @@ enum base_rev { #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) #define MT_HW_REV 0x70010204 +#define MT_HW_REV1 0x8a00 + #define MT_WF_SUBSYS_RST 0x70028600 /* PCIE MAC */ From d4b85aff3ab32fbfde026090c47829e83a0422cc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:58 +0200 Subject: [PATCH 21/62] wifi: mt76: move wed reset common code in mt76 module Move WED reset code shared between mt7915 and mt7996 in common module. This is a preliminary patch to introduce WED reset support for mt7996. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 14 ++++++++++ drivers/net/wireless/mediatek/mt76/dma.h | 9 ++++++ drivers/net/wireless/mediatek/mt76/mmio.c | 8 ++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../net/wireless/mediatek/mt76/mt7915/dma.c | 28 ++----------------- .../net/wireless/mediatek/mt76/mt7915/mmio.c | 9 +----- 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 7c76afdaef68..f2532e67fa78 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -1036,6 +1036,20 @@ void mt76_dma_attach(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_dma_attach); +void mt76_dma_wed_reset(struct mt76_dev *dev) +{ + struct mt76_mmio *mmio = &dev->mmio; + + if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state)) + return; + + complete(&mmio->wed_reset); + + if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ)) + dev_err(dev->dev, "wed reset complete timeout\n"); +} +EXPORT_SYMBOL_GPL(mt76_dma_wed_reset); + void mt76_dma_cleanup(struct mt76_dev *dev) { int i; diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index e549e678b69f..c60dfb817227 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -78,6 +78,15 @@ int mt76_dma_rx_poll(struct napi_struct *napi, int budget); void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset); +void mt76_dma_wed_reset(struct mt76_dev *dev); + +static inline void +mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + dev->queue_ops->reset_q(dev, q); + if (mtk_wed_device_active(&dev->mmio.wed)) + mt76_dma_wed_setup(dev, q, true); +} static inline void mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index c34624978a14..4a006409a373 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -179,6 +179,14 @@ void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) spin_unlock_bh(&dev->token_lock); } EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); + +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed) +{ + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); + + complete(&dev->mmio.wed_reset_complete); +} +EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 7aac973723bc..36e54a32bd1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1102,6 +1102,7 @@ u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); +void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed); #endif /*CONFIG_NET_MEDIATEK_SOC_WED */ #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 1bceeb5227b1..c91a1c54027f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -587,28 +587,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) return 0; } -static void mt7915_dma_wed_reset(struct mt7915_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - - if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state)) - return; - - complete(&mdev->mmio.wed_reset); - - if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete, - 3 * HZ)) - dev_err(dev->mt76.dev, "wed reset complete timeout\n"); -} - -static void -mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q) -{ - mt76_queue_reset(dev, q); - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) - mt76_dma_wed_setup(&dev->mt76, q, true); -} - int mt7915_dma_reset(struct mt7915_dev *dev, bool force) { struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1]; @@ -636,13 +614,13 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) mtk_wed_device_dma_reset(wed); mt7915_dma_disable(dev, force); - mt7915_dma_wed_reset(dev); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (mphy_ext) - mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, mphy_ext->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 85cb3fed9505..c404c90b58a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -595,13 +595,6 @@ out: return ret; } - -static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed) -{ - struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); - - complete(&dev->mmio.wed_reset_complete); -} #endif int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, @@ -685,7 +678,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats; wed->wlan.reset = mt7915_mmio_wed_reset; - wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; dev->mt76.rx_token_size = wed->wlan.rx_npkt; From 00d2ced0deb3b75177f634b2e7c0c87dca7d747e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:30:59 +0200 Subject: [PATCH 22/62] wifi: mt76: mt7996: add wed reset support Introduce the capability to reset mt7996 chipset if requested by wed driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 14 ++++-- .../net/wireless/mediatek/mt76/mt7996/dma.c | 18 +++++-- .../net/wireless/mediatek/mt76/mt7996/mac.c | 47 ++++++++++++++++++- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 37 +++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 7 ++- 5 files changed, 114 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f2532e67fa78..439cdfab6f67 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -854,10 +854,16 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) /* reset WED rx queues */ mt76_dma_wed_setup(dev, q, true); - if (!mt76_queue_is_wed_tx_free(q)) { - mt76_dma_sync_idx(dev, q); - mt76_dma_rx_fill(dev, q, false); - } + + if (mt76_queue_is_wed_tx_free(q)) + return; + + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + return; + + mt76_dma_sync_idx(dev, q); + mt76_dma_rx_fill(dev, q, false); } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 2221d22ccffb..8bc08d993085 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -621,21 +621,33 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) if (force) mt7996_wfsys_reset(dev); + if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_dma_reset(&dev->mt76.mmio.wed); + mt7996_dma_disable(dev, force); + mt76_dma_wed_reset(&dev->mt76); /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) { - mt76_queue_reset(dev, dev->mphy.q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]); if (phy2) - mt76_queue_reset(dev, phy2->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]); if (phy3) - mt76_queue_reset(dev, phy3->q_tx[i]); + mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]); } for (i = 0; i < __MT_MCUQ_MAX; i++) mt76_queue_reset(dev, dev->mt76.q_mcu[i]); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) + continue; + mt76_queue_reset(dev, &dev->mt76.q_rx[i]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index e5d3b7569163..b790d415cd03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1712,6 +1712,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) napi_disable(&dev->mt76.napi[i]); } @@ -1725,6 +1729,10 @@ mt7996_mac_restart(struct mt7996_dev *dev) local_bh_disable(); mt76_for_each_q_rx(mdev, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&mdev->q_rx[i])) + continue; + if (mdev->q_rx[i].ndesc) { napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); @@ -1896,6 +1904,13 @@ void mt7996_mac_reset_work(struct work_struct *work) dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", wiphy_name(dev->mt76.hw->wiphy)); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) + mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + mtk_wed_device_stop(&dev->mt76.mmio.wed); + ieee80211_stop_queues(mt76_hw(dev)); if (phy2) ieee80211_stop_queues(phy2->mt76->hw); @@ -1915,8 +1930,13 @@ void mt7996_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&phy3->mt76->mac_work); } mt76_worker_disable(&dev->mt76.tx_worker); - mt76_for_each_q_rx(&dev->mt76, i) + mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_disable(&dev->mt76.napi[i]); + } napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); @@ -1939,6 +1959,27 @@ void mt7996_mac_reset_work(struct work_struct *work) /* enable DMA Tx/Tx and interrupt */ mt7996_dma_start(dev, false, false); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 | + dev->mt76.mmio.irqmask; + + if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) + wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND; + + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, + true); + mt7996_irq_enable(dev, wed_irq_mask); + mt7996_irq_disable(dev, 0); + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); + } + clear_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_RESET, &dev->mphy.state); if (phy2) @@ -1948,6 +1989,10 @@ void mt7996_mac_reset_work(struct work_struct *work) local_bh_disable(); mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + napi_enable(&dev->mt76.napi[i]); napi_schedule(&dev->mt76.napi[i]); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index c7b6d4bd2ded..739d7f53d347 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -6,9 +6,11 @@ #include #include #include +#include #include "mt7996.h" #include "mac.h" +#include "mcu.h" #include "../trace.h" #include "../dma.h" @@ -195,6 +197,37 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); } +#ifdef CONFIG_NET_MEDIATEK_SOC_WED +static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed) +{ + struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed); + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt76_phy *mphy = &dev->mphy; + int ret; + + ASSERT_RTNL(); + + if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state)) + return -EBUSY; + + ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1, + mphy->band_idx); + if (ret) + goto out; + + rtnl_unlock(); + if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) { + dev_err(mdev->dev, "wed reset timeout\n"); + ret = -ETIMEDOUT; + } + rtnl_lock(); +out: + clear_bit(MT76_STATE_WED_RESET, &mphy->state); + + return ret; +} +#endif + int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, bool hif2, int *irq) { @@ -311,6 +344,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; + if (!hif2) { + wed->wlan.reset = mt7996_mmio_wed_reset; + wed->wlan.reset_complete = mt76_mmio_wed_reset_complete; + } if (mtk_wed_device_attach(wed)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 7cefe8985590..49eb583399c5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -455,8 +455,9 @@ enum base_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_MCU_CMD BIT(29) +#define MT_INT_RX_DONE_BAND2_EXT BIT(23) #define MT_INT_RX_TXFREE_EXT BIT(26) +#define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_DONE_RRO_BAND0 BIT(16) #define MT_INT_RX_DONE_RRO_BAND1 BIT(16) @@ -506,6 +507,10 @@ enum base_rev { #define MT_INT_TX_DONE_BAND1 BIT(31) #define MT_INT_TX_DONE_BAND2 BIT(15) +#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \ + MT_INT_RX_DONE_BAND2_EXT | \ + MT_INT_RX_TXFREE_EXT) + #define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \ MT_INT_TX_MCU(MT_MCUQ_WM) | \ MT_INT_TX_MCU(MT_MCUQ_FWDL)) From a5d028d668360db991e6da67cd48b9b4443198ed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:31:00 +0200 Subject: [PATCH 23/62] wifi: mt76: mt7996: add wed rro delete session garbage collector Introduce the capability to clear WED rro session configured in the hw according to the event reported by the MCU firmware Co-developed-by: Sujuan Chen Signed-off-by: Sujuan Chen Co-developed-by: Bo Jiao Signed-off-by: Bo Jiao Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 52 +++++++++++ .../net/wireless/mediatek/mt76/mt7996/mac.c | 3 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 89 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 35 ++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 10 +++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 6 ++ 8 files changed, 197 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 36e54a32bd1f..b1d3f55d7034 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -404,6 +404,7 @@ struct mt76_rx_tid { spinlock_t lock; struct delayed_work reorder_work; + u16 id; u16 head; u16 size; u16 nframes; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0563b1b22f48..97822f7d46cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1022,6 +1022,7 @@ enum { MCU_UNI_EVENT_ROC = 0x27, MCU_UNI_EVENT_TX_DONE = 0x2d, MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index a1adbc65ae00..5af85ddfdc36 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -641,6 +641,54 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev) #endif } +static void mt7996_wed_rro_work(struct work_struct *work) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mt7996_dev *dev; + LIST_HEAD(list); + + dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev, + wed_rro.work); + + spin_lock_bh(&dev->wed_rro.lock); + list_splice_init(&dev->wed_rro.poll_list, &list); + spin_unlock_bh(&dev->wed_rro.lock); + + while (!list_empty(&list)) { + struct mt7996_wed_rro_session_id *e; + int i; + + e = list_first_entry(&list, struct mt7996_wed_rro_session_id, + list); + list_del_init(&e->list); + + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { + void *ptr = dev->wed_rro.session.ptr; + struct mt7996_wed_rro_addr *elem; + u32 idx, elem_id = i; + + if (e->id == MT7996_RRO_MAX_SESSION) + goto reset; + + idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE; + if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem)) + goto out; + + ptr = dev->wed_rro.addr_elem[idx].ptr; + elem_id += + (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) * + MT7996_RRO_WINDOW_MAX_LEN; +reset: + elem = ptr + elem_id * sizeof(*elem); + elem->signature = 0xff; + } + mt7996_mcu_wed_rro_reset_sessions(dev, e->id); +out: + kfree(e); + } +#endif +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; @@ -648,6 +696,9 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); INIT_WORK(&dev->init_work, mt7996_init_work); + INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); + INIT_LIST_HEAD(&dev->wed_rro.poll_list); + spin_lock_init(&dev->wed_rro.lock); dev->dbdc_support = true; dev->tbtc_support = true; @@ -1100,6 +1151,7 @@ int mt7996_register_device(struct mt7996_dev *dev) void mt7996_unregister_device(struct mt7996_dev *dev) { + cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); mt7996_coredump_unregister(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index b790d415cd03..f653e93349f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1822,6 +1822,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) if (phy3) ieee80211_stop_queues(phy3->mt76->hw); + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) cancel_delayed_work_sync(&phy2->mt76->mac_work); @@ -1920,6 +1921,8 @@ void mt7996_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); + + cancel_work_sync(&dev->wed_rro.work); cancel_delayed_work_sync(&dev->mphy.mac_work); if (phy2) { set_bit(MT76_RESET, &phy2->mt76->state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5369f0a7800c..03a9474120b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -526,6 +526,73 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) dev_kfree_skb(skb); } +static void +mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_wed_rro_event *event = (void *)skb->data; + + if (!dev->has_rro) + return; + + skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4); + + switch (le16_to_cpu(event->tag)) { + case UNI_WED_RRO_BA_SESSION_STATUS: { + struct mt7996_mcu_wed_rro_ba_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt76_rx_tid *tid; + struct mt76_wcid *wcid; + u16 idx; + + e = (void *)skb->data; + idx = le16_to_cpu(e->wlan_id); + if (idx >= ARRAY_SIZE(dev->mt76.wcid)) + break; + + wcid = rcu_dereference(dev->mt76.wcid[idx]); + if (!wcid || !wcid->sta) + break; + + if (e->tid >= ARRAY_SIZE(wcid->aggr)) + break; + + tid = rcu_dereference(wcid->aggr[e->tid]); + if (!tid) + break; + + tid->id = le16_to_cpu(e->id); + skb_pull(skb, sizeof(*e)); + } + break; + } + case UNI_WED_RRO_BA_SESSION_DELETE: { + struct mt7996_mcu_wed_rro_ba_delete_event *e; + + while (skb->len >= sizeof(*e)) { + struct mt7996_wed_rro_session_id *session; + + e = (void *)skb->data; + session = kzalloc(sizeof(*session), GFP_ATOMIC); + if (!session) + break; + + session->id = le16_to_cpu(e->session_id); + + spin_lock_bh(&dev->wed_rro.lock); + list_add_tail(&session->list, &dev->wed_rro.poll_list); + spin_unlock_bh(&dev->wed_rro.lock); + + ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work); + skb_pull(skb, sizeof(*e)); + } + break; + } + default: + break; + } +} + static void mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -544,6 +611,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_UNI_EVENT_ALL_STA_INFO: mt7996_mcu_rx_all_sta_info_event(dev, skb); break; + case MCU_UNI_EVENT_WED_RRO: + mt7996_mcu_wed_rro_event(dev, skb); + break; default: break; } @@ -4087,3 +4157,22 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO), &req, sizeof(req), false); } + +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) +{ + struct { + u8 __rsv[4]; + + __le16 tag; + __le16 len; + __le16 session_id; + u8 pad[4]; + } __packed req = { + .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION), + .len = cpu_to_le16(sizeof(req) - 4), + .session_id = cpu_to_le16(id), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, + sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a4715b8e005b..e32a78d6622b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -179,6 +179,41 @@ struct mt7996_mcu_all_sta_info_event { }; } __packed; +struct mt7996_mcu_wed_rro_event { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; +} __packed; + +struct mt7996_mcu_wed_rro_ba_event { + __le16 tag; + __le16 len; + + __le16 wlan_id; + u8 tid; + u8 __rsv1; + __le32 status; + __le16 id; + u8 __rsv2[2]; +} __packed; + +struct mt7996_mcu_wed_rro_ba_delete_event { + __le16 tag; + __le16 len; + + __le16 session_id; + u8 __rsv2[2]; +} __packed; + +enum { + UNI_WED_RRO_BA_SESSION_STATUS, + UNI_WED_RRO_BA_SESSION_TBL, + UNI_WED_RRO_BA_SESSION_DELETE, +}; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index f7b6945b7acc..e7818b2b253f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -182,6 +182,11 @@ struct mt7996_wed_rro_addr { u32 signature : 8; }; +struct mt7996_wed_rro_session_id { + struct list_head list; + u16 id; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -276,6 +281,10 @@ struct mt7996_dev { void *ptr; dma_addr_t phy_addr; } session; + + struct work_struct work; + struct list_head poll_list; + spinlock_t lock; } wed_rro; bool ibf; @@ -456,6 +465,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); void mt7996_mcu_exit(struct mt7996_dev *dev); int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); +int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 49eb583399c5..e9edba830aff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -71,6 +71,12 @@ enum base_rev { #define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) #define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) +#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0) +#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0) +#define MT_RRO_DBG_RD_EXEC BIT(31) + +#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4) + #define MT_MCU_INT_EVENT 0x2108 #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) From 5f9d5d4fc561e7bd3a18742f1fdb96cab98f1870 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 20 Oct 2023 12:45:19 +0200 Subject: [PATCH 24/62] wifi: mt76: mt7915: fallback to non-wed mode if platform_get_resource fails in mt7915_mmio_wed_init() mt76 assumes mt7915_mmio_wed_init can fail just after wed driver has been attached running mtk_wed_device_attach(). Fall back to non-wed mode if platform_get_resource fails in mt7915_mmio_wed_init routines. Fixes: eebb70976be5 ("wifi: mt76: mt7915: enable wed for mt7986-wmac chipset") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index c404c90b58a6..aff4f21e843d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -636,7 +636,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); if (!res) - return -ENOMEM; + return 0; wed->wlan.platform_dev = plat_dev; wed->wlan.bus_type = MTK_WED_BUS_AXI; From af2825729b52a45d239def2c243531aa9e7bf81a Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 23 Oct 2023 23:38:44 +0800 Subject: [PATCH 25/62] wifi: mt76: mt7996: add support for variants with auxiliary RX path Add support to correctly configure the rx chainmask of variants that have additional auxiliary RX path. e.g., 4T5R. The auxiliary RX path is transparent to driver, but driver needs to correctly configure it in the set channel fw command. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/eeprom.c | 21 +++++++++++++++---- .../wireless/mediatek/mt76/mt7996/eeprom.h | 3 +++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 2 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 14 +++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 544b6c6f1ea3..9db7e531076d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -148,36 +148,49 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy) int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) { - u8 path, nss, band_idx = phy->mt76->band_idx; + u8 path, rx_path, nss, band_idx = phy->mt76->band_idx; u8 *eeprom = dev->mt76.eeprom.data; struct mt76_phy *mphy = phy->mt76; + int max_path = 5, max_nss = 4; int ret; switch (band_idx) { case MT_BAND1: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1, eeprom[MT_EE_WIFI_CONF + 5]); break; case MT_BAND2: path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2, eeprom[MT_EE_WIFI_CONF + 2]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2, + eeprom[MT_EE_WIFI_CONF + 4]); nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2, eeprom[MT_EE_WIFI_CONF + 5]); break; default: path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0, eeprom[MT_EE_WIFI_CONF + 1]); + rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0, + eeprom[MT_EE_WIFI_CONF + 3]); nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0, eeprom[MT_EE_WIFI_CONF + 4]); break; } - if (!path || path > 4) - path = 4; + if (!path || path > max_path) + path = max_path; - nss = min_t(u8, min_t(u8, 4, nss), path); + if (!nss || nss > max_nss) + nss = max_nss; + + nss = min_t(u8, nss, path); + + if (path != rx_path) + phy->has_aux_rx = true; mphy->antenna_mask = BIT(nss) - 1; mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h index 0c749774f6b1..412d6e2f8014 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h @@ -33,6 +33,9 @@ enum mt7996_eeprom_field { #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0) +#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3) +#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0) #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 03a9474120b7..55e97a857963 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3299,7 +3299,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx], + .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx], .band_idx = band_idx, .channel_band = ch_band[chandef->chan->band], }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index e7818b2b253f..6acc0ae286fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -210,6 +210,8 @@ struct mt7996_phy { struct mt76_mib_stats mib; struct mt76_channel_state state_ts; + + bool has_aux_rx; }; struct mt7996_dev { @@ -501,6 +503,18 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask) void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, size_t len); +static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy) +{ + int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx); + int cur_nss = hweight8(phy->mt76->antenna_mask); + u16 tx_chainmask = phy->mt76->chainmask; + + if (cur_nss != max_nss) + return tx_chainmask; + + return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx); +} + 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); From 0afb228d9bd439088d2d1d58bae7295340000e27 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:45 +0800 Subject: [PATCH 26/62] wifi: mt76: mt7996: add TX statistics for EHT mode in debugfs Add EHT statistics of beamforming feedback and BW320 in debugfs tx_stats command. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 4d40ec7ff57f..9bd953586b04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -476,7 +476,7 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) { struct mt76_mib_stats *mib = &phy->mib; static const char * const bw[] = { - "BW20", "BW40", "BW80", "BW160" + "BW20", "BW40", "BW80", "BW160", "BW320" }; /* Tx Beamformer monitor */ @@ -489,8 +489,9 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s) /* Tx Beamformer Rx feedback monitor */ seq_puts(s, "Tx Beamformer Rx feedback statistics: "); - seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ", + seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ", mib->tx_bf_rx_fb_all_cnt, + mib->tx_bf_rx_fb_eht_cnt, mib->tx_bf_rx_fb_he_cnt, mib->tx_bf_rx_fb_vht_cnt, mib->tx_bf_rx_fb_ht_cnt); From 21f290884bc1c911aa9a0875c1d9a1e6fb9e0308 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:46 +0800 Subject: [PATCH 27/62] wifi: mt76: connac: add thermal protection support for mt7996 Implement thermal protection commands and support Linux cooling device control for mt7996 chipsets. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 102 +++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/main.c | 8 ++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 104 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 44 ++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 15 +++ 6 files changed, 274 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 97822f7d46cc..1d8680b153a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1021,6 +1021,7 @@ enum { MCU_UNI_EVENT_RDD_REPORT = 0x11, MCU_UNI_EVENT_ROC = 0x27, MCU_UNI_EVENT_TX_DONE = 0x2d, + MCU_UNI_EVENT_THERMAL = 0x35, MCU_UNI_EVENT_NIC_CAPAB = 0x43, MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 5af85ddfdc36..02b47b299ea8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -43,6 +43,97 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static int +mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = MT7996_CDEV_THROTTLE_MAX; + + return 0; +} + +static int +mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct mt7996_phy *phy = cdev->devdata; + + *state = phy->cdev_state; + + return 0; +} + +static int +mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct mt7996_phy *phy = cdev->devdata; + u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state; + int ret; + + if (state > MT7996_CDEV_THROTTLE_MAX) { + dev_err(phy->dev->mt76.dev, + "please specify a valid throttling state\n"); + return -EINVAL; + } + + if (state == phy->cdev_state) + return 0; + + /* cooling_device convention: 0 = no cooling, more = more cooling + * mcu convention: 1 = max cooling, more = less cooling + */ + ret = mt7996_mcu_set_thermal_throttling(phy, throttling); + if (ret) + return ret; + + phy->cdev_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops mt7996_thermal_ops = { + .get_max_state = mt7996_thermal_get_max_throttle_state, + .get_cur_state = mt7996_thermal_get_cur_throttle_state, + .set_cur_state = mt7996_thermal_set_cur_throttle_state, +}; + +static void mt7996_unregister_thermal(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + + if (!phy->cdev) + return; + + sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); + thermal_cooling_device_unregister(phy->cdev); +} + +static int mt7996_thermal_init(struct mt7996_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct thermal_cooling_device *cdev; + const char *name; + + name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", + wiphy_name(wiphy)); + + cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops); + if (!IS_ERR(cdev)) { + if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj, + "cooling_device") < 0) + thermal_cooling_device_unregister(cdev); + else + phy->cdev = cdev; + } + + /* initialize critical/maximum high temperature */ + phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; + phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + + return 0; +} + static void mt7996_led_set_config(struct led_classdev *led_cdev, u8 delay_on, u8 delay_off) { @@ -429,6 +520,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (ret) goto error; + ret = mt7996_thermal_init(phy); + if (ret) + goto error; + ret = mt7996_init_debugfs(phy); if (ret) goto error; @@ -456,6 +551,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band) if (!phy) return; + mt7996_unregister_thermal(phy); + mphy = phy->dev->mt76.phys[band]; mt76_unregister_phy(mphy); ieee80211_free_hw(mphy->hw); @@ -1130,6 +1227,10 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_thermal_init(&dev->phy); + if (ret) + return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); @@ -1154,6 +1255,7 @@ void mt7996_unregister_device(struct mt7996_dev *dev) cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2); mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1); + mt7996_unregister_thermal(&dev->phy); mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); mt7996_wed_rro_free(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index f074616c7007..33a9d50d3366 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw) if (ret) goto out; + ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); + if (ret) + goto out; + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + goto out; + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 55e97a857963..292a6cd9b1fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -497,6 +497,34 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) } } +static void +mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb) +{ +#define THERMAL_NOTIFY_TAG 0x4 +#define THERMAL_NOTIFY 0x2 + struct mt76_phy *mphy = &dev->mt76.phy; + struct mt7996_mcu_thermal_notify *n; + struct mt7996_phy *phy; + + n = (struct mt7996_mcu_thermal_notify *)skb->data; + + if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG) + return; + + if (n->event_id != THERMAL_NOTIFY) + return; + + if (n->band_idx > MT_BAND2) + return; + + mphy = dev->mt76.phys[n->band_idx]; + if (!mphy) + return; + + phy = (struct mt7996_phy *)mphy->priv; + phy->throttle_state = n->duty_percent; +} + static void mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -520,6 +548,9 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_EVENT_EXT: mt7996_mcu_rx_ext_event(dev, skb); break; + case MCU_UNI_EVENT_THERMAL: + mt7996_mcu_rx_thermal_notify(dev, skb); + break; default: break; } @@ -3571,6 +3602,79 @@ out: return 0; } +int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) +{ + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + } __packed req = { + .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG), + .len = cpu_to_le16(sizeof(req) - 4), + .ctrl = { + .band_idx = phy->mt76->band_idx, + }, + }; + int level, ret; + + /* set duty cycle and level */ + for (level = 0; level < 4; level++) { + req.ctrl.duty.duty_level = level; + req.ctrl.duty.duty_cycle = state; + state /= 2; + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); + if (ret) + return ret; + } + + return 0; +} + +int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable) +{ +#define SUSTAIN_PERIOD 10 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + struct mt7996_mcu_thermal_ctrl ctrl; + struct mt7996_mcu_thermal_enable enable; + } __packed req = { + .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)), + .ctrl = { + .band_idx = phy->mt76->band_idx, + .type.protect_type = 1, + .type.trigger_type = 1, + }, + }; + int ret; + + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE); + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req) - sizeof(req.enable), false); + if (ret || !enable) + return ret; + + /* set high-temperature trigger threshold */ + req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE); + req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]); + req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]); + req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD); + + req.len = cpu_to_le16(sizeof(req) - 4); + + return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), false); +} + int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index e32a78d6622b..4a73850db9c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event { __le32 status; /* 0: success, others: fail */ } __packed; +struct mt7996_mcu_thermal_ctrl { + u8 ctrl_id; + u8 band_idx; + union { + struct { + u8 protect_type; /* 1: duty admit, 2: radio off */ + u8 trigger_type; /* 0: low, 1: high */ + } __packed type; + struct { + u8 duty_level; /* level 0~3 */ + u8 duty_cycle; + } __packed duty; + }; +} __packed; + +struct mt7996_mcu_thermal_enable { + __le32 trigger_temp; + __le32 restore_temp; + __le16 sustain_time; + u8 rsv[2]; +} __packed; + struct mt7996_mcu_csa_notify { struct mt7996_mcu_rxd rxd; @@ -214,6 +236,22 @@ enum { UNI_WED_RRO_BA_SESSION_DELETE, }; +struct mt7996_mcu_thermal_notify { + struct mt7996_mcu_rxd rxd; + + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + + u8 event_id; + u8 band_idx; + u8 level_idx; + u8 duty_percent; + __le32 restore_temp; + u8 __rsv2[4]; +} __packed; + enum mt7996_chan_mib_offs { UNI_MIB_OBSS_AIRTIME = 26, UNI_MIB_NON_WIFI_TIME = 27, @@ -719,6 +757,12 @@ enum{ UNI_CMD_SR_SET_SIGA = 0xd0, }; +enum { + UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6, + UNI_CMD_THERMAL_PROTECT_DISABLE, + UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, +}; + enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 6acc0ae286fa..61e0f905d902 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -50,6 +50,13 @@ #define MT7996_BASIC_RATES_TBL 11 #define MT7996_BEACON_RATES_TBL 25 +#define MT7996_THERMAL_THROTTLE_MAX 100 +#define MT7996_CDEV_THROTTLE_MAX 99 +#define MT7996_CRIT_TEMP_IDX 0 +#define MT7996_MAX_TEMP_IDX 1 +#define MT7996_CRIT_TEMP 110 +#define MT7996_MAX_TEMP 120 + #define MT7996_RRO_MAX_SESSION 1024 #define MT7996_RRO_WINDOW_MAX_LEN 1024 #define MT7996_RRO_ADDR_ELEM_LEN 128 @@ -195,6 +202,11 @@ struct mt7996_phy { struct ieee80211_vif *monitor_vif; + struct thermal_cooling_device *cdev; + u8 cdev_state; + u8 throttle_state; + u32 throttle_temp[2]; /* 0: critical high, 1: maximum */ + u32 rxfilter; u64 omac_mask; @@ -453,6 +465,9 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); +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_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, From 6879b2e94172ed80394dd49d410814ad427d1ca0 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:47 +0800 Subject: [PATCH 28/62] wifi: mt76: mt7996: add thermal sensor device support This patch adds support for thermal sensor device, including the following features: - Support to read current chip temperature. - Support to set/get the trigger/restore temperature for thermal service. - Support to read current chip tx cycle. Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/init.c | 88 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 42 +++++++++ 2 files changed, 130 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 02b47b299ea8..e2d08bf96eb0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include "mt7996.h" #include "mac.h" @@ -43,6 +45,82 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; +static ssize_t mt7996_thermal_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int i = to_sensor_dev_attr(attr)->index; + int temperature; + + switch (i) { + case 0: + temperature = mt7996_mcu_get_temperature(phy); + if (temperature < 0) + return temperature; + /* display in millidegree celcius */ + return sprintf(buf, "%u\n", temperature * 1000); + case 1: + case 2: + return sprintf(buf, "%u\n", + phy->throttle_temp[i - 1] * 1000); + case 3: + return sprintf(buf, "%hhu\n", phy->throttle_state); + default: + return -EINVAL; + } +} + +static ssize_t mt7996_thermal_temp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mt7996_phy *phy = dev_get_drvdata(dev); + int ret, i = to_sensor_dev_attr(attr)->index; + long val; + + ret = kstrtol(buf, 10, &val); + if (ret < 0) + return ret; + + mutex_lock(&phy->dev->mt76.mutex); + val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130); + + /* add a safety margin ~10 */ + if ((i - 1 == MT7996_CRIT_TEMP_IDX && + val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) || + (i - 1 == MT7996_MAX_TEMP_IDX && + val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) { + dev_err(phy->dev->mt76.dev, + "temp1_max shall be 10 degrees higher than temp1_crit."); + mutex_unlock(&phy->dev->mt76.mutex); + return -EINVAL; + } + + phy->throttle_temp[i - 1] = val; + mutex_unlock(&phy->dev->mt76.mutex); + + ret = mt7996_mcu_set_thermal_protect(phy, true); + if (ret) + return ret; + + return count; +} + +static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0); +static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1); +static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2); +static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3); + +static struct attribute *mt7996_hwmon_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_throttle1.dev_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mt7996_hwmon); + static int mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev, unsigned long *state) @@ -113,6 +191,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; struct thermal_cooling_device *cdev; + struct device *hwmon; const char *name; name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s", @@ -131,6 +210,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy) phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP; phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP; + if (!IS_REACHABLE(CONFIG_HWMON)) + return 0; + + hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, + mt7996_hwmon_groups); + + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 292a6cd9b1fb..48c7f4fe1bc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3602,6 +3602,48 @@ out: return 0; } +int mt7996_mcu_get_temperature(struct mt7996_phy *phy) +{ +#define TEMPERATURE_QUERY 0 +#define GET_TEMPERATURE 0 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 rsv1; + u8 action; + u8 band_idx; + u8 rsv2; + } req = { + .tag = cpu_to_le16(TEMPERATURE_QUERY), + .len = cpu_to_le16(sizeof(req) - 4), + .action = GET_TEMPERATURE, + .band_idx = phy->mt76->band_idx, + }; + struct mt7996_mcu_thermal { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + __le32 rsv; + __le32 temperature; + } __packed * res; + struct sk_buff *skb; + int ret; + + ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL), + &req, sizeof(req), true, &skb); + if (ret) + return ret; + + res = (void *)skb->data; + + return le32_to_cpu(res->temperature); +} + int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state) { struct { From 254ab81f3b82a297da5c0684a9ebf21fbc9dcb86 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 23 Oct 2023 23:38:48 +0800 Subject: [PATCH 29/62] wifi: mt76: connac: add beacon duplicate TX mode support for mt7996 For connac3 chipsets, setting of spe_idx is moved from TX descriptor to the fixed rate table. This patch implements the setting to support duplicate TX mode for beacon. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + .../net/wireless/mediatek/mt76/mt7996/init.c | 6 ++-- .../net/wireless/mediatek/mt76/mt7996/mac.c | 11 ------- .../net/wireless/mediatek/mt76/mt7996/main.c | 18 ++++++------ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 29 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 20 +++++++++++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 8 +++-- 7 files changed, 68 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 1d8680b153a7..65844de6dccd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1242,6 +1242,7 @@ enum { MCU_UNI_CMD_CHANNEL_SWITCH = 0x34, MCU_UNI_CMD_THERMAL = 0x35, MCU_UNI_CMD_VOW = 0x37, + MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, MCU_UNI_CMD_PER_STA_INFO = 0x6d, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index e2d08bf96eb0..6a03cddaed04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -354,6 +354,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; phy->slottime = 9; + phy->beacon_rate = -1; hw->sta_data_size = sizeof(struct mt7996_sta); hw->vif_data_size = sizeof(struct mt7996_vif); @@ -468,11 +469,12 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) { u16 rate = mt76_rates[i].hw_value; - u16 idx = MT7996_BASIC_RATES_TBL + i; + /* odd index for driver, even index for firmware */ + u16 idx = MT7996_BASIC_RATES_TBL + 2 * i; rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) | FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0)); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); + mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false); } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index f653e93349f3..08747f7d5429 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -248,17 +248,6 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, mt76_clear(dev, addr, BIT(5)); } -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx) -{ - u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; - - mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); - /* use wtbl spe idx */ - mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); - mt76_wr(dev, MT_WTBL_ITCR, ctrl); -} - /* The HW does not translate the mac header to 802.3 for mesh point */ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 33a9d50d3366..9f12b47eb2bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -522,24 +522,25 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; struct mt76_phy *mphy = hw->priv; u16 rate; - u8 i, idx, ht; + u8 i, idx; rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); - ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; - if (beacon && ht) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); + if (beacon) { + struct mt7996_phy *phy = mphy->priv; + + /* odd index for driver, even index for firmware */ + idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; + if (phy->beacon_rate != rate) + mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon); - /* must odd index */ - idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); - mt7996_mac_set_fixed_rate_table(dev, idx, rate); return idx; } idx = FIELD_GET(MT_TX_RATE_IDX, rate); for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) - return MT7996_BASIC_RATES_TBL + i; + return MT7996_BASIC_RATES_TBL + 2 * i; return mvif->basic_rates_idx; } @@ -965,7 +966,6 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); - /* TODO: update bmc_wtbl spe_idx when antenna changes */ mutex_unlock(&dev->mt76.mutex); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 48c7f4fe1bc7..a13ff8f7be54 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4179,6 +4179,35 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, + u16 rate_idx, bool beacon) +{ +#define UNI_FIXED_RATE_TABLE_SET 0 +#define SPE_IXD_SELECT_TXD 0 +#define SPE_IXD_SELECT_BMC_WTBL 1 + struct mt7996_dev *dev = phy->dev; + struct fixed_rate_table_ctrl req = { + .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET), + .len = cpu_to_le16(sizeof(req) - 4), + .table_idx = table_idx, + .rate_idx = cpu_to_le16(rate_idx), + .gi = 1, + .he_ltf = 1, + }; + u8 band_idx = phy->mt76->band_idx; + + if (beacon) { + req.spe_idx_sel = SPE_IXD_SELECT_TXD; + req.spe_idx = 24 + band_idx; + phy->beacon_rate = rate_idx; + } else { + req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE), + &req, sizeof(req), false); +} + int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set) { struct { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 4a73850db9c0..a2700151ee1c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -801,4 +801,24 @@ enum { #define MT7996_SEC_KEY_IDX GENMASK(2, 1) #define MT7996_SEC_IV BIT(3) +struct fixed_rate_table_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 table_idx; + u8 antenna_idx; + __le16 rate_idx; + u8 spe_idx_sel; + u8 spe_idx; + u8 gi; + u8 he_ltf; + bool ldpc; + bool txbf; + bool dynamic_bw; + + u8 _rsv2; +} __packed; + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 61e0f905d902..ed99432b2d03 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -47,7 +47,7 @@ #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ -#define MT7996_BASIC_RATES_TBL 11 +#define MT7996_BASIC_RATES_TBL 31 #define MT7996_BEACON_RATES_TBL 25 #define MT7996_THERMAL_THROTTLE_MAX 100 @@ -217,6 +217,8 @@ struct mt7996_phy { u8 rdd_state; + u16 beacon_rate; + u32 rx_ampdu_ts; u32 ampdu_ref; @@ -472,6 +474,8 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index, u8 rx_sel, 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, + u16 rate_idx, bool beacon); int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set); int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans); int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val); @@ -538,8 +542,6 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy); void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); void mt7996_mac_enable_rtscts(struct mt7996_dev *dev, struct ieee80211_vif *vif, bool enable); -void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev, - u8 tbl_idx, u16 rate_idx); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, From 4aa9992674e70074fce450f65ebc95c2ba2b79ae Mon Sep 17 00:00:00 2001 From: Sujuan Chen Date: Mon, 23 Oct 2023 23:38:49 +0800 Subject: [PATCH 30/62] wifi: mt76: mt7996: fix the size of struct bss_rate_tlv Align the format of struct bss_rate_tlv to the firmware. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: Sujuan Chen Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a2700151ee1c..d3ac6ac0e5c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -320,7 +320,7 @@ struct bss_rate_tlv { u8 short_preamble; u8 bc_fixed_rate; u8 mc_fixed_rate; - u8 __rsv2[1]; + u8 __rsv2[9]; } __packed; struct bss_ra_tlv { From de2a41cbfc7a78b1dd1941329b9aaf6c49829035 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:50 +0800 Subject: [PATCH 31/62] wifi: mt76: mt7996: adjust WFDMA settings to improve performance Refactor and update dma prefetch parts and also split band 1 traffic to PCIe 1 to enhance throughput. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 70 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7996/regs.h | 9 +++ 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 8bc08d993085..7ec6c64b3fd1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -99,38 +99,49 @@ static void mt7996_dma_config(struct mt7996_dev *dev) MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL); } +static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth) +{ + u32 ret = *base << 16 | depth; + + *base = *base + (depth << 4); + + return ret; +} + static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) { -#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth)) + u16 base = 0; + +#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(0x0, 0x2)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4)); - mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2)); - mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); + 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)); + 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)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x2)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10)); + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x10)); if (dev->has_rro) { mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, - PREFETCH(0x3a0, 0x10)); + PREFETCH(0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, - PREFETCH(0x4a0, 0x10)); + PREFETCH(0x10)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, - PREFETCH(0x5a0, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, - PREFETCH(0x5e0, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, - PREFETCH(0x620, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, - PREFETCH(0x660, 0x4)); + PREFETCH(0x4)); mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, - PREFETCH(0x6a0, 0x4)); + PREFETCH(0x4)); } #undef PREFETCH @@ -295,6 +306,12 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1, WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20); + if (dev->hif2) { /* GLO_CFG_EXT0 */ mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, @@ -306,7 +323,18 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_PDMA_BAND); + MT_WFDMA_HOST_CONFIG_PDMA_BAND | + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + + /* AXI read outstanding number */ + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, + MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); + + /* WFDMA rx threshold */ + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008); + mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20); } if (dev->hif2) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index e9edba830aff..6102df912741 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -379,6 +379,11 @@ enum base_rev { #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268) +#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c) +#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270) +#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c) + #define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18) #define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE BIT(14) @@ -401,10 +406,14 @@ enum base_rev { #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) +#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) #define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0) +#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500) +#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0) + #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) From 4ef49d1858e78da25c204e00b872cd35782cfc84 Mon Sep 17 00:00:00 2001 From: Howard Hsu Date: Mon, 23 Oct 2023 23:38:51 +0800 Subject: [PATCH 32/62] wifi: mt76: connac: set fixed_bw bit in TX descriptor for fixed rate frames Always set the fixed_bw bitfield for fixed rate frames to keep it being sent with specific bandwidth. Without this change, the bw of fixed rate frames will still be decided by hardware. Reported-by: Chank Chen Signed-off-by: Howard Hsu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 2250252b2047..36edf1d3dfca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -239,7 +239,8 @@ enum tx_mgnt_type { #define MT_TXD6_TX_SRC GENMASK(31, 30) #define MT_TXD6_VTA BIT(28) -#define MT_TXD6_BW GENMASK(25, 22) +#define MT_TXD6_FIXED_BW BIT(25) +#define MT_TXD6_BW GENMASK(24, 22) #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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 08747f7d5429..861737fe55cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -943,7 +943,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, idx = mvif->basic_rates_idx; } - txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW; + txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } From 8c8f77e0a6569f8b82ec749c0d3ce16224aeb418 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:52 +0800 Subject: [PATCH 33/62] wifi: mt76: mt7996: handle IEEE80211_RC_SMPS_CHANGED Make mt7996_mcu_set_fixed_field() non-static in order to handle IEEE80211_RC_SMPS_CHANGED in mt7996_mac_sta_rc_work(). Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 8 +++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 861737fe55cd..b17365b8d07b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -2285,7 +2285,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) IEEE80211_RC_BW_CHANGED)) mt7996_mcu_add_rate_ctrl(dev, vif, sta, true); - /* TODO: smps change */ + if (changed & IEEE80211_RC_SMPS_CHANGED) + mt7996_mcu_set_fixed_field(dev, vif, sta, NULL, + RATE_PARAM_MMPS_UPDATE); spin_lock_bh(&dev->mt76.sta_poll_lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index a13ff8f7be54..554ebe794caf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1800,9 +1800,8 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, MCU_WM_UNI_CMD(RA), true); } -static int -mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, void *data, u32 field) +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field) { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; @@ -1830,6 +1829,9 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, if (phy) ra->phy = *phy; break; + case RATE_PARAM_MMPS_UPDATE: + ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode); + break; default: break; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ed99432b2d03..0a150bcb2c19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -452,6 +452,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif); int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version); +int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, void *data, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset); int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); From 22f5dc781574b0f7ce7b491165dcf14bd6151a51 Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Mon, 23 Oct 2023 23:38:53 +0800 Subject: [PATCH 34/62] wifi: mt76: mt7996: align the format of fixed rate command Use the new fixed rate command format to let the fixed field function work normally. Signed-off-by: Peter Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 12 ++-- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 71 ++++++++++++++++++- 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 554ebe794caf..5a8a30115e2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1805,8 +1805,8 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif { struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct sta_phy *phy = data; - struct sta_rec_ra_fixed *ra; + struct sta_phy_uni *phy = data; + struct sta_rec_ra_fixed_uni *ra; struct sk_buff *skb; struct tlv *tlv; @@ -1817,7 +1817,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif return PTR_ERR(skb); tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra)); - ra = (struct sta_rec_ra_fixed *)tlv; + ra = (struct sta_rec_ra_fixed_uni *)tlv; switch (field) { case RATE_PARAM_AUTO: @@ -1849,7 +1849,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_phy phy = {}; + struct sta_phy_uni phy = {}; int ret, nrates = 0; #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ @@ -1937,13 +1937,13 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, struct cfg80211_chan_def *chandef = &mphy->chandef; struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask; enum nl80211_band band = chandef->chan->band; - struct sta_rec_ra *ra; + struct sta_rec_ra_uni *ra; struct tlv *tlv; u32 supp_rate = sta->deflink.supp_rates[band]; u32 cap = sta->wme ? STA_CAP_WMM : 0; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); - ra = (struct sta_rec_ra *)tlv; + ra = (struct sta_rec_ra_uni *)tlv; ra->valid = true; ra->auto_rate = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index d3ac6ac0e5c9..a3eae32c8f10 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -494,6 +494,73 @@ struct sta_rec_sec_uni { struct sec_key_uni key[2]; } __packed; +struct sta_phy_uni { + u8 type; + u8 flag; + u8 stbc; + u8 sgi; + u8 bw; + u8 ldpc; + u8 mcs; + u8 nss; + u8 he_ltf; + u8 rsv[3]; +}; + +struct sta_rec_ra_uni { + __le16 tag; + __le16 len; + + u8 valid; + u8 auto_rate; + u8 phy_mode; + u8 channel; + u8 bw; + u8 disable_cck; + u8 ht_mcs32; + u8 ht_gf; + u8 ht_mcs[4]; + u8 mmps_mode; + u8 gband_256; + u8 af; + u8 auth_wapi_mode; + u8 rate_len; + + u8 supp_mode; + u8 supp_cck_rate; + u8 supp_ofdm_rate; + __le32 supp_ht_mcs; + __le16 supp_vht_mcs[4]; + + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + __le32 sta_cap; + + struct sta_phy_uni phy; + u8 rx_rcpi[4]; +} __packed; + +struct sta_rec_ra_fixed_uni { + __le16 tag; + __le16 len; + + __le32 field; + u8 op_mode; + u8 op_vht_chan_width; + u8 op_vht_rx_nss; + u8 op_vht_rx_nss_type; + + struct sta_phy_uni phy; + + u8 spe_idx; + u8 short_preamble; + u8 is_5g; + u8 mmps_mode; +} __packed; + struct sta_rec_hdrt { __le16 tag; __le16 len; @@ -677,9 +744,9 @@ enum { sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ sizeof(struct sta_rec_phy) + \ - sizeof(struct sta_rec_ra) + \ + sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ - sizeof(struct sta_rec_ra_fixed) + \ + sizeof(struct sta_rec_ra_fixed_uni) + \ sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_eht) + \ sizeof(struct sta_rec_hdrt) + \ From 1e3f387736c744e73b5398a147b90412f82f54da Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Mon, 23 Oct 2023 23:38:54 +0800 Subject: [PATCH 35/62] wifi: mt76: mt7996: fix rate usage of inband discovery frames For UBPR and FILS frames, the BSS_CHANGED_BEACON flag will also be set, which causes those frames to use the beacon rate in TX descriptors. Adjust the statement to fix this issue. Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices") Signed-off-by: MeiChia Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index b17365b8d07b..6f1ade64bcb2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -860,10 +860,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct mt76_vif *mvif; u16 tx_count = 15; u32 val; - bool beacon = !!(changed & (BSS_CHANGED_BEACON | - BSS_CHANGED_BEACON_ENABLED)); bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | BSS_CHANGED_FILS_DISCOVERY)); + bool beacon = !!(changed & (BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc); mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL; if (mvif) { From 11a60bd2a590f8caa89a9079503d9e907e47d129 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 2 Nov 2023 18:02:55 +0800 Subject: [PATCH 36/62] wifi: mt76: change txpower init to per-phy Use per-phy structure for maximum txpower value initializing, since each phy may have a different chainmask, which can impact the calculation of power gain. Co-developed-by: Allen Ye Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7915/init.c | 30 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7915/mac.c | 4 +-- .../wireless/mediatek/mt76/mt7915/mt7915.h | 3 +- .../net/wireless/mediatek/mt76/mt7996/init.c | 30 ++++++++++++------- .../net/wireless/mediatek/mt76/mt7996/mac.c | 6 ++-- .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 6 files changed, 47 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 81478289f17e..cea2f6d9050a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -275,10 +275,11 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev, mt7915_led_set_config(led_cdev, 0xff, 0); } -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7915_init_txpower(struct mt7915_phy *phy, + struct ieee80211_supported_band *sband) { - int i, n_chains = hweight8(dev->mphy.antenna_mask); + struct mt7915_dev *dev = phy->dev; + int i, n_chains = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(n_chains); int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -296,7 +297,7 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -307,6 +308,19 @@ void mt7915_init_txpower(struct mt7915_dev *dev, } } +void mt7915_init_txpower(struct mt7915_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7915_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -322,9 +336,7 @@ mt7915_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7915_mcu_rdd_background_enable(phy, NULL); - mt7915_init_txpower(dev, &mphy->sband_2g.sband); - mt7915_init_txpower(dev, &mphy->sband_5g.sband); - mt7915_init_txpower(dev, &mphy->sband_6g.sband); + mt7915_init_txpower(phy); mphy->dfs_state = MT_DFS_STATE_UNKNOWN; mt7915_dfs_init_radar_detector(phy); @@ -442,6 +454,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy) mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); + mt7915_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -703,9 +716,6 @@ static void mt7915_init_work(struct work_struct *work) mt7915_mcu_set_eeprom(dev); mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7915_txbf_init(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index f12008244db3..b01edbed969c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1401,8 +1401,8 @@ mt7915_mac_restart(struct mt7915_dev *dev) goto out; mt7915_mac_init(dev); - mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); + mt7915_init_txpower(&dev->phy); + mt7915_init_txpower(phy2); ret = mt7915_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index d317c523b23f..4727d9c7b11d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -425,8 +425,7 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev); int mt7915_dma_reset(struct mt7915_dev *dev, bool force); int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset); int mt7915_txbf_init(struct mt7915_dev *dev); -void mt7915_init_txpower(struct mt7915_dev *dev, - struct ieee80211_supported_band *sband); +void mt7915_init_txpower(struct mt7915_phy *phy); void mt7915_reset(struct mt7915_dev *dev); int mt7915_run(struct ieee80211_hw *hw); int mt7915_mcu_init(struct mt7915_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 6a03cddaed04..1896571ad140 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -288,10 +288,11 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev, mt7996_led_set_config(led_cdev, 0xff, 0); } -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband) +static void __mt7996_init_txpower(struct mt7996_phy *phy, + struct ieee80211_supported_band *sband) { - int i, nss = hweight8(dev->mphy.antenna_mask); + struct mt7996_dev *dev = phy->dev; + int i, nss = hweight16(phy->mt76->chainmask); int nss_delta = mt76_tx_power_nss_delta(nss); int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band); struct mt76_power_limits limits; @@ -301,7 +302,7 @@ void mt7996_init_txpower(struct mt7996_dev *dev, int target_power = mt7996_eeprom_get_target_power(dev, chan); target_power += pwr_delta; - target_power = mt76_get_rate_power_limits(&dev->mphy, chan, + target_power = mt76_get_rate_power_limits(phy->mt76, chan, &limits, target_power); target_power += nss_delta; @@ -312,6 +313,19 @@ void mt7996_init_txpower(struct mt7996_dev *dev, } } +void mt7996_init_txpower(struct mt7996_phy *phy) +{ + if (!phy) + return; + + if (phy->mt76->cap.has_2ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband); + if (phy->mt76->cap.has_5ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband); + if (phy->mt76->cap.has_6ghz) + __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband); +} + static void mt7996_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -326,9 +340,7 @@ mt7996_regd_notifier(struct wiphy *wiphy, if (dev->mt76.region == NL80211_DFS_UNSET) mt7996_mcu_rdd_background_enable(phy, NULL); - mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband); - mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband); + mt7996_init_txpower(phy); phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN; mt7996_dfs_init_radar_detector(phy); @@ -424,6 +436,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_init_txpower(phy); wiphy->available_antennas_rx = phy->mt76->antenna_mask; wiphy->available_antennas_tx = phy->mt76->antenna_mask; @@ -656,9 +669,6 @@ static void mt7996_init_work(struct work_struct *work) mt7996_mcu_set_eeprom(dev); mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); mt7996_txbf_init(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 6f1ade64bcb2..1ee64efe0b88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1755,9 +1755,9 @@ mt7996_mac_restart(struct mt7996_dev *dev) goto out; mt7996_mac_init(dev); - mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband); - mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband); + mt7996_init_txpower(&dev->phy); + mt7996_init_txpower(phy2); + mt7996_init_txpower(phy3); ret = mt7996_txbf_init(dev); if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0a150bcb2c19..d3eb564623ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -414,8 +414,7 @@ void mt7996_dma_cleanup(struct mt7996_dev *dev); void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, int ring_base, struct mtk_wed_device *wed); -void mt7996_init_txpower(struct mt7996_dev *dev, - struct ieee80211_supported_band *sband); +void mt7996_init_txpower(struct mt7996_phy *phy); int mt7996_txbf_init(struct mt7996_dev *dev); void mt7996_reset(struct mt7996_dev *dev); int mt7996_run(struct ieee80211_hw *hw); From f75e4779d215a7dbe7eb7ab6f1ed075fe66930bc Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 2 Nov 2023 18:02:56 +0800 Subject: [PATCH 37/62] wifi: mt76: mt7996: add txpower setting support Add support for setting txpower from upper layer and configuring per-rate txpower limit table. Co-developed-by: Allen Ye Signed-off-by: Allen Ye Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/main.c | 8 +++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 58 +++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 16 +++++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 + 4 files changed, 85 insertions(+) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 9f12b47eb2bf..7336eaa7b9ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -396,6 +396,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed) ieee80211_wake_queues(hw); } + if (changed & (IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_CHANNEL)) { + ret = mt7996_mcu_set_txpower_sku(phy); + if (ret) + return ret; + } + mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { @@ -965,6 +972,7 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt76_set_stream_caps(phy->mt76, true); mt7996_set_stream_vht_txbf_caps(phy); mt7996_set_stream_he_eht_caps(phy); + mt7996_mcu_set_txpower_sku(phy); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5a8a30115e2c..2c987b9ca25d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -4353,3 +4353,61 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id) return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req, sizeof(req), true); } + +int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) +{ +#define TX_POWER_LIMIT_TABLE_RATE 0 + struct mt7996_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + struct ieee80211_hw *hw = mphy->hw; + struct tx_power_limit_table_ctrl { + u8 __rsv1[4]; + + __le16 tag; + __le16 len; + u8 power_ctrl_id; + u8 power_limit_type; + u8 band_idx; + } __packed req = { + .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL), + .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4), + .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL, + .power_limit_type = TX_POWER_LIMIT_TABLE_RATE, + .band_idx = phy->mt76->band_idx, + }; + struct mt76_power_limits la = {}; + struct sk_buff *skb; + int i, tx_power; + + tx_power = mt7996_get_power_bound(phy, hw->conf.power_level); + tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan, + &la, tx_power); + mphy->txpower_cur = tx_power; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req) + MT7996_SKU_RATE_NUM); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req, sizeof(req)); + /* cck and ofdm */ + skb_put_data(skb, &la.cck, sizeof(la.cck) + sizeof(la.ofdm)); + /* ht20 */ + skb_put_data(skb, &la.mcs[0], 8); + /* ht40 */ + skb_put_data(skb, &la.mcs[1], 9); + + /* vht */ + for (i = 0; i < 4; i++) { + skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i])); + skb_put_zero(skb, 2); /* padding */ + } + + /* he */ + skb_put_data(skb, &la.ru[0], sizeof(la.ru)); + /* eht */ + skb_put_data(skb, &la.eht[0], sizeof(la.eht)); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD(TXPOWER), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index a3eae32c8f10..1562c8a6a821 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -762,6 +762,18 @@ enum { #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ MT7996_BEACON_UPDATE_SIZE) +static inline s8 +mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower) +{ + struct mt76_phy *mphy = phy->mt76; + int n_chains = hweight16(mphy->chainmask); + + txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); + txpower -= mt76_tx_power_nss_delta(n_chains); + + return txpower; +} + enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, @@ -830,6 +842,10 @@ enum { UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, }; +enum { + UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, +}; + enum { UNI_CMD_ACCESS_REG_BASIC = 0x0, UNI_CMD_ACCESS_RF_REG_BASIC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index d3eb564623ae..c62a42512bd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -42,6 +42,8 @@ #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ +#define MT7996_SKU_RATE_NUM 417 + #define MT7996_MAX_TWT_AGRT 16 #define MT7996_MAX_STA_TWT_AGRT 8 #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3) @@ -471,6 +473,7 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); 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_background_enable(struct mt7996_phy *phy, From 1e12f0f81f36b7470bcd7e65904ff8264fd31a5b Mon Sep 17 00:00:00 2001 From: Allen Ye Date: Thu, 2 Nov 2023 18:02:57 +0800 Subject: [PATCH 38/62] wifi: mt76: use chainmask for power delta calculation The power gain value is related to total TX path, so change the calculation to use per-phy chainmask. Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7915/mcu.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 59586fa134e3..0bc66cc19acd 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -381,7 +381,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, if (!np) return target_power; - txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask)); + txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d4004a62af1d..8a3a90d1bfac 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1548,7 +1548,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int *dbm) { struct mt76_phy *phy = hw->priv; - int n_chains = hweight8(phy->antenna_mask); + int n_chains = hweight16(phy->chainmask); int delta = mt76_tx_power_nss_delta(n_chains); *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 1592b5d6751a..b41ac4aaced7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -519,7 +519,7 @@ static inline s8 mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower) { struct mt76_phy *mphy = phy->mt76; - int n_chains = hweight8(mphy->antenna_mask); + int n_chains = hweight16(mphy->chainmask); txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2); txpower -= mt76_tx_power_nss_delta(n_chains); From d57e1b255475957ab9280f8a2a6119853aef4d05 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Thu, 2 Nov 2023 18:02:58 +0800 Subject: [PATCH 39/62] wifi: mt76: mt7996: switch to mcu command for TX GI report During runtime, the GI value in the WTBL is not updated in real-time. To obtain the latest results for the TX GI, switch to use an MCU command. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- .../net/wireless/mediatek/mt76/mt7996/mac.c | 48 ++----------------- .../net/wireless/mediatek/mt76/mt7996/main.c | 1 + .../net/wireless/mediatek/mt76/mt7996/mcu.c | 47 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.h | 22 +++++++++ 5 files changed, 74 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 65844de6dccd..0185804d8ce3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1328,7 +1328,7 @@ enum { }; enum UNI_ALL_STA_INFO_TAG { - UNI_ALL_STA_TX_RATE, + UNI_ALL_STA_TXRX_RATE, UNI_ALL_STA_TX_STAT, UNI_ALL_STA_TXRX_ADM_STAT, UNI_ALL_STA_TXRX_AIR_TIME, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 1ee64efe0b88..1cc573551bdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -102,7 +102,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) }; struct ieee80211_sta *sta; struct mt7996_sta *msta; - struct rate_info *rate; u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS]; LIST_HEAD(sta_poll_list); int i; @@ -118,7 +117,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) u32 addr, val; u16 idx; s8 rssi[4]; - u8 bw; spin_lock_bh(&dev->mt76.sta_poll_lock); if (list_empty(&sta_poll_list)) { @@ -174,49 +172,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur); } - /* We don't support reading GI info from txs packets. - * For accurate tx status reporting and AQL improvement, - * we need to make sure that flags match so polling GI - * from per-sta counters directly. - */ - rate = &msta->wcid.rate; - - switch (rate->bw) { - case RATE_INFO_BW_320: - bw = IEEE80211_STA_RX_BW_320; - break; - case RATE_INFO_BW_160: - bw = IEEE80211_STA_RX_BW_160; - break; - case RATE_INFO_BW_80: - bw = IEEE80211_STA_RX_BW_80; - break; - case RATE_INFO_BW_40: - bw = IEEE80211_STA_RX_BW_40; - break; - default: - bw = IEEE80211_STA_RX_BW_20; - break; - } - - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6); - val = mt76_rr(dev, addr); - if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) { - addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5); - val = mt76_rr(dev, addr); - rate->eht_gi = FIELD_GET(GENMASK(25, 24), val); - } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) { - u8 offs = 24 + 2 * bw; - - rate->he_gi = (val & (0x3 << offs)) >> offs; - } else if (rate->flags & - (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) { - if (val & BIT(12 + bw)) - rate->flags |= RATE_INFO_FLAGS_SHORT_GI; - else - rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; - } - /* get signal strength of resp frames (CTS/BA/ACK) */ addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34); val = mt76_rr(dev, addr); @@ -1298,6 +1253,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, goto out; rate.flags = RATE_INFO_FLAGS_VHT_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; break; case MT_PHY_TYPE_HE_SU: case MT_PHY_TYPE_HE_EXT_SU: @@ -2312,6 +2269,7 @@ void mt7996_mac_work(struct work_struct *work) mt7996_mac_update_stats(phy); + mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE); if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT); mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 7336eaa7b9ae..d9ba57ae9fdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -998,6 +998,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.he_gi = txrate->he_gi; sinfo->txrate.he_dcm = txrate->he_dcm; sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; + sinfo->txrate.eht_gi = txrate->eht_gi; } sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 2c987b9ca25d..49c364785f2a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -449,6 +449,43 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) } } +static int +mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) +{ + switch (mcu_rate->tx_mode) { + case MT_PHY_TYPE_CCK: + case MT_PHY_TYPE_OFDM: + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + case MT_PHY_TYPE_VHT: + if (mcu_rate->tx_gi) + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + else + rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2) + return -EINVAL; + rate->he_gi = mcu_rate->tx_gi; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2) + return -EINVAL; + rate->eht_gi = mcu_rate->tx_gi; + break; + default: + return -EINVAL; + } + + return 0; +} + static void mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -465,6 +502,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) struct mt76_wcid *wcid; switch (le16_to_cpu(res->tag)) { + case UNI_ALL_STA_TXRX_RATE: + wlan_idx = le16_to_cpu(res->rate[i].wlan_idx); + wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); + + if (!wcid) + break; + + if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i])) + dev_err(dev->mt76.dev, "Failed to update TX GI\n"); + break; case UNI_ALL_STA_TXRX_ADM_STAT: wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx); wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 1562c8a6a821..328edc354165 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -175,6 +175,27 @@ struct mt7996_mcu_mib { __le64 data; } __packed; +struct all_sta_trx_rate { + __le16 wlan_idx; + u8 __rsv1[2]; + u8 tx_mode; + u8 flags; + u8 tx_stbc; + u8 tx_gi; + u8 tx_bw; + u8 tx_ldpc; + u8 tx_mcs; + u8 tx_nss; + u8 rx_rate; + u8 rx_mode; + u8 rx_nsts; + u8 rx_gi; + u8 rx_coding; + u8 rx_stbc; + u8 rx_bw; + u8 __rsv2; +} __packed; + struct mt7996_mcu_all_sta_info_event { u8 rsv[4]; __le16 tag; @@ -185,6 +206,7 @@ struct mt7996_mcu_all_sta_info_event { u8 rsv3[2]; union { + struct all_sta_trx_rate rate[0]; struct { __le16 wlan_idx; u8 rsv[2]; From d58a9778f7ca0634622d2fc2e9f76163467bdf5b Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 2 Nov 2023 18:02:59 +0800 Subject: [PATCH 40/62] wifi: mt76: mt7996: fix alignment of sta info event Fix the alignment of struct mt7996_mcu_all_sta_info_event. Fixes: adde3eed4a75 ("wifi: mt76: mt7996: Add mcu commands for getting sta tx statistic") Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 328edc354165..e23cc96c4dbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -203,7 +203,7 @@ struct mt7996_mcu_all_sta_info_event { u8 more; u8 rsv2; __le16 sta_num; - u8 rsv3[2]; + u8 rsv3[4]; union { struct all_sta_trx_rate rate[0]; From b769f7d8d9002a602232704505a7c593e1fa087c Mon Sep 17 00:00:00 2001 From: Peter Chiu Date: Thu, 2 Nov 2023 18:03:00 +0800 Subject: [PATCH 41/62] wifi: mt76: mt7996: rework ampdu params setting Add sta_rec_ht_uni struct to pass HT ampdu params to firmware. For VHT, HE, and EHT mode, firmware will get the ampdu params by parsing the corresponding capability. Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Peter Chiu Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 48 +++---------------- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 12 ++++- 2 files changed, 16 insertions(+), 44 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 49c364785f2a..5c86e28bcd21 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -1255,7 +1255,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) static void mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) { - struct sta_rec_ht *ht; + struct sta_rec_ht_uni *ht; struct tlv *tlv; if (!sta->deflink.ht_cap.ht_supported) @@ -1263,8 +1263,12 @@ mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); - ht = (struct sta_rec_ht *)tlv; + ht = (struct sta_rec_ht_uni *)tlv; ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap); + ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor, + IEEE80211_HT_AMPDU_PARM_FACTOR) | + u8_encode_bits(sta->deflink.ht_cap.ampdu_density, + IEEE80211_HT_AMPDU_PARM_DENSITY); } static void @@ -1721,44 +1725,6 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } -static void -mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) -{ - struct sta_rec_phy *phy; - struct tlv *tlv; - u8 af = 0, mm = 0; - - if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa) - return; - - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); - - phy = (struct sta_rec_phy *)tlv; - if (sta->deflink.ht_cap.ht_supported) { - af = sta->deflink.ht_cap.ampdu_factor; - mm = sta->deflink.ht_cap.ampdu_density; - } - - if (sta->deflink.vht_cap.vht_supported) { - u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, - sta->deflink.vht_cap.cap); - - af = max_t(u8, af, vht_af); - } - - if (sta->deflink.he_6ghz_capa.capa) { - af = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); - mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); - } - - phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) | - FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm); - phy->max_ampdu_len = af; -} - static void mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -2167,8 +2133,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, /* tag order is in accordance with firmware dependency. */ if (sta) { - /* starec phy */ - mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta); /* starec hdrt mode */ mt7996_mcu_sta_hdrt_tlv(dev, skb); /* starec bfer */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index e23cc96c4dbc..1851528d10ca 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -467,6 +467,15 @@ struct bss_mld_tlv { u8 __rsv[3]; } __packed; +struct sta_rec_ht_uni { + __le16 tag; + __le16 len; + __le16 ht_cap; + __le16 ht_cap_ext; + u8 ampdu_param; + u8 _rsv[3]; +} __packed; + struct sta_rec_ba_uni { __le16 tag; __le16 len; @@ -758,14 +767,13 @@ enum { #define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \ sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_bf) + \ - sizeof(struct sta_rec_ht) + \ + sizeof(struct sta_rec_ht_uni) + \ sizeof(struct sta_rec_he_v2) + \ sizeof(struct sta_rec_ba_uni) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct sta_rec_uapsd) + \ sizeof(struct sta_rec_amsdu) + \ sizeof(struct sta_rec_bfee) + \ - sizeof(struct sta_rec_phy) + \ sizeof(struct sta_rec_ra_uni) + \ sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra_fixed_uni) + \ From eb80e02b2c03141460749d3800126e2cdb674c9e Mon Sep 17 00:00:00 2001 From: Allen Ye Date: Thu, 2 Nov 2023 18:03:01 +0800 Subject: [PATCH 42/62] wifi: mt76: connac: add beacon protection support for mt7996 Implement beacon protection feature for mt7996 chipsets, and also do some cleanup on the set key routine. Co-developed-by: Rudra Shahi Signed-off-by: Rudra Shahi Signed-off-by: Allen Ye Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 24 +++ .../net/wireless/mediatek/mt76/mt7996/main.c | 12 +- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 137 +++++++++++++----- .../net/wireless/mediatek/mt76/mt7996/mcu.h | 17 +++ .../wireless/mediatek/mt76/mt7996/mt7996.h | 3 +- 5 files changed, 152 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0185804d8ce3..ae6d0179727d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -416,6 +416,14 @@ struct sta_rec_he_6g_capa { u8 rsv[2]; } __packed; +struct sta_rec_pn_info { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 tsc_type; + u8 rsv; +} __packed; + struct sec_key { u8 cipher_id; u8 cipher_len; @@ -768,6 +776,7 @@ struct wtbl_raw { sizeof(struct sta_rec_sec) + \ sizeof(struct sta_rec_ra_fixed) + \ sizeof(struct sta_rec_he_6g_capa) + \ + sizeof(struct sta_rec_pn_info) + \ sizeof(struct tlv) + \ MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) @@ -798,6 +807,7 @@ enum { STA_REC_HE_V2 = 0x19, STA_REC_MLD = 0x20, STA_REC_EHT = 0x22, + STA_REC_PN_INFO = 0x26, STA_REC_HDRT = 0x28, STA_REC_HDR_TRANS = 0x2B, STA_REC_MAX_NUM @@ -1090,6 +1100,13 @@ enum mcu_cipher_type { MCU_CIPHER_GCMP_256, MCU_CIPHER_WAPI, MCU_CIPHER_BIP_CMAC_128, + MCU_CIPHER_BIP_CMAC_256, + MCU_CIPHER_BCN_PROT_CMAC_128, + MCU_CIPHER_BCN_PROT_CMAC_256, + MCU_CIPHER_BCN_PROT_GMAC_128, + MCU_CIPHER_BCN_PROT_GMAC_256, + MCU_CIPHER_BIP_GMAC_128, + MCU_CIPHER_BIP_GMAC_256, }; enum { @@ -1310,6 +1327,7 @@ enum { UNI_BSS_INFO_RATE = 11, UNI_BSS_INFO_QBSS = 15, UNI_BSS_INFO_SEC = 16, + UNI_BSS_INFO_BCN_PROT = 17, UNI_BSS_INFO_TXCMD = 18, UNI_BSS_INFO_UAPSD = 19, UNI_BSS_INFO_PS = 21, @@ -1771,6 +1789,12 @@ mt76_connac_mcu_get_cipher(int cipher) return MCU_CIPHER_GCMP; case WLAN_CIPHER_SUITE_GCMP_256: return MCU_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + return MCU_CIPHER_BIP_GMAC_128; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + return MCU_CIPHER_BIP_GMAC_256; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + return MCU_CIPHER_BIP_CMAC_256; case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index d9ba57ae9fdc..51deea84b642 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -350,6 +350,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_SMS4: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -373,9 +375,13 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } mt76_wcid_key_setup(&dev->mt76, wcid, key); - err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, - key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &msta->wcid, cmd); + + if (key->keyidx == 6 || key->keyidx == 7) + err = mt7996_mcu_bcn_prot_enable(dev, vif, key); + else + err = mt7996_mcu_add_key(&dev->mt76, vif, key, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &msta->wcid, cmd); out: mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 5c86e28bcd21..b5e27c29b1c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2171,7 +2171,6 @@ out: static int mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, - struct mt76_connac_sta_key_conf *sta_key_conf, struct sk_buff *skb, struct ieee80211_key_conf *key, enum set_key_cmd cmd) @@ -2192,43 +2191,22 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, return -EOPNOTSUPP; sec_key = &sec->key[0]; + sec_key->wlan_idx = cpu_to_le16(wcid->idx); + sec_key->mgmt_prot = 0; + sec_key->cipher_id = cipher; sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_id = key->keyidx; + sec_key->key_len = key->keylen; + sec_key->need_resp = 0; + memcpy(sec_key->key, key->key, key->keylen); - if (cipher == MCU_CIPHER_BIP_CMAC_128) { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_AES_CCMP; - sec_key->key_id = sta_key_conf->keyidx; - sec_key->key_len = 16; - memcpy(sec_key->key, sta_key_conf->key, 16); - - sec_key = &sec->key[1]; - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128; - sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_len = 16; - memcpy(sec_key->key, key->key, 16); - sec->n_cipher = 2; - } else { - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->cipher_id = cipher; - sec_key->key_id = key->keyidx; - sec_key->key_len = key->keylen; - memcpy(sec_key->key, key->key, key->keylen); - - if (cipher == MCU_CIPHER_TKIP) { - /* Rx/Tx MIC keys are swapped */ - memcpy(sec_key->key + 16, key->key + 24, 8); - memcpy(sec_key->key + 24, key->key + 16, 8); - } - - /* store key_conf for BIP batch update */ - if (cipher == MCU_CIPHER_AES_CCMP) { - memcpy(sta_key_conf->key, key->key, key->keylen); - sta_key_conf->keyidx = key->keyidx; - } - - sec->n_cipher = 1; + if (cipher == MCU_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); } + + sec->n_cipher = 1; } else { sec->n_cipher = 0; } @@ -2237,7 +2215,6 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, } int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd) { @@ -2250,13 +2227,99 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, if (IS_ERR(skb)) return PTR_ERR(skb); - ret = mt7996_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd); + ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd); if (ret) return ret; return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } +static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif, + u8 *pn) +{ +#define TSC_TYPE_BIGTK_PN 2 + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct sta_rec_pn_info *pn_info; + struct sk_buff *skb, *rskb; + struct tlv *tlv; + int ret; + + skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &mvif->sta.wcid); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info)); + pn_info = (struct sta_rec_pn_info *)tlv; + + pn_info->tsc_type = TSC_TYPE_BIGTK_PN; + ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE), + true, &rskb); + if (ret) + return ret; + + skb_pull(rskb, 4); + + pn_info = (struct sta_rec_pn_info *)rskb->data; + if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO) + memcpy(pn, pn_info->pn, 6); + + dev_kfree_skb(rskb); + return 0; +} + +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt7996_mcu_bcn_prot_tlv *bcn_prot; + struct sk_buff *skb; + struct tlv *tlv; + u8 pn[6] = {}; + int len = sizeof(struct bss_req_hdr) + + sizeof(struct mt7996_mcu_bcn_prot_tlv); + int ret; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot)); + + bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv; + + ret = mt7996_mcu_get_pn(dev, vif, pn); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + default: + dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n"); + dev_kfree_skb(skb); + return -EOPNOTSUPP; + } + + pn[0]++; + memcpy(bcn_prot->pn, pn, 6); + bcn_prot->enable = BP_SW_MODE; + memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN); + bcn_prot->key_id = key->keyidx; + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); +} int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, bool enable) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 1851528d10ca..10a1b09ff2fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -345,6 +345,23 @@ struct bss_rate_tlv { u8 __rsv2[9]; } __packed; +enum { + BP_DISABLE, + BP_SW_MODE, + BP_HW_MODE, +}; + +struct mt7996_mcu_bcn_prot_tlv { + __le16 tag; + __le16 len; + u8 pn[6]; + u8 enable; + u8 cipher_id; + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_id; + u8 __rsv[3]; +} __packed; + struct bss_ra_tlv { __le16 tag; __le16 len; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index c62a42512bd6..0ba00e4166d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -584,9 +584,10 @@ int mt7996_init_debugfs(struct mt7996_phy *phy); void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len); bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len); int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, - struct mt76_connac_sta_key_conf *sta_key_conf, struct ieee80211_key_conf *key, int mcu_cmd, struct mt76_wcid *wcid, enum set_key_cmd cmd); +int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_key_conf *key); int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); From 2c2f50bf6407e1fd43a1a257916aeaa5ffdacd6c Mon Sep 17 00:00:00 2001 From: MeiChia Chiu Date: Thu, 2 Nov 2023 18:03:02 +0800 Subject: [PATCH 43/62] wifi: mt76: connac: fix EHT phy mode check Add a BSS eht_support check before returning EHT phy mode. Without this patch, there might be an inconsistency where the softmac layer thinks the BSS is in HE mode, while the FW thinks it is in EHT mode. Signed-off-by: MeiChia Chiu Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ae6bf3c968df..b475555097ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1359,7 +1359,7 @@ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, sband = phy->hw->wiphy->bands[band]; eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); - if (!eht_cap || !eht_cap->has_eht) + if (!eht_cap || !eht_cap->has_eht || !vif->bss_conf.eht_support) return mode; switch (band) { From 3531c72aedb95261f4d78c47efa4b5ba7cdcddd9 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 6 Nov 2023 22:38:53 +0000 Subject: [PATCH 44/62] wifi: mt76: mt7915: fix EEPROM offset of TSSI flag on MT7981 The offset of the TSSI flag on the EEPROM of MT7981 devices was wrong. Set the correct offset instead. Fixes: 6bad146d162e ("wifi: mt76: mt7915: add support for MT7981") Signed-off-by: StanleyYP Wang Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index f3e56817d36e..adc26a222823 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -144,7 +144,8 @@ static inline bool mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band) { u8 *eep = dev->mt76.eeprom.data; - u8 val = eep[MT_EE_WIFI_CONF + 7]; + u8 offs = is_mt7981(&dev->mt76) ? 8 : 7; + u8 val = eep[MT_EE_WIFI_CONF + offs]; if (band == NL80211_BAND_2GHZ) return val & MT_EE_WIFI_CONF7_TSSI0_2G; From ff434cc129d6907e6dbc89dd0ebc59fd3646d4c2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 6 Nov 2023 22:39:31 +0000 Subject: [PATCH 45/62] wifi: mt76: mt7915: also MT7981 is 3T3R but nss2 on 5 GHz band Just like MT7916 also MT7981 can handle 3T3R DBDC frontend and should hence be included in the corresponding conditional expression in the driver. Add it. Fixes: 6bad146d162e ("wifi: mt76: mt7915: add support for MT7981") Signed-off-by: StanleyYP Wang Signed-off-by: Daniel Golle Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index ba34c8e19aab..df2d4279790d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1059,8 +1059,9 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) phy->mt76->antenna_mask = tx_ant; - /* handle a variant of mt7916 which has 3T3R but nss2 on 5 GHz band */ - if (is_mt7916(&dev->mt76) && band && hweight8(tx_ant) == max_nss) + /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ + if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) && + band && hweight8(tx_ant) == max_nss) phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; else phy->mt76->chainmask = tx_ant << (chainshift * band); From 2ee1c40daeb9a33e25c460bf87feca58e91af879 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 10 Nov 2023 15:29:30 +0100 Subject: [PATCH 46/62] wifi: mt76: mt7996: fix mt7996_mcu_all_sta_info_event struct packing The internal struct and union inside mt7996_mcu_all_sta_info_event is marked as being aligned, which conflicts with it being unaligned within that structure: drivers/net/wireless/mediatek/mt76/mt7996/mcu.h:165:2: error: field within 'struct mt7996_mcu_all_sta_info_event' is less aligned than 'union mt7996_mcu_all_sta_info_event::(anonymous at ../drivers/net/wireless/mediatek/mt76/mt7996/mcu.h:165:2)' and is usually due to 'struct mt7996_mcu_all_sta_info_event' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] Mark all three as being packed as well to ensure byte packing for the entire thing. Fixes: adde3eed4a75 ("wifi: mt76: mt7996: Add mcu commands for getting sta tx statistic") Signed-off-by: Arnd Bergmann Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mcu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 10a1b09ff2fb..3e013b20ee5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -212,15 +212,15 @@ struct mt7996_mcu_all_sta_info_event { u8 rsv[2]; __le32 tx_bytes[IEEE80211_NUM_ACS]; __le32 rx_bytes[IEEE80211_NUM_ACS]; - } adm_stat[0]; + } adm_stat[0] __packed; struct { __le16 wlan_idx; u8 rsv[2]; __le32 tx_msdu_cnt; __le32 rx_msdu_cnt; - } msdu_cnt[0]; - }; + } msdu_cnt[0] __packed; + } __packed; } __packed; struct mt7996_mcu_wed_rro_event { From 1e1e563fe3bd2ad9252a98c24d55bb3f3a06990e Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Mon, 13 Nov 2023 15:06:12 +0800 Subject: [PATCH 47/62] wifi: mt76: mt7996: introduce mt7996_band_valid() Replace dbdc_support and tbtc_support with mt7996_band_valid() to support mt7996 variants with band0/band2 dual-band support. This changes reduces ambiguity when checking supported bands on different variants or new chipsets, as well as during the init configurations on DMA TX/RX queues or irq masks. Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 14 ++++----- .../net/wireless/mediatek/mt76/mt7996/init.c | 29 ++++++++++--------- .../net/wireless/mediatek/mt76/mt7996/mcu.c | 16 +++++----- .../wireless/mediatek/mt76/mt7996/mt7996.h | 16 ++++++++-- .../net/wireless/mediatek/mt76/mt7996/regs.h | 3 ++ 5 files changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 7ec6c64b3fd1..7c5801e1ebdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -233,13 +233,13 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) /* enable interrupts for TX/RX rings */ irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; - if (!dev->mphy.band_idx) + if (mt7996_band_valid(dev, MT_BAND0)) irq_mask |= MT_INT_BAND0_RX_DONE; - if (dev->dbdc_support) + if (mt7996_band_valid(dev, MT_BAND1)) irq_mask |= MT_INT_BAND1_RX_DONE; - if (dev->tbtc_support) + if (mt7996_band_valid(dev, MT_BAND2)) irq_mask |= MT_INT_BAND2_RX_DONE; if (mtk_wed_device_active(wed) && wed_reset) { @@ -382,7 +382,7 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1)) { /* rx msdu page queue for band1 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; @@ -396,7 +396,7 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) return ret; } - if (dev->tbtc_support) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx msdu page queue for band2 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; @@ -516,7 +516,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx data queue for band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], @@ -570,7 +570,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { + if (mt7996_band_valid(dev, MT_BAND2)) { /* rx rro data queue for band2 */ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 1896571ad140..64fa2f28c8c2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -540,7 +540,8 @@ int mt7996_txbf_init(struct mt7996_dev *dev) { int ret; - if (dev->dbdc_support) { + if (mt7996_band_valid(dev, MT_BAND1) || + mt7996_band_valid(dev, MT_BAND2)) { ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL); if (ret) return ret; @@ -563,11 +564,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, int ret; struct mtk_wed_device *wed = &dev->mt76.mmio.wed; - if (band != MT_BAND1 && band != MT_BAND2) - return 0; - - if ((band == MT_BAND1 && !dev->dbdc_support) || - (band == MT_BAND2 && !dev->tbtc_support)) + if (!mt7996_band_valid(dev, band) || band == MT_BAND0) return 0; if (phy) @@ -897,9 +894,6 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) INIT_LIST_HEAD(&dev->wed_rro.poll_list); spin_lock_init(&dev->wed_rro.lock); - dev->dbdc_support = true; - dev->tbtc_support = true; - ret = mt7996_dma_init(dev); if (ret) return ret; @@ -1331,8 +1325,6 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; - ieee80211_queue_work(mt76_hw(dev), &dev->init_work); - ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1); if (ret) return ret; @@ -1341,13 +1333,24 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + ieee80211_queue_work(mt76_hw(dev), &dev->init_work); + dev->recovery.hw_init_done = true; ret = mt7996_init_debugfs(&dev->phy); if (ret) - return ret; + goto error; - return mt7996_coredump_register(dev); + ret = mt7996_coredump_register(dev); + if (ret) + goto error; + + return 0; + +error: + cancel_work_sync(&dev->init_work); + + return ret; } void mt7996_unregister_device(struct mt7996_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index b5e27c29b1c4..be4beeb47a19 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2964,9 +2964,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) { struct uni_header hdr = {}; struct sk_buff *skb; - int len, num; + int len, num, i; - num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support); + num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime); skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); if (!skb) @@ -2974,13 +2975,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev) skb_put_data(skb, &hdr, sizeof(hdr)); - mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx); - - if (dev->dbdc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND1); - - if (dev->tbtc_support) - mt7996_add_rx_airtime_tlv(skb, MT_BAND2); + for (i = 0; i < __MT_MAX_BAND; i++) { + if (mt7996_band_valid(dev, i)) + mt7996_add_rx_airtime_tlv(skb, i); + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(VOW), true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0ba00e4166d9..aefd09c7d6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -280,8 +280,6 @@ struct mt7996_dev { u32 hw_pattern; - bool dbdc_support:1; - bool tbtc_support:1; bool flash_mode:1; bool has_eht:1; bool has_rro:1; @@ -393,6 +391,17 @@ mt7996_phy3(struct mt7996_dev *dev) return __mt7996_phy(dev, MT_BAND2); } +static inline bool +mt7996_band_valid(struct mt7996_dev *dev, u8 band) +{ + /* tri-band support */ + if (band <= MT_BAND2 && + mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1) + return true; + + return band == MT_BAND0 || band == MT_BAND2; +} + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; @@ -494,7 +503,8 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support); + return MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 6102df912741..d8904cbc2856 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -629,6 +629,9 @@ enum base_rev { #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +#define MT_PAD_GPIO 0x700056f0 +#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15) + #define MT_HW_REV 0x70010204 #define MT_HW_REV1 0x8a00 From a63b75aac8468e7216930c698d5676259afb44fd Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:13 +0800 Subject: [PATCH 48/62] wifi: mt76: connac: add firmware support for mt7992 Support firmware download and enable related AFE PLL for mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Co-developed-by: Benjamin Lin Signed-off-by: Benjamin Lin Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: StanleyYP Wang Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt76_connac.h | 5 +++++ .../wireless/mediatek/mt76/mt76_connac_mcu.c | 3 ++- .../net/wireless/mediatek/mt76/mt7996/init.c | 4 ++++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 22 +++++++++++++++---- .../wireless/mediatek/mt76/mt7996/mt7996.h | 5 +++++ .../net/wireless/mediatek/mt76/mt7996/pci.c | 4 ++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 7 ++++++ 7 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index e5ebde19af8f..fdde3d70b300 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -222,6 +222,11 @@ static inline bool is_mt7996(struct mt76_dev *dev) return mt76_chip(dev) == 0x7990; } +static inline bool is_mt7992(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7992; +} + static inline bool is_mt7622(struct mt76_dev *dev) { if (!IS_ENABLED(CONFIG_MT7622_WMAC)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index b475555097ff..96494ba2fdf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -67,7 +67,8 @@ 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) || - (is_mt7996(dev) && addr == 0x900000)) + (is_mt7996(dev) && addr == 0x900000) || + (is_mt7992(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/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 64fa2f28c8c2..2a7c367afae1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -888,6 +888,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) int ret, idx; mt76_wr(dev, MT_INT_SOURCE_CSR, ~0); + if (is_mt7992(&dev->mt76)) { + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0); + } INIT_WORK(&dev->init_work, mt7996_init_work); INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index be4beeb47a19..3c729b563edc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -10,6 +10,20 @@ #include "mac.h" #include "eeprom.h" +#define fw_name(_dev, name, ...) ({ \ + char *_fw; \ + switch (mt76_chip(&(_dev)->mt76)) { \ + case 0x7992: \ + _fw = MT7992_##name; \ + break; \ + case 0x7990: \ + default: \ + _fw = MT7996_##name; \ + break; \ + } \ + _fw; \ +}) + struct mt7996_patch_hdr { char build_date[16]; char platform[4]; @@ -2639,7 +2653,7 @@ static int mt7996_load_patch(struct mt7996_dev *dev) return -EAGAIN; } - ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev); + ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev); if (ret) goto out; @@ -2802,17 +2816,17 @@ static int mt7996_load_ram(struct mt7996_dev *dev) { int ret; - ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM, + ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM), MT7996_RAM_TYPE_WM); if (ret) return ret; - ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP, + ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP), MT7996_RAM_TYPE_DSP); if (ret) return ret; - return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA, + return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA), MT7996_RAM_TYPE_WA); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index aefd09c7d6e6..1a36ef50f6e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -33,6 +33,11 @@ #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin" +#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin" +#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin" +#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin" +#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 93ecc9a8dde0..baa5fb97a121 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -244,3 +244,7 @@ MODULE_FIRMWARE(MT7996_FIRMWARE_WA); MODULE_FIRMWARE(MT7996_FIRMWARE_WM); MODULE_FIRMWARE(MT7996_FIRMWARE_DSP); MODULE_FIRMWARE(MT7996_ROM_PATCH); +MODULE_FIRMWARE(MT7992_FIRMWARE_WA); +MODULE_FIRMWARE(MT7992_FIRMWARE_WM); +MODULE_FIRMWARE(MT7992_FIRMWARE_DSP); +MODULE_FIRMWARE(MT7992_ROM_PATCH); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index d8904cbc2856..aee577d90ddb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -683,4 +683,11 @@ enum base_rev { #define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200) #define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204) +/* CONN AFE CTL CON */ +#define MT_AFE_CTL_BASE 0x18043000 +#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \ + ((_band) * 0x1000) + (ofs)) +#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c) +#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1) + #endif From 9fe6690b8bef58848294bf5de9c6c31748e11941 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Mon, 13 Nov 2023 15:06:14 +0800 Subject: [PATCH 49/62] wifi: mt76: mt7996: add DMA support for mt7992 Add DMA TX/RX queues and RRO init flow for mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Co-developed-by: Shayne Chen Signed-off-by: Shayne Chen Signed-off-by: Benjamin Lin Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/dma.c | 58 +++++++++++++++---- .../net/wireless/mediatek/mt76/mt7996/init.c | 9 ++- .../wireless/mediatek/mt76/mt7996/mt7996.h | 7 ++- .../net/wireless/mediatek/mt76/mt7996/regs.h | 4 +- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 7c5801e1ebdb..0bc4681fc18a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -57,13 +57,19 @@ static void mt7996_dma_config(struct mt7996_dev *dev) RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM); RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA); - /* band0/band1 */ + /* 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); - /* 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); + if (is_mt7996(&dev->mt76)) { + /* mt7996 band2 */ + RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); + RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); + } else { + /* mt7992 band1 */ + RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1); + RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT); + } if (dev->has_rro) { /* band0 */ @@ -90,8 +96,12 @@ static void mt7996_dma_config(struct mt7996_dev *dev) /* data tx queue */ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + if (is_mt7996(&dev->mt76)) { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + } else { + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + } /* mcu tx queue */ MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM); @@ -111,6 +121,7 @@ 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; #define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth))) /* prefetch SRAM wrapping boundary for tx/rx ring. */ @@ -123,9 +134,14 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) 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)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_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)); - mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + 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)); if (dev->has_rro) { mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, @@ -488,7 +504,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* rx data queue for band0 and band1 */ + /* rx data queue for band0 and mt7996 band1 */ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; @@ -517,7 +533,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; if (mt7996_band_valid(dev, MT_BAND2)) { - /* rx data queue for band2 */ + /* rx data queue for mt7996 band2 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], MT_RXQ_ID(MT_RXQ_BAND2), @@ -527,7 +543,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* tx free notify event from WA for band2 + /* tx free notify event from WA for mt7996 band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { @@ -542,6 +558,26 @@ int mt7996_dma_init(struct mt7996_dev *dev) MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA)); if (ret) return ret; + } else if (mt7996_band_valid(dev, MT_BAND1)) { + /* rx data queue for mt7992 band1 */ + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs; + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], + MT_RXQ_ID(MT_RXQ_BAND1), + MT7996_RX_RING_SIZE, + MT_RX_BUF_SIZE, + rx_base); + if (ret) + 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 (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 2a7c367afae1..0cf0d1fe420a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -513,7 +513,12 @@ void mt7996_mac_init(struct mt7996_dev *dev) mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0); /* rro module init */ - mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + if (is_mt7996(&dev->mt76)) + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); + else + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, + dev->hif2 ? 7 : 0); + if (dev->has_rro) { u16 timeout; @@ -570,7 +575,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, if (phy) return 0; - if (band == MT_BAND2 && dev->hif2) { + if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); wed = &dev->mt76.mmio.wed_hif2; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 1a36ef50f6e1..87822663870f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -104,10 +104,10 @@ enum mt7996_rxq_id { MT7996_RXQ_MCU_WM = 0, MT7996_RXQ_MCU_WA, MT7996_RXQ_MCU_WA_MAIN = 2, - MT7996_RXQ_MCU_WA_EXT = 2,/* unused */ + MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */ MT7996_RXQ_MCU_WA_TRI = 3, MT7996_RXQ_BAND0 = 4, - MT7996_RXQ_BAND1 = 4,/* unused */ + MT7996_RXQ_BAND1 = 5, /* for mt7992 */ MT7996_RXQ_BAND2 = 5, MT7996_RXQ_RRO_BAND0 = 8, MT7996_RXQ_RRO_BAND1 = 8,/* unused */ @@ -399,6 +399,9 @@ mt7996_phy3(struct mt7996_dev *dev) static inline bool mt7996_band_valid(struct mt7996_dev *dev, u8 band) { + if (is_mt7992(&dev->mt76)) + return band <= MT_BAND1; + /* tri-band support */ if (band <= MT_BAND2 && mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index aee577d90ddb..6623a6ba12d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -461,12 +461,12 @@ enum base_rev { #define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204) #define MT_INT_RX_DONE_BAND0 BIT(12) -#define MT_INT_RX_DONE_BAND1 BIT(12) +#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */ #define MT_INT_RX_DONE_BAND2 BIT(13) #define MT_INT_RX_DONE_WM BIT(0) #define MT_INT_RX_DONE_WA BIT(1) #define MT_INT_RX_DONE_WA_MAIN BIT(2) -#define MT_INT_RX_DONE_WA_EXT BIT(2) +#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */ #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) From 50fbebf6a151bc70c43ffab1f884aa510d548d7e Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:15 +0800 Subject: [PATCH 50/62] wifi: mt76: mt7996: rework register offsets for mt7992 Add mt7992_offs to differentiate registers that share the same definitions with mt7996 chipsets but have differnet offsets. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/mmio.c | 59 ++++++++++++++ .../net/wireless/mediatek/mt76/mt7996/regs.h | 76 +++++++++++++------ 2 files changed, 112 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 739d7f53d347..b1119f62c946 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -30,6 +30,58 @@ static const struct __base mt7996_reg_base[] = { [WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } }, }; +static const u32 mt7996_offs[] = { + [MIB_RVSR0] = 0x720, + [MIB_RVSR1] = 0x724, + [MIB_BTSCR5] = 0x788, + [MIB_BTSCR6] = 0x798, + [MIB_RSCR1] = 0x7ac, + [MIB_RSCR27] = 0x954, + [MIB_RSCR28] = 0x958, + [MIB_RSCR29] = 0x95c, + [MIB_RSCR30] = 0x960, + [MIB_RSCR31] = 0x964, + [MIB_RSCR33] = 0x96c, + [MIB_RSCR35] = 0x974, + [MIB_RSCR36] = 0x978, + [MIB_BSCR0] = 0x9cc, + [MIB_BSCR1] = 0x9d0, + [MIB_BSCR2] = 0x9d4, + [MIB_BSCR3] = 0x9d8, + [MIB_BSCR4] = 0x9dc, + [MIB_BSCR5] = 0x9e0, + [MIB_BSCR6] = 0x9e4, + [MIB_BSCR7] = 0x9e8, + [MIB_BSCR17] = 0xa10, + [MIB_TRDR1] = 0xa28, +}; + +static const u32 mt7992_offs[] = { + [MIB_RVSR0] = 0x760, + [MIB_RVSR1] = 0x764, + [MIB_BTSCR5] = 0x7c8, + [MIB_BTSCR6] = 0x7d8, + [MIB_RSCR1] = 0x7f0, + [MIB_RSCR27] = 0x998, + [MIB_RSCR28] = 0x99c, + [MIB_RSCR29] = 0x9a0, + [MIB_RSCR30] = 0x9a4, + [MIB_RSCR31] = 0x9a8, + [MIB_RSCR33] = 0x9b0, + [MIB_RSCR35] = 0x9b8, + [MIB_RSCR36] = 0x9bc, + [MIB_BSCR0] = 0xac8, + [MIB_BSCR1] = 0xacc, + [MIB_BSCR2] = 0xad0, + [MIB_BSCR3] = 0xad4, + [MIB_BSCR4] = 0xad8, + [MIB_BSCR5] = 0xadc, + [MIB_BSCR6] = 0xae0, + [MIB_BSCR7] = 0xae4, + [MIB_BSCR17] = 0xb0c, + [MIB_TRDR1] = 0xb24, +}; + static const struct __map mt7996_reg_map[] = { { 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */ @@ -382,6 +434,13 @@ static int mt7996_mmio_init(struct mt76_dev *mdev, switch (device_id) { case 0x7990: 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: + dev->reg.base = mt7996_reg_base; + dev->reg.offs_rev = mt7992_offs; dev->reg.map = mt7996_reg_map; dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map); break; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 6623a6ba12d6..21637e3aae42 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -19,6 +19,7 @@ struct __base { /* used to differentiate between generations */ struct mt7996_reg_desc { const struct __base *base; + const u32 *offs_rev; const struct __map *map; u32 map_size; }; @@ -39,6 +40,35 @@ enum base_rev { #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) +enum offs_rev { + MIB_RVSR0, + MIB_RVSR1, + MIB_BTSCR5, + MIB_BTSCR6, + MIB_RSCR1, + MIB_RSCR27, + MIB_RSCR28, + MIB_RSCR29, + MIB_RSCR30, + MIB_RSCR31, + MIB_RSCR33, + MIB_RSCR35, + MIB_RSCR36, + MIB_BSCR0, + MIB_BSCR1, + MIB_BSCR2, + MIB_BSCR3, + MIB_BSCR4, + MIB_BSCR5, + MIB_BSCR6, + MIB_BSCR7, + MIB_BSCR17, + MIB_TRDR1, + __MT_OFFS_MAX, +}; + +#define __OFFS(id) (dev->reg.offs_rev[(id)]) + /* RRO TOP */ #define MT_RRO_TOP_BASE 0xA000 #define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) @@ -178,32 +208,32 @@ enum base_rev { #define MT_WF_MIB_BASE(_band) __BASE(WF_MIB_BASE, (_band)) #define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs)) -#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc) -#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0) -#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4) -#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8) -#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc) -#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0) -#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4) -#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8) -#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10) +#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0)) +#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1)) +#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2)) +#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3)) +#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4)) +#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5)) +#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6)) +#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7)) +#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17)) #define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4) #define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8) #define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0) -#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac) +#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1)) /* rx mpdu counter, full 32 bits */ -#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964) -#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c) +#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31)) +#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33)) #define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020) #define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0) -#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720) +#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0)) -#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974) -#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978) +#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35)) +#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36)) /* tx ampdu cnt, full 32 bits */ #define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0) @@ -216,16 +246,16 @@ enum base_rev { #define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0) /* rx ampdu count, 32-bit */ -#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954) +#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27)) /* rx ampdu bytes count, 32-bit */ -#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958) +#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28)) /* rx ampdu valid subframe count */ -#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c) +#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29)) /* rx ampdu valid subframe bytes count, 32bits */ -#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960) +#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30)) /* remaining windows protected stats */ #define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080) @@ -234,18 +264,18 @@ enum base_rev { #define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084) #define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0) -#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724) +#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1)) /* rx blockack count, 32 bits */ #define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4) #define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0) -#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788) -#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798) +#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5)) +#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6)) #define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0) -#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2)) +#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2)) #define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2)) #define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0)) From 2cbbefdc5c9ccf5911b41dca43d2d1533c160f4e Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:16 +0800 Subject: [PATCH 51/62] wifi: mt76: mt7996: support mt7992 eeprom loading Add the default eeprom and 0x7992 check to mt7996_check_eeprom(). This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 14 +++++++++++--- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 9db7e531076d..f876bb1f3ba4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -14,7 +14,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) switch (val) { case 0x7990: - return 0; + return is_mt7996(&dev->mt76) ? 0 : -EINVAL; + case 0x7992: + return is_mt7992(&dev->mt76) ? 0 : -EINVAL; default: return -EINVAL; } @@ -22,8 +24,14 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) static char *mt7996_eeprom_name(struct mt7996_dev *dev) { - /* reserve for future variants */ - return MT7996_EEPROM_DEFAULT; + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + return MT7996_EEPROM_DEFAULT; + case 0x7992: + return MT7992_EEPROM_DEFAULT; + default: + return MT7996_EEPROM_DEFAULT; + } } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 87822663870f..5cdde28ce83f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -39,6 +39,7 @@ #define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin" #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" +#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 From 8df63a4bbe3d89ad24e07f952ccaa8702af937f2 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:17 +0800 Subject: [PATCH 52/62] wifi: mt76: mt7996: adjust interface num and wtbl size for mt7992 MT7992 chipsets support up to 32 interfaces (with maximum 19 per-band) and 512 station entries. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index f876bb1f3ba4..4a8237118287 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -111,7 +111,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP); } - if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4) + if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 || + is_mt7992(&dev->mt76)) dev->wtbl_size_group = 2; /* set default */ return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 5cdde28ce83f..bc73bcb47bf0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -13,6 +13,7 @@ #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_RESERVED (mt7996_wtbl_size(dev) - 1) #define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \ mt7996_max_interface_num(dev)) @@ -512,13 +513,14 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { - return MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + - mt7996_band_valid(dev, MT_BAND2)); + return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + + mt7996_band_valid(dev, MT_BAND2)), + MT7996_WTBL_BMC_SIZE); } static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev) { - return (dev->wtbl_size_group << 8) + 64; + return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE; } void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, From 408566db8cad2788356ccd75e946c236ba381bc2 Mon Sep 17 00:00:00 2001 From: Benjamin Lin Date: Mon, 13 Nov 2023 15:06:18 +0800 Subject: [PATCH 53/62] wifi: mt76: connac: add new definition of tx descriptor Add MT_TXD6_MSDU_CNT_V2 bitfield, which is used by mt7992 chipsets. This is a preliminary patch for mt7992 chipsets support. Signed-off-by: Benjamin Lin Signed-off-by: Shayne Chen Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h | 1 + drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 36edf1d3dfca..ecd7889209f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -245,6 +245,7 @@ enum tx_mgnt_type { #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) +#define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) #define MT_TXD6_DAS BIT(2) #define MT_TXD6_AMSDU_CAP BIT(1) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 1cc573551bdf..ccdec1cc9b2c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -873,8 +873,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD5_TX_STATUS_HOST; txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DIS_MAT | MT_TXD6_DAS | - FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + val = MT_TXD6_DIS_MAT | MT_TXD6_DAS; + if (is_mt7996(&dev->mt76)) + val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + else + val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1); txwi[6] = cpu_to_le32(val); txwi[7] = 0; From 3d3f117a259a65353bf2714a18e25731b3ca5770 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Mon, 13 Nov 2023 15:06:19 +0800 Subject: [PATCH 54/62] wifi: mt76: mt7996: add PCI IDs for mt7992 Add PCI device IDs to enable mt7992 chipsets support. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen 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 baa5fb97a121..a35939cbf3bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -17,11 +17,13 @@ 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) }, { }, }; static const struct pci_device_id mt7996_hif_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) }, { }, }; @@ -60,7 +62,9 @@ static void mt7996_put_hif2(struct mt7996_hif *hif) static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL)) + + if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) && + !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL)) return NULL; writel(hif_idx | MT_PCIE_RECOG_ID_SEM, @@ -113,7 +117,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mt76_pci_disable_aspm(pdev); - if (id->device == 0x7991) + if (id->device == 0x7991 || id->device == 0x799a) return mt7996_pci_hif2_probe(pdev); dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], From 170a8969db8877252e6b6cd6e821a0ddde4b9152 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 13 Nov 2023 11:16:19 +0100 Subject: [PATCH 55/62] wifi: mt76: mt7925: remove iftype from mt7925_init_eht_caps signature Get rid of nl80211_iftype from mt7925_init_eht_caps routine signature since it is not actually used. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 15c2fb0bcb1b..a080df58120f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -154,8 +154,7 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, static void mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, - struct ieee80211_sband_iftype_data *data, - enum nl80211_iftype iftype) + struct ieee80211_sband_iftype_data *data) { struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; @@ -256,7 +255,7 @@ __mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy, data[n].types_mask = BIT(i); mt7925_init_he_caps(phy, band, &data[n], i); - mt7925_init_eht_caps(phy, band, &data[n], i); + mt7925_init_eht_caps(phy, band, &data[n]); n++; } From d079746455700ca1eacc25a4aac0d6323c8130c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 17 Nov 2023 10:31:03 +0100 Subject: [PATCH 56/62] wifi: mt76: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert the three mt76 drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Jeff Johnson Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/soc.c | 7 ++----- drivers/net/wireless/mediatek/mt76/mt7615/soc.c | 6 ++---- drivers/net/wireless/mediatek/mt76/mt7915/soc.c | 6 ++---- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index ba927033bbe8..ec02148a7f1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -52,15 +52,12 @@ error: return ret; } -static int -mt76_wmac_remove(struct platform_device *pdev) +static void mt76_wmac_remove(struct platform_device *pdev) { struct mt76_dev *mdev = platform_get_drvdata(pdev); struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); mt7603_unregister_device(dev); - - return 0; } static const struct of_device_id of_wmac_match[] = { @@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, - .remove = mt76_wmac_remove, + .remove_new = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index f13d1b418742..12e3e4a91d27 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct platform_device *pdev) return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map); } -static int mt7622_wmac_remove(struct platform_device *pdev) +static void mt7622_wmac_remove(struct platform_device *pdev) { struct mt7615_dev *dev = platform_get_drvdata(pdev); mt7615_unregister_device(dev); - - return 0; } static const struct of_device_id mt7622_wmac_of_match[] = { @@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = { .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, - .remove = mt7622_wmac_remove, + .remove_new = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 06e3d9db996c..8b4809703efc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1282,13 +1282,11 @@ free_device: return ret; } -static int mt798x_wmac_remove(struct platform_device *pdev) +static void mt798x_wmac_remove(struct platform_device *pdev) { struct mt7915_dev *dev = platform_get_drvdata(pdev); mt7915_unregister_device(dev); - - return 0; } static const struct of_device_id mt798x_wmac_of_match[] = { @@ -1305,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = { .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, - .remove = mt798x_wmac_remove, + .remove_new = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); From 92184eae1d5ad804884e2c6e289d885b9e3194d1 Mon Sep 17 00:00:00 2001 From: Wang Zhao Date: Fri, 17 Nov 2023 20:54:49 +0800 Subject: [PATCH 57/62] wifi: mt76: mt7921s: fix workqueue problem causes STA association fail The ieee80211_queue_work function queues work into the mac80211 local->workqueue, which is widely used for mac80211 internal work processes. In the mt76 driver, both the mt76-sido-status and mt76-sdio-net threads enqueue workers to the workqueue with this function. However, in some cases, when two workers are enqueued to the workqueue almost simultaneously, the second worker may not be scheduled immediately and may get stuck for a while. This can cause timing issues. To avoid these timing conflicts caused by worker scheduling, replace the worker with an independent thread. Fixes: 48fab5bbef40 ("mt76: mt7921: introduce mt7921s support") Signed-off-by: Wang Zhao Signed-off-by: Deren Wu Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 +-- .../net/wireless/mediatek/mt76/mt7615/sdio.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/sdio.c | 4 +++- .../wireless/mediatek/mt76/mt7921/sdio_mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/sdio.c | 18 +++++++++++------- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b1d3f55d7034..d66864afaf38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -609,8 +609,7 @@ struct mt76_sdio { struct mt76_worker txrx_worker; struct mt76_worker status_worker; struct mt76_worker net_worker; - - struct work_struct stat_work; + struct mt76_worker stat_worker; u8 *xmit_buf; u32 xmit_buf_sz; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c index fc547a0031ea..67cedd2555f9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -204,8 +204,8 @@ static int mt7663s_suspend(struct device *dev) mt76_worker_disable(&mdev->mt76.sdio.txrx_worker); mt76_worker_disable(&mdev->mt76.sdio.status_worker); mt76_worker_disable(&mdev->mt76.sdio.net_worker); + mt76_worker_disable(&mdev->mt76.sdio.stat_worker); - cancel_work_sync(&mdev->mt76.sdio.stat_work); clear_bit(MT76_READING_STATS, &mdev->mphy.state); mt76_tx_status_check(&mdev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index dc1beb76df3e..7591e54d2897 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -228,7 +228,7 @@ static int mt7921s_suspend(struct device *__dev) mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&mdev->tx_worker); mt76_worker_disable(&mdev->sdio.status_worker); - cancel_work_sync(&mdev->sdio.stat_work); + mt76_worker_disable(&mdev->sdio.stat_worker); clear_bit(MT76_READING_STATS, &dev->mphy.state); mt76_tx_status_check(mdev, true); @@ -260,6 +260,7 @@ restore_txrx_worker: restore_worker: mt76_worker_enable(&mdev->tx_worker); mt76_worker_enable(&mdev->sdio.status_worker); + mt76_worker_enable(&mdev->sdio.stat_worker); if (!pm->ds_enable) mt76_connac_mcu_set_deep_sleep(mdev, false); @@ -292,6 +293,7 @@ static int mt7921s_resume(struct device *__dev) mt76_worker_enable(&mdev->sdio.txrx_worker); mt76_worker_enable(&mdev->sdio.status_worker); mt76_worker_enable(&mdev->sdio.net_worker); + mt76_worker_enable(&mdev->sdio.stat_worker); /* restore previous ds setting */ if (!pm->ds_enable) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c index 8edd0291c128..389eb0903807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -107,7 +107,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev) mt76_worker_disable(&dev->mt76.sdio.txrx_worker); mt76_worker_disable(&dev->mt76.sdio.status_worker); mt76_worker_disable(&dev->mt76.sdio.net_worker); - cancel_work_sync(&dev->mt76.sdio.stat_work); + mt76_worker_disable(&dev->mt76.sdio.stat_worker); mt7921s_disable_irq(&dev->mt76); mt7921s_wfsys_reset(dev); @@ -115,6 +115,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev) mt76_worker_enable(&dev->mt76.sdio.txrx_worker); mt76_worker_enable(&dev->mt76.sdio.status_worker); mt76_worker_enable(&dev->mt76.sdio.net_worker); + mt76_worker_enable(&dev->mt76.sdio.stat_worker); dev->fw_assert = false; clear_bit(MT76_MCU_RESET, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 419723118ded..c52d550f0c32 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -481,21 +481,21 @@ static void mt76s_status_worker(struct mt76_worker *w) if (dev->drv->tx_status_data && ndata_frames > 0 && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state) && !test_bit(MT76_STATE_SUSPEND, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &dev->sdio.stat_work); + mt76_worker_schedule(&sdio->stat_worker); } while (nframes > 0); if (resched) mt76_worker_schedule(&dev->tx_worker); } -static void mt76s_tx_status_data(struct work_struct *work) +static void mt76s_tx_status_data(struct mt76_worker *worker) { struct mt76_sdio *sdio; struct mt76_dev *dev; u8 update = 1; u16 count = 0; - sdio = container_of(work, struct mt76_sdio, stat_work); + sdio = container_of(worker, struct mt76_sdio, stat_worker); dev = container_of(sdio, struct mt76_dev, sdio); while (true) { @@ -508,7 +508,7 @@ static void mt76s_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - ieee80211_queue_work(dev->hw, &sdio->stat_work); + mt76_worker_schedule(&sdio->status_worker); else clear_bit(MT76_READING_STATS, &dev->phy.state); } @@ -600,8 +600,8 @@ void mt76s_deinit(struct mt76_dev *dev) mt76_worker_teardown(&sdio->txrx_worker); mt76_worker_teardown(&sdio->status_worker); mt76_worker_teardown(&sdio->net_worker); + mt76_worker_teardown(&sdio->stat_worker); - cancel_work_sync(&sdio->stat_work); clear_bit(MT76_READING_STATS, &dev->phy.state); mt76_tx_status_check(dev, true); @@ -644,10 +644,14 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, if (err) return err; + err = mt76_worker_setup(dev->hw, &sdio->stat_worker, mt76s_tx_status_data, + "sdio-sta"); + if (err) + return err; + sched_set_fifo_low(sdio->status_worker.task); sched_set_fifo_low(sdio->net_worker.task); - - INIT_WORK(&sdio->stat_work, mt76s_tx_status_data); + sched_set_fifo_low(sdio->stat_worker.task); dev->queue_ops = &sdio_queue_ops; dev->bus = bus_ops; From 4920a3a1285f5fd0b4f7c2cbd589903d3fc2824b Mon Sep 17 00:00:00 2001 From: Sujuan Chen Date: Fri, 17 Nov 2023 18:13:19 +0100 Subject: [PATCH 58/62] wifi: mt76: mt7996: set DMA mask to 36 bits for boards with more than 4GB of RAM Introduce the capability to run mt7996 driver on boards with more than 4GB of memory. Co-developed-by: Rex Lu Signed-off-by: Rex Lu Signed-off-by: Sujuan Chen Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 12 +++++++++++- drivers/net/wireless/mediatek/mt76/dma.h | 2 ++ drivers/net/wireless/mediatek/mt76/mmio.c | 7 +++++-- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- .../net/wireless/mediatek/mt76/mt76_connac3_mac.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7996/dma.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 10 +++++++++- drivers/net/wireless/mediatek/mt76/mt7996/mmio.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt7996/pci.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt7996/regs.h | 5 +++-- 10 files changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 439cdfab6f67..8bbb0e17229d 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -232,8 +232,8 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; struct mt76_desc *desc; - u32 buf1 = 0, ctrl; int idx = q->head; + u32 buf1 = 0, ctrl; int rx_token; if (mt76_queue_is_wed_rro_ind(q)) { @@ -246,6 +246,9 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, desc = &q->desc[q->head]; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32); +#endif if (mt76_queue_is_wed_rx(q)) { txwi = mt76_get_rxwi(dev); @@ -312,11 +315,18 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, entry->dma_len[0] = buf[0].len; ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32); +#endif if (i < nbufs - 1) { entry->dma_addr[1] = buf[1].addr; entry->dma_len[1] = buf[1].len; buf1 = buf[1].addr; ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + info |= FIELD_PREP(MT_DMA_CTL_SDP1_H, + buf[1].addr >> 32); +#endif if (buf[1].skip_unmap) entry->skip_buf1 = true; } diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index c60dfb817227..c479cc6388ef 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -19,6 +19,8 @@ #define MT_DMA_CTL_TO_HOST_A BIT(12) #define MT_DMA_CTL_DROP BIT(14) #define MT_DMA_CTL_TOKEN GENMASK(31, 16) +#define MT_DMA_CTL_SDP1_H GENMASK(19, 16) +#define MT_DMA_CTL_SDP0_H GENMASK(3, 0) #define MT_DMA_CTL_WO_DROP BIT(8) #define MT_DMA_PPE_CPU_REASON GENMASK(15, 11) diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 4a006409a373..c3e0e23e0161 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -142,8 +142,11 @@ u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) goto unmap; } - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, - token)); + token = FIELD_PREP(MT_DMA_CTL_TOKEN, token); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32); +#endif + desc->token |= cpu_to_le32(token); desc++; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d66864afaf38..b20c34d5a0f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -183,7 +183,7 @@ struct mt76_queue_entry { struct urb *urb; int buf_sz; }; - u32 dma_addr[2]; + dma_addr_t dma_addr[2]; u16 dma_len[2]; u16 wcid; bool skip_buf0:1; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index ecd7889209f3..83dcd964bfd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -261,6 +261,9 @@ enum tx_mgnt_type { #define MT_TXD9_WLAN_IDX GENMASK(23, 8) +#define MT_TXP_BUF_LEN GENMASK(11, 0) +#define MT_TXP_DMA_ADDR_H GENMASK(15, 12) + #define MT_TX_RATE_STBC BIT(14) #define MT_TX_RATE_NSS GENMASK(13, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 0bc4681fc18a..483ad81b6eec 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -230,7 +230,8 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO); + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + MT_WFDMA0_GLO_CFG_EXT_EN); else mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | @@ -243,7 +244,8 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN | MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 | + MT_WFDMA0_GLO_CFG_EXT_EN); } /* enable interrupts for TX/RX rings */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index ccdec1cc9b2c..53258488d49f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -942,8 +942,16 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); for (i = 0; i < nbuf; i++) { + u16 len; + + len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + len |= FIELD_PREP(MT_TXP_DMA_ADDR_H, + tx_info->buf[i + 1].addr >> 32); +#endif + txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); - txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len); + txp->fw.len[i] = cpu_to_le16(len); } txp->fw.nbuf = nbuf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index b1119f62c946..c50d89a445e9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -287,7 +287,6 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, struct mtk_wed_device *wed = &dev->mt76.mmio.wed; struct pci_dev *pci_dev = pdev_ptr; u32 hif1_ofs = 0; - int ret; if (!wed_enable) return 0; @@ -407,14 +406,6 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, *irq = wed->irq; dev->mt76.dma_dev = wed->dev; - ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - ret = dma_set_coherent_mask(wed->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - return 1; #else return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index a35939cbf3bf..04056181368a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -111,7 +111,11 @@ static int mt7996_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36)); + if (ret) + return ret; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 21637e3aae42..47b429d8bfbe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -405,9 +405,10 @@ enum offs_rev { #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208) #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0) #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2) -#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) -#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) #define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21) +#define MT_WFDMA0_GLO_CFG_EXT_EN BIT(26) +#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27) +#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28) #define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268) #define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c) From 4812ba9ab9408f3aa5bcbb4ff80ddca84611ea17 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 22 Nov 2023 06:27:22 +0800 Subject: [PATCH 59/62] wifi: mt76: mt7921: reduce the size of MCU firmware download Rx queue We actually don't need the reserve the 512 entries for the MCU firmware download Rx queue because the queue was only used in the firmware download phase to save the most of space and the reduction can significantly help with reducing latency we spent by ~20% further in resetting the Rx queue as the device was waking up from deep sleep mode. Signed-off-by: Sean Wang Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index f28621121927..fcca93b3e14c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -12,7 +12,8 @@ #define MT7921_TX_FWDL_RING_SIZE 128 #define MT7921_RX_RING_SIZE 1536 -#define MT7921_RX_MCU_RING_SIZE 512 +#define MT7921_RX_MCU_RING_SIZE 8 +#define MT7921_RX_MCU_WA_RING_SIZE 512 #define MT7921_EEPROM_SIZE 3584 #define MT7921_TOKEN_SIZE 8192 diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 6f83c4c5fce2..9bdaddd310be 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -200,7 +200,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* Change mcu queue after firmware download */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], MT7921_RXQ_MCU_WM, - MT7921_RX_MCU_RING_SIZE, + MT7921_RX_MCU_WA_RING_SIZE, MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); if (ret) return ret; From fa6ad88e023ddfa6c5dcdb466d159e89f451e305 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Wed, 22 Nov 2023 11:06:44 +0800 Subject: [PATCH 60/62] wifi: mt76: mt7921: fix country count limitation for CLC Due to the increase in the number of power tables for 6Ghz on CLC, the variable nr_country is no longer sufficient to represent the total quantity. Therefore, we have switched to calculating the length of clc buf to obtain the correct power table. Additionally, the version number has been incremented to 1. Fixes: 23bdc5d8cadf ("wifi: mt76: mt7921: introduce Country Location Control support") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index a9056b55b0a4..5fcee178b698 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1263,6 +1263,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u8 mtcl_conf; u8 rsvd[62]; } __packed req = { + .ver = 1, .idx = idx, .env = env_cap, .env_6g = dev->phy.power_type, @@ -1270,7 +1271,8 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; int ret, valid_cnt = 0; - u8 i, *pos; + u16 buf_len = 0; + u8 *pos; if (!clc) return 0; @@ -1280,12 +1282,15 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, if (mt76_find_power_limits_node(&dev->mt76)) req.cap |= CLC_CAP_DTS_EN; + buf_len = le16_to_cpu(clc->len) - sizeof(*clc); pos = clc->data; - for (i = 0; i < clc->nr_country; i++) { + while (buf_len > 16) { struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos; u16 len = le16_to_cpu(rule->len); + u16 offset = len + sizeof(*rule); - pos += len + sizeof(*rule); + pos += offset; + buf_len -= offset; if (rule->alpha2[0] != alpha2[0] || rule->alpha2[1] != alpha2[1]) continue; From d0a2bc5fe712217d2c73822ae75fd4e69a15cb2c Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Wed, 22 Nov 2023 11:06:45 +0800 Subject: [PATCH 61/62] wifi: mt76: mt7921: fix CLC command timeout when suspend/resume When enter suspend/resume while in a connected state, the upper layer will trigger disconnection before entering suspend, and at the same time, it will trigger regd_notifier() and update CLC, causing the CLC event to not be received due to suspend, resulting in a command timeout. Therefore, the update of CLC is postponed until resume, to ensure data consistency and avoid the occurrence of command timeout. Fixes: 4fc8df50fd41 ("wifi: mt76: mt7921: get regulatory information from the clc event") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/init.c | 25 ++++++++++++++----- .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 + .../net/wireless/mediatek/mt76/mt7921/pci.c | 3 +++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 7d6a9d746011..48433c6d5e7d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -110,24 +110,37 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) } } +void mt7921_regd_update(struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_hw *hw = mdev->hw; + struct wiphy *wiphy = hw->wiphy; + + mt7921_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env); + mt7921_regd_channel_update(wiphy, dev); + mt76_connac_mcu_set_channel_domain(hw->priv); + mt7921_set_tx_sar_pwr(hw, NULL); +} +EXPORT_SYMBOL_GPL(mt7921_regd_update); + static void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_connac_pm *pm = &dev->pm; memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); dev->mt76.region = request->dfs_region; dev->country_ie_env = request->country_ie_env; - mt792x_mutex_acquire(dev); - mt7921_mcu_set_clc(dev, request->alpha2, request->country_ie_env); - mt76_connac_mcu_set_channel_domain(hw->priv); - mt7921_set_tx_sar_pwr(hw, NULL); - mt792x_mutex_release(dev); + if (pm->suspended) + return; - mt7921_regd_channel_update(wiphy, dev); + mt792x_mutex_acquire(dev); + mt7921_regd_update(dev); + mt792x_mutex_release(dev); } int mt7921_mac_init(struct mt792x_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index fcca93b3e14c..1cb21133992b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -234,6 +234,7 @@ mt7921_l1_rmw(struct mt792x_dev *dev, u32 addr, u32 mask, u32 val) #define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val) #define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0) +void mt7921_regd_update(struct mt792x_dev *dev); int mt7921_mac_init(struct mt792x_dev *dev); bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask); int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 9bdaddd310be..57903c6e4f11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -507,6 +507,9 @@ static int mt7921_pci_resume(struct device *device) mt76_connac_mcu_set_deep_sleep(&dev->mt76, false); err = mt76_connac_mcu_set_hif_suspend(mdev, false); + + mt7921_regd_update(dev); + failed: pm->suspended = false; From 10f2903147ed04784522ab841c20bb469bdd8681 Mon Sep 17 00:00:00 2001 From: Ming Yen Hsieh Date: Wed, 22 Nov 2023 11:06:46 +0800 Subject: [PATCH 62/62] wifi: mt76: mt7921: fix wrong 6Ghz power type To avoid using incorrect 6g power settings after disconnection, it should to update back to the default state when disconnected. Fixes: 51ba0e3a15eb ("wifi: mt76: mt7921: add 6GHz power type support for clc") Signed-off-by: Ming Yen Hsieh Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7921/main.c | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 510a575a973b..0645417e0582 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -683,17 +683,45 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, } static void -mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif) +mt7921_calc_vif_num(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + u32 *num = priv; + + if (!priv) + return; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + *num += 1; + break; + default: + break; + } +} + +static void +mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_phy *phy = mvif->phy; struct mt792x_dev *dev = phy->dev; + u32 valid_vif_num = 0; - if (hweight64(dev->mt76.vif_mask) > 1) { + ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_calc_vif_num, &valid_vif_num); + + if (valid_vif_num > 1) { phy->power_type = MT_AP_DEFAULT; goto out; } + if (!is_add) + vif->bss_conf.power_type = IEEE80211_REG_UNSET_AP; + switch (vif->bss_conf.power_type) { case IEEE80211_REG_SP_AP: phy->power_type = MT_AP_SP; @@ -705,6 +733,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif) phy->power_type = MT_AP_LPI; break; case IEEE80211_REG_UNSET_AP: + phy->power_type = MT_AP_UNSET; + break; default: phy->power_type = MT_AP_DEFAULT; break; @@ -749,7 +779,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (ret) return ret; - mt7921_regd_set_6ghz_power_type(vif); + mt7921_regd_set_6ghz_power_type(vif, true); mt76_connac_power_save_sched(&dev->mphy, &dev->pm); @@ -811,6 +841,8 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, list_del_init(&msta->wcid.poll_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); + mt7921_regd_set_6ghz_power_type(vif, false); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);