]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: identify assoc link vif in station mode
authorBaochen Qiang <quic_bqiang@quicinc.com>
Wed, 9 Apr 2025 02:26:37 +0000 (10:26 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Tue, 15 Apr 2025 14:35:52 +0000 (07:35 -0700)
In MLO scenario, for station mode interface, WCN7850 firmware requests
the assoc link vdev to get started before any other link vdevs starts.
Firmware internally checks assoc_link field of
wmi_vdev_start_mlo_params.flags when the first vdev starts. And if the
check fails firmware crashes.

Current connection flow guarantees the assoc link vdev gets started
first (at assoc stage only one link vdev is created/started, i.e. the
assoc link vdev), however the assoc_link flag is never set, resulting
in WCN7850 firmware crash.

Note ath12k_link_sta structure already has is_assoc_link flag, and it
is properly set for assoc link. However we can not use it because it
won't be available before peer gets created, which is too late for vdev
starts.

So add a new flag 'is_sta_assoc_link' in ath12k_link_vif structure and
set it when deflink vdev is created. This is valid because we always
use deflink as the assoc link. This flag is passed to firmware vdev
starts to avoid firmware crash. Also verify the link vif/sta pair has
the same settings when creating link sta.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
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.3.1-00209-QCAHKSWPL_SILICONZ-1

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Link: https://patch.msgid.link/20250409-ath12k-wcn7850-mlo-support-v2-4-3801132ca2c3@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c

index 06dddf66a83b11ee1333c78eb2f77631412cb228..1bc2a391171dbd8a71f8321c7e4ec600956387d9 100644 (file)
@@ -314,6 +314,9 @@ struct ath12k_link_vif {
        spinlock_t link_stats_lock; /* Protects updates to link_stats */
 
        u8 current_cntdown_counter;
+
+       /* only used in station mode */
+       bool is_sta_assoc_link;
 };
 
 struct ath12k_vif {
index 7af12733a1ff9eddff09630f604f20d24de8cce0..37e76fff57a5ca1efa770337b7c533207082ceda 100644 (file)
@@ -3477,6 +3477,8 @@ static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah,
                 */
                if (!ahvif->links_map && link_id != ATH12K_DEFAULT_SCAN_LINK) {
                        arvif = &ahvif->deflink;
+                       if (vif->type == NL80211_IFTYPE_STATION)
+                               arvif->is_sta_assoc_link = true;
                } else {
                        arvif = (struct ath12k_link_vif *)
                        kzalloc(sizeof(struct ath12k_link_vif), GFP_KERNEL);
@@ -5867,6 +5869,17 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
                 * link sta
                 */
                if (sta->mlo) {
+                       /* For station mode, arvif->is_sta_assoc_link has been set when
+                        * vdev starts. Make sure the arvif/arsta pair have same setting
+                        */
+                       if (vif->type == NL80211_IFTYPE_STATION &&
+                           !arsta->arvif->is_sta_assoc_link) {
+                               ath12k_hw_warn(ah, "failed to verify assoc link setting with link id %u\n",
+                                              link_id);
+                               ret = -EINVAL;
+                               goto exit;
+                       }
+
                        arsta->is_assoc_link = true;
                        ahsta->assoc_link_id = link_id;
                }
@@ -9123,6 +9136,9 @@ ath12k_mac_mlo_get_vdev_args(struct ath12k_link_vif *arvif,
         * link vdevs which are advertised as partners below
         */
        ml_arg->link_add = true;
+
+       ml_arg->assoc_link = arvif->is_sta_assoc_link;
+
        partner_info = ml_arg->partner_info;
 
        links = ahvif->links_map;