]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Add MLO peer assoc command support
authorSriram R <quic_srirrama@quicinc.com>
Fri, 1 Nov 2024 15:17:05 +0000 (17:17 +0200)
committerJeff Johnson <quic_jjohnson@quicinc.com>
Wed, 6 Nov 2024 19:36:29 +0000 (11:36 -0800)
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>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Link: https://patch.msgid.link/20241101151705.165987-9-kvalo@kernel.org
Signed-off-by: Jeff Johnson <quic_jjohnson@quicinc.com>
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/wmi.c
drivers/net/wireless/ath/ath12k/wmi.h

index 7324dae3fcb88e74883b0469b5a47f2f58d6b0c6..8dbdf6818f58c5ad2e24fa8f9200897605168992 100644 (file)
@@ -495,9 +495,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];
index 076e4da4875f8904f53d221d7cb8899794b27bcc..ad27a2552a2c927da8f5572c8a9e76e6a0e80c0b 100644 (file)
@@ -2859,6 +2859,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,
@@ -2883,6 +2944,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? */
 }
index 0583d832fac7c2ce63eb7bd5a7d06fc45d88cb29..50ed7e72f178f162f0324e86e69427a44748e73d 100644 (file)
@@ -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_params *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,
index 2378d94b2409843721f107b84764207dedb8d2da..05aa9754118a09b2637c3b0a3f71a14faea5c70a 100644 (file)
@@ -3687,6 +3687,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];
@@ -3761,8 +3779,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_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 ath12k_wmi_mac_addr_params 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;