Skip to content

Commit d9dbc6b

Browse files
Baochen Qiangjeff-t-johnson
authored andcommitted
wifi: ath12k: don't activate more links than firmware supports
In case of ML connection, currently all useful links are activated at ASSOC stage: ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif)) this results in firmware crash when the number of links activated on the same device is more than supported. Since firmware supports activating at most 2 links for a ML connection, to avoid firmware crash, host needs to select 2 links out of the useful links. As the assoc link has already been chosen, the question becomes how to determine partner links. A straightforward principle applied here is that the resulted combination should achieve the best throughput. For that purpose, ideally various factors like bandwidth, RSSI etc should be considered. But that would be too complicate. To make it easy, the choice is to only take hardware modes into consideration. The SBS (single band simultaneously) mode frequency range covers 5 GHz and 6 GHz bands. In this mode, the two individual MACs are both active, with one working on 5g-high band and the other on 5g-low band (from hardware perspective 5 GHz and 6 GHz bands are referred to as a 'large' single 5 GHz band). The DBS (dual band simultaneously) mode covers 2 GHz band and the 'large' 5 GHz band, with one MAC working on 2 GHz band and the other working on 5 GHz band or 6 GHz band. Since 5,6 GHz bands could provide higher bandwidth than 2 GHz band, the preference is given to SBS mode. Other hardware modes results in only one working MAC at any given time, so it is chosen only when both SBS are DBS are not possible. For each hardware mode, if there are more than one partner candidate, just choose the first one. For now only single device MLO case is handled as it is easy. Other cases could be addressed in the future. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1 Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Signed-off-by: Baochen Qiang <[email protected]> Reviewed-by: Vasanthakumar Thiagarajan <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jeff Johnson <[email protected]>
1 parent 2296038 commit d9dbc6b

File tree

2 files changed

+141
-2
lines changed

2 files changed

+141
-2
lines changed

drivers/net/wireless/ath/ath12k/core.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,12 @@ struct ath12k_sta {
601601
#define ATH12K_NUM_CHANS 101
602602
#define ATH12K_MAX_5GHZ_CHAN 173
603603

604+
static inline bool ath12k_is_2ghz_channel_freq(u32 freq)
605+
{
606+
return freq >= ATH12K_MIN_2GHZ_FREQ &&
607+
freq <= ATH12K_MAX_2GHZ_FREQ;
608+
}
609+
604610
enum ath12k_hw_state {
605611
ATH12K_HW_STATE_OFF,
606612
ATH12K_HW_STATE_ON,

drivers/net/wireless/ath/ath12k/mac.c

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6095,6 +6095,122 @@ static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab,
60956095
return 0;
60966096
}
60976097

6098+
static bool ath12k_mac_are_sbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2)
6099+
{
6100+
if (!ath12k_mac_is_hw_sbs_capable(ab))
6101+
return false;
6102+
6103+
if (ath12k_is_2ghz_channel_freq(freq_1) ||
6104+
ath12k_is_2ghz_channel_freq(freq_2))
6105+
return false;
6106+
6107+
return !ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_1, freq_2);
6108+
}
6109+
6110+
static bool ath12k_mac_are_dbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2)
6111+
{
6112+
if (!ath12k_mac_is_hw_dbs_capable(ab))
6113+
return false;
6114+
6115+
return !ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_1, freq_2);
6116+
}
6117+
6118+
static int ath12k_mac_select_links(struct ath12k_base *ab,
6119+
struct ieee80211_vif *vif,
6120+
struct ieee80211_hw *hw,
6121+
u16 *selected_links)
6122+
{
6123+
unsigned long useful_links = ieee80211_vif_usable_links(vif);
6124+
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
6125+
u8 num_useful_links = hweight_long(useful_links);
6126+
struct ieee80211_chanctx_conf *chanctx;
6127+
struct ath12k_link_vif *assoc_arvif;
6128+
u32 assoc_link_freq, partner_freq;
6129+
u16 sbs_links = 0, dbs_links = 0;
6130+
struct ieee80211_bss_conf *info;
6131+
struct ieee80211_channel *chan;
6132+
struct ieee80211_sta *sta;
6133+
struct ath12k_sta *ahsta;
6134+
u8 link_id;
6135+
6136+
/* activate all useful links if less than max supported */
6137+
if (num_useful_links <= ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) {
6138+
*selected_links = useful_links;
6139+
return 0;
6140+
}
6141+
6142+
/* only in station mode we can get here, so it's safe
6143+
* to use ap_addr
6144+
*/
6145+
rcu_read_lock();
6146+
sta = ieee80211_find_sta(vif, vif->cfg.ap_addr);
6147+
if (!sta) {
6148+
rcu_read_unlock();
6149+
ath12k_warn(ab, "failed to find sta with addr %pM\n", vif->cfg.ap_addr);
6150+
return -EINVAL;
6151+
}
6152+
6153+
ahsta = ath12k_sta_to_ahsta(sta);
6154+
assoc_arvif = wiphy_dereference(hw->wiphy, ahvif->link[ahsta->assoc_link_id]);
6155+
info = ath12k_mac_get_link_bss_conf(assoc_arvif);
6156+
chanctx = rcu_dereference(info->chanctx_conf);
6157+
assoc_link_freq = chanctx->def.chan->center_freq;
6158+
rcu_read_unlock();
6159+
ath12k_dbg(ab, ATH12K_DBG_MAC, "assoc link %u freq %u\n",
6160+
assoc_arvif->link_id, assoc_link_freq);
6161+
6162+
/* assoc link is already activated and has to be kept active,
6163+
* only need to select a partner link from others.
6164+
*/
6165+
useful_links &= ~BIT(assoc_arvif->link_id);
6166+
for_each_set_bit(link_id, &useful_links, IEEE80211_MLD_MAX_NUM_LINKS) {
6167+
info = wiphy_dereference(hw->wiphy, vif->link_conf[link_id]);
6168+
if (!info) {
6169+
ath12k_warn(ab, "failed to get link info for link: %u\n",
6170+
link_id);
6171+
return -ENOLINK;
6172+
}
6173+
6174+
chan = info->chanreq.oper.chan;
6175+
if (!chan) {
6176+
ath12k_warn(ab, "failed to get chan for link: %u\n", link_id);
6177+
return -EINVAL;
6178+
}
6179+
6180+
partner_freq = chan->center_freq;
6181+
if (ath12k_mac_are_sbs_chan(ab, assoc_link_freq, partner_freq)) {
6182+
sbs_links |= BIT(link_id);
6183+
ath12k_dbg(ab, ATH12K_DBG_MAC, "new SBS link %u freq %u\n",
6184+
link_id, partner_freq);
6185+
continue;
6186+
}
6187+
6188+
if (ath12k_mac_are_dbs_chan(ab, assoc_link_freq, partner_freq)) {
6189+
dbs_links |= BIT(link_id);
6190+
ath12k_dbg(ab, ATH12K_DBG_MAC, "new DBS link %u freq %u\n",
6191+
link_id, partner_freq);
6192+
continue;
6193+
}
6194+
6195+
ath12k_dbg(ab, ATH12K_DBG_MAC, "non DBS/SBS link %u freq %u\n",
6196+
link_id, partner_freq);
6197+
}
6198+
6199+
/* choose the first candidate no matter how many is in the list */
6200+
if (sbs_links)
6201+
link_id = __ffs(sbs_links);
6202+
else if (dbs_links)
6203+
link_id = __ffs(dbs_links);
6204+
else
6205+
link_id = ffs(useful_links) - 1;
6206+
6207+
ath12k_dbg(ab, ATH12K_DBG_MAC, "select partner link %u\n", link_id);
6208+
6209+
*selected_links = BIT(assoc_arvif->link_id) | BIT(link_id);
6210+
6211+
return 0;
6212+
}
6213+
60986214
static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
60996215
struct ieee80211_vif *vif,
61006216
struct ieee80211_sta *sta,
@@ -6108,6 +6224,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
61086224
struct ath12k_link_vif *arvif;
61096225
struct ath12k_link_sta *arsta;
61106226
unsigned long valid_links;
6227+
u16 selected_links = 0;
61116228
u8 link_id = 0, i;
61126229
struct ath12k *ar;
61136230
int ret;
@@ -6179,8 +6296,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
61796296
* about to move to the associated state.
61806297
*/
61816298
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
6182-
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC)
6183-
ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif));
6299+
old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) {
6300+
/* TODO: for now only do link selection for single device
6301+
* MLO case. Other cases would be handled in the future.
6302+
*/
6303+
ab = ah->radio[0].ab;
6304+
if (ab->ag->num_devices == 1) {
6305+
ret = ath12k_mac_select_links(ab, vif, hw, &selected_links);
6306+
if (ret) {
6307+
ath12k_warn(ab,
6308+
"failed to get selected links: %d\n", ret);
6309+
goto exit;
6310+
}
6311+
} else {
6312+
selected_links = ieee80211_vif_usable_links(vif);
6313+
}
6314+
6315+
ieee80211_set_active_links(vif, selected_links);
6316+
}
61846317

61856318
/* Handle all the other state transitions in generic way */
61866319
valid_links = ahsta->links_map;

0 commit comments

Comments
 (0)