wifi: ath10k: Avoid vdev delete timeout when firmware is already down
authorLoic Poulain <loic.poulain@oss.qualcomm.com>
Thu, 22 May 2025 13:17:04 +0000 (15:17 +0200)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Sat, 7 Jun 2025 14:36:01 +0000 (07:36 -0700)
In some scenarios, the firmware may be stopped before the interface is
removed, either due to a crash or because the remoteproc (e.g., MPSS)
is shut down early during system reboot or shutdown.

This leads to a delay during interface teardown, as the driver waits for
a vdev delete response that never arrives, eventually timing out.

Example (SNOC):
$ echo stop > /sys/class/remoteproc/remoteproc0/state
[ 71.64] remoteproc remoteproc0: stopped remote processor modem
$ reboot
[ 74.84] ath10k_snoc c800000.wifi: failed to transmit packet, dropping: -108
[ 74.84] ath10k_snoc c800000.wifi: failed to submit frame: -108
[...]
[ 82.39] ath10k_snoc c800000.wifi: Timeout in receiving vdev delete response

To avoid this, skip waiting for the vdev delete response if the firmware is
already marked as unreachable (`ATH10K_FLAG_CRASH_FLUSH`), similar to how
`ath10k_mac_wait_tx_complete()` and `ath10k_vdev_setup_sync()` handle this case.

Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
Link: https://patch.msgid.link/20250522131704.612206-1-loic.poulain@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath10k/mac.c

index 8c7ffea0fa44b5d3c03f2fd7191fb757a4966ad6..07fe05384cdfb13924a956f7d672042b782e166f 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
  * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
  * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  */
 
 #include "mac.h"
@@ -1022,6 +1023,26 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
        return ar->last_wmi_vdev_start_status;
 }
 
+static inline int ath10k_vdev_delete_sync(struct ath10k *ar)
+{
+       unsigned long time_left;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (!test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map))
+               return 0;
+
+       if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
+               return -ESHUTDOWN;
+
+       time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
+                                               ATH10K_VDEV_DELETE_TIMEOUT_HZ);
+       if (time_left == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 {
        struct cfg80211_chan_def *chandef = NULL;
@@ -5900,7 +5921,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = (void *)vif->drv_priv;
        struct ath10k_peer *peer;
-       unsigned long time_left;
        int ret;
        int i;
 
@@ -5940,13 +5960,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
 
-       if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) {
-               time_left = wait_for_completion_timeout(&ar->vdev_delete_done,
-                                                       ATH10K_VDEV_DELETE_TIMEOUT_HZ);
-               if (time_left == 0) {
-                       ath10k_warn(ar, "Timeout in receiving vdev delete response\n");
-                       goto out;
-               }
+       ret = ath10k_vdev_delete_sync(ar);
+       if (ret) {
+               ath10k_warn(ar, "Error in receiving vdev delete response: %d\n", ret);
+               goto out;
        }
 
        /* Some firmware revisions don't notify host about self-peer removal