Move regd logic to regd.c and regd.h files Signed-off-by: JB Tsai --- .../wireless/mediatek/mt76/mt7921/Makefile | 2 +- .../net/wireless/mediatek/mt76/mt7921/init.c | 98 +---------------- .../net/wireless/mediatek/mt76/mt7921/main.c | 1 + .../wireless/mediatek/mt76/mt7921/mt7921.h | 1 - .../net/wireless/mediatek/mt76/mt7921/pci.c | 1 + .../net/wireless/mediatek/mt76/mt7921/regd.c | 104 ++++++++++++++++++ .../net/wireless/mediatek/mt76/mt7921/regd.h | 13 +++ 7 files changed, 121 insertions(+), 99 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/regd.c create mode 100644 drivers/net/wireless/mediatek/mt76/mt7921/regd.h diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile index 2ad3c1cc3779..3ef7c9c45386 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_MT7921E) += mt7921e.o obj-$(CONFIG_MT7921S) += mt7921s.o obj-$(CONFIG_MT7921U) += mt7921u.o -mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o +mt7921-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7921e-y := pci.o pci_mac.o pci_mcu.o mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 29732315af1c..1fe2f2bc3881 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -9,6 +9,7 @@ #include "mt7921.h" #include "../mt76_connac2_mac.h" #include "mcu.h" +#include "regd.h" static ssize_t mt7921_thermal_temp_show(struct device *dev, struct device_attribute *attr, @@ -60,103 +61,6 @@ static int mt7921_thermal_init(struct mt792x_phy *phy) return PTR_ERR_OR_ZERO(hwmon); } -static void -mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) -{ -#define IS_UNII_INVALID(idx, sfreq, efreq) \ - (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq)) - struct ieee80211_supported_band *sband; - struct mt76_dev *mdev = &dev->mt76; - struct device_node *np, *band_np; - struct ieee80211_channel *ch; - int i, cfreq; - - np = mt76_find_power_limits_node(mdev); - - sband = wiphy->bands[NL80211_BAND_5GHZ]; - band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL; - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - cfreq = ch->center_freq; - - if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { - ch->flags |= IEEE80211_CHAN_DISABLED; - continue; - } - - /* UNII-4 */ - if (IS_UNII_INVALID(0, 5845, 5925)) - ch->flags |= IEEE80211_CHAN_DISABLED; - } - - sband = wiphy->bands[NL80211_BAND_6GHZ]; - if (!sband) - return; - - band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL; - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - cfreq = ch->center_freq; - - if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { - ch->flags |= IEEE80211_CHAN_DISABLED; - continue; - } - - /* UNII-5/6/7/8 */ - if (IS_UNII_INVALID(1, 5925, 6425) || - IS_UNII_INVALID(2, 6425, 6525) || - IS_UNII_INVALID(3, 6525, 6875) || - IS_UNII_INVALID(4, 6875, 7125)) - ch->flags |= IEEE80211_CHAN_DISABLED; - } -} - -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; - - if (request->initiator == NL80211_REGDOM_SET_BY_USER) { - if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0') - wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; - else - wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; - } - - if (pm->suspended) - return; - - dev->regd_in_progress = true; - - mt792x_mutex_acquire(dev); - mt7921_regd_update(dev); - mt792x_mutex_release(dev); - - dev->regd_in_progress = false; - wake_up(&dev->wait); -} - int mt7921_mac_init(struct mt792x_dev *dev) { int i; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 42b9514e04e7..00ca3d3f3ef0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -7,6 +7,7 @@ #include #include #include "mt7921.h" +#include "regd.h" #include "mcu.h" static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index ad92af98e314..5239ea970d24 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -246,7 +246,6 @@ 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 65c7fe671137..a173a61f2b49 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -12,6 +12,7 @@ #include "../mt76_connac2_mac.h" #include "../dma.h" #include "mcu.h" +#include "regd.h" static const struct pci_device_id mt7921_pci_device_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961), diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c new file mode 100644 index 000000000000..6e6c81189222 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2025 MediaTek Inc. */ + +#include +#include +#include "mt7921.h" +#include "regd.h" +#include "mcu.h" + +static void +mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) +{ +#define IS_UNII_INVALID(idx, sfreq, efreq) \ + (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq)) + struct ieee80211_supported_band *sband; + struct mt76_dev *mdev = &dev->mt76; + struct device_node *np, *band_np; + struct ieee80211_channel *ch; + int i, cfreq; + + np = mt76_find_power_limits_node(mdev); + + sband = wiphy->bands[NL80211_BAND_5GHZ]; + band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL; + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + cfreq = ch->center_freq; + + if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + ch->flags |= IEEE80211_CHAN_DISABLED; + continue; + } + + /* UNII-4 */ + if (IS_UNII_INVALID(0, 5845, 5925)) + ch->flags |= IEEE80211_CHAN_DISABLED; + } + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL; + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + cfreq = ch->center_freq; + + if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + ch->flags |= IEEE80211_CHAN_DISABLED; + continue; + } + + /* UNII-5/6/7/8 */ + if (IS_UNII_INVALID(1, 5925, 6425) || + IS_UNII_INVALID(2, 6425, 6525) || + IS_UNII_INVALID(3, 6525, 6875) || + IS_UNII_INVALID(4, 6875, 7125)) + ch->flags |= IEEE80211_CHAN_DISABLED; + } +} + +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); + +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; + + if (request->initiator == NL80211_REGDOM_SET_BY_USER) { + if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0') + wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; + else + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + } + + if (pm->suspended) + return; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + mt7921_regd_update(dev); + mt792x_mutex_release(dev); + + dev->regd_in_progress = false; + wake_up(&dev->wait); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h new file mode 100644 index 000000000000..0ba6161e1919 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: ISC */ +/* Copyright (C) 2025 MediaTek Inc. */ + +#ifndef __MT7921_REGD_H +#define __MT7921_REGD_H + +#include "mt7921.h" + +void mt7921_regd_update(struct mt792x_dev *dev); +void mt7921_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request); + +#endif -- 2.45.2 Move the disable_clc module parameter to regd.c and introduce mt7925_regd_clc_supported() to centralize CLC support checks. Signed-off-by: JB Tsai --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 14 ++++++++------ drivers/net/wireless/mediatek/mt76/mt7921/regd.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt7921/regd.h | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 8442dbd2ee23..1e2afa736cdf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -4,6 +4,7 @@ #include #include #include "mt7921.h" +#include "regd.h" #include "mcu.h" #include "../mt76_connac2_mac.h" #include "../mt792x_trace.h" @@ -11,10 +12,6 @@ #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) -static bool mt7921_disable_clc; -module_param_named(disable_clc, mt7921_disable_clc, bool, 0644); -MODULE_PARM_DESC(disable_clc, "disable CLC support"); - int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { @@ -422,8 +419,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) u8 *clc_base = NULL, hw_encap = 0; dev->phy.clc_chan_conf = 0xff; - if (mt7921_disable_clc || - mt76_is_usb(&dev->mt76)) + if (!mt7921_regd_clc_supported(dev)) return 0; if (mt76_is_mmio(&dev->mt76)) { @@ -470,6 +466,9 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { clc = (const struct mt7921_clc *)(clc_base + offset); + if (clc->idx >= ARRAY_SIZE(phy->clc)) + break; + /* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx]) continue; @@ -1403,6 +1402,9 @@ int mt7921_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++) { ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index 6e6c81189222..70440ab8ba82 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -7,6 +7,19 @@ #include "regd.h" #include "mcu.h" +static bool mt7921_disable_clc; +module_param_named(disable_clc, mt7921_disable_clc, bool, 0644); +MODULE_PARM_DESC(disable_clc, "disable CLC support"); + +bool mt7921_regd_clc_supported(struct mt792x_dev *dev) +{ + if (mt7921_disable_clc || + mt76_is_usb(&dev->mt76)) + return false; + + return true; +} + static void mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h index 0ba6161e1919..74bc2fdd532c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -9,5 +9,6 @@ void mt7921_regd_update(struct mt792x_dev *dev); void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); +bool mt7921_regd_clc_supported(struct mt792x_dev *dev); #endif -- 2.45.2 Rename mt7921_regd_update() to mt7921_mcu_regd_update() to centralize regd updates with error handling. Signed-off-by: JB Tsai --- .../net/wireless/mediatek/mt76/mt7921/pci.c | 2 +- .../net/wireless/mediatek/mt76/mt7921/regd.c | 45 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7921/regd.h | 3 +- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index a173a61f2b49..3fdf55c056a6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -545,7 +545,7 @@ static int mt7921_pci_resume(struct device *device) if (err < 0) goto failed; - mt7921_regd_update(dev); + mt7921_mcu_regd_update(dev, mdev->alpha2, dev->country_ie_env); err = mt7921_mcu_radio_led_ctrl(dev, EXT_CMD_RADIO_ON_LED); failed: pm->suspended = false; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index 70440ab8ba82..f795ee2eb446 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -72,18 +72,43 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) } } -void mt7921_regd_update(struct mt792x_dev *dev) +int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) { struct mt76_dev *mdev = &dev->mt76; struct ieee80211_hw *hw = mdev->hw; struct wiphy *wiphy = hw->wiphy; + int ret = 0; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + if (!dev->regd_change) + goto err; + + ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env); + if (ret < 0) + goto err; - 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); + + ret = mt76_connac_mcu_set_channel_domain(hw->priv); + if (ret < 0) + goto err; + + ret = mt7921_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(mt7921_regd_update); +EXPORT_SYMBOL_GPL(mt7921_mcu_regd_update); void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request) @@ -106,12 +131,6 @@ void mt7921_regd_notifier(struct wiphy *wiphy, if (pm->suspended) return; - dev->regd_in_progress = true; - - mt792x_mutex_acquire(dev); - mt7921_regd_update(dev); - mt792x_mutex_release(dev); - - dev->regd_in_progress = false; - wake_up(&dev->wait); + mt7921_mcu_regd_update(dev, request->alpha2, + request->country_ie_env); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h index 74bc2fdd532c..da5bd4450312 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -6,7 +6,8 @@ #include "mt7921.h" -void mt7921_regd_update(struct mt792x_dev *dev); +int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env); void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); bool mt7921_regd_clc_supported(struct mt792x_dev *dev); -- 2.45.2 Implement 802.11d-based automatic regulatory domain switching to dynamically determine the regulatory domain at runtime. Signed-off-by: JB Tsai --- .../wireless/mediatek/mt76/mt76_connac_mcu.h | 3 +- .../net/wireless/mediatek/mt76/mt7921/mac.c | 3 + .../net/wireless/mediatek/mt76/mt7921/main.c | 12 ++- .../net/wireless/mediatek/mt76/mt7921/mcu.c | 3 +- .../net/wireless/mediatek/mt76/mt7921/regd.c | 81 +++++++++++++++++-- .../net/wireless/mediatek/mt76/mt7921/regd.h | 2 + 6 files changed, 93 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index f44977f9093d..263778be4a34 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1586,7 +1586,7 @@ struct mt76_connac_hw_scan_done { u8 pno_enabled; u8 pad2[3]; u8 sparse_channel_valid_num; - u8 pad3[3]; + u8 alpha2[3]; u8 channel_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; /* idle format for channel_idle_time * 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) @@ -1599,6 +1599,7 @@ struct mt76_connac_hw_scan_done { u8 mdrdy_count[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; __le32 beacon_2g_num; __le32 beacon_5g_num; + __le16 channel_scan_time[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM]; } __packed; struct mt76_connac_sched_scan_req { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index 03b4960db73f..bcca4b17e8f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -7,6 +7,7 @@ #include "mt7921.h" #include "../dma.h" #include "../mt76_connac2_mac.h" +#include "regd.h" #include "mcu.h" #define MT_WTBL_TXRX_CAP_RATE_OFFSET 7 @@ -697,6 +698,8 @@ void mt7921_mac_reset_work(struct work_struct *work) IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_vif_connect_iter, NULL); mt76_connac_power_save_sched(&dev->mt76.phy, pm); + + mt7921_regd_change(&dev->phy, "00"); } void mt7921_coredump_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 00ca3d3f3ef0..dfe8cbd7dfa5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -1027,8 +1027,16 @@ void mt7921_scan_work(struct work_struct *work) rxd = (struct mt76_connac2_mcu_rxd *)skb->data; if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) { ieee80211_sched_scan_results(phy->mt76->hw); - } else if (test_and_clear_bit(MT76_HW_SCANNING, - &phy->mt76->state)) { + } else if (rxd->eid == MCU_EVENT_SCAN_DONE) { + struct mt76_connac_hw_scan_done *event = NULL; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt76_connac_hw_scan_done *)skb->data; + mt7921_regd_change(phy, event->alpha2); + } + + if (test_and_clear_bit(MT76_HW_SCANNING, + &phy->mt76->state)) { struct cfg80211_scan_info info = { .aborted = false, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 1e2afa736cdf..4e455aad2f4c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -487,7 +487,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) goto out; } } - ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR); + + ret = mt7921_regd_init(phy); out: release_firmware(fw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index f795ee2eb446..b53fa1f5c6db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -111,26 +111,93 @@ int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, EXPORT_SYMBOL_GPL(mt7921_mcu_regd_update); void mt7921_regd_notifier(struct wiphy *wiphy, - struct regulatory_request *request) + 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; + + /* 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(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2)); - dev->mt76.region = request->dfs_region; - dev->country_ie_env = request->country_ie_env; + memcpy(mdev->alpha2, req->alpha2, 2); + mdev->region = req->dfs_region; + dev->country_ie_env = req->country_ie_env; - if (request->initiator == NL80211_REGDOM_SET_BY_USER) { + if (req->initiator == NL80211_REGDOM_SET_BY_USER) { if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0') wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; else wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; } + dev->regd_change = true; + if (pm->suspended) return; - mt7921_mcu_regd_update(dev, request->alpha2, - request->country_ie_env); + mt7921_mcu_regd_update(dev, req->alpha2, + req->country_ie_env); +} + +static bool +mt7921_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 mt7921_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 (!mt7921_regd_is_valid_alpha2(alpha2) || + !mt7921_regd_clc_supported(dev)) + 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 mt7921_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR); +} +EXPORT_SYMBOL_GPL(mt7921_regd_change); + +int mt7921_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/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h index da5bd4450312..f125427192b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -11,5 +11,7 @@ int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); bool mt7921_regd_clc_supported(struct mt792x_dev *dev); +int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2); +int mt7921_regd_init(struct mt792x_phy *phy); #endif -- 2.45.2 Add regd_user flag to block automatic regulatory domain updates if set by user. Signed-off-by: JB Tsai --- drivers/net/wireless/mediatek/mt76/mt7921/mcu.c | 1 + drivers/net/wireless/mediatek/mt76/mt7921/regd.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 4e455aad2f4c..3806798081a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -419,6 +419,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) u8 *clc_base = NULL, hw_encap = 0; dev->phy.clc_chan_conf = 0xff; + dev->regd_user = false; if (!mt7921_regd_clc_supported(dev)) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index b53fa1f5c6db..58d68d7cf1a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -118,6 +118,10 @@ void mt7921_regd_notifier(struct wiphy *wiphy, 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; + /* do not need to update the same country twice */ if (!memcmp(req->alpha2, mdev->alpha2, 2) && dev->country_ie_env == req->country_ie_env) @@ -169,7 +173,8 @@ int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2) return 0; if (!mt7921_regd_is_valid_alpha2(alpha2) || - !mt7921_regd_clc_supported(dev)) + !mt7921_regd_clc_supported(dev) || + dev->regd_user) return -EINVAL; if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') -- 2.45.2