wifi: ath12k: flush all packets before suspend
authorBaochen Qiang <quic_bqiang@quicinc.com>
Mon, 22 Apr 2024 12:11:45 +0000 (15:11 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Tue, 23 Apr 2024 09:27:15 +0000 (12:27 +0300)
In order to send out all packets before going to suspend, current code
adds a 500ms delay as a workaround. It is a rough estimate and may not
work.

Fix this by checking packet counters, if counters become zero, then all
packets are sent out or dropped.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240412060620.27519-7-quic_bqiang@quicinc.com
drivers/net/wireless/ath/ath12k/core.c
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/mac.h

index 90e04d6028226df4ae81cc8a66701152411f6d92..d55245b480208976a6981a19ab04d5987938d18e 100644 (file)
@@ -44,15 +44,25 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab)
 
 int ath12k_core_suspend(struct ath12k_base *ab)
 {
-       int ret;
+       struct ath12k *ar;
+       int ret, i;
 
        if (!ab->hw_params->supports_suspend)
                return -EOPNOTSUPP;
 
-       /* TODO: there can frames in queues so for now add delay as a hack.
-        * Need to implement to handle and remove this delay.
-        */
-       msleep(500);
+       rcu_read_lock();
+       for (i = 0; i < ab->num_radios; i++) {
+               ar = ath12k_mac_get_ar_by_pdev_id(ab, i);
+               if (!ar)
+                       continue;
+               ret = ath12k_mac_wait_tx_complete(ar);
+               if (ret) {
+                       ath12k_warn(ab, "failed to wait tx complete: %d\n", ret);
+                       rcu_read_unlock();
+                       return ret;
+               }
+       }
+       rcu_read_unlock();
 
        ret = ath12k_dp_rx_pktlog_stop(ab, true);
        if (ret) {
index cfb8831816166a6b93bd105199eb3ebaacee4b50..f6cf8b8c4b1815c77c3ab1f510a60cebe81cc6de 100644 (file)
@@ -7417,22 +7417,38 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
        return -EOPNOTSUPP;
 }
 
-static void ath12k_mac_flush(struct ath12k *ar)
+static int ath12k_mac_flush(struct ath12k *ar)
 {
        long time_left;
+       int ret = 0;
 
        time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
                                       (atomic_read(&ar->dp.num_tx_pending) == 0),
                                       ATH12K_FLUSH_TIMEOUT);
-       if (time_left == 0)
-               ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
+       if (time_left == 0) {
+               ath12k_warn(ar->ab,
+                           "failed to flush transmit queue, data pkts pending %d\n",
+                           atomic_read(&ar->dp.num_tx_pending));
+               ret = -ETIMEDOUT;
+       }
 
        time_left = wait_event_timeout(ar->txmgmt_empty_waitq,
                                       (atomic_read(&ar->num_pending_mgmt_tx) == 0),
                                       ATH12K_FLUSH_TIMEOUT);
-       if (time_left == 0)
-               ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n",
-                           time_left);
+       if (time_left == 0) {
+               ath12k_warn(ar->ab,
+                           "failed to flush mgmt transmit queue, mgmt pkts pending %d\n",
+                           atomic_read(&ar->num_pending_mgmt_tx));
+               ret = -ETIMEDOUT;
+       }
+
+       return ret;
+}
+
+int ath12k_mac_wait_tx_complete(struct ath12k *ar)
+{
+       ath12k_mac_drain_tx(ar);
+       return ath12k_mac_flush(ar);
 }
 
 static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
index 3f5e1be0dff9fbcfa4a75e0ada341be701e4c9f8..f826822d30c81cb711a0904c39f172227827066e 100644 (file)
@@ -78,4 +78,5 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b
 enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
 int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
 int ath12k_mac_rfkill_config(struct ath12k *ar);
+int ath12k_mac_wait_tx_complete(struct ath12k *ar);
 #endif