aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRameshkumar Sundaram <[email protected]>2025-05-22 11:15:14 +0000
committerJeff Johnson <[email protected]>2025-06-23 14:28:32 +0000
commitacc152f9be205d76771f8156002d55c3fcd21252 (patch)
tree6f89bd9e5e4f2ea267bc2de97b81ad1f332fe109
parentwifi: ath12k: Split scan request for split band device (diff)
downloadkernel-acc152f9be205d76771f8156002d55c3fcd21252.tar.gz
kernel-acc152f9be205d76771f8156002d55c3fcd21252.zip
wifi: ath12k: combine channel list for split-phy devices in single-wiphy
When two split-phy devices that support overlapping frequency ranges within the same band are grouped into an ath12k hardware (HW) setup, they share a common wiphy instance. Consequently, the channel list (wiphy->bands[]) becomes unified across all associated radios (ar). For reference, the devices are: 2.4 GHz + 5 GHz Low Band 5 GHz High Band + 6 GHz The first radio probed within the 5 GHz range (say 5 GHz Low Band) updates its sband reference (&ar->mac.sbands[NL80211_BAND_5GHZ]) within wiphy->bands[]. However, when the second 5 GHz radio (5 GHz High Band) is probed, it replaces the existing wiphy->bands[] entry with its own sub-band reference. As a result, wiphy->bands[] always reflects the channel list from the most recently probed radio in that band, restricting supported channels to those within its specific range for upper-layer. Fix this by updating the wiphy->bands[] to just enable the channels of current radio when there exist a radio which already has set it. This will make sure wiphy->bands[] holds reference of first radio which got probed in 5 GHz band and subsequent radio just updates the channel list in the same address space. Since same sband memory space is shared between radios of a band, while determining the allowed frequency range of radio, its frequency limits (ar->freq_range.start_freq, end_freq) should be used. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 Signed-off-by: Rameshkumar Sundaram <[email protected]> Reviewed-by: Vasanthakumar Thiagarajan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jeff Johnson <[email protected]>
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c93
-rw-r--r--drivers/net/wireless/ath/ath12k/reg.c13
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c9
3 files changed, 109 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 302ad6da48f4..fa069ac30e0d 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4152,8 +4152,9 @@ ath12k_mac_select_scan_device(struct ieee80211_hw *hw,
band = NL80211_BAND_6GHZ;
for_each_ar(ah, ar, i) {
- /* TODO 5 GHz low high split changes */
- if (ar->mac.sbands[band].channels)
+ if (ar->mac.sbands[band].channels &&
+ center_freq >= KHZ_TO_MHZ(ar->freq_range.start_freq) &&
+ center_freq <= KHZ_TO_MHZ(ar->freq_range.end_freq))
return ar;
}
@@ -11881,6 +11882,32 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band)
return 0;
}
+static int ath12k_mac_update_band(struct ath12k *ar,
+ struct ieee80211_supported_band *orig_band,
+ struct ieee80211_supported_band *new_band)
+{
+ int i;
+
+ if (!orig_band || !new_band)
+ return -EINVAL;
+
+ if (orig_band->band != new_band->band)
+ return -EINVAL;
+
+ for (i = 0; i < new_band->n_channels; i++) {
+ if (new_band->channels[i].flags & IEEE80211_CHAN_DISABLED)
+ continue;
+ /* An enabled channel in new_band should not be already enabled
+ * in the orig_band
+ */
+ if (WARN_ON(!(orig_band->channels[i].flags &
+ IEEE80211_CHAN_DISABLED)))
+ return -EINVAL;
+ orig_band->channels[i].flags &= ~IEEE80211_CHAN_DISABLED;
+ }
+ return 0;
+}
+
static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
u32 supported_bands,
struct ieee80211_supported_band *bands[])
@@ -11891,6 +11918,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
u32 phy_id, freq_low, freq_high;
struct ath12k_hw *ah = ar->ah;
void *channels;
+ int ret;
BUILD_BUG_ON((ARRAY_SIZE(ath12k_2ghz_channels) +
ARRAY_SIZE(ath12k_5ghz_channels) +
@@ -11912,7 +11940,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_g_rates_size;
band->bitrates = ath12k_g_rates;
- bands[NL80211_BAND_2GHZ] = band;
if (ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2GHZ_CAP);
@@ -11929,6 +11956,22 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
reg_cap->high_2ghz_chan);
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
+
+ if (!bands[NL80211_BAND_2GHZ]) {
+ bands[NL80211_BAND_2GHZ] = band;
+ } else {
+ /* Split mac in same band under same wiphy */
+ ret = ath12k_mac_update_band(ar, bands[NL80211_BAND_2GHZ], band);
+ if (ret) {
+ kfree(channels);
+ band->channels = NULL;
+ return ret;
+ }
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 2 GHz split mac with start freq %d end freq %d",
+ ar->pdev->pdev_id,
+ KHZ_TO_MHZ(ar->freq_range.start_freq),
+ KHZ_TO_MHZ(ar->freq_range.end_freq));
+ }
}
if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) {
@@ -11947,7 +11990,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
- bands[NL80211_BAND_6GHZ] = band;
freq_low = max(reg_cap->low_5ghz_chan,
ab->reg_freq_6ghz.start_freq);
@@ -11960,6 +12002,26 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
ah->use_6ghz_regd = true;
+
+ if (!bands[NL80211_BAND_6GHZ]) {
+ bands[NL80211_BAND_6GHZ] = band;
+ } else {
+ /* Split mac in same band under same wiphy */
+ ret = ath12k_mac_update_band(ar,
+ bands[NL80211_BAND_6GHZ],
+ band);
+ if (ret) {
+ kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
+ ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
+ kfree(channels);
+ band->channels = NULL;
+ return ret;
+ }
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 6 GHz split mac with start freq %d end freq %d",
+ ar->pdev->pdev_id,
+ KHZ_TO_MHZ(ar->freq_range.start_freq),
+ KHZ_TO_MHZ(ar->freq_range.end_freq));
+ }
}
if (reg_cap->low_5ghz_chan < ATH12K_MIN_6GHZ_FREQ) {
@@ -11978,7 +12040,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
- bands[NL80211_BAND_5GHZ] = band;
if (ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5GHZ_CAP);
@@ -11995,6 +12056,28 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
reg_cap->high_5ghz_chan);
ath12k_mac_update_freq_range(ar, freq_low, freq_high);
+
+ if (!bands[NL80211_BAND_5GHZ]) {
+ bands[NL80211_BAND_5GHZ] = band;
+ } else {
+ /* Split mac in same band under same wiphy */
+ ret = ath12k_mac_update_band(ar,
+ bands[NL80211_BAND_5GHZ],
+ band);
+ if (ret) {
+ kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
+ ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
+ kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
+ ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL;
+ kfree(channels);
+ band->channels = NULL;
+ return ret;
+ }
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 5 GHz split mac with start freq %d end freq %d",
+ ar->pdev->pdev_id,
+ KHZ_TO_MHZ(ar->freq_range.start_freq),
+ KHZ_TO_MHZ(ar->freq_range.end_freq));
+ }
}
}
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 28bb26d2dd82..a7b9ecc14c39 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -176,6 +176,12 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
if (bands[band]->channels[i].flags &
IEEE80211_CHAN_DISABLED)
continue;
+ /* Skip Channels that are not in current radio's range */
+ if (bands[band]->channels[i].center_freq <
+ KHZ_TO_MHZ(ar->freq_range.start_freq) ||
+ bands[band]->channels[i].center_freq >
+ KHZ_TO_MHZ(ar->freq_range.end_freq))
+ continue;
num_channels++;
}
@@ -207,6 +213,13 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
if (channel->flags & IEEE80211_CHAN_DISABLED)
continue;
+ /* Skip Channels that are not in current radio's range */
+ if (bands[band]->channels[i].center_freq <
+ KHZ_TO_MHZ(ar->freq_range.start_freq) ||
+ bands[band]->channels[i].center_freq >
+ KHZ_TO_MHZ(ar->freq_range.end_freq))
+ continue;
+
/* TODO: Set to true/false based on some condition? */
ch->allow_ht = true;
ch->allow_vht = true;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 465f877fc0fb..1b82fe0e5099 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6445,9 +6445,16 @@ static int freq_to_idx(struct ath12k *ar, int freq)
if (!sband)
continue;
- for (ch = 0; ch < sband->n_channels; ch++, idx++)
+ for (ch = 0; ch < sband->n_channels; ch++, idx++) {
+ if (sband->channels[ch].center_freq <
+ KHZ_TO_MHZ(ar->freq_range.start_freq) ||
+ sband->channels[ch].center_freq >
+ KHZ_TO_MHZ(ar->freq_range.end_freq))
+ continue;
+
if (sband->channels[ch].center_freq == freq)
goto exit;
+ }
}
exit: