[PATCH ath-next 1/2] wifi: ath12k: Prepare ahvif scan link for parallel scan
Mahendran P
quic_mahep at quicinc.com
Mon Apr 28 21:36:11 PDT 2025
On 4/28/2025 8:49 PM, Rameshkumar Sundaram wrote:
> When two split-phy devices that support overlapping frequency ranges within
> the same band(say 5 GHz low and 5 GHz high) 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).
>
> When a scan is triggered with frequency list containing frequencies of
> both 5 GHz low and 5 GHz high, mac80211 generates a single scan request
> to driver with all the frequencies. This is because mac80211 splits the
> scan request based on band.
>
> ath12k checks the first frequency in the requested scan frequency list and
> initiates scan to corresponding radio's(ar) firmware with all the
> frequencies. Firmware rejects this scan since some of the frequencies in
> the scan request are not supported, resulting in a scan failure.
> To fix this ath12k driver should split the scan request into multiple
> scans based on requested frequencies and schedule them to corresponding
> underlying radio(s) in parallel.
>
> Currently, ath12k driver assigns the scan link (link 15) in ahvif->links[]
> for scan vdev creation. However, with parallel scan support being
> introduced in the following patch, multiple radios (e.g., 5 GHz low and
> 5 GHz high) in the same HW group may attempt to use the same scan link
> concurrently, causing conflicts where the vdev created by one radio could
> be deleted and re-initialized by another.
>
> To address this, reserve space for additional scan links for each radio in
> a MLO group and allow subsequent radios to use different available scan
> links (ahvif->link[15..MAX_SCAN_LINKS]) when scan link (15) is
> pre-occupied.
> While at it, rename ATH12K_DEFAULT_SCAN_LINK as ATH12K_FIRST_SCAN_LINK
> as there is no longer only one scan link.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Rameshkumar Sundaram <rameshkumar.sundaram at oss.qualcomm.com>
> ---
> drivers/net/wireless/ath/ath12k/core.h | 2 +-
> drivers/net/wireless/ath/ath12k/mac.c | 49 +++++++++++++++++++-------
> drivers/net/wireless/ath/ath12k/mac.h | 7 ++--
> 3 files changed, 42 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 4b8f434e3e9a..0d512818ee96 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -352,7 +352,7 @@ struct ath12k_vif {
> struct ath12k_link_vif __rcu *link[ATH12K_NUM_MAX_LINKS];
> struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS];
> /* indicates bitmap of link vif created in FW */
> - u16 links_map;
> + u32 links_map;
> u8 last_scan_link;
>
> /* Must be last - ends in a flexible-array member.
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 8949073c0163..6dab2f3a9e0d 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -3483,7 +3483,7 @@ static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah,
> /* If this is the first link arvif being created for an ML VIF
> * use the preallocated deflink memory except for scan arvifs
> */
> - if (!ahvif->links_map && link_id != ATH12K_DEFAULT_SCAN_LINK) {
> + if (!ahvif->links_map && link_id < ATH12K_FIRST_SCAN_LINK) {
> arvif = &ahvif->deflink;
>
> if (vif->type == NL80211_IFTYPE_STATION)
> @@ -4475,11 +4475,12 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
> struct ath12k_link_vif *arvif;
> struct ath12k_hw *ah = ahvif->ah;
> unsigned long links = ahvif->links_map;
> + unsigned long scan_links_map;
> u8 link_id;
>
> lockdep_assert_wiphy(ah->hw->wiphy);
>
> - for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
> + for_each_set_bit(link_id, &links, ATH12K_NUM_MAX_LINKS) {
> arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]);
>
> if (!arvif || !arvif->is_created)
> @@ -4489,10 +4490,20 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar)
> return link_id;
> }
>
> - /* input ar is not assigned to any of the links of ML VIF, use scan
> - * link (15) for scan vdev creation.
> + /* input ar is not assigned to any of the links of ML VIF, use next
> + * available scan link for scan vdev creation. There are cases where
> + * single scan req needs to be split in driver and initiate separate
> + * scan requests to firmware based on device.
> */
> - return ATH12K_DEFAULT_SCAN_LINK;
> +
> + /* Unset all non-scan links (0-14) of scan_links_map so that ffs() will
> + * choose an available link among scan links (i.e link id >= 15)
> + */
> + scan_links_map = ~ahvif->links_map & ATH12K_SCAN_LINKS_MASK;
> + if (scan_links_map)
> + return __ffs(scan_links_map);
> +
> + return ATH12K_FIRST_SCAN_LINK;
> }
>
> static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
> @@ -4523,9 +4534,16 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
>
> /* check if any of the links of ML VIF is already started on
> * radio(ar) corresponding to given scan frequency and use it,
> - * if not use scan link (link 15) for scan purpose.
> + * if not use scan link (link id >= 15) for scan purpose.
> */
> link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar);
> + /* All scan links are occupied. ideally this shouldn't happen as
> + * mac80211 won't schedule scan for same band until ongoing scan is
> + * completed, don't try to exceed max links just in case if it happens.
> + */
> + if (link_id >= ATH12K_NUM_MAX_LINKS)
> + return -EBUSY;
> +
> arvif = ath12k_mac_assign_link_vif(ah, vif, link_id);
>
> ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac link ID %d selected for scan",
> @@ -8654,7 +8672,8 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
> struct ath12k_hw *ah = hw->priv;
> struct ath12k *ar;
> struct ath12k_base *ab;
> - u8 link_id = arvif->link_id;
> + u8 link_id = arvif->link_id, scan_link_id;
> + unsigned long scan_link_map;
> int ret;
>
> lockdep_assert_wiphy(hw->wiphy);
> @@ -8673,12 +8692,16 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw,
> * and now we want to create for actual usage.
> */
> if (ieee80211_vif_is_mld(vif)) {
> - scan_arvif = wiphy_dereference(hw->wiphy,
> - ahvif->link[ATH12K_DEFAULT_SCAN_LINK]);
> - if (scan_arvif && scan_arvif->ar == ar) {
> - ar->scan.arvif = NULL;
> - ath12k_mac_remove_link_interface(hw, scan_arvif);
> - ath12k_mac_unassign_link_vif(scan_arvif);
> + scan_link_map = ahvif->links_map & ATH12K_SCAN_LINKS_MASK;
> + for_each_set_bit(scan_link_id, &scan_link_map, ATH12K_NUM_MAX_LINKS) {
> + scan_arvif = wiphy_dereference(hw->wiphy,
> + ahvif->link[scan_link_id]);
> + if (scan_arvif && scan_arvif->ar == ar) {
> + ar->scan.arvif = NULL;
> + ath12k_mac_remove_link_interface(hw, scan_arvif);
> + ath12k_mac_unassign_link_vif(scan_arvif);
> + break;
> + }
> }
> }
>
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index da37332352fe..8ec4a890172c 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -51,8 +51,11 @@ struct ath12k_generic_iter {
> /* Default link after the IEEE802.11 defined Max link id limit
> * for driver usage purpose.
> */
> -#define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
> -#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
> +#define ATH12K_FIRST_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
> +#define ATH12K_SCAN_MAX_LINKS ATH12K_GROUP_MAX_RADIO
> +/* Define 1 scan link for each radio for parallel scan purposes */
> +#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + ATH12K_SCAN_MAX_LINKS)
> +#define ATH12K_SCAN_LINKS_MASK GENMASK(ATH12K_NUM_MAX_LINKS, IEEE80211_MLD_MAX_NUM_LINKS)
>
> enum ath12k_supported_bw {
> ATH12K_BW_20 = 0,
Reviewed-by: Mahendran P <quic_mahep at quicinc.com>
More information about the ath12k
mailing list