Commit acc152f9 authored by Rameshkumar Sundaram's avatar Rameshkumar Sundaram Committed by Jeff Johnson
Browse files

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: default avatarRameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: default avatarVasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250522111514.3735107-1-rameshkumar.sundaram@oss.qualcomm.com


Signed-off-by: default avatarJeff Johnson <jeff.johnson@oss.qualcomm.com>
parent feed05f1
Loading
Loading
Loading
Loading
+88 −5
Original line number Diff line number Diff line
@@ -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));
			}
		}
	}

+13 −0
Original line number Diff line number Diff line
@@ -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;
+8 −1
Original line number Diff line number Diff line
@@ -6445,10 +6445,17 @@ 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:
	return idx;