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@xxxxxxxxxxxxxxxx> > --- > 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@xxxxxxxxxxx>