1 | // SPDX-License-Identifier: BSD-3-Clause-Clear |
2 | /* |
3 | * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include "core.h" |
8 | #include "dp_tx.h" |
9 | #include "debug.h" |
10 | #include "debugfs_sta.h" |
11 | #include "hw.h" |
12 | #include "peer.h" |
13 | #include "mac.h" |
14 | |
15 | static enum hal_tcl_encap_type |
16 | ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb) |
17 | { |
18 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
19 | struct ath11k_base *ab = arvif->ar->ab; |
20 | |
21 | if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) |
22 | return HAL_TCL_ENCAP_TYPE_RAW; |
23 | |
24 | if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) |
25 | return HAL_TCL_ENCAP_TYPE_ETHERNET; |
26 | |
27 | return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI; |
28 | } |
29 | |
30 | static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb) |
31 | { |
32 | struct ieee80211_hdr *hdr = (void *)skb->data; |
33 | u8 *qos_ctl; |
34 | |
35 | if (!ieee80211_is_data_qos(fc: hdr->frame_control)) |
36 | return; |
37 | |
38 | qos_ctl = ieee80211_get_qos_ctl(hdr); |
39 | memmove(skb->data + IEEE80211_QOS_CTL_LEN, |
40 | skb->data, (void *)qos_ctl - (void *)skb->data); |
41 | skb_pull(skb, IEEE80211_QOS_CTL_LEN); |
42 | |
43 | hdr = (void *)skb->data; |
44 | hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
45 | } |
46 | |
47 | static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb) |
48 | { |
49 | struct ieee80211_hdr *hdr = (void *)skb->data; |
50 | struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb); |
51 | |
52 | if (cb->flags & ATH11K_SKB_HW_80211_ENCAP) |
53 | return skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
54 | else if (!ieee80211_is_data_qos(fc: hdr->frame_control)) |
55 | return HAL_DESC_REO_NON_QOS_TID; |
56 | else |
57 | return skb->priority & IEEE80211_QOS_CTL_TID_MASK; |
58 | } |
59 | |
60 | enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher) |
61 | { |
62 | switch (cipher) { |
63 | case WLAN_CIPHER_SUITE_WEP40: |
64 | return HAL_ENCRYPT_TYPE_WEP_40; |
65 | case WLAN_CIPHER_SUITE_WEP104: |
66 | return HAL_ENCRYPT_TYPE_WEP_104; |
67 | case WLAN_CIPHER_SUITE_TKIP: |
68 | return HAL_ENCRYPT_TYPE_TKIP_MIC; |
69 | case WLAN_CIPHER_SUITE_CCMP: |
70 | return HAL_ENCRYPT_TYPE_CCMP_128; |
71 | case WLAN_CIPHER_SUITE_CCMP_256: |
72 | return HAL_ENCRYPT_TYPE_CCMP_256; |
73 | case WLAN_CIPHER_SUITE_GCMP: |
74 | return HAL_ENCRYPT_TYPE_GCMP_128; |
75 | case WLAN_CIPHER_SUITE_GCMP_256: |
76 | return HAL_ENCRYPT_TYPE_AES_GCMP_256; |
77 | default: |
78 | return HAL_ENCRYPT_TYPE_OPEN; |
79 | } |
80 | } |
81 | |
82 | int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, |
83 | struct ath11k_sta *arsta, struct sk_buff *skb) |
84 | { |
85 | struct ath11k_base *ab = ar->ab; |
86 | struct ath11k_dp *dp = &ab->dp; |
87 | struct hal_tx_info ti = {0}; |
88 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
89 | struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); |
90 | struct hal_srng *tcl_ring; |
91 | struct ieee80211_hdr *hdr = (void *)skb->data; |
92 | struct dp_tx_ring *tx_ring; |
93 | void *hal_tcl_desc; |
94 | u8 pool_id; |
95 | u8 hal_ring_id; |
96 | int ret; |
97 | u32 ring_selector = 0; |
98 | u8 ring_map = 0; |
99 | bool tcl_ring_retry; |
100 | |
101 | if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))) |
102 | return -ESHUTDOWN; |
103 | |
104 | if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && |
105 | !ieee80211_is_data(hdr->frame_control))) |
106 | return -EOPNOTSUPP; |
107 | |
108 | pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); |
109 | |
110 | ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb); |
111 | |
112 | tcl_ring_sel: |
113 | tcl_ring_retry = false; |
114 | |
115 | ti.ring_id = ring_selector % ab->hw_params.max_tx_ring; |
116 | ti.rbm_id = ab->hw_params.hal_params->tcl2wbm_rbm_map[ti.ring_id].rbm_id; |
117 | |
118 | ring_map |= BIT(ti.ring_id); |
119 | |
120 | tx_ring = &dp->tx_ring[ti.ring_id]; |
121 | |
122 | spin_lock_bh(lock: &tx_ring->tx_idr_lock); |
123 | ret = idr_alloc(&tx_ring->txbuf_idr, ptr: skb, start: 0, |
124 | DP_TX_IDR_SIZE - 1, GFP_ATOMIC); |
125 | spin_unlock_bh(lock: &tx_ring->tx_idr_lock); |
126 | |
127 | if (unlikely(ret < 0)) { |
128 | if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1) || |
129 | !ab->hw_params.tcl_ring_retry) { |
130 | atomic_inc(v: &ab->soc_stats.tx_err.misc_fail); |
131 | return -ENOSPC; |
132 | } |
133 | |
134 | /* Check if the next ring is available */ |
135 | ring_selector++; |
136 | goto tcl_ring_sel; |
137 | } |
138 | |
139 | ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) | |
140 | FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) | |
141 | FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id); |
142 | ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb); |
143 | |
144 | if (ieee80211_has_a4(fc: hdr->frame_control) && |
145 | is_multicast_ether_addr(addr: hdr->addr3) && arsta && |
146 | arsta->use_4addr_set) { |
147 | ti.meta_data_flags = arsta->tcl_metadata; |
148 | ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TO_FW, 1); |
149 | } else { |
150 | ti.meta_data_flags = arvif->tcl_metadata; |
151 | } |
152 | |
153 | if (unlikely(ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW)) { |
154 | if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { |
155 | ti.encrypt_type = |
156 | ath11k_dp_tx_get_encrypt_type(cipher: skb_cb->cipher); |
157 | |
158 | if (ieee80211_has_protected(fc: hdr->frame_control)) |
159 | skb_put(skb, IEEE80211_CCMP_MIC_LEN); |
160 | } else { |
161 | ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; |
162 | } |
163 | } |
164 | |
165 | ti.addr_search_flags = arvif->hal_addr_search_flags; |
166 | ti.search_type = arvif->search_type; |
167 | ti.type = HAL_TCL_DESC_TYPE_BUFFER; |
168 | ti.pkt_offset = 0; |
169 | ti.lmac_id = ar->lmac_id; |
170 | ti.bss_ast_hash = arvif->ast_hash; |
171 | ti.bss_ast_idx = arvif->ast_idx; |
172 | ti.dscp_tid_tbl_idx = 0; |
173 | |
174 | if (likely(skb->ip_summed == CHECKSUM_PARTIAL && |
175 | ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) { |
176 | ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) | |
177 | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) | |
178 | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) | |
179 | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN, 1) | |
180 | FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN, 1); |
181 | } |
182 | |
183 | if (ieee80211_vif_is_mesh(vif: arvif->vif)) |
184 | ti.enable_mesh = true; |
185 | |
186 | ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1); |
187 | |
188 | ti.tid = ath11k_dp_tx_get_tid(skb); |
189 | |
190 | switch (ti.encap_type) { |
191 | case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI: |
192 | ath11k_dp_tx_encap_nwifi(skb); |
193 | break; |
194 | case HAL_TCL_ENCAP_TYPE_RAW: |
195 | if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { |
196 | ret = -EINVAL; |
197 | goto fail_remove_idr; |
198 | } |
199 | break; |
200 | case HAL_TCL_ENCAP_TYPE_ETHERNET: |
201 | /* no need to encap */ |
202 | break; |
203 | case HAL_TCL_ENCAP_TYPE_802_3: |
204 | default: |
205 | /* TODO: Take care of other encap modes as well */ |
206 | ret = -EINVAL; |
207 | atomic_inc(v: &ab->soc_stats.tx_err.misc_fail); |
208 | goto fail_remove_idr; |
209 | } |
210 | |
211 | ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); |
212 | if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) { |
213 | atomic_inc(v: &ab->soc_stats.tx_err.misc_fail); |
214 | ath11k_warn(ab, fmt: "failed to DMA map data Tx buffer\n" ); |
215 | ret = -ENOMEM; |
216 | goto fail_remove_idr; |
217 | } |
218 | |
219 | ti.data_len = skb->len; |
220 | skb_cb->paddr = ti.paddr; |
221 | skb_cb->vif = arvif->vif; |
222 | skb_cb->ar = ar; |
223 | |
224 | hal_ring_id = tx_ring->tcl_data_ring.ring_id; |
225 | tcl_ring = &ab->hal.srng_list[hal_ring_id]; |
226 | |
227 | spin_lock_bh(lock: &tcl_ring->lock); |
228 | |
229 | ath11k_hal_srng_access_begin(ab, srng: tcl_ring); |
230 | |
231 | hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, srng: tcl_ring); |
232 | if (unlikely(!hal_tcl_desc)) { |
233 | /* NOTE: It is highly unlikely we'll be running out of tcl_ring |
234 | * desc because the desc is directly enqueued onto hw queue. |
235 | */ |
236 | ath11k_hal_srng_access_end(ab, srng: tcl_ring); |
237 | ab->soc_stats.tx_err.desc_na[ti.ring_id]++; |
238 | spin_unlock_bh(lock: &tcl_ring->lock); |
239 | ret = -ENOMEM; |
240 | |
241 | /* Checking for available tcl descriptors in another ring in |
242 | * case of failure due to full tcl ring now, is better than |
243 | * checking this ring earlier for each pkt tx. |
244 | * Restart ring selection if some rings are not checked yet. |
245 | */ |
246 | if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) && |
247 | ab->hw_params.tcl_ring_retry && ab->hw_params.max_tx_ring > 1) { |
248 | tcl_ring_retry = true; |
249 | ring_selector++; |
250 | } |
251 | |
252 | goto fail_unmap_dma; |
253 | } |
254 | |
255 | ath11k_hal_tx_cmd_desc_setup(ab, cmd: hal_tcl_desc + |
256 | sizeof(struct hal_tlv_hdr), ti: &ti); |
257 | |
258 | ath11k_hal_srng_access_end(ab, srng: tcl_ring); |
259 | |
260 | ath11k_dp_shadow_start_timer(ab, srng: tcl_ring, update_timer: &dp->tx_ring_timer[ti.ring_id]); |
261 | |
262 | spin_unlock_bh(lock: &tcl_ring->lock); |
263 | |
264 | ath11k_dbg_dump(ab, mask: ATH11K_DBG_DP_TX, NULL, prefix: "dp tx msdu: " , |
265 | buf: skb->data, len: skb->len); |
266 | |
267 | atomic_inc(v: &ar->dp.num_tx_pending); |
268 | |
269 | return 0; |
270 | |
271 | fail_unmap_dma: |
272 | dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE); |
273 | |
274 | fail_remove_idr: |
275 | spin_lock_bh(lock: &tx_ring->tx_idr_lock); |
276 | idr_remove(&tx_ring->txbuf_idr, |
277 | FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id)); |
278 | spin_unlock_bh(lock: &tx_ring->tx_idr_lock); |
279 | |
280 | if (tcl_ring_retry) |
281 | goto tcl_ring_sel; |
282 | |
283 | return ret; |
284 | } |
285 | |
286 | static void ath11k_dp_tx_free_txbuf(struct ath11k_base *ab, u8 mac_id, |
287 | int msdu_id, |
288 | struct dp_tx_ring *tx_ring) |
289 | { |
290 | struct ath11k *ar; |
291 | struct sk_buff *msdu; |
292 | struct ath11k_skb_cb *skb_cb; |
293 | |
294 | spin_lock(lock: &tx_ring->tx_idr_lock); |
295 | msdu = idr_remove(&tx_ring->txbuf_idr, id: msdu_id); |
296 | spin_unlock(lock: &tx_ring->tx_idr_lock); |
297 | |
298 | if (unlikely(!msdu)) { |
299 | ath11k_warn(ab, fmt: "tx completion for unknown msdu_id %d\n" , |
300 | msdu_id); |
301 | return; |
302 | } |
303 | |
304 | skb_cb = ATH11K_SKB_CB(skb: msdu); |
305 | |
306 | dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
307 | dev_kfree_skb_any(skb: msdu); |
308 | |
309 | ar = ab->pdevs[mac_id].ar; |
310 | if (atomic_dec_and_test(v: &ar->dp.num_tx_pending)) |
311 | wake_up(&ar->dp.tx_empty_waitq); |
312 | } |
313 | |
314 | static void |
315 | ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, |
316 | struct dp_tx_ring *tx_ring, |
317 | struct ath11k_dp_htt_wbm_tx_status *ts) |
318 | { |
319 | struct ieee80211_tx_status status = { 0 }; |
320 | struct sk_buff *msdu; |
321 | struct ieee80211_tx_info *info; |
322 | struct ath11k_skb_cb *skb_cb; |
323 | struct ath11k *ar; |
324 | struct ath11k_peer *peer; |
325 | |
326 | spin_lock(lock: &tx_ring->tx_idr_lock); |
327 | msdu = idr_remove(&tx_ring->txbuf_idr, id: ts->msdu_id); |
328 | spin_unlock(lock: &tx_ring->tx_idr_lock); |
329 | |
330 | if (unlikely(!msdu)) { |
331 | ath11k_warn(ab, fmt: "htt tx completion for unknown msdu_id %d\n" , |
332 | ts->msdu_id); |
333 | return; |
334 | } |
335 | |
336 | skb_cb = ATH11K_SKB_CB(skb: msdu); |
337 | info = IEEE80211_SKB_CB(skb: msdu); |
338 | |
339 | ar = skb_cb->ar; |
340 | |
341 | if (atomic_dec_and_test(v: &ar->dp.num_tx_pending)) |
342 | wake_up(&ar->dp.tx_empty_waitq); |
343 | |
344 | dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
345 | |
346 | if (!skb_cb->vif) { |
347 | ieee80211_free_txskb(hw: ar->hw, skb: msdu); |
348 | return; |
349 | } |
350 | |
351 | memset(&info->status, 0, sizeof(info->status)); |
352 | |
353 | if (ts->acked) { |
354 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { |
355 | info->flags |= IEEE80211_TX_STAT_ACK; |
356 | info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR + |
357 | ts->ack_rssi; |
358 | info->status.flags |= |
359 | IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; |
360 | } else { |
361 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
362 | } |
363 | } |
364 | |
365 | spin_lock_bh(lock: &ab->base_lock); |
366 | peer = ath11k_peer_find_by_id(ab, peer_id: ts->peer_id); |
367 | if (!peer || !peer->sta) { |
368 | ath11k_dbg(ab, ATH11K_DBG_DATA, |
369 | "dp_tx: failed to find the peer with peer_id %d\n" , |
370 | ts->peer_id); |
371 | spin_unlock_bh(lock: &ab->base_lock); |
372 | ieee80211_free_txskb(hw: ar->hw, skb: msdu); |
373 | return; |
374 | } |
375 | spin_unlock_bh(lock: &ab->base_lock); |
376 | |
377 | status.sta = peer->sta; |
378 | status.info = info; |
379 | status.skb = msdu; |
380 | |
381 | ieee80211_tx_status_ext(hw: ar->hw, status: &status); |
382 | } |
383 | |
384 | static void |
385 | ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab, |
386 | void *desc, u8 mac_id, |
387 | u32 msdu_id, struct dp_tx_ring *tx_ring) |
388 | { |
389 | struct htt_tx_wbm_completion *status_desc; |
390 | struct ath11k_dp_htt_wbm_tx_status ts = {0}; |
391 | enum hal_wbm_htt_tx_comp_status wbm_status; |
392 | |
393 | status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET; |
394 | |
395 | wbm_status = FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS, |
396 | status_desc->info0); |
397 | switch (wbm_status) { |
398 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK: |
399 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: |
400 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: |
401 | ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); |
402 | ts.msdu_id = msdu_id; |
403 | ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI, |
404 | status_desc->info1); |
405 | |
406 | if (FIELD_GET(HTT_TX_WBM_COMP_INFO2_VALID, status_desc->info2)) |
407 | ts.peer_id = FIELD_GET(HTT_TX_WBM_COMP_INFO2_SW_PEER_ID, |
408 | status_desc->info2); |
409 | else |
410 | ts.peer_id = HTT_INVALID_PEER_ID; |
411 | |
412 | ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, ts: &ts); |
413 | |
414 | break; |
415 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ: |
416 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT: |
417 | ath11k_dp_tx_free_txbuf(ab, mac_id, msdu_id, tx_ring); |
418 | break; |
419 | case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY: |
420 | /* This event is to be handled only when the driver decides to |
421 | * use WDS offload functionality. |
422 | */ |
423 | break; |
424 | default: |
425 | ath11k_warn(ab, fmt: "Unknown htt tx status %d\n" , wbm_status); |
426 | break; |
427 | } |
428 | } |
429 | |
430 | static void ath11k_dp_tx_cache_peer_stats(struct ath11k *ar, |
431 | struct sk_buff *msdu, |
432 | struct hal_tx_status *ts) |
433 | { |
434 | struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; |
435 | |
436 | if (ts->try_cnt > 1) { |
437 | peer_stats->retry_pkts += ts->try_cnt - 1; |
438 | peer_stats->retry_bytes += (ts->try_cnt - 1) * msdu->len; |
439 | |
440 | if (ts->status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) { |
441 | peer_stats->failed_pkts += 1; |
442 | peer_stats->failed_bytes += msdu->len; |
443 | } |
444 | } |
445 | } |
446 | |
447 | void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts) |
448 | { |
449 | struct ath11k_base *ab = ar->ab; |
450 | struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; |
451 | enum hal_tx_rate_stats_pkt_type pkt_type; |
452 | enum hal_tx_rate_stats_sgi sgi; |
453 | enum hal_tx_rate_stats_bw bw; |
454 | struct ath11k_peer *peer; |
455 | struct ath11k_sta *arsta; |
456 | struct ieee80211_sta *sta; |
457 | u16 rate, ru_tones; |
458 | u8 mcs, rate_idx = 0, ofdma; |
459 | int ret; |
460 | |
461 | spin_lock_bh(lock: &ab->base_lock); |
462 | peer = ath11k_peer_find_by_id(ab, peer_id: ts->peer_id); |
463 | if (!peer || !peer->sta) { |
464 | ath11k_dbg(ab, ATH11K_DBG_DP_TX, |
465 | "failed to find the peer by id %u\n" , ts->peer_id); |
466 | goto err_out; |
467 | } |
468 | |
469 | sta = peer->sta; |
470 | arsta = ath11k_sta_to_arsta(sta); |
471 | |
472 | memset(&arsta->txrate, 0, sizeof(arsta->txrate)); |
473 | pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, |
474 | ts->rate_stats); |
475 | mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, |
476 | ts->rate_stats); |
477 | sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, |
478 | ts->rate_stats); |
479 | bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); |
480 | ru_tones = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, ts->rate_stats); |
481 | ofdma = FIELD_GET(HAL_TX_RATE_STATS_INFO0_OFDMA_TX, ts->rate_stats); |
482 | |
483 | /* This is to prefer choose the real NSS value arsta->last_txrate.nss, |
484 | * if it is invalid, then choose the NSS value while assoc. |
485 | */ |
486 | if (arsta->last_txrate.nss) |
487 | arsta->txrate.nss = arsta->last_txrate.nss; |
488 | else |
489 | arsta->txrate.nss = arsta->peer_nss; |
490 | |
491 | if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || |
492 | pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { |
493 | ret = ath11k_mac_hw_ratecode_to_legacy_rate(hw_rc: mcs, |
494 | preamble: pkt_type, |
495 | rateidx: &rate_idx, |
496 | rate: &rate); |
497 | if (ret < 0) |
498 | goto err_out; |
499 | arsta->txrate.legacy = rate; |
500 | } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { |
501 | if (mcs > 7) { |
502 | ath11k_warn(ab, fmt: "Invalid HT mcs index %d\n" , mcs); |
503 | goto err_out; |
504 | } |
505 | |
506 | if (arsta->txrate.nss != 0) |
507 | arsta->txrate.mcs = mcs + 8 * (arsta->txrate.nss - 1); |
508 | arsta->txrate.flags = RATE_INFO_FLAGS_MCS; |
509 | if (sgi) |
510 | arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
511 | } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { |
512 | if (mcs > 9) { |
513 | ath11k_warn(ab, fmt: "Invalid VHT mcs index %d\n" , mcs); |
514 | goto err_out; |
515 | } |
516 | |
517 | arsta->txrate.mcs = mcs; |
518 | arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; |
519 | if (sgi) |
520 | arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; |
521 | } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { |
522 | if (mcs > 11) { |
523 | ath11k_warn(ab, fmt: "Invalid HE mcs index %d\n" , mcs); |
524 | goto err_out; |
525 | } |
526 | |
527 | arsta->txrate.mcs = mcs; |
528 | arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS; |
529 | arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi); |
530 | } |
531 | |
532 | arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); |
533 | if (ofdma && pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { |
534 | arsta->txrate.bw = RATE_INFO_BW_HE_RU; |
535 | arsta->txrate.he_ru_alloc = |
536 | ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones); |
537 | } |
538 | |
539 | if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) |
540 | ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, legacy_rate_idx: rate_idx); |
541 | |
542 | err_out: |
543 | spin_unlock_bh(lock: &ab->base_lock); |
544 | } |
545 | |
546 | static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, |
547 | struct sk_buff *msdu, |
548 | struct hal_tx_status *ts) |
549 | { |
550 | struct ieee80211_tx_status status = { 0 }; |
551 | struct ieee80211_rate_status status_rate = { 0 }; |
552 | struct ath11k_base *ab = ar->ab; |
553 | struct ieee80211_tx_info *info; |
554 | struct ath11k_skb_cb *skb_cb; |
555 | struct ath11k_peer *peer; |
556 | struct ath11k_sta *arsta; |
557 | struct rate_info rate; |
558 | |
559 | if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { |
560 | /* Must not happen */ |
561 | return; |
562 | } |
563 | |
564 | skb_cb = ATH11K_SKB_CB(skb: msdu); |
565 | |
566 | dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
567 | |
568 | if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) { |
569 | ieee80211_free_txskb(hw: ar->hw, skb: msdu); |
570 | return; |
571 | } |
572 | |
573 | if (unlikely(!skb_cb->vif)) { |
574 | ieee80211_free_txskb(hw: ar->hw, skb: msdu); |
575 | return; |
576 | } |
577 | |
578 | info = IEEE80211_SKB_CB(skb: msdu); |
579 | memset(&info->status, 0, sizeof(info->status)); |
580 | |
581 | /* skip tx rate update from ieee80211_status*/ |
582 | info->status.rates[0].idx = -1; |
583 | |
584 | if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED && |
585 | !(info->flags & IEEE80211_TX_CTL_NO_ACK)) { |
586 | info->flags |= IEEE80211_TX_STAT_ACK; |
587 | info->status.ack_signal = ATH11K_DEFAULT_NOISE_FLOOR + |
588 | ts->ack_rssi; |
589 | info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; |
590 | } |
591 | |
592 | if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX && |
593 | (info->flags & IEEE80211_TX_CTL_NO_ACK)) |
594 | info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; |
595 | |
596 | if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)) || |
597 | ab->hw_params.single_pdev_only) { |
598 | if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) { |
599 | if (ar->last_ppdu_id == 0) { |
600 | ar->last_ppdu_id = ts->ppdu_id; |
601 | } else if (ar->last_ppdu_id == ts->ppdu_id || |
602 | ar->cached_ppdu_id == ar->last_ppdu_id) { |
603 | ar->cached_ppdu_id = ar->last_ppdu_id; |
604 | ar->cached_stats.is_ampdu = true; |
605 | ath11k_dp_tx_update_txcompl(ar, ts); |
606 | memset(&ar->cached_stats, 0, |
607 | sizeof(struct ath11k_per_peer_tx_stats)); |
608 | } else { |
609 | ar->cached_stats.is_ampdu = false; |
610 | ath11k_dp_tx_update_txcompl(ar, ts); |
611 | memset(&ar->cached_stats, 0, |
612 | sizeof(struct ath11k_per_peer_tx_stats)); |
613 | } |
614 | ar->last_ppdu_id = ts->ppdu_id; |
615 | } |
616 | |
617 | ath11k_dp_tx_cache_peer_stats(ar, msdu, ts); |
618 | } |
619 | |
620 | spin_lock_bh(lock: &ab->base_lock); |
621 | peer = ath11k_peer_find_by_id(ab, peer_id: ts->peer_id); |
622 | if (!peer || !peer->sta) { |
623 | ath11k_dbg(ab, ATH11K_DBG_DATA, |
624 | "dp_tx: failed to find the peer with peer_id %d\n" , |
625 | ts->peer_id); |
626 | spin_unlock_bh(lock: &ab->base_lock); |
627 | ieee80211_free_txskb(hw: ar->hw, skb: msdu); |
628 | return; |
629 | } |
630 | arsta = ath11k_sta_to_arsta(sta: peer->sta); |
631 | status.sta = peer->sta; |
632 | status.skb = msdu; |
633 | status.info = info; |
634 | rate = arsta->last_txrate; |
635 | |
636 | status_rate.rate_idx = rate; |
637 | status_rate.try_count = 1; |
638 | |
639 | status.rates = &status_rate; |
640 | status.n_rates = 1; |
641 | |
642 | spin_unlock_bh(lock: &ab->base_lock); |
643 | |
644 | ieee80211_tx_status_ext(hw: ar->hw, status: &status); |
645 | } |
646 | |
647 | static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, |
648 | struct hal_wbm_release_ring *desc, |
649 | struct hal_tx_status *ts) |
650 | { |
651 | ts->buf_rel_source = |
652 | FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); |
653 | if (unlikely(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && |
654 | ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) |
655 | return; |
656 | |
657 | if (unlikely(ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) |
658 | return; |
659 | |
660 | ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, |
661 | desc->info0); |
662 | ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER, |
663 | desc->info1); |
664 | ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT, |
665 | desc->info1); |
666 | ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI, |
667 | desc->info2); |
668 | if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU) |
669 | ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU; |
670 | ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3); |
671 | ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3); |
672 | if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID) |
673 | ts->rate_stats = desc->rate_stats.info0; |
674 | else |
675 | ts->rate_stats = 0; |
676 | } |
677 | |
678 | void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) |
679 | { |
680 | struct ath11k *ar; |
681 | struct ath11k_dp *dp = &ab->dp; |
682 | int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; |
683 | struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; |
684 | struct sk_buff *msdu; |
685 | struct hal_tx_status ts = { 0 }; |
686 | struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; |
687 | u32 *desc; |
688 | u32 msdu_id; |
689 | u8 mac_id; |
690 | |
691 | spin_lock_bh(lock: &status_ring->lock); |
692 | |
693 | ath11k_hal_srng_access_begin(ab, srng: status_ring); |
694 | |
695 | while ((ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) != |
696 | tx_ring->tx_status_tail) && |
697 | (desc = ath11k_hal_srng_dst_get_next_entry(ab, srng: status_ring))) { |
698 | memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], |
699 | desc, sizeof(struct hal_wbm_release_ring)); |
700 | tx_ring->tx_status_head = |
701 | ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head); |
702 | } |
703 | |
704 | if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && |
705 | (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == |
706 | tx_ring->tx_status_tail))) { |
707 | /* TODO: Process pending tx_status messages when kfifo_is_full() */ |
708 | ath11k_warn(ab, fmt: "Unable to process some of the tx_status ring desc because status_fifo is full\n" ); |
709 | } |
710 | |
711 | ath11k_hal_srng_access_end(ab, srng: status_ring); |
712 | |
713 | spin_unlock_bh(lock: &status_ring->lock); |
714 | |
715 | while (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) { |
716 | struct hal_wbm_release_ring *tx_status; |
717 | u32 desc_id; |
718 | |
719 | tx_ring->tx_status_tail = |
720 | ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail); |
721 | tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; |
722 | ath11k_dp_tx_status_parse(ab, desc: tx_status, ts: &ts); |
723 | |
724 | desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, |
725 | tx_status->buf_addr_info.info1); |
726 | mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); |
727 | msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); |
728 | |
729 | if (unlikely(ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) { |
730 | ath11k_dp_tx_process_htt_tx_complete(ab, |
731 | desc: (void *)tx_status, |
732 | mac_id, msdu_id, |
733 | tx_ring); |
734 | continue; |
735 | } |
736 | |
737 | spin_lock(lock: &tx_ring->tx_idr_lock); |
738 | msdu = idr_remove(&tx_ring->txbuf_idr, id: msdu_id); |
739 | if (unlikely(!msdu)) { |
740 | ath11k_warn(ab, fmt: "tx completion for unknown msdu_id %d\n" , |
741 | msdu_id); |
742 | spin_unlock(lock: &tx_ring->tx_idr_lock); |
743 | continue; |
744 | } |
745 | |
746 | spin_unlock(lock: &tx_ring->tx_idr_lock); |
747 | |
748 | ar = ab->pdevs[mac_id].ar; |
749 | |
750 | if (atomic_dec_and_test(v: &ar->dp.num_tx_pending)) |
751 | wake_up(&ar->dp.tx_empty_waitq); |
752 | |
753 | ath11k_dp_tx_complete_msdu(ar, msdu, ts: &ts); |
754 | } |
755 | } |
756 | |
757 | int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, |
758 | enum hal_reo_cmd_type type, |
759 | struct ath11k_hal_reo_cmd *cmd, |
760 | void (*cb)(struct ath11k_dp *, void *, |
761 | enum hal_reo_cmd_status)) |
762 | { |
763 | struct ath11k_dp *dp = &ab->dp; |
764 | struct dp_reo_cmd *dp_cmd; |
765 | struct hal_srng *cmd_ring; |
766 | int cmd_num; |
767 | |
768 | if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags)) |
769 | return -ESHUTDOWN; |
770 | |
771 | cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id]; |
772 | cmd_num = ath11k_hal_reo_cmd_send(ab, srng: cmd_ring, type, cmd); |
773 | |
774 | /* cmd_num should start from 1, during failure return the error code */ |
775 | if (cmd_num < 0) |
776 | return cmd_num; |
777 | |
778 | /* reo cmd ring descriptors has cmd_num starting from 1 */ |
779 | if (cmd_num == 0) |
780 | return -EINVAL; |
781 | |
782 | if (!cb) |
783 | return 0; |
784 | |
785 | /* Can this be optimized so that we keep the pending command list only |
786 | * for tid delete command to free up the resource on the command status |
787 | * indication? |
788 | */ |
789 | dp_cmd = kzalloc(size: sizeof(*dp_cmd), GFP_ATOMIC); |
790 | |
791 | if (!dp_cmd) |
792 | return -ENOMEM; |
793 | |
794 | memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid)); |
795 | dp_cmd->cmd_num = cmd_num; |
796 | dp_cmd->handler = cb; |
797 | |
798 | spin_lock_bh(lock: &dp->reo_cmd_lock); |
799 | list_add_tail(new: &dp_cmd->list, head: &dp->reo_cmd_list); |
800 | spin_unlock_bh(lock: &dp->reo_cmd_lock); |
801 | |
802 | return 0; |
803 | } |
804 | |
805 | static int |
806 | ath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab, |
807 | int mac_id, u32 ring_id, |
808 | enum hal_ring_type ring_type, |
809 | enum htt_srng_ring_type *htt_ring_type, |
810 | enum htt_srng_ring_id *htt_ring_id) |
811 | { |
812 | int lmac_ring_id_offset = 0; |
813 | int ret = 0; |
814 | |
815 | switch (ring_type) { |
816 | case HAL_RXDMA_BUF: |
817 | lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC; |
818 | |
819 | /* for QCA6390, host fills rx buffer to fw and fw fills to |
820 | * rxbuf ring for each rxdma |
821 | */ |
822 | if (!ab->hw_params.rx_mac_buf_ring) { |
823 | if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF + |
824 | lmac_ring_id_offset) || |
825 | ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF + |
826 | lmac_ring_id_offset))) { |
827 | ret = -EINVAL; |
828 | } |
829 | *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; |
830 | *htt_ring_type = HTT_SW_TO_HW_RING; |
831 | } else { |
832 | if (ring_id == HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF) { |
833 | *htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; |
834 | *htt_ring_type = HTT_SW_TO_SW_RING; |
835 | } else { |
836 | *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; |
837 | *htt_ring_type = HTT_SW_TO_HW_RING; |
838 | } |
839 | } |
840 | break; |
841 | case HAL_RXDMA_DST: |
842 | *htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; |
843 | *htt_ring_type = HTT_HW_TO_SW_RING; |
844 | break; |
845 | case HAL_RXDMA_MONITOR_BUF: |
846 | *htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING; |
847 | *htt_ring_type = HTT_SW_TO_HW_RING; |
848 | break; |
849 | case HAL_RXDMA_MONITOR_STATUS: |
850 | *htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING; |
851 | *htt_ring_type = HTT_SW_TO_HW_RING; |
852 | break; |
853 | case HAL_RXDMA_MONITOR_DST: |
854 | *htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING; |
855 | *htt_ring_type = HTT_HW_TO_SW_RING; |
856 | break; |
857 | case HAL_RXDMA_MONITOR_DESC: |
858 | *htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING; |
859 | *htt_ring_type = HTT_SW_TO_HW_RING; |
860 | break; |
861 | default: |
862 | ath11k_warn(ab, fmt: "Unsupported ring type in DP :%d\n" , ring_type); |
863 | ret = -EINVAL; |
864 | } |
865 | return ret; |
866 | } |
867 | |
868 | int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, |
869 | int mac_id, enum hal_ring_type ring_type) |
870 | { |
871 | struct htt_srng_setup_cmd *cmd; |
872 | struct hal_srng *srng = &ab->hal.srng_list[ring_id]; |
873 | struct hal_srng_params params; |
874 | struct sk_buff *skb; |
875 | u32 ring_entry_sz; |
876 | int len = sizeof(*cmd); |
877 | dma_addr_t hp_addr, tp_addr; |
878 | enum htt_srng_ring_type htt_ring_type; |
879 | enum htt_srng_ring_id htt_ring_id; |
880 | int ret; |
881 | |
882 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
883 | if (!skb) |
884 | return -ENOMEM; |
885 | |
886 | memset(¶ms, 0, sizeof(params)); |
887 | ath11k_hal_srng_get_params(ab, srng, params: ¶ms); |
888 | |
889 | hp_addr = ath11k_hal_srng_get_hp_addr(ab, srng); |
890 | tp_addr = ath11k_hal_srng_get_tp_addr(ab, srng); |
891 | |
892 | ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id, |
893 | ring_type, htt_ring_type: &htt_ring_type, |
894 | htt_ring_id: &htt_ring_id); |
895 | if (ret) |
896 | goto err_free; |
897 | |
898 | skb_put(skb, len); |
899 | cmd = (struct htt_srng_setup_cmd *)skb->data; |
900 | cmd->info0 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE, |
901 | HTT_H2T_MSG_TYPE_SRING_SETUP); |
902 | if (htt_ring_type == HTT_SW_TO_HW_RING || |
903 | htt_ring_type == HTT_HW_TO_SW_RING) |
904 | cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID, |
905 | DP_SW2HW_MACID(mac_id)); |
906 | else |
907 | cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID, |
908 | mac_id); |
909 | cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE, |
910 | htt_ring_type); |
911 | cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_ID, htt_ring_id); |
912 | |
913 | cmd->ring_base_addr_lo = params.ring_base_paddr & |
914 | HAL_ADDR_LSB_REG_MASK; |
915 | |
916 | cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >> |
917 | HAL_ADDR_MSB_REG_SHIFT; |
918 | |
919 | ret = ath11k_hal_srng_get_entrysize(ab, ring_type); |
920 | if (ret < 0) |
921 | goto err_free; |
922 | |
923 | ring_entry_sz = ret; |
924 | |
925 | ring_entry_sz >>= 2; |
926 | cmd->info1 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE, |
927 | ring_entry_sz); |
928 | cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE, |
929 | params.num_entries * ring_entry_sz); |
930 | cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP, |
931 | !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP)); |
932 | cmd->info1 |= FIELD_PREP( |
933 | HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP, |
934 | !!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)); |
935 | cmd->info1 |= FIELD_PREP( |
936 | HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP, |
937 | !!(params.flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)); |
938 | if (htt_ring_type == HTT_SW_TO_HW_RING) |
939 | cmd->info1 |= HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS; |
940 | |
941 | cmd->ring_head_off32_remote_addr_lo = hp_addr & HAL_ADDR_LSB_REG_MASK; |
942 | cmd->ring_head_off32_remote_addr_hi = (u64)hp_addr >> |
943 | HAL_ADDR_MSB_REG_SHIFT; |
944 | |
945 | cmd->ring_tail_off32_remote_addr_lo = tp_addr & HAL_ADDR_LSB_REG_MASK; |
946 | cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >> |
947 | HAL_ADDR_MSB_REG_SHIFT; |
948 | |
949 | cmd->ring_msi_addr_lo = lower_32_bits(params.msi_addr); |
950 | cmd->ring_msi_addr_hi = upper_32_bits(params.msi_addr); |
951 | cmd->msi_data = params.msi_data; |
952 | |
953 | cmd->intr_info = FIELD_PREP( |
954 | HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH, |
955 | params.intr_batch_cntr_thres_entries * ring_entry_sz); |
956 | cmd->intr_info |= FIELD_PREP( |
957 | HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH, |
958 | params.intr_timer_thres_us >> 3); |
959 | |
960 | cmd->info2 = 0; |
961 | if (params.flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) { |
962 | cmd->info2 = FIELD_PREP( |
963 | HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH, |
964 | params.low_threshold); |
965 | } |
966 | |
967 | ath11k_dbg(ab, ATH11K_DBG_DP_TX, |
968 | "htt srng setup msi_addr_lo 0x%x msi_addr_hi 0x%x msi_data 0x%x ring_id %d ring_type %d intr_info 0x%x flags 0x%x\n" , |
969 | cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi, |
970 | cmd->msi_data, ring_id, ring_type, cmd->intr_info, cmd->info2); |
971 | |
972 | ret = ath11k_htc_send(htc: &ab->htc, eid: ab->dp.eid, packet: skb); |
973 | if (ret) |
974 | goto err_free; |
975 | |
976 | return 0; |
977 | |
978 | err_free: |
979 | dev_kfree_skb_any(skb); |
980 | |
981 | return ret; |
982 | } |
983 | |
984 | #define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ) |
985 | |
986 | int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab) |
987 | { |
988 | struct ath11k_dp *dp = &ab->dp; |
989 | struct sk_buff *skb; |
990 | struct htt_ver_req_cmd *cmd; |
991 | int len = sizeof(*cmd); |
992 | int ret; |
993 | |
994 | init_completion(x: &dp->htt_tgt_version_received); |
995 | |
996 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
997 | if (!skb) |
998 | return -ENOMEM; |
999 | |
1000 | skb_put(skb, len); |
1001 | cmd = (struct htt_ver_req_cmd *)skb->data; |
1002 | cmd->ver_reg_info = FIELD_PREP(HTT_VER_REQ_INFO_MSG_ID, |
1003 | HTT_H2T_MSG_TYPE_VERSION_REQ); |
1004 | |
1005 | ret = ath11k_htc_send(htc: &ab->htc, eid: dp->eid, packet: skb); |
1006 | if (ret) { |
1007 | dev_kfree_skb_any(skb); |
1008 | return ret; |
1009 | } |
1010 | |
1011 | ret = wait_for_completion_timeout(x: &dp->htt_tgt_version_received, |
1012 | HTT_TARGET_VERSION_TIMEOUT_HZ); |
1013 | if (ret == 0) { |
1014 | ath11k_warn(ab, fmt: "htt target version request timed out\n" ); |
1015 | return -ETIMEDOUT; |
1016 | } |
1017 | |
1018 | if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { |
1019 | ath11k_err(ab, fmt: "unsupported htt major version %d supported version is %d\n" , |
1020 | dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); |
1021 | return -EOPNOTSUPP; |
1022 | } |
1023 | |
1024 | return 0; |
1025 | } |
1026 | |
1027 | int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask) |
1028 | { |
1029 | struct ath11k_base *ab = ar->ab; |
1030 | struct ath11k_dp *dp = &ab->dp; |
1031 | struct sk_buff *skb; |
1032 | struct htt_ppdu_stats_cfg_cmd *cmd; |
1033 | int len = sizeof(*cmd); |
1034 | u8 pdev_mask; |
1035 | int ret; |
1036 | int i; |
1037 | |
1038 | for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { |
1039 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
1040 | if (!skb) |
1041 | return -ENOMEM; |
1042 | |
1043 | skb_put(skb, len); |
1044 | cmd = (struct htt_ppdu_stats_cfg_cmd *)skb->data; |
1045 | cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE, |
1046 | HTT_H2T_MSG_TYPE_PPDU_STATS_CFG); |
1047 | |
1048 | pdev_mask = 1 << (ar->pdev_idx + i); |
1049 | cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask); |
1050 | cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask); |
1051 | |
1052 | ret = ath11k_htc_send(htc: &ab->htc, eid: dp->eid, packet: skb); |
1053 | if (ret) { |
1054 | dev_kfree_skb_any(skb); |
1055 | return ret; |
1056 | } |
1057 | } |
1058 | |
1059 | return 0; |
1060 | } |
1061 | |
1062 | int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id, |
1063 | int mac_id, enum hal_ring_type ring_type, |
1064 | int rx_buf_size, |
1065 | struct htt_rx_ring_tlv_filter *tlv_filter) |
1066 | { |
1067 | struct htt_rx_ring_selection_cfg_cmd *cmd; |
1068 | struct hal_srng *srng = &ab->hal.srng_list[ring_id]; |
1069 | struct hal_srng_params params; |
1070 | struct sk_buff *skb; |
1071 | int len = sizeof(*cmd); |
1072 | enum htt_srng_ring_type htt_ring_type; |
1073 | enum htt_srng_ring_id htt_ring_id; |
1074 | int ret; |
1075 | |
1076 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
1077 | if (!skb) |
1078 | return -ENOMEM; |
1079 | |
1080 | memset(¶ms, 0, sizeof(params)); |
1081 | ath11k_hal_srng_get_params(ab, srng, params: ¶ms); |
1082 | |
1083 | ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id, |
1084 | ring_type, htt_ring_type: &htt_ring_type, |
1085 | htt_ring_id: &htt_ring_id); |
1086 | if (ret) |
1087 | goto err_free; |
1088 | |
1089 | skb_put(skb, len); |
1090 | cmd = (struct htt_rx_ring_selection_cfg_cmd *)skb->data; |
1091 | cmd->info0 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE, |
1092 | HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG); |
1093 | if (htt_ring_type == HTT_SW_TO_HW_RING || |
1094 | htt_ring_type == HTT_HW_TO_SW_RING) |
1095 | cmd->info0 |= |
1096 | FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID, |
1097 | DP_SW2HW_MACID(mac_id)); |
1098 | else |
1099 | cmd->info0 |= |
1100 | FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID, |
1101 | mac_id); |
1102 | cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID, |
1103 | htt_ring_id); |
1104 | cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS, |
1105 | !!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP)); |
1106 | cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS, |
1107 | !!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)); |
1108 | |
1109 | cmd->info1 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE, |
1110 | rx_buf_size); |
1111 | cmd->pkt_type_en_flags0 = tlv_filter->pkt_filter_flags0; |
1112 | cmd->pkt_type_en_flags1 = tlv_filter->pkt_filter_flags1; |
1113 | cmd->pkt_type_en_flags2 = tlv_filter->pkt_filter_flags2; |
1114 | cmd->pkt_type_en_flags3 = tlv_filter->pkt_filter_flags3; |
1115 | cmd->rx_filter_tlv = tlv_filter->rx_filter; |
1116 | |
1117 | ret = ath11k_htc_send(htc: &ab->htc, eid: ab->dp.eid, packet: skb); |
1118 | if (ret) |
1119 | goto err_free; |
1120 | |
1121 | return 0; |
1122 | |
1123 | err_free: |
1124 | dev_kfree_skb_any(skb); |
1125 | |
1126 | return ret; |
1127 | } |
1128 | |
1129 | int |
1130 | ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type, |
1131 | struct htt_ext_stats_cfg_params *cfg_params, |
1132 | u64 cookie) |
1133 | { |
1134 | struct ath11k_base *ab = ar->ab; |
1135 | struct ath11k_dp *dp = &ab->dp; |
1136 | struct sk_buff *skb; |
1137 | struct htt_ext_stats_cfg_cmd *cmd; |
1138 | u32 pdev_id; |
1139 | int len = sizeof(*cmd); |
1140 | int ret; |
1141 | |
1142 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
1143 | if (!skb) |
1144 | return -ENOMEM; |
1145 | |
1146 | skb_put(skb, len); |
1147 | |
1148 | cmd = (struct htt_ext_stats_cfg_cmd *)skb->data; |
1149 | memset(cmd, 0, sizeof(*cmd)); |
1150 | cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; |
1151 | |
1152 | if (ab->hw_params.single_pdev_only) |
1153 | pdev_id = ath11k_mac_get_target_pdev_id(ar); |
1154 | else |
1155 | pdev_id = ar->pdev->pdev_id; |
1156 | |
1157 | cmd->hdr.pdev_mask = 1 << pdev_id; |
1158 | |
1159 | cmd->hdr.stats_type = type; |
1160 | cmd->cfg_param0 = cfg_params->cfg0; |
1161 | cmd->cfg_param1 = cfg_params->cfg1; |
1162 | cmd->cfg_param2 = cfg_params->cfg2; |
1163 | cmd->cfg_param3 = cfg_params->cfg3; |
1164 | cmd->cookie_lsb = lower_32_bits(cookie); |
1165 | cmd->cookie_msb = upper_32_bits(cookie); |
1166 | |
1167 | ret = ath11k_htc_send(htc: &ab->htc, eid: dp->eid, packet: skb); |
1168 | if (ret) { |
1169 | ath11k_warn(ab, fmt: "failed to send htt type stats request: %d" , |
1170 | ret); |
1171 | dev_kfree_skb_any(skb); |
1172 | return ret; |
1173 | } |
1174 | |
1175 | return 0; |
1176 | } |
1177 | |
1178 | int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) |
1179 | { |
1180 | struct ath11k_pdev_dp *dp = &ar->dp; |
1181 | struct ath11k_base *ab = ar->ab; |
1182 | struct htt_rx_ring_tlv_filter tlv_filter = {0}; |
1183 | int ret = 0, ring_id = 0, i; |
1184 | |
1185 | if (ab->hw_params.full_monitor_mode) { |
1186 | ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab, |
1187 | mac_id: dp->mac_id, config: !reset); |
1188 | if (ret < 0) { |
1189 | ath11k_err(ab, fmt: "failed to setup full monitor %d\n" , ret); |
1190 | return ret; |
1191 | } |
1192 | } |
1193 | |
1194 | ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; |
1195 | |
1196 | if (!reset) { |
1197 | tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING; |
1198 | tlv_filter.pkt_filter_flags0 = |
1199 | HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 | |
1200 | HTT_RX_MON_MO_MGMT_FILTER_FLAGS0; |
1201 | tlv_filter.pkt_filter_flags1 = |
1202 | HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 | |
1203 | HTT_RX_MON_MO_MGMT_FILTER_FLAGS1; |
1204 | tlv_filter.pkt_filter_flags2 = |
1205 | HTT_RX_MON_FP_CTRL_FILTER_FLASG2 | |
1206 | HTT_RX_MON_MO_CTRL_FILTER_FLASG2; |
1207 | tlv_filter.pkt_filter_flags3 = |
1208 | HTT_RX_MON_FP_CTRL_FILTER_FLASG3 | |
1209 | HTT_RX_MON_MO_CTRL_FILTER_FLASG3 | |
1210 | HTT_RX_MON_FP_DATA_FILTER_FLASG3 | |
1211 | HTT_RX_MON_MO_DATA_FILTER_FLASG3; |
1212 | } |
1213 | |
1214 | if (ab->hw_params.rxdma1_enable) { |
1215 | ret = ath11k_dp_tx_htt_rx_filter_setup(ab: ar->ab, ring_id, mac_id: dp->mac_id, |
1216 | ring_type: HAL_RXDMA_MONITOR_BUF, |
1217 | DP_RXDMA_REFILL_RING_SIZE, |
1218 | tlv_filter: &tlv_filter); |
1219 | } else if (!reset) { |
1220 | /* set in monitor mode only */ |
1221 | for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { |
1222 | ring_id = dp->rx_mac_buf_ring[i].ring_id; |
1223 | ret = ath11k_dp_tx_htt_rx_filter_setup(ab: ar->ab, ring_id, |
1224 | mac_id: dp->mac_id + i, |
1225 | ring_type: HAL_RXDMA_BUF, |
1226 | rx_buf_size: 1024, |
1227 | tlv_filter: &tlv_filter); |
1228 | } |
1229 | } |
1230 | |
1231 | if (ret) |
1232 | return ret; |
1233 | |
1234 | for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { |
1235 | ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id; |
1236 | if (!reset) { |
1237 | tlv_filter.rx_filter = |
1238 | HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING; |
1239 | } else { |
1240 | tlv_filter = ath11k_mac_mon_status_filter_default; |
1241 | |
1242 | if (ath11k_debugfs_is_extd_rx_stats_enabled(ar)) |
1243 | tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); |
1244 | } |
1245 | |
1246 | ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id, |
1247 | mac_id: dp->mac_id + i, |
1248 | ring_type: HAL_RXDMA_MONITOR_STATUS, |
1249 | DP_RXDMA_REFILL_RING_SIZE, |
1250 | tlv_filter: &tlv_filter); |
1251 | } |
1252 | |
1253 | if (!ar->ab->hw_params.rxdma1_enable) |
1254 | mod_timer(timer: &ar->ab->mon_reap_timer, expires: jiffies + |
1255 | msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); |
1256 | |
1257 | return ret; |
1258 | } |
1259 | |
1260 | int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id, |
1261 | bool config) |
1262 | { |
1263 | struct htt_rx_full_monitor_mode_cfg_cmd *cmd; |
1264 | struct sk_buff *skb; |
1265 | int ret, len = sizeof(*cmd); |
1266 | |
1267 | skb = ath11k_htc_alloc_skb(ar: ab, size: len); |
1268 | if (!skb) |
1269 | return -ENOMEM; |
1270 | |
1271 | skb_put(skb, len); |
1272 | cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data; |
1273 | memset(cmd, 0, sizeof(*cmd)); |
1274 | cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE, |
1275 | HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE); |
1276 | |
1277 | cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id); |
1278 | |
1279 | cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE | |
1280 | FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING, |
1281 | HTT_RX_MON_RING_SW); |
1282 | if (config) { |
1283 | cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END | |
1284 | HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END; |
1285 | } |
1286 | |
1287 | ret = ath11k_htc_send(htc: &ab->htc, eid: ab->dp.eid, packet: skb); |
1288 | if (ret) |
1289 | goto err_free; |
1290 | |
1291 | return 0; |
1292 | |
1293 | err_free: |
1294 | dev_kfree_skb_any(skb); |
1295 | |
1296 | return ret; |
1297 | } |
1298 | |