Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions drivers/net/wireless/ath/ath12k/mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -3773,6 +3773,79 @@ static int ath12k_mac_vif_recalc_sta_he_txbf(struct ath12k *ar,
return 0;
}

static int ath12k_mac_vif_recalc_sta_eht_txbf(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_link_sta *link_sta,
u32 *ehtmode)
{
const struct ieee80211_sta_eht_cap *peer_eht_cap;
const struct ieee80211_sta_eht_cap *own_eht_cap;
const struct ieee80211_sband_iftype_data *iftd;
struct ieee80211_vif *vif = arvif->ahvif->vif;
struct ieee80211_bss_conf *link_conf;
struct cfg80211_chan_def def;
enum nl80211_band band;
u8 mu_bformer;

*ehtmode = 0;

if (vif->type != NL80211_IFTYPE_STATION)
return -EINVAL;

link_conf = ath12k_mac_get_link_bss_conf(arvif);
if (!link_conf) {
ath12k_warn(ar->ab, "unable to access bss link conf in recalc eht txbf conf\n");
return -EINVAL;
}

if (!link_conf->eht_support || !link_sta->eht_cap.has_eht)
return 0;

if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)))
return -EINVAL;

band = def.chan->band;
iftd = ieee80211_get_sband_iftype_data(&ar->mac.sbands[band], vif->type);
if (!iftd) {
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"unable to access iftype data in recalc eht txbf conf\n");
return 0;
}

own_eht_cap = &iftd->eht_cap;
peer_eht_cap = &link_sta->eht_cap;

if (!own_eht_cap->has_eht)
return 0;

*ehtmode |= u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, EHT_MODE_DL_OFDMA) |
u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, EHT_MODE_UL_OFDMA);

if ((own_eht_cap->eht_cap_elem.phy_cap_info[0] &
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE) &&
(peer_eht_cap->eht_cap_elem.phy_cap_info[0] &
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER))
*ehtmode |= u32_encode_bits(EHT_SU_BFEE_ENABLE, EHT_MODE_SU_TX_BFEE);

switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_320:
mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
break;
case IEEE80211_STA_RX_BW_160:
mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ;
break;
default:
mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ;
break;
}

if (u32_get_bits(*ehtmode, EHT_MODE_SU_TX_BFEE) &&
(peer_eht_cap->eht_cap_elem.phy_cap_info[7] & mu_bformer))
*ehtmode |= u32_encode_bits(EHT_MU_BFEE_ENABLE, EHT_MODE_MU_TX_BFEE);

return 0;
}

static int ath12k_mac_set_eht_txbf_conf(struct ath12k_link_vif *arvif)
{
struct ath12k_vif *ahvif = arvif->ahvif;
Expand Down Expand Up @@ -3916,6 +3989,7 @@ static void ath12k_bss_assoc(struct ath12k *ar,
struct ath12k_sta *ahsta;
struct ath12k_dp_link_peer *peer;
bool is_auth = false;
u32 ehtmode = 0;
u32 hemode = 0;
int ret;
struct ath12k_dp *dp = ath12k_ab_to_dp(ar->ab);
Expand Down Expand Up @@ -3970,6 +4044,14 @@ static void ath12k_bss_assoc(struct ath12k *ar,
return;
}

ret = ath12k_mac_vif_recalc_sta_eht_txbf(ar, arvif, link_sta, &ehtmode);
if (ret) {
ath12k_warn(ar->ab, "failed to recalc eht txbf for vdev %i on bss %pM: %d\n",
arvif->vdev_id, bss_conf->bssid, ret);
rcu_read_unlock();
return;
}

rcu_read_unlock();

/* keep this before ath12k_wmi_send_peer_assoc_cmd() */
Expand All @@ -3981,6 +4063,15 @@ static void ath12k_bss_assoc(struct ath12k *ar,
return;
}

ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
WMI_VDEV_PARAM_SET_EHT_MU_MODE,
ehtmode);
if (ret) {
ath12k_warn(ar->ab, "failed to submit vdev param eht txbf 0x%x: %d\n",
ehtmode, ret);
return;
}

peer_arg->is_assoc = true;

ret = ath12k_mac_peer_assoc(ar, peer_arg);
Expand Down Expand Up @@ -9603,6 +9694,7 @@ u8 ath12k_mac_get_tx_link(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta;
struct ieee80211_bss_conf *bss_conf;
struct ath12k_sta *ahsta;
bool req_unspecified_link = (link == IEEE80211_LINK_UNSPECIFIED);

/* Use the link id passed or the default vif link */
if (!sta) {
Expand Down Expand Up @@ -9648,6 +9740,33 @@ u8 ath12k_mac_get_tx_link(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
if (!ieee80211_is_mgmt(hdr->frame_control))
return link;

/*
* Keep ML management Tx on an active link only when mac80211 did
* not request a specific link and the selected link is inactive.
*/
if (req_unspecified_link && !(vif->active_links & BIT(link))) {
unsigned long tx_links = vif->active_links;
unsigned long peer_tx_links;

if (!tx_links)
goto out_keep_link;

peer_tx_links = tx_links & sta->valid_links;

/*
* Prefer links that are both active on the vif and valid for
* this MLO peer. If no overlap exists, fall back to vif
* active links.
*/
if (peer_tx_links)
tx_links = peer_tx_links;
else
WARN_ON_ONCE(1);

link = __ffs(tx_links);
}

out_keep_link:
/* Perform address conversion for ML STA Tx */
bss_conf = rcu_dereference(vif->link_conf[link]);
link_sta = rcu_dereference(sta->link[link]);
Expand Down
Loading