Message ID | 20241023133004.2253830-9-kvalo@kernel.org (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Jeff Johnson |
Headers | show |
Series | wifi: ath12k: MLO support part 2 | expand |
On 10/23/2024 6:30 AM, Kalle Valo wrote: > From: Sriram R <quic_srirrama@quicinc.com> > > Add changes to send MLO peer assoc command with partner link details and > primary umac details > > Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 > Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 > > Signed-off-by: Sriram R <quic_srirrama@quicinc.com> > Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com> > Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com> > --- > drivers/net/wireless/ath/ath12k/core.h | 7 +++ > drivers/net/wireless/ath/ath12k/mac.c | 62 ++++++++++++++++++++ > drivers/net/wireless/ath/ath12k/wmi.c | 79 ++++++++++++++++++++++++-- > drivers/net/wireless/ath/ath12k/wmi.h | 46 +++++++++++++++ > 4 files changed, 188 insertions(+), 6 deletions(-) > > diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h > index 0a0c1a1594f2..e7a2d43e7b8a 100644 > --- a/drivers/net/wireless/ath/ath12k/core.h > +++ b/drivers/net/wireless/ath/ath12k/core.h > @@ -487,9 +487,16 @@ struct ath12k_link_sta { > struct ath12k_rx_peer_stats *rx_stats; > struct ath12k_wbm_tx_stats *wbm_tx_stats; > u32 bw_prev; > + > + /* For now the assoc link will be considered primary */ > + bool is_assoc_link; > + > + /* for firmware use only */ > + u8 link_idx; > }; > > struct ath12k_sta { > + struct ath12k_vif *ahvif; > enum hal_pn_type pn_type; > struct ath12k_link_sta deflink; > struct ath12k_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; > diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c > index b628bc2fd0f5..2e79849974f0 100644 > --- a/drivers/net/wireless/ath/ath12k/mac.c > +++ b/drivers/net/wireless/ath/ath12k/mac.c > @@ -2873,6 +2873,67 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, > arg->punct_bitmap = ~arvif->punct_bitmap; > } > > +static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta, > + struct ath12k_wmi_peer_assoc_arg *arg) > +{ > + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); > + struct peer_assoc_mlo_params *ml = &arg->ml; > + struct ath12k_sta *ahsta = arsta->ahsta; > + struct ath12k_link_sta *arsta_p; > + struct ath12k_link_vif *arvif; > + unsigned long links; > + u8 link_id; > + int i; > + > + if (!sta->mlo || ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) > + return; > + > + ml->enabled = true; > + ml->assoc_link = arsta->is_assoc_link; > + > + /* For now considering the primary umac based on assoc link */ > + ml->primary_umac = arsta->is_assoc_link; > + ml->peer_id_valid = true; > + ml->logical_link_idx_valid = true; > + > + ether_addr_copy(ml->mld_addr, sta->addr); > + ml->logical_link_idx = arsta->link_idx; > + ml->ml_peer_id = ahsta->ml_peer_id; > + ml->ieee_link_id = arsta->link_id; > + ml->num_partner_links = 0; > + links = ahsta->links_map; > + > + rcu_read_lock(); > + > + i = 0; nit: setting i=0 doesn't need to be RCU protected > + > + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { > + if (i >= ATH12K_WMI_MLO_MAX_LINKS) > + break; > + > + arsta_p = rcu_dereference(ahsta->link[link_id]); > + arvif = rcu_dereference(ahsta->ahvif->link[link_id]); > + > + if (arsta_p == arsta) > + continue; > + > + if (!arvif->is_started) > + continue; > + > + ml->partner_info[i].vdev_id = arvif->vdev_id; > + ml->partner_info[i].hw_link_id = arvif->ar->pdev->hw_link_id; > + ml->partner_info[i].assoc_link = arsta_p->is_assoc_link; > + ml->partner_info[i].primary_umac = arsta_p->is_assoc_link; > + ml->partner_info[i].logical_link_idx_valid = true; > + ml->partner_info[i].logical_link_idx = arsta_p->link_idx; > + ml->num_partner_links++; > + > + i++; > + } > + > + rcu_read_unlock(); > +} > + > static void ath12k_peer_assoc_prepare(struct ath12k *ar, > struct ath12k_link_vif *arvif, > struct ath12k_link_sta *arsta, > @@ -2897,6 +2958,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar, > ath12k_peer_assoc_h_qos(ar, arvif, arsta, arg); > ath12k_peer_assoc_h_phymode(ar, arvif, arsta, arg); > ath12k_peer_assoc_h_smps(arsta, arg); > + ath12k_peer_assoc_h_mlo(arsta, arg); > > /* TODO: amsdu_disable req? */ > } > diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c > index 0583d832fac7..73c1c6bcf48b 100644 > --- a/drivers/net/wireless/ath/ath12k/wmi.c > +++ b/drivers/net/wireless/ath/ath12k/wmi.c > @@ -2101,12 +2101,15 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, > struct ath12k_wmi_vht_rate_set_params *mcs; > struct ath12k_wmi_he_rate_set_params *he_mcs; > struct ath12k_wmi_eht_rate_set_params *eht_mcs; > + struct wmi_peer_assoc_mlo_params *ml_params; > + struct wmi_peer_assoc_mlo_partner_info *partner_info; > struct sk_buff *skb; > struct wmi_tlv *tlv; > void *ptr; > u32 peer_legacy_rates_align; > u32 peer_ht_rates_align; > int i, ret, len; > + __le32 v; > > peer_legacy_rates_align = roundup(arg->peer_legacy_rates.num_rates, > sizeof(u32)); > @@ -2118,8 +2121,13 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, > TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) + > sizeof(*mcs) + TLV_HDR_SIZE + > (sizeof(*he_mcs) * arg->peer_he_mcs_count) + > - TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) + > - TLV_HDR_SIZE + TLV_HDR_SIZE; > + TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count); > + > + if (arg->ml.enabled) > + len += TLV_HDR_SIZE + sizeof(*ml_params) + > + TLV_HDR_SIZE + (arg->ml.num_partner_links * sizeof(*partner_info)); > + else > + len += (2 * TLV_HDR_SIZE); > > skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); > if (!skb) > @@ -2243,12 +2251,38 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, > ptr += sizeof(*he_mcs); > } > > - /* MLO header tag with 0 length */ > - len = 0; > tlv = ptr; > + len = arg->ml.enabled ? sizeof(*ml_params) : 0; > tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); > ptr += TLV_HDR_SIZE; > + if (!len) > + goto skip_ml_params; > > + ml_params = ptr; > + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PEER_ASSOC_PARAMS, > + len); this is another instance where we are using the same length for two consecutive TLVs -- that doesn't seem right > + ml_params->flags = cpu_to_le32(ATH12K_WMI_FLAG_MLO_ENABLED); > + > + if (arg->ml.assoc_link) > + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_ASSOC_LINK); > + > + if (arg->ml.primary_umac) > + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC); > + > + if (arg->ml.logical_link_idx_valid) > + ml_params->flags |= > + cpu_to_le32(ATH12K_WMI_FLAG_MLO_LOGICAL_LINK_IDX_VALID); > + > + if (arg->ml.peer_id_valid) > + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_PEER_ID_VALID); > + > + ether_addr_copy(ml_params->mld_addr.addr, arg->ml.mld_addr); > + ml_params->logical_link_idx = cpu_to_le32(arg->ml.logical_link_idx); > + ml_params->ml_peer_id = cpu_to_le32(arg->ml.ml_peer_id); > + ml_params->ieee_link_id = cpu_to_le32(arg->ml.ieee_link_id); > + ptr += sizeof(*ml_params); > + > +skip_ml_params: > /* Loop through the EHT rate set */ > len = arg->peer_eht_mcs_count * sizeof(*eht_mcs); > tlv = ptr; > @@ -2265,12 +2299,45 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, > ptr += sizeof(*eht_mcs); > } > > - /* ML partner links tag with 0 length */ > - len = 0; > tlv = ptr; > + len = arg->ml.enabled ? arg->ml.num_partner_links * sizeof(*partner_info) : 0; > + /* fill ML Partner links */ > tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); > ptr += TLV_HDR_SIZE; > > + if (len == 0) > + goto send; > + > + for (i = 0; i < arg->ml.num_partner_links; i++) { > + u32 cmd = WMI_TAG_MLO_PARTNER_LINK_PARAMS_PEER_ASSOC; > + > + partner_info = ptr; > + partner_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd, > + sizeof(*partner_info)); > + partner_info->vdev_id = cpu_to_le32(arg->ml.partner_info[i].vdev_id); > + partner_info->hw_link_id = > + cpu_to_le32(arg->ml.partner_info[i].hw_link_id); > + partner_info->flags = cpu_to_le32(ATH12K_WMI_FLAG_MLO_ENABLED); > + > + if (arg->ml.partner_info[i].assoc_link) > + partner_info->flags |= > + cpu_to_le32(ATH12K_WMI_FLAG_MLO_ASSOC_LINK); > + > + if (arg->ml.partner_info[i].primary_umac) > + partner_info->flags |= > + cpu_to_le32(ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC); > + > + if (arg->ml.partner_info[i].logical_link_idx_valid) { > + v = cpu_to_le32(ATH12K_WMI_FLAG_MLO_LINK_ID_VALID); > + partner_info->flags |= v; > + } > + > + partner_info->logical_link_idx = > + cpu_to_le32(arg->ml.partner_info[i].logical_link_idx); > + ptr += sizeof(*partner_info); > + } > + > +send: > ath12k_dbg(ar->ab, ATH12K_DBG_WMI, > "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n", > cmd->vdev_id, cmd->peer_associd, arg->peer_mac, > diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h > index 07bd275608bf..e93f74e97771 100644 > --- a/drivers/net/wireless/ath/ath12k/wmi.h > +++ b/drivers/net/wireless/ath/ath12k/wmi.h > @@ -3698,6 +3698,24 @@ struct wmi_vdev_install_key_arg { > #define WMI_HECAP_TXRX_MCS_NSS_IDX_160 1 > #define WMI_HECAP_TXRX_MCS_NSS_IDX_80_80 2 > > +#define ATH12K_WMI_MLO_MAX_PARTNER_LINKS \ > + (ATH12K_WMI_MLO_MAX_LINKS + ATH12K_MAX_NUM_BRIDGE_LINKS - 1) > + > +struct peer_assoc_mlo_params { > + bool enabled; > + bool assoc_link; > + bool primary_umac; > + bool peer_id_valid; > + bool logical_link_idx_valid; > + bool bridge_peer; > + u8 mld_addr[ETH_ALEN]; > + u32 logical_link_idx; > + u32 ml_peer_id; > + u32 ieee_link_id; > + u8 num_partner_links; > + struct wmi_ml_partner_info partner_info[ATH12K_WMI_MLO_MAX_LINKS]; > +}; > + > struct wmi_rate_set_arg { > u32 num_rates; > u8 rates[WMI_MAX_SUPPORTED_RATES]; > @@ -3772,8 +3790,36 @@ struct ath12k_wmi_peer_assoc_arg { > u32 peer_eht_tx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; > struct ath12k_wmi_ppe_threshold_arg peer_eht_ppet; > u32 punct_bitmap; > + bool is_assoc; > + struct peer_assoc_mlo_params ml; > }; > > +#define ATH12K_WMI_FLAG_MLO_ENABLED BIT(0) > +#define ATH12K_WMI_FLAG_MLO_ASSOC_LINK BIT(1) > +#define ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC BIT(2) > +#define ATH12K_WMI_FLAG_MLO_LINK_ID_VALID BIT(3) > +#define ATH12K_WMI_FLAG_MLO_PEER_ID_VALID BIT(4) > + > +struct wmi_peer_assoc_mlo_partner_info { this doesn't follow the WMI naming convention, should be _params > + __le32 tlv_header; > + __le32 vdev_id; > + __le32 hw_link_id; > + __le32 flags; > + __le32 logical_link_idx; > +} __packed; > + > +struct wmi_peer_assoc_mlo_params { > + __le32 tlv_header; > + __le32 flags; > + struct wmi_mac_addr mld_addr; > + __le32 logical_link_idx; > + __le32 ml_peer_id; > + __le32 ieee_link_id; > + __le32 emlsr_trans_timeout_us; > + __le32 emlsr_trans_delay_us; > + __le32 emlsr_padding_delay_us; > +} __packed; > + > struct wmi_peer_assoc_complete_cmd { > __le32 tlv_header; > struct ath12k_wmi_mac_addr_params peer_macaddr;
Jeff Johnson <quic_jjohnson@quicinc.com> writes: > On 10/23/2024 6:30 AM, Kalle Valo wrote: > >> + rcu_read_lock(); >> + >> + i = 0; > > nit: setting i=0 doesn't need to be RCU protected Yeah, but that doesn't cause any issues and this way it's closer to the for loop where it's used: >> + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { >> + if (i >= ATH12K_WMI_MLO_MAX_LINKS) >> + break; [...] >> @@ -2243,12 +2251,38 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, >> ptr += sizeof(*he_mcs); >> } >> >> - /* MLO header tag with 0 length */ >> - len = 0; >> tlv = ptr; >> + len = arg->ml.enabled ? sizeof(*ml_params) : 0; >> tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); >> ptr += TLV_HDR_SIZE; >> + if (!len) >> + goto skip_ml_params; >> >> + ml_params = ptr; >> + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PEER_ASSOC_PARAMS, >> + len); > > this is another instance where we are using the same length for two > consecutive TLVs -- that doesn't seem right This is also a similar case of _hdr() vs _cmd_hdr(), does that look ok?
On 10/29/2024 9:05 AM, Kalle Valo wrote: > Jeff Johnson <quic_jjohnson@quicinc.com> writes: > >> On 10/23/2024 6:30 AM, Kalle Valo wrote: >> >>> + rcu_read_lock(); >>> + >>> + i = 0; >> >> nit: setting i=0 doesn't need to be RCU protected > > Yeah, but that doesn't cause any issues and this way it's closer to the > for loop where it's used: > >>> + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { >>> + if (i >= ATH12K_WMI_MLO_MAX_LINKS) >>> + break; > > [...] > >>> @@ -2243,12 +2251,38 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, >>> ptr += sizeof(*he_mcs); >>> } >>> >>> - /* MLO header tag with 0 length */ >>> - len = 0; >>> tlv = ptr; >>> + len = arg->ml.enabled ? sizeof(*ml_params) : 0; >>> tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); >>> ptr += TLV_HDR_SIZE; >>> + if (!len) >>> + goto skip_ml_params; >>> >>> + ml_params = ptr; >>> + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PEER_ASSOC_PARAMS, >>> + len); >> >> this is another instance where we are using the same length for two >> consecutive TLVs -- that doesn't seem right > > This is also a similar case of _hdr() vs _cmd_hdr(), does that look ok? > here again this is evil. please change to _hdr() and explicitly subtract out the tlv header size
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 0a0c1a1594f2..e7a2d43e7b8a 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -487,9 +487,16 @@ struct ath12k_link_sta { struct ath12k_rx_peer_stats *rx_stats; struct ath12k_wbm_tx_stats *wbm_tx_stats; u32 bw_prev; + + /* For now the assoc link will be considered primary */ + bool is_assoc_link; + + /* for firmware use only */ + u8 link_idx; }; struct ath12k_sta { + struct ath12k_vif *ahvif; enum hal_pn_type pn_type; struct ath12k_link_sta deflink; struct ath12k_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b628bc2fd0f5..2e79849974f0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -2873,6 +2873,67 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, arg->punct_bitmap = ~arvif->punct_bitmap; } +static void ath12k_peer_assoc_h_mlo(struct ath12k_link_sta *arsta, + struct ath12k_wmi_peer_assoc_arg *arg) +{ + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); + struct peer_assoc_mlo_params *ml = &arg->ml; + struct ath12k_sta *ahsta = arsta->ahsta; + struct ath12k_link_sta *arsta_p; + struct ath12k_link_vif *arvif; + unsigned long links; + u8 link_id; + int i; + + if (!sta->mlo || ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) + return; + + ml->enabled = true; + ml->assoc_link = arsta->is_assoc_link; + + /* For now considering the primary umac based on assoc link */ + ml->primary_umac = arsta->is_assoc_link; + ml->peer_id_valid = true; + ml->logical_link_idx_valid = true; + + ether_addr_copy(ml->mld_addr, sta->addr); + ml->logical_link_idx = arsta->link_idx; + ml->ml_peer_id = ahsta->ml_peer_id; + ml->ieee_link_id = arsta->link_id; + ml->num_partner_links = 0; + links = ahsta->links_map; + + rcu_read_lock(); + + i = 0; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + if (i >= ATH12K_WMI_MLO_MAX_LINKS) + break; + + arsta_p = rcu_dereference(ahsta->link[link_id]); + arvif = rcu_dereference(ahsta->ahvif->link[link_id]); + + if (arsta_p == arsta) + continue; + + if (!arvif->is_started) + continue; + + ml->partner_info[i].vdev_id = arvif->vdev_id; + ml->partner_info[i].hw_link_id = arvif->ar->pdev->hw_link_id; + ml->partner_info[i].assoc_link = arsta_p->is_assoc_link; + ml->partner_info[i].primary_umac = arsta_p->is_assoc_link; + ml->partner_info[i].logical_link_idx_valid = true; + ml->partner_info[i].logical_link_idx = arsta_p->link_idx; + ml->num_partner_links++; + + i++; + } + + rcu_read_unlock(); +} + static void ath12k_peer_assoc_prepare(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -2897,6 +2958,7 @@ static void ath12k_peer_assoc_prepare(struct ath12k *ar, ath12k_peer_assoc_h_qos(ar, arvif, arsta, arg); ath12k_peer_assoc_h_phymode(ar, arvif, arsta, arg); ath12k_peer_assoc_h_smps(arsta, arg); + ath12k_peer_assoc_h_mlo(arsta, arg); /* TODO: amsdu_disable req? */ } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 0583d832fac7..73c1c6bcf48b 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -2101,12 +2101,15 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, struct ath12k_wmi_vht_rate_set_params *mcs; struct ath12k_wmi_he_rate_set_params *he_mcs; struct ath12k_wmi_eht_rate_set_params *eht_mcs; + struct wmi_peer_assoc_mlo_params *ml_params; + struct wmi_peer_assoc_mlo_partner_info *partner_info; struct sk_buff *skb; struct wmi_tlv *tlv; void *ptr; u32 peer_legacy_rates_align; u32 peer_ht_rates_align; int i, ret, len; + __le32 v; peer_legacy_rates_align = roundup(arg->peer_legacy_rates.num_rates, sizeof(u32)); @@ -2118,8 +2121,13 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) + sizeof(*mcs) + TLV_HDR_SIZE + (sizeof(*he_mcs) * arg->peer_he_mcs_count) + - TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) + - TLV_HDR_SIZE + TLV_HDR_SIZE; + TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count); + + if (arg->ml.enabled) + len += TLV_HDR_SIZE + sizeof(*ml_params) + + TLV_HDR_SIZE + (arg->ml.num_partner_links * sizeof(*partner_info)); + else + len += (2 * TLV_HDR_SIZE); skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -2243,12 +2251,38 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, ptr += sizeof(*he_mcs); } - /* MLO header tag with 0 length */ - len = 0; tlv = ptr; + len = arg->ml.enabled ? sizeof(*ml_params) : 0; tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); ptr += TLV_HDR_SIZE; + if (!len) + goto skip_ml_params; + ml_params = ptr; + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_PEER_ASSOC_PARAMS, + len); + ml_params->flags = cpu_to_le32(ATH12K_WMI_FLAG_MLO_ENABLED); + + if (arg->ml.assoc_link) + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_ASSOC_LINK); + + if (arg->ml.primary_umac) + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC); + + if (arg->ml.logical_link_idx_valid) + ml_params->flags |= + cpu_to_le32(ATH12K_WMI_FLAG_MLO_LOGICAL_LINK_IDX_VALID); + + if (arg->ml.peer_id_valid) + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_PEER_ID_VALID); + + ether_addr_copy(ml_params->mld_addr.addr, arg->ml.mld_addr); + ml_params->logical_link_idx = cpu_to_le32(arg->ml.logical_link_idx); + ml_params->ml_peer_id = cpu_to_le32(arg->ml.ml_peer_id); + ml_params->ieee_link_id = cpu_to_le32(arg->ml.ieee_link_id); + ptr += sizeof(*ml_params); + +skip_ml_params: /* Loop through the EHT rate set */ len = arg->peer_eht_mcs_count * sizeof(*eht_mcs); tlv = ptr; @@ -2265,12 +2299,45 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, ptr += sizeof(*eht_mcs); } - /* ML partner links tag with 0 length */ - len = 0; tlv = ptr; + len = arg->ml.enabled ? arg->ml.num_partner_links * sizeof(*partner_info) : 0; + /* fill ML Partner links */ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len); ptr += TLV_HDR_SIZE; + if (len == 0) + goto send; + + for (i = 0; i < arg->ml.num_partner_links; i++) { + u32 cmd = WMI_TAG_MLO_PARTNER_LINK_PARAMS_PEER_ASSOC; + + partner_info = ptr; + partner_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd, + sizeof(*partner_info)); + partner_info->vdev_id = cpu_to_le32(arg->ml.partner_info[i].vdev_id); + partner_info->hw_link_id = + cpu_to_le32(arg->ml.partner_info[i].hw_link_id); + partner_info->flags = cpu_to_le32(ATH12K_WMI_FLAG_MLO_ENABLED); + + if (arg->ml.partner_info[i].assoc_link) + partner_info->flags |= + cpu_to_le32(ATH12K_WMI_FLAG_MLO_ASSOC_LINK); + + if (arg->ml.partner_info[i].primary_umac) + partner_info->flags |= + cpu_to_le32(ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC); + + if (arg->ml.partner_info[i].logical_link_idx_valid) { + v = cpu_to_le32(ATH12K_WMI_FLAG_MLO_LINK_ID_VALID); + partner_info->flags |= v; + } + + partner_info->logical_link_idx = + cpu_to_le32(arg->ml.partner_info[i].logical_link_idx); + ptr += sizeof(*partner_info); + } + +send: ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n", cmd->vdev_id, cmd->peer_associd, arg->peer_mac, diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 07bd275608bf..e93f74e97771 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -3698,6 +3698,24 @@ struct wmi_vdev_install_key_arg { #define WMI_HECAP_TXRX_MCS_NSS_IDX_160 1 #define WMI_HECAP_TXRX_MCS_NSS_IDX_80_80 2 +#define ATH12K_WMI_MLO_MAX_PARTNER_LINKS \ + (ATH12K_WMI_MLO_MAX_LINKS + ATH12K_MAX_NUM_BRIDGE_LINKS - 1) + +struct peer_assoc_mlo_params { + bool enabled; + bool assoc_link; + bool primary_umac; + bool peer_id_valid; + bool logical_link_idx_valid; + bool bridge_peer; + u8 mld_addr[ETH_ALEN]; + u32 logical_link_idx; + u32 ml_peer_id; + u32 ieee_link_id; + u8 num_partner_links; + struct wmi_ml_partner_info partner_info[ATH12K_WMI_MLO_MAX_LINKS]; +}; + struct wmi_rate_set_arg { u32 num_rates; u8 rates[WMI_MAX_SUPPORTED_RATES]; @@ -3772,8 +3790,36 @@ struct ath12k_wmi_peer_assoc_arg { u32 peer_eht_tx_mcs_set[WMI_MAX_EHTCAP_RATE_SET]; struct ath12k_wmi_ppe_threshold_arg peer_eht_ppet; u32 punct_bitmap; + bool is_assoc; + struct peer_assoc_mlo_params ml; }; +#define ATH12K_WMI_FLAG_MLO_ENABLED BIT(0) +#define ATH12K_WMI_FLAG_MLO_ASSOC_LINK BIT(1) +#define ATH12K_WMI_FLAG_MLO_PRIMARY_UMAC BIT(2) +#define ATH12K_WMI_FLAG_MLO_LINK_ID_VALID BIT(3) +#define ATH12K_WMI_FLAG_MLO_PEER_ID_VALID BIT(4) + +struct wmi_peer_assoc_mlo_partner_info { + __le32 tlv_header; + __le32 vdev_id; + __le32 hw_link_id; + __le32 flags; + __le32 logical_link_idx; +} __packed; + +struct wmi_peer_assoc_mlo_params { + __le32 tlv_header; + __le32 flags; + struct wmi_mac_addr mld_addr; + __le32 logical_link_idx; + __le32 ml_peer_id; + __le32 ieee_link_id; + __le32 emlsr_trans_timeout_us; + __le32 emlsr_trans_delay_us; + __le32 emlsr_padding_delay_us; +} __packed; + struct wmi_peer_assoc_complete_cmd { __le32 tlv_header; struct ath12k_wmi_mac_addr_params peer_macaddr;