Skip to content

Commit 2296038

Browse files
Baochen Qiangjeff-t-johnson
authored andcommitted
wifi: ath12k: update link active in case two links fall on the same MAC
In case of two links established on the same device in an ML connection, depending on device's hardware mode capability, it is possible that both links fall on the same MAC. Currently, no specific action is taken to address this but just keep both links active. However this would result in lower throughput compared to even one link, because switching between these two links on the resulted MAC significantly impacts throughput. Check if both links fall in the frequency range of a single MAC. If so, send WMI_MLO_LINK_SET_ACTIVE_CMDID command to firmware such that firmware can deactivate one of them. Note the decision of which link getting deactivated is made by firmware, host only sends the vdev lists. 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 c36f2cd commit 2296038

File tree

2 files changed

+228
-1
lines changed

2 files changed

+228
-1
lines changed

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

Lines changed: 226 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5890,6 +5890,211 @@ static int ath12k_mac_handle_link_sta_state(struct ieee80211_hw *hw,
58905890
return ret;
58915891
}
58925892

5893+
static bool ath12k_mac_is_freq_on_mac(struct ath12k_hw_mode_freq_range_arg *freq_range,
5894+
u32 freq, u8 mac_id)
5895+
{
5896+
return (freq >= freq_range[mac_id].low_2ghz_freq &&
5897+
freq <= freq_range[mac_id].high_2ghz_freq) ||
5898+
(freq >= freq_range[mac_id].low_5ghz_freq &&
5899+
freq <= freq_range[mac_id].high_5ghz_freq);
5900+
}
5901+
5902+
static bool
5903+
ath12k_mac_2_freq_same_mac_in_freq_range(struct ath12k_base *ab,
5904+
struct ath12k_hw_mode_freq_range_arg *freq_range,
5905+
u32 freq_link1, u32 freq_link2)
5906+
{
5907+
u8 i;
5908+
5909+
for (i = 0; i < MAX_RADIOS; i++) {
5910+
if (ath12k_mac_is_freq_on_mac(freq_range, freq_link1, i) &&
5911+
ath12k_mac_is_freq_on_mac(freq_range, freq_link2, i))
5912+
return true;
5913+
}
5914+
5915+
return false;
5916+
}
5917+
5918+
static bool ath12k_mac_is_hw_dbs_capable(struct ath12k_base *ab)
5919+
{
5920+
return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
5921+
ab->wmi_ab.svc_map) &&
5922+
ab->wmi_ab.hw_mode_info.support_dbs;
5923+
}
5924+
5925+
static bool ath12k_mac_2_freq_same_mac_in_dbs(struct ath12k_base *ab,
5926+
u32 freq_link1, u32 freq_link2)
5927+
{
5928+
struct ath12k_hw_mode_freq_range_arg *freq_range;
5929+
5930+
if (!ath12k_mac_is_hw_dbs_capable(ab))
5931+
return true;
5932+
5933+
freq_range = ab->wmi_ab.hw_mode_info.freq_range_caps[ATH12K_HW_MODE_DBS];
5934+
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, freq_range,
5935+
freq_link1, freq_link2);
5936+
}
5937+
5938+
static bool ath12k_mac_is_hw_sbs_capable(struct ath12k_base *ab)
5939+
{
5940+
return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT,
5941+
ab->wmi_ab.svc_map) &&
5942+
ab->wmi_ab.hw_mode_info.support_sbs;
5943+
}
5944+
5945+
static bool ath12k_mac_2_freq_same_mac_in_sbs(struct ath12k_base *ab,
5946+
u32 freq_link1, u32 freq_link2)
5947+
{
5948+
struct ath12k_hw_mode_info *info = &ab->wmi_ab.hw_mode_info;
5949+
struct ath12k_hw_mode_freq_range_arg *sbs_uppr_share;
5950+
struct ath12k_hw_mode_freq_range_arg *sbs_low_share;
5951+
struct ath12k_hw_mode_freq_range_arg *sbs_range;
5952+
5953+
if (!ath12k_mac_is_hw_sbs_capable(ab))
5954+
return true;
5955+
5956+
if (ab->wmi_ab.sbs_lower_band_end_freq) {
5957+
sbs_uppr_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_UPPER_SHARE];
5958+
sbs_low_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_LOWER_SHARE];
5959+
5960+
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_low_share,
5961+
freq_link1, freq_link2) ||
5962+
ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_uppr_share,
5963+
freq_link1, freq_link2);
5964+
}
5965+
5966+
sbs_range = info->freq_range_caps[ATH12K_HW_MODE_SBS];
5967+
return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_range,
5968+
freq_link1, freq_link2);
5969+
}
5970+
5971+
static bool ath12k_mac_freqs_on_same_mac(struct ath12k_base *ab,
5972+
u32 freq_link1, u32 freq_link2)
5973+
{
5974+
return ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_link1, freq_link2) &&
5975+
ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_link1, freq_link2);
5976+
}
5977+
5978+
static int ath12k_mac_mlo_sta_set_link_active(struct ath12k_base *ab,
5979+
enum wmi_mlo_link_force_reason reason,
5980+
enum wmi_mlo_link_force_mode mode,
5981+
u8 *mlo_vdev_id_lst,
5982+
u8 num_mlo_vdev,
5983+
u8 *mlo_inactive_vdev_lst,
5984+
u8 num_mlo_inactive_vdev)
5985+
{
5986+
struct wmi_mlo_link_set_active_arg param = {0};
5987+
u32 entry_idx, entry_offset, vdev_idx;
5988+
u8 vdev_id;
5989+
5990+
param.reason = reason;
5991+
param.force_mode = mode;
5992+
5993+
for (vdev_idx = 0; vdev_idx < num_mlo_vdev; vdev_idx++) {
5994+
vdev_id = mlo_vdev_id_lst[vdev_idx];
5995+
entry_idx = vdev_id / 32;
5996+
entry_offset = vdev_id % 32;
5997+
if (entry_idx >= WMI_MLO_LINK_NUM_SZ) {
5998+
ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d",
5999+
entry_idx, num_mlo_vdev, vdev_id);
6000+
return -EINVAL;
6001+
}
6002+
param.vdev_bitmap[entry_idx] |= 1 << entry_offset;
6003+
/* update entry number if entry index changed */
6004+
if (param.num_vdev_bitmap < entry_idx + 1)
6005+
param.num_vdev_bitmap = entry_idx + 1;
6006+
}
6007+
6008+
ath12k_dbg(ab, ATH12K_DBG_MAC,
6009+
"num_vdev_bitmap %d vdev_bitmap[0] = 0x%x, vdev_bitmap[1] = 0x%x",
6010+
param.num_vdev_bitmap, param.vdev_bitmap[0], param.vdev_bitmap[1]);
6011+
6012+
if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) {
6013+
for (vdev_idx = 0; vdev_idx < num_mlo_inactive_vdev; vdev_idx++) {
6014+
vdev_id = mlo_inactive_vdev_lst[vdev_idx];
6015+
entry_idx = vdev_id / 32;
6016+
entry_offset = vdev_id % 32;
6017+
if (entry_idx >= WMI_MLO_LINK_NUM_SZ) {
6018+
ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d",
6019+
entry_idx, num_mlo_inactive_vdev, vdev_id);
6020+
return -EINVAL;
6021+
}
6022+
param.inactive_vdev_bitmap[entry_idx] |= 1 << entry_offset;
6023+
/* update entry number if entry index changed */
6024+
if (param.num_inactive_vdev_bitmap < entry_idx + 1)
6025+
param.num_inactive_vdev_bitmap = entry_idx + 1;
6026+
}
6027+
6028+
ath12k_dbg(ab, ATH12K_DBG_MAC,
6029+
"num_vdev_bitmap %d inactive_vdev_bitmap[0] = 0x%x, inactive_vdev_bitmap[1] = 0x%x",
6030+
param.num_inactive_vdev_bitmap,
6031+
param.inactive_vdev_bitmap[0],
6032+
param.inactive_vdev_bitmap[1]);
6033+
}
6034+
6035+
if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM ||
6036+
mode == WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM) {
6037+
param.num_link_entry = 1;
6038+
param.link_num[0].num_of_link = num_mlo_vdev - 1;
6039+
}
6040+
6041+
return ath12k_wmi_send_mlo_link_set_active_cmd(ab, &param);
6042+
}
6043+
6044+
static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab,
6045+
struct ieee80211_hw *hw,
6046+
struct ath12k_vif *ahvif)
6047+
{
6048+
u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {0};
6049+
u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {0};
6050+
unsigned long links = ahvif->links_map;
6051+
enum wmi_mlo_link_force_reason reason;
6052+
struct ieee80211_chanctx_conf *conf;
6053+
enum wmi_mlo_link_force_mode mode;
6054+
struct ieee80211_bss_conf *info;
6055+
struct ath12k_link_vif *arvif;
6056+
u8 num_mlo_vdev = 0;
6057+
u8 link_id;
6058+
6059+
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
6060+
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
6061+
/* make sure vdev is created on this device */
6062+
if (!arvif || !arvif->is_created || arvif->ar->ab != ab)
6063+
continue;
6064+
6065+
info = ath12k_mac_get_link_bss_conf(arvif);
6066+
conf = wiphy_dereference(hw->wiphy, info->chanctx_conf);
6067+
mlo_freq_list[num_mlo_vdev] = conf->def.chan->center_freq;
6068+
6069+
mlo_vdev_id_lst[num_mlo_vdev] = arvif->vdev_id;
6070+
num_mlo_vdev++;
6071+
}
6072+
6073+
/* It is not allowed to activate more links than a single device
6074+
* supported. Something goes wrong if we reach here.
6075+
*/
6076+
if (num_mlo_vdev > ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) {
6077+
WARN_ON_ONCE(1);
6078+
return -EINVAL;
6079+
}
6080+
6081+
/* if 2 links are established and both link channels fall on the
6082+
* same hardware MAC, send command to firmware to deactivate one
6083+
* of them.
6084+
*/
6085+
if (num_mlo_vdev == 2 &&
6086+
ath12k_mac_freqs_on_same_mac(ab, mlo_freq_list[0],
6087+
mlo_freq_list[1])) {
6088+
mode = WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM;
6089+
reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT;
6090+
return ath12k_mac_mlo_sta_set_link_active(ab, reason, mode,
6091+
mlo_vdev_id_lst, num_mlo_vdev,
6092+
NULL, 0);
6093+
}
6094+
6095+
return 0;
6096+
}
6097+
58936098
static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
58946099
struct ieee80211_vif *vif,
58956100
struct ieee80211_sta *sta,
@@ -5899,10 +6104,12 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
58996104
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
59006105
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
59016106
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
6107+
struct ath12k_base *prev_ab = NULL, *ab;
59026108
struct ath12k_link_vif *arvif;
59036109
struct ath12k_link_sta *arsta;
59046110
unsigned long valid_links;
5905-
u8 link_id = 0;
6111+
u8 link_id = 0, i;
6112+
struct ath12k *ar;
59066113
int ret;
59076114

59086115
lockdep_assert_wiphy(hw->wiphy);
@@ -5997,6 +6204,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
59976204
}
59986205
}
59996206

6207+
if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION &&
6208+
old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) {
6209+
for_each_ar(ah, ar, i) {
6210+
ab = ar->ab;
6211+
if (prev_ab == ab)
6212+
continue;
6213+
6214+
ret = ath12k_mac_mlo_sta_update_link_active(ab, hw, ahvif);
6215+
if (ret) {
6216+
ath12k_warn(ab,
6217+
"failed to update link active state on connect %d\n",
6218+
ret);
6219+
goto exit;
6220+
}
6221+
6222+
prev_ab = ab;
6223+
}
6224+
}
60006225
/* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST:
60016226
* Remove the station from driver (handle ML sta here since that
60026227
* needs special handling. Normal sta will be handled in generic

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ struct ath12k_generic_iter {
5454
#define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
5555
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1)
5656

57+
#define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2
58+
5759
enum ath12k_supported_bw {
5860
ATH12K_BW_20 = 0,
5961
ATH12K_BW_40 = 1,

0 commit comments

Comments
 (0)