]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: mld: Fix MLO scan timing
authorPagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Tue, 24 Mar 2026 09:33:24 +0000 (11:33 +0200)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 24 Mar 2026 11:55:53 +0000 (13:55 +0200)
Calculate MLO scan start time based on actual
scan start notification from firmware instead of recording
time when scan command is sent.

Currently, MLO scan start time was captured immediately
after sending the scan command to firmware. However, the
actual scan start time may differ due to the FW being busy
with a previous scan.

In that case, the link selection code will think that the MLO
scan is too old, and will warn.

To fix it, Implement start scan notification handling to
capture the precise moment when firmware begins the scan
operation.

Fixes: 9324731b9985 ("wifi: iwlwifi: mld: avoid selecting bad links")
Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260324113316.4c56b8bac533.I6e656d8cc30bb82c96aabadedd62bd67f4c46bf9@changeid
drivers/net/wireless/intel/iwlwifi/fw/api/commands.h
drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
drivers/net/wireless/intel/iwlwifi/mld/mld.c
drivers/net/wireless/intel/iwlwifi/mld/mlo.c
drivers/net/wireless/intel/iwlwifi/mld/notif.c
drivers/net/wireless/intel/iwlwifi/mld/scan.c
drivers/net/wireless/intel/iwlwifi/mld/scan.h

index 8d64a271bb9452a1fbb5d50ded2b29269606181b..36159a7699167429c1b59423585cdca60e10b1c8 100644 (file)
@@ -296,6 +296,11 @@ enum iwl_legacy_cmds {
         */
        SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
 
+       /**
+        * @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start
+        */
+       SCAN_START_NOTIFICATION_UMAC = 0xb2,
+
        /**
         * @MATCH_FOUND_NOTIFICATION: scan match found
         */
index 60f0a4924ddfb0e6cf006aee71ab499accf739d2..46fcc32608e34e989531ea3eb8dca1afe4128a99 100644 (file)
@@ -1156,6 +1156,16 @@ enum iwl_umac_scan_abort_status {
        IWL_UMAC_SCAN_ABORT_STATUS_NOT_FOUND,
 };
 
+/**
+ * struct iwl_umac_scan_start - scan start notification
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @reserved: for future use
+ */
+struct iwl_umac_scan_start {
+       __le32 uid;
+       __le32 reserved;
+} __packed; /* SCAN_START_UMAC_API_S_VER_1 */
+
 /**
  * struct iwl_umac_scan_complete - scan complete notification
  * @uid: scan id, &enum iwl_umac_scan_uid_offsets
index 495e9d8f3af621ac5b01ec13c8a64abdd3d48e62..9af79297c3b6ae3689d3c76a76bdbe4728361d59 100644 (file)
@@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = {
        HCMD_NAME(MISSED_BEACONS_NOTIFICATION),
        HCMD_NAME(MAC_PM_POWER_TABLE),
        HCMD_NAME(MFUART_LOAD_NOTIFICATION),
+       HCMD_NAME(SCAN_START_NOTIFICATION_UMAC),
        HCMD_NAME(RSS_CONFIG_CMD),
        HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
        HCMD_NAME(REPLY_RX_MPDU_CMD),
index f842f5183223b2526a4788f96f61e090d55bf312..fbff5915f7fd56702515ad0eff9d24effbd2b10d 100644 (file)
@@ -739,7 +739,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld,
 
                /* Ignore any BSS that was not seen in the last MLO scan */
                if (ktime_before(link_conf->bss->ts_boottime,
-                                mld->scan.last_mlo_scan_time))
+                                mld->scan.last_mlo_scan_start_time))
                        continue;
 
                data[n_data].link_id = link_id;
@@ -945,7 +945,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld,
        if (!mld_vif->authorized || hweight16(usable_links) <= 1)
                return;
 
-       if (WARN(ktime_before(mld->scan.last_mlo_scan_time,
+       if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time,
                              ktime_sub_ns(ktime_get_boottime_ns(),
                                           5ULL * NSEC_PER_SEC)),
                "Last MLO scan was too long ago, can't select links\n"))
index 240526d8b6326854153b57d9162945af52ba9830..9c88a8579a7599129f7fa945c709c4c00074312d 100644 (file)
@@ -287,6 +287,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld,
  * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY.
  */
 
+CMD_VERSIONS(scan_start_notif,
+            CMD_VER_ENTRY(1, iwl_umac_scan_start))
 CMD_VERSIONS(scan_complete_notif,
             CMD_VER_ENTRY(1, iwl_umac_scan_complete))
 CMD_VERSIONS(scan_iter_complete_notif,
@@ -360,6 +362,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif,
                           link_id)
 DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity)
 DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid)
+DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid)
 DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif,
                           mac_id)
 DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif,
@@ -402,6 +405,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
                             RX_HANDLER_SYNC)
        RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif,
                             RX_HANDLER_SYNC)
+       RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC,
+                          scan_start_notif)
        RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC,
                           scan_complete_notif)
        RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC,
index a1a4cf3ab3d311872dc94967b90befcb686569ed..abd4281b4b0ed6b9744a47d46d1cb39a2ae3b6d3 100644 (file)
@@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld,
            params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN;
 
+       if (scan_status == IWL_MLD_SCAN_INT_MLO)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START;
+
        if (params->enable_6ghz_passive)
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN;
 
@@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
        ret = _iwl_mld_single_scan_start(mld, vif, req, &ies,
                                         IWL_MLD_SCAN_INT_MLO);
 
-       if (!ret)
-               mld->scan.last_mlo_scan_time = ktime_get_boottime_ns();
-
        IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
 }
 
@@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
        ieee80211_sched_scan_results(mld->hw);
 }
 
+void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
+                                    struct iwl_rx_packet *pkt)
+{
+       struct iwl_umac_scan_complete *notif = (void *)pkt->data;
+       u32 uid = le32_to_cpu(notif->uid);
+
+       if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status),
+                        "FW reports out-of-range scan UID %d\n", uid))
+               return;
+
+       if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status),
+                        "FW reports scan UID %d we didn't trigger\n", uid))
+               return;
+
+       IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid,
+                      mld->scan.uid_status[uid]);
+       if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO,
+                        "FW reports scan start notification %d we didn't trigger\n",
+                        mld->scan.uid_status[uid]))
+               return;
+
+       mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns();
+}
+
 void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
                                        struct iwl_rx_packet *pkt)
 {
index 69110f0cfc8e2ad17ea1ffc09f67a2dd14168de4..de5620e7f463b535cb24d30138e90b718251b0af 100644 (file)
@@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld,
 void iwl_mld_handle_match_found_notif(struct iwl_mld *mld,
                                      struct iwl_rx_packet *pkt);
 
+void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld,
+                                    struct iwl_rx_packet *pkt);
+
 void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld,
                                        struct iwl_rx_packet *pkt);
 
@@ -114,8 +117,8 @@ enum iwl_mld_traffic_load {
  *     in jiffies.
  * @last_start_time_jiffies: stores the last start time in jiffies
  *     (interface up/reset/resume).
- * @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since
- *     boot.
+ * @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds
+ * since boot.
  */
 struct iwl_mld_scan {
        /* Add here fields that need clean up on restart */
@@ -136,7 +139,7 @@ struct iwl_mld_scan {
        void *cmd;
        unsigned long last_6ghz_passive_jiffies;
        unsigned long last_start_time_jiffies;
-       u64 last_mlo_scan_time;
+       u64 last_mlo_scan_start_time;
 };
 
 /**