[PATCH ath-next v2] wifi: ath12k: combine channel list for split-phy devices in single-wiphy

Kang Yang kang.yang at oss.qualcomm.com
Wed May 14 23:34:39 PDT 2025



On 5/6/2025 6:56 PM, Rameshkumar Sundaram wrote:
> 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


Offline sync with aditya:

This patch and patch [1][2] will make WCN7850 update regulatory rules 
and trigger scan incorrectly.

They are based on the design that one chip only supports one band.

This design will limit WCN7850 to one band.
During init, WCN7850 will be limited to one band(such as 5G band) due to 
patch[1]. Then will only update 5G regulatory rules and trigger 5G scan.
If manually set country code by "iw reg set XX", WCN7850 will be limited 
to 2G band due to patch[2]. Then similar issue will happen.


If QCN supports multi bands like WCN i think you will have the same problem.

WIN team needs to figure a new design for this issue to support multi 
bands on one chip too.



[1] 
https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git/commit/?h=pending&id=b7544de8a2984e61b95c58c1c6c1e8ce659b1021
[2] 
https://git.kernel.org/pub/scm/linux/kernel/git/ath/ath.git/commit/?h=pending&id=13324cecbb2c390a11f1fbfe87f3a5e62d6e4591



> 
> Signed-off-by: Rameshkumar Sundaram <rameshkumar.sundaram at oss.qualcomm.com>
> ---
> 
> *v2:
>    - Fixed frequency conversion from KHZ to MHZ in freq_to_idx()
> 
> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 93 +++++++++++++++++++++++++--
>   drivers/net/wireless/ath/ath12k/reg.c | 13 ++++
>   drivers/net/wireless/ath/ath12k/wmi.c |  9 ++-
>   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 4dae941c9615..23cbf348e836 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -4131,8 +4131,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))


Though WCN7850 won't reach here, but this is also not good for those 
chips who support multi bands.


>   			return ar;
>   	}
>   
> @@ -10925,6 +10926,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[])
> @@ -10935,6 +10962,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) +
> @@ -10956,7 +10984,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);
> @@ -10973,6 +11000,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) {
> @@ -10991,7 +11034,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);
> @@ -11004,6 +11046,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) {
> @@ -11022,7 +11084,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);
> @@ -11039,6 +11100,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 7048834e0d14..5c577188fa74 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;

Here will make WCN7850 only updates one band's channel list.

>   
>   			num_channels++;
>   		}
> @@ -204,6 +210,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;


Here will make WCN7850 only updates one band's channel list.


> +
>   			/* 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 ea303dca38b5..dfd36491c024 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5887,9 +5887,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:
> 
> base-commit: 21346cd925c2567d5f56cdb1421c94815ac10221




More information about the ath12k mailing list