e2fe419158f391f72279fff0b5685aa1d2c25d99
[librecmc/librecmc.git] /
1 From 6257c702264c44d74c6b71f0c62a7665da2dc356 Mon Sep 17 00:00:00 2001
2 From: Pradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
3 Date: Mon, 17 Apr 2023 13:35:02 +0300
4 Subject: [PATCH] wifi: ath11k: fix tx status reporting in encap offload mode
5
6 ieee80211_tx_status() treats packets in 802.11 frame format and
7 tries to extract sta address from packet header. When tx encap
8 offload is enabled, this becomes invalid operation. Hence, switch
9 to using ieee80211_tx_status_ext() after filling in station
10 address for handling both 802.11 and 802.3 frames.
11
12 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
13
14 Signed-off-by: Pradeep Kumar Chitrapu <quic_pradeepc@quicinc.com>
15 Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
16 Link: https://lore.kernel.org/r/20230403195738.25367-2-quic_pradeepc@quicinc.com
17 ---
18  drivers/net/wireless/ath/ath11k/dp.h    |  4 +++
19  drivers/net/wireless/ath/ath11k/dp_tx.c | 33 ++++++++++++++++++++++++-
20  drivers/net/wireless/ath/ath11k/dp_tx.h |  1 +
21  3 files changed, 37 insertions(+), 1 deletion(-)
22
23 --- a/drivers/net/wireless/ath/ath11k/dp.h
24 +++ b/drivers/net/wireless/ath/ath11k/dp.h
25 @@ -303,12 +303,16 @@ struct ath11k_dp {
26  
27  #define HTT_TX_WBM_COMP_STATUS_OFFSET 8
28  
29 +#define HTT_INVALID_PEER_ID    0xffff
30 +
31  /* HTT tx completion is overlaid in wbm_release_ring */
32  #define HTT_TX_WBM_COMP_INFO0_STATUS           GENMASK(12, 9)
33  #define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON  GENMASK(16, 13)
34  #define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON  GENMASK(16, 13)
35  
36  #define HTT_TX_WBM_COMP_INFO1_ACK_RSSI         GENMASK(31, 24)
37 +#define HTT_TX_WBM_COMP_INFO2_SW_PEER_ID       GENMASK(15, 0)
38 +#define HTT_TX_WBM_COMP_INFO2_VALID            BIT(21)
39  
40  struct htt_tx_wbm_completion {
41         u32 info0;
42 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c
43 +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
44 @@ -316,10 +316,12 @@ ath11k_dp_tx_htt_tx_complete_buf(struct
45                                  struct dp_tx_ring *tx_ring,
46                                  struct ath11k_dp_htt_wbm_tx_status *ts)
47  {
48 +       struct ieee80211_tx_status status = { 0 };
49         struct sk_buff *msdu;
50         struct ieee80211_tx_info *info;
51         struct ath11k_skb_cb *skb_cb;
52         struct ath11k *ar;
53 +       struct ath11k_peer *peer;
54  
55         spin_lock(&tx_ring->tx_idr_lock);
56         msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id);
57 @@ -341,6 +343,11 @@ ath11k_dp_tx_htt_tx_complete_buf(struct
58  
59         dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
60  
61 +       if (!skb_cb->vif) {
62 +               dev_kfree_skb_any(msdu);
63 +               return;
64 +       }
65 +
66         memset(&info->status, 0, sizeof(info->status));
67  
68         if (ts->acked) {
69 @@ -355,7 +362,23 @@ ath11k_dp_tx_htt_tx_complete_buf(struct
70                 }
71         }
72  
73 -       ieee80211_tx_status(ar->hw, msdu);
74 +       spin_lock_bh(&ab->base_lock);
75 +       peer = ath11k_peer_find_by_id(ab, ts->peer_id);
76 +       if (!peer || !peer->sta) {
77 +               ath11k_dbg(ab, ATH11K_DBG_DATA,
78 +                          "dp_tx: failed to find the peer with peer_id %d\n",
79 +                           ts->peer_id);
80 +               spin_unlock_bh(&ab->base_lock);
81 +               dev_kfree_skb_any(msdu);
82 +               return;
83 +       }
84 +       spin_unlock_bh(&ab->base_lock);
85 +
86 +       status.sta = peer->sta;
87 +       status.info = info;
88 +       status.skb = msdu;
89 +
90 +       ieee80211_tx_status_ext(ar->hw, &status);
91  }
92  
93  static void
94 @@ -379,7 +402,15 @@ ath11k_dp_tx_process_htt_tx_complete(str
95                 ts.msdu_id = msdu_id;
96                 ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI,
97                                         status_desc->info1);
98 +
99 +               if (FIELD_GET(HTT_TX_WBM_COMP_INFO2_VALID, status_desc->info2))
100 +                       ts.peer_id = FIELD_GET(HTT_TX_WBM_COMP_INFO2_SW_PEER_ID,
101 +                                              status_desc->info2);
102 +               else
103 +                       ts.peer_id = HTT_INVALID_PEER_ID;
104 +
105                 ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, &ts);
106 +
107                 break;
108         case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
109         case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
110 --- a/drivers/net/wireless/ath/ath11k/dp_tx.h
111 +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h
112 @@ -13,6 +13,7 @@ struct ath11k_dp_htt_wbm_tx_status {
113         u32 msdu_id;
114         bool acked;
115         int ack_rssi;
116 +       u16 peer_id;
117  };
118  
119  void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts);