diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7925')
18 files changed, 425 insertions, 203 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7925/Kconfig index 5854e95e68a5..f4f7c93c2ea7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7925/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: ISC +# SPDX-License-Identifier: BSD-3-Clause-Clear config MT7925_COMMON tristate select MT792x_LIB diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile index ade5e647c941..8f1078ce3231 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile @@ -1,10 +1,10 @@ -# SPDX-License-Identifier: ISC +# SPDX-License-Identifier: BSD-3-Clause-Clear obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o obj-$(CONFIG_MT7925E) += mt7925e.o obj-$(CONFIG_MT7925U) += mt7925u.o -mt7925-common-y := mac.o mcu.o main.o init.o debugfs.o +mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7925e-y := pci.o pci_mac.o pci_mcu.o mt7925u-y := usb.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c index 1e2fc6577e78..e2498659c884 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include "mt7925.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index d7d5afe365ed..3ce5d6fcc69d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/etherdevice.h> @@ -7,6 +7,7 @@ #include <linux/thermal.h> #include <linux/firmware.h> #include "mt7925.h" +#include "regd.h" #include "mac.h" #include "mcu.h" @@ -60,151 +61,6 @@ static int mt7925_thermal_init(struct mt792x_phy *phy) return PTR_ERR_OR_ZERO(hwmon); } -void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2) -{ - struct mt792x_phy *phy = &dev->phy; - struct mt7925_clc_rule_v2 *rule; - struct mt7925_clc *clc; - bool old = dev->has_eht, new = true; - u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2); - u8 *pos; - - if (mtcl_conf != MT792X_ACPI_MTCL_INVALID && - (((mtcl_conf >> 4) & 0x3) == 0)) { - new = false; - goto out; - } - - if (!phy->clc[MT792x_CLC_BE_CTRL]) - goto out; - - clc = (struct mt7925_clc *)phy->clc[MT792x_CLC_BE_CTRL]; - pos = clc->data; - - while (1) { - rule = (struct mt7925_clc_rule_v2 *)pos; - - if (rule->alpha2[0] == alpha2[0] && - rule->alpha2[1] == alpha2[1]) { - new = false; - break; - } - - /* Check the last one */ - if (rule->flag & BIT(0)) - break; - - pos += sizeof(*rule); - } - -out: - if (old == new) - return; - - dev->has_eht = new; - mt7925_set_stream_he_eht_caps(phy); -} - -static void -mt7925_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) -{ -#define IS_UNII_INVALID(idx, sfreq, efreq, cfreq) \ - (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq)) -#define MT7925_UNII_59G_IS_VALID 0x1 -#define MT7925_UNII_6G_IS_VALID 0x1e - struct ieee80211_supported_band *sband; - struct mt76_dev *mdev = &dev->mt76; - struct ieee80211_channel *ch; - u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, mdev->alpha2); - int i; - - if (mtcl_conf != MT792X_ACPI_MTCL_INVALID) { - if ((mtcl_conf & 0x3) == 0) - dev->phy.clc_chan_conf &= ~MT7925_UNII_59G_IS_VALID; - if (((mtcl_conf >> 2) & 0x3) == 0) - dev->phy.clc_chan_conf &= ~MT7925_UNII_6G_IS_VALID; - } - - sband = wiphy->bands[NL80211_BAND_5GHZ]; - if (!sband) - return; - - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - - /* UNII-4 */ - if (IS_UNII_INVALID(0, 5845, 5925, ch->center_freq)) - ch->flags |= IEEE80211_CHAN_DISABLED; - } - - sband = wiphy->bands[NL80211_BAND_6GHZ]; - if (!sband) - return; - - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - - /* UNII-5/6/7/8 */ - if (IS_UNII_INVALID(1, 5925, 6425, ch->center_freq) || - IS_UNII_INVALID(2, 6425, 6525, ch->center_freq) || - IS_UNII_INVALID(3, 6525, 6875, ch->center_freq) || - IS_UNII_INVALID(4, 6875, 7125, ch->center_freq)) - ch->flags |= IEEE80211_CHAN_DISABLED; - } -} - -void mt7925_regd_update(struct mt792x_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - struct ieee80211_hw *hw = mdev->hw; - struct wiphy *wiphy = hw->wiphy; - - if (!dev->regd_change) - return; - - mt7925_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env); - mt7925_regd_channel_update(wiphy, dev); - mt7925_mcu_set_channel_domain(hw->priv); - mt7925_set_tx_sar_pwr(hw, NULL); - dev->regd_change = false; -} -EXPORT_SYMBOL_GPL(mt7925_regd_update); - -static void -mt7925_regd_notifier(struct wiphy *wiphy, - struct regulatory_request *req) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct mt792x_dev *dev = mt792x_hw_dev(hw); - struct mt76_dev *mdev = &dev->mt76; - struct mt76_connac_pm *pm = &dev->pm; - - /* allow world regdom at the first boot only */ - if (!memcmp(req->alpha2, "00", 2) && - mdev->alpha2[0] && mdev->alpha2[1]) - return; - - /* do not need to update the same country twice */ - if (!memcmp(req->alpha2, mdev->alpha2, 2) && - dev->country_ie_env == req->country_ie_env) - return; - - memcpy(mdev->alpha2, req->alpha2, 2); - mdev->region = req->dfs_region; - dev->country_ie_env = req->country_ie_env; - dev->regd_change = true; - - if (pm->suspended) - return; - - dev->regd_in_progress = true; - mt792x_mutex_acquire(dev); - mt7925_regd_update(dev); - mt792x_mutex_release(dev); - dev->regd_in_progress = false; - wake_up(&dev->wait); -} - static void mt7925_mac_init_basic_rates(struct mt792x_dev *dev) { int i; @@ -235,8 +91,6 @@ int mt7925_mac_init(struct mt792x_dev *dev) mt7925_mac_init_basic_rates(dev); - memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); - return 0; } EXPORT_SYMBOL_GPL(mt7925_mac_init); @@ -420,7 +274,7 @@ int mt7925_register_device(struct mt792x_dev *dev) dev->mphy.hw->wiphy->available_antennas_rx = dev->mphy.chainmask; dev->mphy.hw->wiphy->available_antennas_tx = dev->mphy.chainmask; - queue_work(system_wq, &dev->init_work); + queue_work(system_percpu_wq, &dev->init_work); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 1e44e96f034e..871b67101976 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/devcoredump.h> @@ -6,6 +6,7 @@ #include <linux/timekeeping.h> #include "mt7925.h" #include "../dma.h" +#include "regd.h" #include "mac.h" #include "mcu.h" @@ -1329,9 +1330,7 @@ void mt7925_mac_reset_work(struct work_struct *work) mt7925_vif_connect_iter, NULL); mt76_connac_power_save_sched(&dev->mt76.phy, pm); - mt792x_mutex_acquire(dev); - mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR); - mt792x_mutex_release(dev); + mt7925_regd_change(&dev->phy, "00"); } void mt7925_coredump_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.h b/drivers/net/wireless/mediatek/mt76/mt7925/mac.h index b10a993326b9..83ea9021daea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT7925_MAC_H diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index ac3d485a2f78..2d358a96640c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/etherdevice.h> @@ -8,6 +8,7 @@ #include <linux/ctype.h> #include <net/ipv6.h> #include "mt7925.h" +#include "regd.h" #include "mcu.h" #include "mac.h" @@ -138,10 +139,14 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, } if (band == NL80211_BAND_6GHZ) { + struct ieee80211_supported_band *sband = + &phy->mt76->sband_5g.sband; + struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; + u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS | IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; - cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5, + cap |= u16_encode_bits(ht_cap->ampdu_density, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | @@ -430,6 +435,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) goto out; vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; + out: mt792x_mutex_release(dev); @@ -1312,20 +1320,6 @@ void mt7925_mlo_pm_work(struct work_struct *work) mt7925_mlo_pm_iter, dev); } -static bool is_valid_alpha2(const char *alpha2) -{ - if (!alpha2) - return false; - - if (alpha2[0] == '0' && alpha2[1] == '0') - return true; - - if (isalpha(alpha2[0]) && isalpha(alpha2[1])) - return true; - - return false; -} - void mt7925_scan_work(struct work_struct *work) { struct mt792x_phy *phy; @@ -1334,7 +1328,6 @@ void mt7925_scan_work(struct work_struct *work) scan_work.work); while (true) { - struct mt76_dev *mdev = &phy->dev->mt76; struct sk_buff *skb; struct tlv *tlv; int tlv_len; @@ -1365,15 +1358,7 @@ void mt7925_scan_work(struct work_struct *work) case UNI_EVENT_SCAN_DONE_CHNLINFO: evt = (struct mt7925_mcu_scan_chinfo_event *)tlv->data; - if (!is_valid_alpha2(evt->alpha2)) - break; - - mt7925_regd_be_ctrl(phy->dev, evt->alpha2); - - if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') - break; - - mt7925_mcu_set_clc(phy->dev, evt->alpha2, ENVIRON_INDOOR); + mt7925_regd_change(phy, evt->alpha2); break; case UNI_EVENT_SCAN_DONE_NLO: @@ -1958,6 +1943,9 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, link_conf, NULL); + if (changed & BSS_CHANGED_CQM) + mt7925_mcu_set_rssimonitor(dev, vif); + mt792x_mutex_release(dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8eda407e4135..cf0fdea45cf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1,19 +1,16 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/fs.h> #include <linux/firmware.h> #include "mt7925.h" +#include "regd.h" #include "mcu.h" #include "mac.h" #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) -static bool mt7925_disable_clc; -module_param_named(disable_clc, mt7925_disable_clc, bool, 0644); -MODULE_PARM_DESC(disable_clc, "disable CLC support"); - int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { @@ -451,6 +448,56 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) } static void +mt7925_mcu_rssi_monitor_iter(void *priv, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt7925_uni_rssi_monitor_event *event = priv; + enum nl80211_cqm_rssi_threshold_event nl_event; + s32 rssi = le32_to_cpu(event->rssi); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (!(vif->driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + return; + + if (rssi > vif->bss_conf.cqm_rssi_thold) + nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + else + nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + + ieee80211_cqm_rssi_notify(vif, nl_event, rssi, GFP_KERNEL); +} + +static void +mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct tlv *tlv; + u32 tlv_len; + struct mt7925_uni_rssi_monitor_event *event; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; + + while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_RSSI_MONITOR_INFO: + event = (struct mt7925_uni_rssi_monitor_event *)skb->data; + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_rssi_monitor_iter, + event); + break; + default: + break; + } + tlv_len -= le16_to_cpu(tlv->len); + tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); + } +} + +static void mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt7925_uni_debug_msg { @@ -546,6 +593,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev, case MCU_UNI_EVENT_BSS_BEACON_LOSS: mt7925_mcu_connection_loss_event(dev, skb); break; + case MCU_UNI_EVENT_RSSI_MONITOR: + mt7925_mcu_rssi_monitor_event(dev, skb); + break; case MCU_UNI_EVENT_COREDUMP: dev->fw_assert = true; mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); @@ -688,8 +738,8 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name) int ret, i, len, offset = 0; dev->phy.clc_chan_conf = 0xff; - if (mt7925_disable_clc || - mt76_is_usb(&dev->mt76)) + dev->regd_user = false; + if (!mt7925_regd_clc_supported(dev)) return 0; if (mt76_is_mmio(&dev->mt76)) { @@ -759,6 +809,7 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name) } } + ret = mt7925_regd_init(phy); out: release_firmware(fw); @@ -1003,10 +1054,10 @@ int mt7925_run_firmware(struct mt792x_dev *dev) if (err) return err; - set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); err = mt7925_load_clc(dev, mt792x_ram_name(dev)); if (err) return err; + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); return mt7925_mcu_fw_log_2_host(dev, 1); } @@ -3383,6 +3434,9 @@ int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy; int i, ret; + if (!ARRAY_SIZE(phy->clc)) + return -ESRCH; + /* submit all clc config */ for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { if (i == MT792x_CLC_BE_CTRL) @@ -3818,3 +3872,32 @@ int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, return mt76_mcu_send_msg(&phy->dev->mt76, MCU_UNI_CMD(BAND_CONFIG), &req, sizeof(req), true); } + +int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif) +{ + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(&vif->bss_conf); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + __le16 tag; + __le16 len; + u8 enable; + s8 cqm_rssi_high; + s8 cqm_rssi_low; + u8 rsv; + } req = { + .hdr = { + .bss_idx = mconf->mt76.idx, + }, + .tag = cpu_to_le16(UNI_CMD_RSSI_MONITOR_SET), + .len = cpu_to_le16(sizeof(req) - 4), + .enable = vif->cfg.assoc, + .cqm_rssi_high = (s8)(vif->bss_conf.cqm_rssi_thold + vif->bss_conf.cqm_rssi_hyst), + .cqm_rssi_low = (s8)(vif->bss_conf.cqm_rssi_thold - vif->bss_conf.cqm_rssi_hyst), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(RSSI_MONITOR), &req, + sizeof(req), false); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index a40764d89a1f..e09e0600534a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT7925_MCU_H @@ -152,6 +152,14 @@ enum { UNI_EVENT_SCAN_DONE_NLO = 3, }; +enum { + UNI_CMD_RSSI_MONITOR_SET = 0, +}; + +enum { + UNI_EVENT_RSSI_MONITOR_INFO = 0, +}; + enum connac3_mcu_cipher_type { CONNAC3_CIPHER_NONE = 0, CONNAC3_CIPHER_WEP40 = 1, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 1b165d0d8bd3..6b9bf1b89032 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT7925_H @@ -103,6 +103,12 @@ struct mt7925_uni_beacon_loss_event { struct mt7925_beacon_loss_tlv beacon_loss; } __packed; +struct mt7925_uni_rssi_monitor_event { + __le16 tag; + __le16 len; + __le32 rssi; +} __packed; + #define to_rssi(field, rxv) ((FIELD_GET(field, rxv) - 220) / 2) #define to_rcpi(rssi) (2 * (rssi) + 220) @@ -257,8 +263,6 @@ int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd); int mt7925_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, u8 bit_op, u32 bit_map); -void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2); -void mt7925_regd_update(struct mt792x_dev *dev); int mt7925_mac_init(struct mt792x_dev *dev); int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); @@ -372,4 +376,5 @@ int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int mt7925_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, struct netlink_callback *cb, void *data, int len); +int mt7925_mcu_set_rssimonitor(struct mt792x_dev *dev, struct ieee80211_vif *vif); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 8eb1fe1082d1..c4161754c01d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/kernel.h> @@ -8,6 +8,7 @@ #include "mt7925.h" #include "mac.h" #include "mcu.h" +#include "regd.h" #include "../dma.h" static const struct pci_device_id mt7925_pci_device_table[] = { @@ -584,7 +585,7 @@ static int _mt7925_pci_resume(struct device *device, bool restore) if (!pm->ds_enable) mt7925_mcu_set_deep_sleep(dev, false); - mt7925_regd_update(dev); + mt7925_mcu_regd_update(dev, mdev->alpha2, dev->country_ie_env); failed: pm->suspended = false; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index 4578d16bf456..3072850c2752 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include "mt7925.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c index f95bc5dcd830..6cceff88c656 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include "mt7925.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c new file mode 100644 index 000000000000..292087e882d1 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* Copyright (C) 2025 MediaTek Inc. */ + +#include "mt7925.h" +#include "regd.h" +#include "mcu.h" + +static bool mt7925_disable_clc; +module_param_named(disable_clc, mt7925_disable_clc, bool, 0644); +MODULE_PARM_DESC(disable_clc, "disable CLC support"); + +bool mt7925_regd_clc_supported(struct mt792x_dev *dev) +{ + if (mt7925_disable_clc || + mt76_is_usb(&dev->mt76)) + return false; + + return true; +} + +void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2) +{ + struct mt792x_phy *phy = &dev->phy; + struct mt7925_clc_rule_v2 *rule; + struct mt7925_clc *clc; + bool old = dev->has_eht, new = true; + u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2); + u8 *pos; + + if (mtcl_conf != MT792X_ACPI_MTCL_INVALID && + (((mtcl_conf >> 4) & 0x3) == 0)) { + new = false; + goto out; + } + + if (!phy->clc[MT792x_CLC_BE_CTRL]) + goto out; + + clc = (struct mt7925_clc *)phy->clc[MT792x_CLC_BE_CTRL]; + pos = clc->data; + + while (1) { + rule = (struct mt7925_clc_rule_v2 *)pos; + + if (rule->alpha2[0] == alpha2[0] && + rule->alpha2[1] == alpha2[1]) { + new = false; + break; + } + + /* Check the last one */ + if (rule->flag & BIT(0)) + break; + + pos += sizeof(*rule); + } + +out: + if (old == new) + return; + + dev->has_eht = new; + mt7925_set_stream_he_eht_caps(phy); +} + +static void +mt7925_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) +{ +#define IS_UNII_INVALID(idx, sfreq, efreq, cfreq) \ + (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq)) +#define MT7925_UNII_59G_IS_VALID 0x1 +#define MT7925_UNII_6G_IS_VALID 0x1e + struct ieee80211_supported_band *sband; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_channel *ch; + u32 mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, mdev->alpha2); + int i; + + if (mtcl_conf != MT792X_ACPI_MTCL_INVALID) { + if ((mtcl_conf & 0x3) == 0) + dev->phy.clc_chan_conf &= ~MT7925_UNII_59G_IS_VALID; + if (((mtcl_conf >> 2) & 0x3) == 0) + dev->phy.clc_chan_conf &= ~MT7925_UNII_6G_IS_VALID; + } + + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (!dev->has_eht) + ch->flags |= IEEE80211_CHAN_NO_EHT; + } + + sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + /* UNII-4 */ + if (IS_UNII_INVALID(0, 5845, 5925, ch->center_freq)) + ch->flags |= IEEE80211_CHAN_DISABLED; + + if (!dev->has_eht) + ch->flags |= IEEE80211_CHAN_NO_EHT; + } + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + /* UNII-5/6/7/8 */ + if (IS_UNII_INVALID(1, 5925, 6425, ch->center_freq) || + IS_UNII_INVALID(2, 6425, 6525, ch->center_freq) || + IS_UNII_INVALID(3, 6525, 6875, ch->center_freq) || + IS_UNII_INVALID(4, 6875, 7125, ch->center_freq)) + ch->flags |= IEEE80211_CHAN_DISABLED; + + if (!dev->has_eht) + ch->flags |= IEEE80211_CHAN_NO_EHT; + } +} + +int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + int ret = 0; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + if (!dev->regd_change) + goto err; + + ret = mt7925_mcu_set_clc(dev, alpha2, country_ie_env); + if (ret < 0) + goto err; + + mt7925_regd_be_ctrl(dev, alpha2); + mt7925_regd_channel_update(wiphy, dev); + + ret = mt7925_mcu_set_channel_domain(hw->priv); + if (ret < 0) + goto err; + + ret = mt7925_set_tx_sar_pwr(hw, NULL); + if (ret < 0) + goto err; + +err: + mt792x_mutex_release(dev); + dev->regd_change = false; + dev->regd_in_progress = false; + wake_up(&dev->wait); + + return ret; +} +EXPORT_SYMBOL_GPL(mt7925_mcu_regd_update); + +void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_connac_pm *pm = &dev->pm; + struct mt76_dev *mdev = &dev->mt76; + + if (req->initiator == NL80211_REGDOM_SET_BY_USER && + !dev->regd_user) + dev->regd_user = true; + + /* allow world regdom at the first boot only */ + if (!memcmp(req->alpha2, "00", 2) && + mdev->alpha2[0] && mdev->alpha2[1]) + return; + + /* do not need to update the same country twice */ + if (!memcmp(req->alpha2, mdev->alpha2, 2) && + dev->country_ie_env == req->country_ie_env) + return; + + memcpy(mdev->alpha2, req->alpha2, 2); + mdev->region = req->dfs_region; + dev->country_ie_env = req->country_ie_env; + + dev->regd_change = true; + + if (pm->suspended) + /* postpone the mcu update to resume */ + return; + + mt7925_mcu_regd_update(dev, req->alpha2, + req->country_ie_env); + return; +} + +static bool +mt7925_regd_is_valid_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + + if (alpha2[0] == '0' && alpha2[1] == '0') + return true; + + if (isalpha(alpha2[0]) && isalpha(alpha2[1])) + return true; + + return false; +} + +int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; + + if (dev->hw_full_reset) + return 0; + + if (!mt7925_regd_is_valid_alpha2(alpha2) || + !mt7925_regd_clc_supported(dev) || + dev->regd_user) + return -EINVAL; + + if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') + return 0; + + /* do not need to update the same country twice */ + if (!memcmp(alpha2, mdev->alpha2, 2)) + return 0; + + if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { + return regulatory_hint(wiphy, alpha2); + } else { + return mt7925_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR); + } +} +EXPORT_SYMBOL_GPL(mt7925_regd_change); + +int mt7925_regd_init(struct mt792x_phy *phy) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_dev *mdev = &dev->mt76; + + if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE | + REGULATORY_DISABLE_BEACON_HINTS; + } else { + memzero_explicit(&mdev->alpha2, sizeof(mdev->alpha2)); + } + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.h b/drivers/net/wireless/mediatek/mt76/mt7925/regd.h new file mode 100644 index 000000000000..0767f078862e --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* Copyright (C) 2025 MediaTek Inc. */ + +#ifndef __MT7925_REGD_H +#define __MT7925_REGD_H + +#include "mt7925.h" + +int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env); + +void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2); +void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req); +bool mt7925_regd_clc_supported(struct mt792x_dev *dev); +int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2); +int mt7925_regd_init(struct mt792x_phy *phy); + +#endif + diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h index 341987e47f67..24985bba1b90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* Copyright (C) 2023 MediaTek Inc. */ #ifndef __MT7925_REGS_H diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c index a3c97164ba21..3d40aacfc011 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear #include "mt7925.h" #include "mcu.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index bf040f34e4b9..d9968f03856d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: ISC +// SPDX-License-Identifier: BSD-3-Clause-Clear /* Copyright (C) 2023 MediaTek Inc. */ #include <linux/kernel.h> |
