]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: Fix TX status reporting to mac80211 when offload is enabled
authorNithyanantham Paramasivam <nithyanantham.paramasivam@oss.qualcomm.com>
Fri, 18 Jul 2025 02:55:12 +0000 (08:25 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Sat, 19 Jul 2025 16:14:45 +0000 (09:14 -0700)
Currently, the ath12k driver supports only the native Wi-Fi
frame format. In this mode, the ieee80211_tx_status() function
works correctly to report transmission status to mac80211, as
it retrieves station information using sta_info_get_by_addrs().

However, this method is not applicable for Ethernet-converted
packets, since sta_info_get_by_addrs() cannot extract station
information from such formats.

Retrieve station information using ath12k_peer_find_by_id() to
support all frame formats, including native Wi-Fi, raw, and Ethernet.
Report transmission status using ieee80211_tx_status_ext(), and
include rate information as part of the datapath TX status report.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00217-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: Nithyanantham Paramasivam <nithyanantham.paramasivam@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250718025513.32982-3-nithyanantham.paramasivam@oss.qualcomm.com
[changed instances of { 0 } to {}]
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/dp_tx.c

index 899d1dc51eae03288e47c12b14d2ae2612eb3150..d79c2ff7795228c71358cf06a0a6c8bd219d4a87 100644 (file)
@@ -568,7 +568,8 @@ static void
 ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
                                 struct ath12k_tx_desc_params *desc_params,
                                 struct dp_tx_ring *tx_ring,
-                                struct ath12k_dp_htt_wbm_tx_status *ts)
+                                struct ath12k_dp_htt_wbm_tx_status *ts,
+                                u16 peer_id)
 {
        struct ieee80211_tx_info *info;
        struct ath12k_link_vif *arvif;
@@ -578,6 +579,8 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
        struct ath12k *ar;
        struct sk_buff *msdu = desc_params->skb;
        s32 noise_floor;
+       struct ieee80211_tx_status status = {};
+       struct ath12k_peer *peer;
 
        skb_cb = ATH12K_SKB_CB(msdu);
        info = IEEE80211_SKB_CB(msdu);
@@ -629,8 +632,25 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
                        info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
                }
        }
+       rcu_read_lock();
+       spin_lock_bh(&ab->base_lock);
+       peer = ath12k_peer_find_by_id(ab, peer_id);
+       if (!peer || !peer->sta) {
+               ath12k_dbg(ab, ATH12K_DBG_DATA,
+                          "dp_tx: failed to find the peer with peer_id %d\n", peer_id);
+               spin_unlock_bh(&ab->base_lock);
+               ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu);
+               goto exit;
+       } else {
+               status.sta = peer->sta;
+       }
+       spin_unlock_bh(&ab->base_lock);
 
-       ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
+       status.info = info;
+       status.skb = msdu;
+       ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status);
+exit:
+       rcu_read_unlock();
 }
 
 static void
@@ -641,6 +661,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc,
        struct htt_tx_wbm_completion *status_desc;
        struct ath12k_dp_htt_wbm_tx_status ts = {0};
        enum hal_wbm_htt_tx_comp_status wbm_status;
+       u16 peer_id;
 
        status_desc = desc;
 
@@ -653,7 +674,11 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc,
                ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
                ts.ack_rssi = le32_get_bits(status_desc->info2,
                                            HTT_TX_WBM_COMP_INFO2_ACK_RSSI);
-               ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts);
+
+               peer_id = le32_get_bits(((struct hal_wbm_completion_ring_tx *)desc)->
+                               info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID);
+
+               ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts, peer_id);
                break;
        case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
        case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
@@ -805,6 +830,12 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
        struct ath12k_vif *ahvif;
        struct sk_buff *msdu = desc_params->skb;
        s32 noise_floor;
+       struct ieee80211_tx_status status = {};
+       struct ieee80211_rate_status status_rate = {};
+       struct ath12k_peer *peer;
+       struct ath12k_link_sta *arsta;
+       struct ath12k_sta *ahsta;
+       struct rate_info rate;
 
        if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) {
                /* Must not happen */
@@ -896,7 +927,32 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
 
        ath12k_dp_tx_update_txcompl(ar, ts);
 
-       ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu);
+       spin_lock_bh(&ab->base_lock);
+       peer = ath12k_peer_find_by_id(ab, ts->peer_id);
+       if (!peer || !peer->sta) {
+               ath12k_err(ab,
+                          "dp_tx: failed to find the peer with peer_id %d\n",
+                          ts->peer_id);
+               spin_unlock_bh(&ab->base_lock);
+               ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu);
+               goto exit;
+       }
+       ahsta = ath12k_sta_to_ahsta(peer->sta);
+       arsta = &ahsta->deflink;
+
+       spin_unlock_bh(&ab->base_lock);
+
+       status.sta = peer->sta;
+       status.info = info;
+       status.skb = msdu;
+       rate = arsta->last_txrate;
+
+       status_rate.rate_idx = rate;
+       status_rate.try_count = 1;
+
+       status.rates = &status_rate;
+       status.n_rates = 1;
+       ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status);
 
 exit:
        rcu_read_unlock();