From 413859e909a425a04a221240e1066e48cd2220a2 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 26 Dec 2024 01:13:54 +0000 Subject: [PATCH 01/16] wifi: iwlegacy: Remove unused il3945_calc_db_from_ratio() The last use of il3945_calc_db_from_ratio() was removed in 2010 by commit ed1b6e99b5e6 ("iwlwifi: remove noise reporting") when it was still called iwl3945_calc_db_from_ratio(). Remove it. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241226011355.135417-2-linux@treblig.org --- .../net/wireless/intel/iwlegacy/3945-mac.c | 38 ------------------- drivers/net/wireless/intel/iwlegacy/3945.h | 1 - 2 files changed, 39 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 74fc76c00ebc..4013443698a2 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -1127,44 +1127,6 @@ il3945_rx_queue_free(struct il_priv *il, struct il_rx_queue *rxq) rxq->rb_stts = NULL; } -/* Convert linear signal-to-noise ratio into dB */ -static u8 ratio2dB[100] = { -/* 0 1 2 3 4 5 6 7 8 9 */ - 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */ - 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */ - 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */ - 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */ - 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */ - 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */ - 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */ - 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */ - 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */ - 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */ -}; - -/* Calculates a relative dB value from a ratio of linear - * (i.e. not dB) signal levels. - * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int -il3945_calc_db_from_ratio(int sig_ratio) -{ - /* 1000:1 or higher just report as 60 dB */ - if (sig_ratio >= 1000) - return 60; - - /* 100:1 or higher, divide by 10 and use table, - * add 20 dB to make up for divide by 10 */ - if (sig_ratio >= 100) - return 20 + (int)ratio2dB[sig_ratio / 10]; - - /* We shouldn't see this */ - if (sig_ratio < 1) - return 0; - - /* Use table for ratios 1:1 - 99:1 */ - return (int)ratio2dB[sig_ratio]; -} - /* * il3945_rx_handle - Main entry function for receiving responses from uCode * diff --git a/drivers/net/wireless/intel/iwlegacy/3945.h b/drivers/net/wireless/intel/iwlegacy/3945.h index ffbe11902628..fb1e33c89d0e 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.h +++ b/drivers/net/wireless/intel/iwlegacy/3945.h @@ -173,7 +173,6 @@ struct il3945_ibss_seq { * for use by iwl-*.c * *****************************************************************************/ -int il3945_calc_db_from_ratio(int sig_ratio); void il3945_rx_replenish(void *data); void il3945_rx_queue_reset(struct il_priv *il, struct il_rx_queue *rxq); unsigned int il3945_fill_beacon_frame(struct il_priv *il, -- 2.51.0 From 83ed80dd25f6ed8db5d0751a9a49a22d1bc9a8bc Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 26 Dec 2024 01:13:55 +0000 Subject: [PATCH 02/16] wifi: iwlegacy: Remove unused il_get_single_channel_number() THe last use of il_get_single_channel_number() was removed in 2011 by commit dd6d2a8aef69 ("iwlegacy: remove reset rf infrastructure") when it was still called iwl_legacy_get_single_channel_number. Remove it. Signed-off-by: Dr. David Alan Gilbert Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20241226011355.135417-3-linux@treblig.org --- drivers/net/wireless/intel/iwlegacy/common.c | 31 -------------------- drivers/net/wireless/intel/iwlegacy/common.h | 1 - 2 files changed, 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 958dd4f9bc69..af4f42534ea0 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -3915,37 +3915,6 @@ il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf) } EXPORT_SYMBOL(il_set_rxon_ht); -/* Return valid, unused, channel for a passive scan to reset the RF */ -u8 -il_get_single_channel_number(struct il_priv *il, enum nl80211_band band) -{ - const struct il_channel_info *ch_info; - int i; - u8 channel = 0; - u8 min, max; - - if (band == NL80211_BAND_5GHZ) { - min = 14; - max = il->channel_count; - } else { - min = 0; - max = 14; - } - - for (i = min; i < max; i++) { - channel = il->channel_info[i].channel; - if (channel == le16_to_cpu(il->staging.channel)) - continue; - - ch_info = il_get_channel_info(il, band, channel); - if (il_is_channel_valid(ch_info)) - break; - } - - return channel; -} -EXPORT_SYMBOL(il_get_single_channel_number); - /* * il_set_rxon_channel - Set the band and channel values in staging RXON * @ch: requested channel as a pointer to struct ieee80211_channel diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 725c2a88ddb7..92285412ab10 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -1705,7 +1705,6 @@ int il_full_rxon_required(struct il_priv *il); int il_set_rxon_channel(struct il_priv *il, struct ieee80211_channel *ch); void il_set_flags_for_band(struct il_priv *il, enum nl80211_band band, struct ieee80211_vif *vif); -u8 il_get_single_channel_number(struct il_priv *il, enum nl80211_band band); void il_set_rxon_ht(struct il_priv *il, struct il_ht_config *ht_conf); bool il_is_ht40_tx_allowed(struct il_priv *il, struct ieee80211_sta_ht_cap *ht_cap); -- 2.51.0 From 8221712a174ad83e36489c414c26619010f4e348 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 6 Jan 2025 12:34:02 -0800 Subject: [PATCH 03/16] wifi: brcmfmac: Add missing Return: to function documentation Running 'scripts/kernel-doc -Wall -Werror -none' flagged the following kernel-doc issues: drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:823: warning: No description found for return value of 'brcmf_apsta_add_vif' drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:907: warning: No description found for return value of 'brcmf_mon_add_vif' drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:7419: warning: No description found for return value of 'brcmf_setup_ifmodes' Add the missing 'Return:' tags to the kernel-doc of these functions. Signed-off-by: Jeff Johnson Signed-off-by: Kalle Valo Link: https://patch.msgid.link/20250106-brcmfmac-kdoc-v1-1-ed72196e21a1@oss.qualcomm.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 902ac3108782..4b70845e1a26 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -814,6 +814,8 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) * @name: name of the new interface. * @params: contains mac address for AP or STA device. * @type: interface type. + * + * Return: pointer to new vif on success, ERR_PTR(-errno) if not */ static struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name, @@ -900,6 +902,8 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) * * @wiphy: wiphy device of new interface. * @name: name of the new interface. + * + * Return: pointer to new vif on success, ERR_PTR(-errno) if not */ static struct wireless_dev *brcmf_mon_add_vif(struct wiphy *wiphy, const char *name) @@ -7412,6 +7416,8 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { * p2p, rsdb, and no mbss: * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2, * channels = 2, 4 total + * + * Return: 0 on success, negative errno on failure */ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) { -- 2.51.0 From 0da2e410705e87c75d0f96d73c4a563746cc2709 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 26 Sep 2024 11:24:38 +0800 Subject: [PATCH 04/16] wifi: mt76: mt7996: extend flexibility of mt7996_mcu_get_eeprom() Support passing customized buffer pointer and length to mt7996_mcu_get_eeprom(). This is the preparation for adding more variants support which needs to prefetch FEM module from efuse, and also fixes potential OOB issue when reading the last efuse block. Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Tested-by: Daniel Golle Link: https://patch.msgid.link/20240926032440.15978-1-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c | 9 +++++++-- drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 14 ++++++++++---- drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 4a8237118287..861aba68a725 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -86,8 +86,13 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) /* read eeprom data from efuse */ block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); for (i = 0; i < block_num; i++) { - ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size); - if (ret < 0) + u32 len = eeprom_blk_size; + + if (i == block_num - 1) + len = MT7996_EEPROM_SIZE % eeprom_blk_size; + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, + NULL, len); + if (ret && ret != -EINVAL) return ret; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 6c445a9dbc03..bfa0f1002029 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -3548,7 +3548,7 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) &req, sizeof(req), true); } -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len) { struct { u8 _rsv[4]; @@ -3577,15 +3577,21 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset) valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); if (valid) { u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); - u8 *buf = (u8 *)dev->mt76.eeprom.data + addr; + + if (!buf) + buf = (u8 *)dev->mt76.eeprom.data + addr; + if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EEPROM_BLOCK_SIZE; skb_pull(skb, 48); - memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE); + memcpy(buf, skb->data, buf_len); + } else { + ret = -EINVAL; } dev_kfree_skb(skb); - return 0; + return ret; } int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index ab8c9070630b..55aa5f6ab77d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -476,7 +476,7 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, 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(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len); int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); -- 2.51.0 From e8cb33ad546a908f6c6a7c382b0fdf1a0c743af6 Mon Sep 17 00:00:00 2001 From: Shayne Chen Date: Thu, 26 Sep 2024 11:24:39 +0800 Subject: [PATCH 05/16] wifi: mt76: mt7996: add support for more variants Current varaints supported: - mt7996 chipset: tri-band, 4+4+4 NSS, eFEM - mt7992 chipset: dual-band, 4+4 NSS, eFEM This patch adds support for the following variants: - mt7996 chipset: - tri-band, 4+4+4 NSS, iFEM - tri-band, 2+3+3 NSS, eFEM - tri-band, 2+3+3 NSS, iFEM - mt7992 chipset: - dual-band, 4+4 NSS, iFEM - dual-band, 4+4 NSS, with band0 iFEM and band1 eFEM - dual-band, 2+3 NSS, eFEM - dual-band, 2+3 NSS, iFEM Co-developed-by: StanleyYP Wang Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Tested-by: Daniel Golle Link: https://patch.msgid.link/20240926032440.15978-2-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../wireless/mediatek/mt76/mt7996/eeprom.c | 206 +++++++++++++----- .../wireless/mediatek/mt76/mt7996/eeprom.h | 2 + .../net/wireless/mediatek/mt76/mt7996/init.c | 78 +++++++ .../net/wireless/mediatek/mt76/mt7996/mcu.c | 16 +- .../wireless/mediatek/mt76/mt7996/mt7996.h | 46 +++- .../net/wireless/mediatek/mt76/mt7996/regs.h | 9 + 6 files changed, 289 insertions(+), 68 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 861aba68a725..da94751df020 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -25,17 +25,108 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev) static char *mt7996_eeprom_name(struct mt7996_dev *dev) { switch (mt76_chip(&dev->mt76)) { - case 0x7990: - return MT7996_EEPROM_DEFAULT; case 0x7992: - return MT7992_EEPROM_DEFAULT; + switch (dev->var.type) { + case MT7992_VAR_TYPE_23: + if (dev->var.fem == MT7996_FEM_INT) + return MT7992_EEPROM_DEFAULT_23_INT; + return MT7992_EEPROM_DEFAULT_23; + case MT7992_VAR_TYPE_44: + default: + if (dev->var.fem == MT7996_FEM_INT) + return MT7992_EEPROM_DEFAULT_INT; + if (dev->var.fem == MT7996_FEM_MIX) + return MT7992_EEPROM_DEFAULT_MIX; + return MT7992_EEPROM_DEFAULT; + } + case 0x7990: + default: + switch (dev->var.type) { + case MT7996_VAR_TYPE_233: + if (dev->var.fem == MT7996_FEM_INT) + return MT7996_EEPROM_DEFAULT_233_INT; + return MT7996_EEPROM_DEFAULT_233; + case MT7996_VAR_TYPE_444: + default: + if (dev->var.fem == MT7996_FEM_INT) + return MT7996_EEPROM_DEFAULT_INT; + return MT7996_EEPROM_DEFAULT; + } + } +} + +static void +mt7996_eeprom_parse_stream(const u8 *eeprom, u8 band_idx, u8 *path, + u8 *rx_path, u8 *nss) +{ + 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: - return MT7996_EEPROM_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; } } +static bool mt7996_eeprom_variant_valid(struct mt7996_dev *dev, const u8 *def) +{ +#define FEM_INT 0 +#define FEM_EXT 3 + u8 *eeprom = dev->mt76.eeprom.data, fem[2]; + int i; + + for (i = 0; i < 2; i++) + fem[i] = u8_get_bits(eeprom[MT_EE_WIFI_CONF + 6 + i], + MT_EE_WIFI_PA_LNA_CONFIG); + + if (dev->var.fem == MT7996_FEM_EXT && + !(fem[0] == FEM_EXT && fem[1] == FEM_EXT)) + return false; + else if (dev->var.fem == MT7996_FEM_INT && + !(fem[0] == FEM_INT && fem[1] == FEM_INT)) + return false; + else if (dev->var.fem == MT7996_FEM_MIX && + !(fem[0] == FEM_INT && fem[1] == FEM_EXT)) + return false; + + for (i = 0; i < __MT_MAX_BAND; i++) { + u8 path, rx_path, nss; + u8 def_path, def_rx_path, def_nss; + + if (!dev->mt76.phys[i]) + continue; + + mt7996_eeprom_parse_stream(eeprom, i, &path, &rx_path, &nss); + mt7996_eeprom_parse_stream(def, i, &def_path, &def_rx_path, + &def_nss); + if (path > def_path || rx_path > def_rx_path || nss > def_nss) + return false; + } + + return true; +} + static int -mt7996_eeprom_load_default(struct mt7996_dev *dev) +mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) { u8 *eeprom = dev->mt76.eeprom.data; const struct firmware *fw = NULL; @@ -51,6 +142,10 @@ mt7996_eeprom_load_default(struct mt7996_dev *dev) goto out; } + if (!use_default && mt7996_eeprom_variant_valid(dev, fw->data)) + goto out; + + dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); dev->flash_mode = true; @@ -62,48 +157,68 @@ out: static int mt7996_eeprom_load(struct mt7996_dev *dev) { + bool use_default = false; int ret; ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); if (ret < 0) return ret; - if (ret) { + if (ret && !mt7996_check_eeprom(dev)) { dev->flash_mode = true; - } else { - u8 free_block_num; - u32 block_num, i; + goto out; + } + + if (!dev->flash_mode) { u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; + u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + u8 free_block_num; + int i; + memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); if (ret < 0) return ret; /* efuse info isn't enough */ - if (free_block_num >= 59) - return -EINVAL; + if (free_block_num >= 59) { + use_default = true; + goto out; + } + + /* check if eeprom data from fw is valid */ + if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || + mt7996_check_eeprom(dev)) { + use_default = true; + goto out; + } - /* read eeprom data from efuse */ - block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); - for (i = 0; i < block_num; i++) { + /* read eeprom data from fw */ + for (i = 1; i < block_num; i++) { u32 len = eeprom_blk_size; if (i == block_num - 1) len = MT7996_EEPROM_SIZE % eeprom_blk_size; ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL, len); - if (ret && ret != -EINVAL) - return ret; + if (ret && ret != -EINVAL) { + use_default = true; + goto out; + } } } - return mt7996_check_eeprom(dev); +out: + return mt7996_eeprom_check_or_use_default(dev, use_default); } -static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) +static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_phy *phy, + u8 *path, u8 *rx_path, u8 *nss) { #define MODE_HE_ONLY BIT(0) #define WTBL_SIZE_GROUP GENMASK(31, 28) +#define STREAM_CAP(_offs) ((cap & (0x7 << (_offs))) >> (_offs)) + struct mt7996_dev *dev = phy->dev; u32 cap = 0; int ret; @@ -112,13 +227,17 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev) return ret; if (cap) { + u8 band_offs = phy->mt76->band_idx * 3; + dev->has_eht = !(cap & MODE_HE_ONLY); dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP); + *nss = min_t(u8, *nss, STREAM_CAP(1 + band_offs)); + *path = min_t(u8, *path, STREAM_CAP(10 + band_offs)); + *rx_path = min_t(u8, *rx_path, STREAM_CAP(19 + band_offs)); } - if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 || - is_mt7992(&dev->mt76)) - dev->wtbl_size_group = 2; /* set default */ + if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4) + dev->wtbl_size_group = is_mt7996(&dev->mt76) ? 4 : 2; return 0; } @@ -168,32 +287,10 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) 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; - } + mt7996_eeprom_parse_stream(eeprom, band_idx, &path, &rx_path, &nss); + ret = mt7996_eeprom_parse_efuse_hw_cap(phy, &path, &rx_path, &nss); + if (ret) + return ret; if (!path || path > max_path) path = max_path; @@ -213,10 +310,6 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy) dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] + hweight16(mphy->chainmask); - ret = mt7996_eeprom_parse_efuse_hw_cap(dev); - if (ret) - return ret; - return mt7996_eeprom_parse_band_config(phy); } @@ -225,15 +318,8 @@ int mt7996_eeprom_init(struct mt7996_dev *dev) int ret; ret = mt7996_eeprom_load(dev); - if (ret < 0) { - if (ret != -EINVAL) - return ret; - - dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); - ret = mt7996_eeprom_load_default(dev); - if (ret) - return ret; - } + if (ret < 0) + return ret; ret = mt7996_eeprom_parse_hw_cap(dev, &dev->phy); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h index 412d6e2f8014..7a771ca2434c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h @@ -40,6 +40,8 @@ enum mt7996_eeprom_field { #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0) #define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3) +#define MT_EE_WIFI_PA_LNA_CONFIG GENMASK(1, 0) + #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0) #define MT_EE_RATE_DELTA_SIGN BIT(6) #define MT_EE_RATE_DELTA_EN BIT(7) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index efa7b0697a40..3c1d3f251dfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -881,6 +881,76 @@ out: #endif } +static int mt7996_variant_type_init(struct mt7996_dev *dev) +{ + u32 val = mt76_rr(dev, MT_PAD_GPIO); + u8 var_type; + + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + if (val & MT_PAD_GPIO_2ADIE_TBTC) + var_type = MT7996_VAR_TYPE_233; + else + var_type = MT7996_VAR_TYPE_444; + break; + case 0x7992: + if (val & MT_PAD_GPIO_ADIE_SINGLE) + var_type = MT7992_VAR_TYPE_23; + else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) + var_type = MT7992_VAR_TYPE_44; + else + return -EINVAL; + break; + default: + return -EINVAL; + } + + dev->var.type = var_type; + return 0; +} + +static int mt7996_variant_fem_init(struct mt7996_dev *dev) +{ +#define MT7976C_EFUSE_OFFSET 0x470 + u8 buf[MT7996_EEPROM_BLOCK_SIZE], idx, adie_idx, adie_comb; + u32 regval, val = mt76_rr(dev, MT_PAD_GPIO); + u16 adie_id, adie_ver; + bool is_7976c; + int ret; + + if (is_mt7992(&dev->mt76)) { + adie_idx = (val & MT_PAD_GPIO_ADIE_SINGLE) ? 0 : 1; + adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992); + } else { + adie_idx = 0; + adie_comb = u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB); + } + + ret = mt7996_mcu_rf_regval(dev, MT_ADIE_CHIP_ID(adie_idx), ®val, false); + if (ret) + return ret; + + ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf)); + if (ret && ret != -EINVAL) + return ret; + + adie_ver = u32_get_bits(regval, MT_ADIE_VERSION_MASK); + idx = MT7976C_EFUSE_OFFSET % MT7996_EEPROM_BLOCK_SIZE; + is_7976c = adie_ver == 0x8a10 || adie_ver == 0x8b00 || + adie_ver == 0x8c10 || buf[idx] == 0xc; + + adie_id = u32_get_bits(regval, MT_ADIE_CHIP_ID_MASK); + if (adie_id == 0x7975 || adie_id == 0x7979 || + (adie_id == 0x7976 && is_7976c)) + dev->var.fem = MT7996_FEM_INT; + else if (adie_id == 0x7977 && adie_comb == 1) + dev->var.fem = MT7996_FEM_MIX; + else + dev->var.fem = MT7996_FEM_EXT; + + return 0; +} + static int mt7996_init_hardware(struct mt7996_dev *dev) { int ret, idx; @@ -896,6 +966,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) INIT_LIST_HEAD(&dev->wed_rro.poll_list); spin_lock_init(&dev->wed_rro.lock); + ret = mt7996_variant_type_init(dev); + if (ret) + return ret; + ret = mt7996_dma_init(dev); if (ret) return ret; @@ -910,6 +984,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) if (ret) return ret; + ret = mt7996_variant_fem_init(dev); + if (ret) + return ret; + ret = mt7996_eeprom_init(dev); if (ret < 0) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index bfa0f1002029..29b6e0565868 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -14,11 +14,23 @@ char *_fw; \ switch (mt76_chip(&(_dev)->mt76)) { \ case 0x7992: \ - _fw = MT7992_##name; \ + switch ((_dev)->var.type) { \ + case MT7992_VAR_TYPE_23: \ + _fw = MT7992_##name##_23; \ + break; \ + default: \ + _fw = MT7992_##name; \ + } \ break; \ case 0x7990: \ default: \ - _fw = MT7996_##name; \ + switch ((_dev)->var.type) { \ + case MT7996_VAR_TYPE_233: \ + _fw = MT7996_##name##_233; \ + break; \ + default: \ + _fw = MT7996_##name; \ + } \ break; \ } \ _fw; \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 55aa5f6ab77d..3f3278f43c79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -34,13 +34,32 @@ #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin" #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin" +#define MT7996_FIRMWARE_WA_233 "mediatek/mt7996/mt7996_wa_233.bin" +#define MT7996_FIRMWARE_WM_233 "mediatek/mt7996/mt7996_wm_233.bin" +#define MT7996_FIRMWARE_DSP_233 MT7996_FIRMWARE_DSP +#define MT7996_ROM_PATCH_233 "mediatek/mt7996/mt7996_rom_patch_233.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 MT7992_FIRMWARE_WA_23 "mediatek/mt7996/mt7992_wa_23.bin" +#define MT7992_FIRMWARE_WM_23 "mediatek/mt7996/mt7992_wm_23.bin" +#define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" +#define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" + #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin" +#define MT7996_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7996_eeprom_2i5i6i.bin" +#define MT7996_EEPROM_DEFAULT_233 "mediatek/mt7996/mt7996_eeprom_233.bin" +#define MT7996_EEPROM_DEFAULT_233_INT "mediatek/mt7996/mt7996_eeprom_233_2i5i6i.bin" + #define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin" +#define MT7992_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7992_eeprom_2i5i.bin" +#define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" +#define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" +#define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" + #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 #define MT7996_TOKEN_SIZE 16384 @@ -95,6 +114,22 @@ enum mt7996_ram_type { MT7996_RAM_TYPE_DSP, }; +enum mt7996_var_type { + MT7996_VAR_TYPE_444, + MT7996_VAR_TYPE_233, +}; + +enum mt7992_var_type { + MT7992_VAR_TYPE_44, + MT7992_VAR_TYPE_23, +}; + +enum mt7996_fem_type { + MT7996_FEM_EXT, + MT7996_FEM_INT, + MT7996_FEM_MIX, +}; + enum mt7996_txq_id { MT7996_TXQ_FWDL = 16, MT7996_TXQ_MCU_WM, @@ -329,6 +364,10 @@ struct mt7996_dev { spinlock_t reg_lock; u8 wtbl_size_group; + struct { + u8 type:4; + u8 fem:4; + } var; }; enum { @@ -405,12 +444,7 @@ 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) - return true; - - return band == MT_BAND0 || band == MT_BAND2; + return band <= MT_BAND2; } extern const struct ieee80211_ops mt7996_ops; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 47b429d8bfbe..06e307b5b02e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -660,8 +660,17 @@ enum offs_rev { #define MT_TOP_MISC MT_TOP(0xf0) #define MT_TOP_MISC_FW_STATE GENMASK(2, 0) +/* ADIE */ +#define MT_ADIE_CHIP_ID(_idx) (0x0f00002c + ((_idx) << 28)) +#define MT_ADIE_VERSION_MASK GENMASK(15, 0) +#define MT_ADIE_CHIP_ID_MASK GENMASK(31, 16) + #define MT_PAD_GPIO 0x700056f0 #define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15) +#define MT_PAD_GPIO_2ADIE_TBTC BIT(19) +/* for mt7992 */ +#define MT_PAD_GPIO_ADIE_COMB_7992 GENMASK(17, 16) +#define MT_PAD_GPIO_ADIE_SINGLE BIT(15) #define MT_HW_REV 0x70010204 #define MT_HW_REV1 0x8a00 -- 2.51.0 From 569dd75b71471e63caf4a0302e042f9c2dafe970 Mon Sep 17 00:00:00 2001 From: StanleyYP Wang Date: Thu, 26 Sep 2024 11:24:40 +0800 Subject: [PATCH 06/16] wifi: mt76: mt7996: set correct background radar capability Some of the variants do not support background radar, so add a helper to report background radar capability. Signed-off-by: StanleyYP Wang Signed-off-by: Shayne Chen Tested-by: Daniel Golle Link: https://patch.msgid.link/20240926032440.15978-3-shayne.chen@mediatek.com Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7996/init.c | 7 ++++--- .../wireless/mediatek/mt76/mt7996/mt7996.h | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 3c1d3f251dfb..2d36c7325137 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -387,9 +387,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); - if (!mdev->dev->of_node || - !of_property_read_bool(mdev->dev->of_node, - "mediatek,disable-radar-background")) + if (mt7996_has_background_radar(phy->dev) && + (!mdev->dev->of_node || + !of_property_read_bool(mdev->dev->of_node, + "mediatek,disable-radar-background"))) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RADAR_BACKGROUND); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 3f3278f43c79..9aec97dd81d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -447,6 +447,25 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band) return band <= MT_BAND2; } +static inline bool +mt7996_has_background_radar(struct mt7996_dev *dev) +{ + switch (mt76_chip(&dev->mt76)) { + case 0x7990: + if (dev->var.type == MT7996_VAR_TYPE_233) + return false; + break; + case 0x7992: + if (dev->var.type == MT7992_VAR_TYPE_23) + return false; + break; + default: + return false; + } + + return true; +} + extern const struct ieee80211_ops mt7996_ops; extern struct pci_driver mt7996_pci_driver; extern struct pci_driver mt7996_hif_driver; -- 2.51.0 From 5a569e90162a37364f22d9f0ff9d2added7b3ee5 Mon Sep 17 00:00:00 2001 From: Hao Zhang Date: Thu, 19 Sep 2024 16:17:13 +0800 Subject: [PATCH 07/16] wifi: mt76: mt792x: add P2P_DEVICE support Regist the NL80211_IFTYPE_P2P_DEVICE to support p2p device for mt792x chips Signed-off-by: Hao Zhang Signed-off-by: allan.wang Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20240919081713.23787-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt792x_core.c | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 864246f94088..77f3e92d581a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1202,6 +1202,9 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, case NL80211_IFTYPE_STATION: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA); break; + case NL80211_IFTYPE_P2P_DEVICE: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_P2P_GO); + break; case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); break; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 78fe37c2e07b..042aa8d1b6e7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -38,6 +38,10 @@ static const struct ieee80211_iface_limit if_limits_chanctx[] = { .max = 1, .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE) } }; @@ -45,7 +49,7 @@ static const struct ieee80211_iface_combination if_comb_chanctx[] = { { .limits = if_limits_chanctx, .n_limits = ARRAY_SIZE(if_limits_chanctx), - .max_interfaces = 2, + .max_interfaces = 3, .num_different_channels = 2, .beacon_int_infra_match = false, } @@ -614,7 +618,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_DEVICE); wiphy->max_remain_on_channel_duration = 5000; wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; -- 2.51.0 From fbce6136da0a40f62ea22361e7d13f6a502c20ad Mon Sep 17 00:00:00 2001 From: Leon Yen Date: Mon, 16 Sep 2024 14:01:57 +0800 Subject: [PATCH 08/16] wifi: mt76: mt7921s: fix a potential firmware freeze during startup The maximum command quota of the firmware may be exceeded because the command to retrieve the quota setting has not been taken into account. This patch considers not only the quota usage of the command retrieving quota settings but also limits the total quota usage. Signed-off-by: Leon Yen Signed-off-by: Ming Yen Hsieh Link: https://patch.msgid.link/20240916060157.10157-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 5 ++++- drivers/net/wireless/mediatek/mt76/sdio_txrx.c | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ca2dba3ac65d..599123967af6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -636,6 +636,7 @@ struct mt76_sdio { u8 hw_ver; wait_queue_head_t wait; + int pse_mcu_quota_max; struct { int pse_data_quota; int ple_data_quota; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 02c1de8620a7..ddc5986086d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -507,7 +507,10 @@ static void mt7921_mcu_parse_tx_resource(struct mt76_dev *dev, tx_res = (struct mt7921_tx_resource *)skb->data; sdio->sched.pse_data_quota = le32_to_cpu(tx_res->pse_data_quota); - sdio->sched.pse_mcu_quota = le32_to_cpu(tx_res->pse_mcu_quota); + sdio->pse_mcu_quota_max = le32_to_cpu(tx_res->pse_mcu_quota); + /* The mcu quota usage of this function itself must be taken into consideration */ + sdio->sched.pse_mcu_quota = + sdio->sched.pse_mcu_quota ? sdio->pse_mcu_quota_max : sdio->pse_mcu_quota_max - 1; sdio->sched.ple_data_quota = le32_to_cpu(tx_res->ple_data_quota); sdio->sched.pse_page_size = le16_to_cpu(tx_res->pse_page_size); sdio->sched.deficit = tx_res->pp_padding; diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index ddd8c0cc744d..0a927a7313a6 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -46,6 +46,10 @@ static int mt76s_refill_sched_quota(struct mt76_dev *dev, u32 *data) return 0; sdio->sched.pse_mcu_quota += pse_mcu_quota; + if (sdio->pse_mcu_quota_max && + sdio->sched.pse_mcu_quota > sdio->pse_mcu_quota_max) { + sdio->sched.pse_mcu_quota = sdio->pse_mcu_quota_max; + } sdio->sched.pse_data_quota += pse_data_quota; sdio->sched.ple_data_quota += ple_data_quota; -- 2.51.0 From 08fa656c91fd5fdf47ba393795b9c0d1e97539ed Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Sep 2024 10:43:03 +0300 Subject: [PATCH 09/16] wifi: mt76: mt7925: fix off by one in mt7925_load_clc() This comparison should be >= instead of > to prevent an out of bounds read and write. Fixes: 9679ca7326e5 ("wifi: mt76: mt7925: fix a potential array-index-out-of-bounds issue for clc") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/84bf5dd2-2fe3-4410-a7af-ae841e41082a@stanley.mountain Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 748ea6adbc6b..0c2a2337c313 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -638,7 +638,7 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name) for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { clc = (const struct mt7925_clc *)(clc_base + offset); - if (clc->idx > ARRAY_SIZE(phy->clc)) + if (clc->idx >= ARRAY_SIZE(phy->clc)) break; /* do not init buf again if chip reset triggered */ -- 2.51.0 From 458417efd5f9e7450eec65c9546c7bcc7efd7306 Mon Sep 17 00:00:00 2001 From: Shen Lichuan Date: Wed, 11 Sep 2024 11:42:43 +0800 Subject: [PATCH 10/16] wifi: mt76: mt7615: Convert comma to semicolon To ensure code clarity and prevent potential errors, it's advisable to employ the ';' as a statement separator, except when ',' are intentionally used for specific purposes. Signed-off-by: Shen Lichuan Reviewed-by: AngeloGioacchino Del Regno Link: https://patch.msgid.link/20240911034243.31596-1-shenlichuan@vivo.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 96e34277fece..804d3f5a5244 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1700,7 +1700,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev) }; int ret; - dev->mt76.mcu_ops = &mt7615_mcu_ops, + dev->mt76.mcu_ops = &mt7615_mcu_ops; ret = mt7615_mcu_drv_pmctrl(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c index b0094205ba95..a7b8acb2da83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -147,7 +147,7 @@ int mt7663s_mcu_init(struct mt7615_dev *dev) if (ret) return ret; - dev->mt76.mcu_ops = &mt7663s_mcu_ops, + dev->mt76.mcu_ops = &mt7663s_mcu_ops; ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); if (ret) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index a8b1a0f8b2d7..33c01f8ce8e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -72,7 +72,7 @@ int mt7663u_mcu_init(struct mt7615_dev *dev) }; int ret; - dev->mt76.mcu_ops = &mt7663u_mcu_ops, + dev->mt76.mcu_ops = &mt7663u_mcu_ops; mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { -- 2.51.0 From f21b77cb556296116b1cce1d62295d13e35da574 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Fri, 27 Sep 2024 10:53:17 +0200 Subject: [PATCH 11/16] wifi: mt76: mt7915: Fix mesh scan on MT7916 DBDC commit c4f075582304 ("wifi: mt76: mt7915: fix command timeout in AP stop period") changes the behavior of mt7915_bss_info_changed() in mesh mode when enable_beacon becomes false: it calls mt7915_mcu_add_bss_info(..., false) and mt7915_mcu_add_sta(..., false) while the previous code didn't. These sends mcu commands that apparently confuse the firmware. This breaks scanning while in mesh mode on AsiaRF MT7916 DBDC-based cards: scanning works but no mesh frames get sent afterwards and the firmware seems to be hosed. It breaks on MT7916 DBDC but not on MT7915 DBDC. Fixes: c4f075582304 ("wifi: mt76: mt7915: fix command timeout in AP stop period") Signed-off-by: Nicolas Cavallari Link: https://patch.msgid.link/20240927085350.4594-1-nicolas.cavallari@green-communications.fr Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7915/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index c6f498fc81ff..8183708a9b35 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -619,8 +619,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) set_bss_info = vif->cfg.assoc; if (changed & BSS_CHANGED_BEACON_ENABLED && + info->enable_beacon && vif->type != NL80211_IFTYPE_AP) - set_bss_info = set_sta = info->enable_beacon; + set_bss_info = set_sta = 1; if (set_bss_info == 1) mt7915_mcu_add_bss_info(phy, vif, true); -- 2.51.0 From e016239fcb9802e58dc059b85e0fb25ac1777df4 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 9 Sep 2024 14:12:37 -0700 Subject: [PATCH 12/16] wifi: mt76: mt7996: Add eht radiotap tlv This duplicates what the 7925 driver is doing, wireshark seems to at least mostly decode it as expected. Signed-off-by: Ben Greear Link: https://patch.msgid.link/20240909211238.3237111-1-greearb@candelatech.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 0d21414e2c88..4706ddefea9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -679,14 +679,25 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, if (ieee80211_has_a4(fc) && is_mesh && status->amsdu) *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; } + skb_set_mac_header(skb, (unsigned char *)hdr - skb->data); } 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 (rxv && !(status->flag & RX_FLAG_8023)) { + switch (status->encoding) { + case RX_ENC_EHT: + mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode); + break; + case RX_ENC_HE: + mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); + break; + default: + break; + } + } if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) return 0; -- 2.51.0 From 512e26db3565b310052dc2b8975ac7c973bf8ab6 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 9 Sep 2024 14:12:38 -0700 Subject: [PATCH 13/16] wifi: mt76: Fix EHT NSS radiotap reporting. Wireshark and iwlwifi use zero-based NSS reporting, adjust mt76 to do the same. Signed-off-by: Ben Greear Link: https://patch.msgid.link/20240909211238.3237111-2-greearb@candelatech.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c index 92ad1ecf6c9d..2d300948308d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.c @@ -231,7 +231,8 @@ void mt76_connac3_mac_decode_eht_radiotap(struct sk_buff *skb, __le32 *rxv, EHT_PREP(DATA0_PE_DISAMBIGUITY_OM, PE_DISAMBIG, rxv[5]) | EHT_PREP(DATA0_LDPC_EXTRA_SYM_OM, LDPC_EXT_SYM, rxv[4]); - eht->data[7] |= le32_encode_bits(status->nss, IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); + /* iwlwifi and wireshark expect radiotap to report zero-based NSS, so subtract 1. */ + eht->data[7] |= le32_encode_bits(status->nss - 1, IEEE80211_RADIOTAP_EHT_DATA7_NSS_S); eht->user_info[0] |= EHT_BITS(USER_INFO_MCS_KNOWN) | @@ -240,7 +241,7 @@ void mt76_connac3_mac_decode_eht_radiotap(struct sk_buff *skb, __le32 *rxv, EHT_BITS(USER_INFO_BEAMFORMING_KNOWN_O) | EHT_BITS(USER_INFO_DATA_FOR_USER) | le32_encode_bits(status->rate_idx, IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) | - le32_encode_bits(status->nss, IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O); + le32_encode_bits(status->nss - 1, IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O); if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF) eht->user_info[0] |= EHT_BITS(USER_INFO_BEAMFORMING_O); -- 2.51.0 From 5ed54896b6bd444223092cab361b0785932119ab Mon Sep 17 00:00:00 2001 From: Quan Zhou Date: Thu, 18 Jul 2024 21:49:09 +0800 Subject: [PATCH 14/16] wifi: mt76: mt7921: fix a potential scan no APs In multi-channel scenarios, the granted channel must be aborted before station remove. Otherwise, the firmware will be put into a wrong state, resulting in have chance to make subsequence scan no APs. With this patch, the granted channel will be always aborted before station remove. Signed-off-by: Quan Zhou Reviewed-by: Sean Wang Tested-by: David Ruth Reviewed-by: David Ruth Link: https://patch.msgid.link/1ac1ae779db86d4012199a24ea2ca74050ed4af6.1721300411.git.quan.zhou@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index a7f5bfbc02ed..2ef8dbfc4a95 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -360,9 +360,9 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev) del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - ieee80211_iterate_active_interfaces(mt76_hw(dev), - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7921_roc_iter, (void *)phy); + ieee80211_iterate_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_roc_iter, (void *)phy); } EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); @@ -858,6 +858,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + mt7921_roc_abort_sync(dev); mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->deflink.wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); -- 2.51.0 From f1b1e133a770fcdbd89551651232b034d2f7a27a Mon Sep 17 00:00:00 2001 From: WangYuli Date: Mon, 13 Jan 2025 15:02:41 +0800 Subject: [PATCH 15/16] wifi: mt76: mt76u_vendor_request: Do not print error messages when -EPROTO MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When initializing the network card, unplugging the device will trigger an -EPROTO error, resulting in a flood of error messages being printed frantically. The exception is printed as follows: mt76x2u 2-2.4:1.0: vendor request req:47 off:9018 failed:-71 mt76x2u 2-2.4:1.0: vendor request req:47 off:9018 failed:-71 ... It will continue to print more than 2000 times for about 5 minutes, causing the usb device to be unable to be disconnected. During this period, the usb port cannot recognize the new device because the old device has not disconnected. There may be other operating methods that cause -EPROTO, but -EPROTO is a low-level hardware error. It is unwise to repeat vendor requests expecting to read correct data. It is a better choice to treat -EPROTO and -ENODEV the same way. Similar to commit 9b0f100c1970 ("mt76: usb: process URBs with status EPROTO properly") do no schedule rx_worker for urb marked with status set -EPROTO. I also reproduced this situation when plugging and unplugging the device, and this patch is effective. Just do not vendor request again for urb marked with status set -EPROTO. Link: https://lore.kernel.org/all/531681bd-30f5-4a70-a156-bf8754b8e072@intel.com/ Link: https://lore.kernel.org/all/D4B9CC1FFC0CBAC3+20250105040607.154706-1-wangyuli@uniontech.com/ Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Co-developed-by: Xu Rao Signed-off-by: Xu Rao Signed-off-by: WangYuli Link: https://patch.msgid.link/9DD7DE7AAB497CB7+20250113070241.63590-1-wangyuli@uniontech.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 58ff06823389..f9e67b8c3b3c 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -33,9 +33,9 @@ int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, ret = usb_control_msg(udev, pipe, req, req_type, val, offset, buf, len, MT_VEND_REQ_TOUT_MS); - if (ret == -ENODEV) + if (ret == -ENODEV || ret == -EPROTO) set_bit(MT76_REMOVED, &dev->phy.state); - if (ret >= 0 || ret == -ENODEV) + if (ret >= 0 || ret == -ENODEV || ret == -EPROTO) return ret; usleep_range(5000, 10000); } -- 2.51.0 From aa566ac6b7272e7ea5359cb682bdca36d2fc7e73 Mon Sep 17 00:00:00 2001 From: Michael Lo Date: Thu, 1 Aug 2024 10:43:35 +0800 Subject: [PATCH 16/16] wifi: mt76: mt7921: fix using incorrect group cipher after disconnection. To avoid incorrect cipher after disconnection, we should do the key deletion process in this case. Fixes: e6db67fa871d ("wifi: mt76: ignore key disable commands") Signed-off-by: Michael Lo Signed-off-by: Ming Yen Hsieh Tested-by: David Ruth Reviewed-by: David Ruth Link: https://patch.msgid.link/20240801024335.12981-1-mingyen.hsieh@mediatek.com Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7921/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 2ef8dbfc4a95..573a2cd7fe45 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -531,7 +531,13 @@ static int mt7921_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } else { if (idx == *wcid_keyidx) *wcid_keyidx = -1; - goto out; + + /* For security issue we don't trigger the key deletion when + * reassociating. But we should trigger the deletion process + * to avoid using incorrect cipher after disconnection, + */ + if (vif->type != NL80211_IFTYPE_STATION || vif->cfg.assoc) + goto out; } mt76_wcid_key_setup(&dev->mt76, wcid, key); -- 2.51.0