1 /*
2 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18 #include "cdp_txrx_cmn_struct.h"
19 #include "dp_types.h"
20 #include "dp_tx.h"
21 #include "dp_rh_tx.h"
22 #include "dp_tx_desc.h"
23 #include <dp_internal.h>
24 #include <dp_htt.h>
25 #include <hal_rh_api.h>
26 #include <hal_rh_tx.h>
27 #include "dp_peer.h"
28 #include "dp_rh.h"
29 #include <ce_api.h>
30 #include <ce_internal.h>
31 #include "dp_rh_htt.h"
32
33 extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE];
34
35 #if defined(FEATURE_TSO)
36 /**
37 * dp_tx_adjust_tso_download_len_rh() - Adjust download length for TSO packet
38 * @nbuf: socket buffer
39 * @msdu_info: handle to struct dp_tx_msdu_info_s
40 * @download_len: Packet download length that needs adjustment
41 *
42 * Return: uint32_t (Adjusted packet download length)
43 */
44 static uint32_t
dp_tx_adjust_tso_download_len_rh(qdf_nbuf_t nbuf,struct dp_tx_msdu_info_s * msdu_info,uint32_t download_len)45 dp_tx_adjust_tso_download_len_rh(qdf_nbuf_t nbuf,
46 struct dp_tx_msdu_info_s *msdu_info,
47 uint32_t download_len)
48 {
49 uint32_t frag0_len;
50 uint32_t delta;
51 uint32_t eit_hdr_len;
52
53 frag0_len = qdf_nbuf_get_frag_len(nbuf, 0);
54 download_len -= frag0_len;
55
56 eit_hdr_len = msdu_info->u.tso_info.curr_seg->seg.tso_frags[0].length;
57
58 /* If EIT header length is less than the MSDU download length, then
59 * adjust the download length to just hold EIT header.
60 */
61 if (eit_hdr_len < download_len) {
62 delta = download_len - eit_hdr_len;
63 download_len -= delta;
64 }
65
66 return download_len;
67 }
68 #else
69 static uint32_t
dp_tx_adjust_tso_download_len_rh(qdf_nbuf_t nbuf,struct dp_tx_msdu_info_s * msdu_info,uint32_t download_len)70 dp_tx_adjust_tso_download_len_rh(qdf_nbuf_t nbuf,
71 struct dp_tx_msdu_info_s *msdu_info,
72 uint32_t download_len)
73 {
74 return download_len;
75 }
76 #endif /* FEATURE_TSO */
77
78 QDF_STATUS
dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc * soc,void * tx_comp_hal_desc,struct dp_tx_desc_s ** r_tx_desc)79 dp_tx_comp_get_params_from_hal_desc_rh(struct dp_soc *soc,
80 void *tx_comp_hal_desc,
81 struct dp_tx_desc_s **r_tx_desc)
82 {
83 return QDF_STATUS_SUCCESS;
84 }
85
86 /**
87 * dp_tx_comp_find_tx_desc_rh() - Find software TX descriptor using sw_cookie
88 *
89 * @soc: Handle to DP SoC structure
90 * @sw_cookie: Key to find the TX descriptor
91 *
92 * Return: TX descriptor handle or NULL (if not found)
93 */
94 static struct dp_tx_desc_s *
dp_tx_comp_find_tx_desc_rh(struct dp_soc * soc,uint32_t sw_cookie)95 dp_tx_comp_find_tx_desc_rh(struct dp_soc *soc, uint32_t sw_cookie)
96 {
97 uint8_t pool_id;
98 struct dp_tx_desc_s *tx_desc;
99
100 pool_id = (sw_cookie & DP_TX_DESC_ID_POOL_MASK) >>
101 DP_TX_DESC_ID_POOL_OS;
102
103 /* Find Tx descriptor */
104 tx_desc = dp_tx_desc_find(soc, pool_id,
105 (sw_cookie & DP_TX_DESC_ID_PAGE_MASK) >>
106 DP_TX_DESC_ID_PAGE_OS,
107 (sw_cookie & DP_TX_DESC_ID_OFFSET_MASK) >>
108 DP_TX_DESC_ID_OFFSET_OS, false);
109 /* pool id is not matching. Error */
110 if (tx_desc && tx_desc->pool_id != pool_id) {
111 dp_tx_comp_alert("Tx Comp pool id %d not matched %d",
112 pool_id, tx_desc->pool_id);
113
114 qdf_assert_always(0);
115 }
116
117 return tx_desc;
118 }
119
dp_tx_process_htt_completion_rh(struct dp_soc * soc,struct dp_tx_desc_s * tx_desc,uint8_t * status,uint8_t ring_id)120 void dp_tx_process_htt_completion_rh(struct dp_soc *soc,
121 struct dp_tx_desc_s *tx_desc,
122 uint8_t *status,
123 uint8_t ring_id)
124 {
125 }
126
127 static inline uint32_t
dp_tx_adjust_download_len_rh(qdf_nbuf_t nbuf,uint32_t download_len)128 dp_tx_adjust_download_len_rh(qdf_nbuf_t nbuf, uint32_t download_len)
129 {
130 uint32_t frag0_len; /* TCL_DATA_CMD */
131 uint32_t frag1_len; /* 64 byte payload */
132
133 frag0_len = qdf_nbuf_get_frag_len(nbuf, 0);
134 frag1_len = download_len - frag0_len;
135
136 if (qdf_unlikely(qdf_nbuf_len(nbuf) < frag1_len))
137 frag1_len = qdf_nbuf_len(nbuf);
138
139 return frag0_len + frag1_len;
140 }
141
dp_tx_fill_nbuf_data_attr_rh(qdf_nbuf_t nbuf)142 static inline void dp_tx_fill_nbuf_data_attr_rh(qdf_nbuf_t nbuf)
143 {
144 uint32_t pkt_offset;
145 uint32_t tx_classify;
146 uint32_t data_attr;
147
148 /* Enable tx_classify bit in CE SRC DESC for all data packets */
149 tx_classify = 1;
150 pkt_offset = qdf_nbuf_get_frag_len(nbuf, 0);
151
152 data_attr = tx_classify << CE_DESC_TX_CLASSIFY_BIT_S;
153 data_attr |= pkt_offset << CE_DESC_PKT_OFFSET_BIT_S;
154
155 qdf_nbuf_data_attr_set(nbuf, data_attr);
156 }
157
158 #ifdef DP_TX_HW_DESC_HISTORY
159 static inline void
dp_tx_record_hw_desc_rh(uint8_t * hal_tx_desc_cached,struct dp_soc * soc)160 dp_tx_record_hw_desc_rh(uint8_t *hal_tx_desc_cached, struct dp_soc *soc)
161 {
162 struct dp_tx_hw_desc_history *tx_hw_desc_history =
163 &soc->tx_hw_desc_history;
164 struct dp_tx_hw_desc_evt *evt;
165 uint32_t idx = 0;
166 uint16_t slot = 0;
167
168 if (!tx_hw_desc_history->allocated)
169 return;
170
171 dp_get_frag_hist_next_atomic_idx(&tx_hw_desc_history->index, &idx,
172 &slot,
173 DP_TX_HW_DESC_HIST_SLOT_SHIFT,
174 DP_TX_HW_DESC_HIST_PER_SLOT_MAX,
175 DP_TX_HW_DESC_HIST_MAX);
176
177 evt = &tx_hw_desc_history->entry[slot][idx];
178 qdf_mem_copy(evt->tcl_desc, hal_tx_desc_cached, HAL_TX_DESC_LEN_BYTES);
179 evt->posted = qdf_get_log_timestamp();
180 evt->tcl_ring_id = 0;
181 }
182 #else
183 static inline void
dp_tx_record_hw_desc_rh(uint8_t * hal_tx_desc_cached,struct dp_soc * soc)184 dp_tx_record_hw_desc_rh(uint8_t *hal_tx_desc_cached, struct dp_soc *soc)
185 {
186 }
187 #endif
188
189 #if defined(FEATURE_RUNTIME_PM)
dp_tx_update_write_index(struct dp_soc * soc,struct dp_tx_ep_info_rh * tx_ep_info,int coalesce)190 static void dp_tx_update_write_index(struct dp_soc *soc,
191 struct dp_tx_ep_info_rh *tx_ep_info,
192 int coalesce)
193 {
194 int ret;
195
196 /* Avoid runtime get and put APIs under high throughput scenarios */
197 if (dp_get_rtpm_tput_policy_requirement(soc)) {
198 ce_tx_ring_write_idx_update_wrapper(tx_ep_info->ce_tx_hdl,
199 coalesce);
200 return;
201 }
202
203 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, HIF_RTPM_ID_DP);
204 if (QDF_IS_STATUS_SUCCESS(ret)) {
205 if (hif_system_pm_state_check(soc->hif_handle)) {
206 ce_ring_set_event(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring,
207 CE_RING_FLUSH_EVENT);
208 ce_ring_inc_flush_cnt(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring);
209 } else {
210 ce_tx_ring_write_idx_update_wrapper(tx_ep_info->ce_tx_hdl,
211 coalesce);
212 }
213 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_DP);
214 } else {
215 dp_runtime_get(soc);
216 ce_ring_set_event(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring,
217 CE_RING_FLUSH_EVENT);
218 ce_ring_inc_flush_cnt(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring);
219 qdf_atomic_inc(&soc->tx_pending_rtpm);
220 dp_runtime_put(soc);
221 }
222 }
223 #elif defined(DP_POWER_SAVE)
dp_tx_update_write_index(struct dp_soc * soc,struct dp_tx_ep_info_rh * tx_ep_info)224 static void dp_tx_update_write_index(struct dp_soc *soc,
225 struct dp_tx_ep_info_rh *tx_ep_info)
226 {
227 if (hif_system_pm_state_check(soc->hif_handle)) {
228 ce_ring_set_event(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring,
229 CE_RING_FLUSH_EVENT);
230 ce_ring_inc_flush_cnt(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring);
231 } else {
232 ce_tx_ring_write_idx_update_wrapper(tx_ep_info->ce_tx_hdl,
233 coalesce);
234 }
235 }
236 #else
dp_tx_update_write_index(struct dp_soc * soc,struct dp_tx_ep_info_rh * tx_ep_info)237 static void dp_tx_update_write_index(struct dp_soc *soc,
238 struct dp_tx_ep_info_rh *tx_ep_info)
239 {
240 ce_tx_ring_write_idx_update_wrapper(tx_ep_info->ce_tx_hdl,
241 coalesce);
242 }
243 #endif
244
245 /*
246 * dp_flush_tx_ring_rh() - flush tx ring write index
247 * @pdev: dp pdev handle
248 * @ring_id: Tx ring id
249 *
250 * Return: 0 on success and error code on failure
251 */
dp_flush_tx_ring_rh(struct dp_pdev * pdev,int ring_id)252 int dp_flush_tx_ring_rh(struct dp_pdev *pdev, int ring_id)
253 {
254 struct dp_pdev_rh *rh_pdev = dp_get_rh_pdev_from_dp_pdev(pdev);
255 struct dp_tx_ep_info_rh *tx_ep_info = &rh_pdev->tx_ep_info;
256 int ret;
257
258 ce_ring_aquire_lock(tx_ep_info->ce_tx_hdl);
259 ret = hif_rtpm_get(HIF_RTPM_GET_ASYNC, HIF_RTPM_ID_DP);
260 if (ret) {
261 ce_ring_release_lock(tx_ep_info->ce_tx_hdl);
262 ce_ring_set_event(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring,
263 CE_RING_FLUSH_EVENT);
264 ce_ring_inc_flush_cnt(((struct CE_state *)(tx_ep_info->ce_tx_hdl))->src_ring);
265 return ret;
266 }
267
268 ce_tx_ring_write_idx_update_wrapper(tx_ep_info->ce_tx_hdl, false);
269 ce_ring_release_lock(tx_ep_info->ce_tx_hdl);
270 hif_rtpm_put(HIF_RTPM_PUT_ASYNC, HIF_RTPM_ID_DP);
271
272 return ret;
273 }
274
275 QDF_STATUS
dp_tx_hw_enqueue_rh(struct dp_soc * soc,struct dp_vdev * vdev,struct dp_tx_desc_s * tx_desc,uint16_t fw_metadata,struct cdp_tx_exception_metadata * tx_exc_metadata,struct dp_tx_msdu_info_s * msdu_info)276 dp_tx_hw_enqueue_rh(struct dp_soc *soc, struct dp_vdev *vdev,
277 struct dp_tx_desc_s *tx_desc, uint16_t fw_metadata,
278 struct cdp_tx_exception_metadata *tx_exc_metadata,
279 struct dp_tx_msdu_info_s *msdu_info)
280 {
281 struct dp_pdev_rh *rh_pdev = dp_get_rh_pdev_from_dp_pdev(vdev->pdev);
282 struct dp_tx_ep_info_rh *tx_ep_info = &rh_pdev->tx_ep_info;
283 uint32_t download_len = tx_ep_info->download_len;
284 qdf_nbuf_t nbuf = tx_desc->nbuf;
285 uint8_t tid = msdu_info->tid;
286 uint32_t *hal_tx_desc_cached;
287 int coalesce = 0;
288 int ret;
289
290 /*
291 * Setting it initialization statically here to avoid
292 * a memset call jump with qdf_mem_set call
293 */
294 uint8_t cached_desc[HAL_TX_DESC_LEN_BYTES] = { 0 };
295
296 enum cdp_sec_type sec_type = ((tx_exc_metadata &&
297 tx_exc_metadata->sec_type != CDP_INVALID_SEC_TYPE) ?
298 tx_exc_metadata->sec_type : vdev->sec_type);
299
300 QDF_STATUS status = QDF_STATUS_E_RESOURCES;
301
302 if (!dp_tx_is_desc_id_valid(soc, tx_desc->id)) {
303 dp_err_rl("Invalid tx desc id:%d", tx_desc->id);
304 return QDF_STATUS_E_RESOURCES;
305 }
306
307 hal_tx_desc_cached = (void *)cached_desc;
308
309 hal_tx_desc_set_buf_addr(soc->hal_soc, hal_tx_desc_cached,
310 tx_desc->dma_addr, 0, tx_desc->id,
311 (tx_desc->flags & DP_TX_DESC_FLAG_FRAG));
312 hal_tx_desc_set_lmac_id(soc->hal_soc, hal_tx_desc_cached,
313 vdev->lmac_id);
314 hal_tx_desc_set_search_type(soc->hal_soc, hal_tx_desc_cached,
315 vdev->search_type);
316 hal_tx_desc_set_search_index(soc->hal_soc, hal_tx_desc_cached,
317 vdev->bss_ast_idx);
318
319 hal_tx_desc_set_encrypt_type(hal_tx_desc_cached,
320 sec_type_map[sec_type]);
321 hal_tx_desc_set_cache_set_num(soc->hal_soc, hal_tx_desc_cached,
322 (vdev->bss_ast_hash & 0xF));
323
324 hal_tx_desc_set_fw_metadata(hal_tx_desc_cached, fw_metadata);
325 hal_tx_desc_set_buf_length(hal_tx_desc_cached, tx_desc->length);
326 hal_tx_desc_set_buf_offset(hal_tx_desc_cached, tx_desc->pkt_offset);
327 hal_tx_desc_set_encap_type(hal_tx_desc_cached, tx_desc->tx_encap_type);
328 hal_tx_desc_set_addr_search_flags(hal_tx_desc_cached,
329 vdev->hal_desc_addr_search_flags);
330
331 if (tx_desc->flags & DP_TX_DESC_FLAG_TO_FW)
332 hal_tx_desc_set_to_fw(hal_tx_desc_cached, 1);
333
334 /* verify checksum offload configuration*/
335 if ((qdf_nbuf_get_tx_cksum(nbuf) == QDF_NBUF_TX_CKSUM_TCP_UDP) ||
336 qdf_nbuf_is_tso(nbuf)) {
337 hal_tx_desc_set_l3_checksum_en(hal_tx_desc_cached, 1);
338 hal_tx_desc_set_l4_checksum_en(hal_tx_desc_cached, 1);
339 }
340
341 if (tid != HTT_TX_EXT_TID_INVALID)
342 hal_tx_desc_set_hlos_tid(hal_tx_desc_cached, tid);
343
344 if (tx_desc->flags & DP_TX_DESC_FLAG_MESH)
345 hal_tx_desc_set_mesh_en(soc->hal_soc, hal_tx_desc_cached, 1);
346
347 if (!dp_tx_desc_set_ktimestamp(vdev, tx_desc))
348 dp_tx_desc_set_timestamp(tx_desc);
349
350 dp_verbose_debug("length:%d , type = %d, dma_addr %llx, offset %d desc id %u",
351 tx_desc->length,
352 (tx_desc->flags & DP_TX_DESC_FLAG_FRAG),
353 (uint64_t)tx_desc->dma_addr, tx_desc->pkt_offset,
354 tx_desc->id);
355
356 hal_tx_desc_sync(hal_tx_desc_cached, tx_desc->tcl_cmd_vaddr);
357
358 qdf_nbuf_frag_push_head(nbuf, DP_RH_TX_TCL_DESC_SIZE,
359 (char *)tx_desc->tcl_cmd_vaddr,
360 tx_desc->tcl_cmd_paddr);
361
362 download_len = dp_tx_adjust_download_len_rh(nbuf, download_len);
363
364 if (qdf_nbuf_is_tso(nbuf)) {
365 QDF_NBUF_CB_PADDR(nbuf) =
366 msdu_info->u.tso_info.curr_seg->seg.tso_frags[0].paddr;
367 download_len = dp_tx_adjust_tso_download_len_rh(nbuf, msdu_info,
368 download_len);
369 }
370
371 dp_tx_fill_nbuf_data_attr_rh(nbuf);
372
373 ce_ring_aquire_lock(tx_ep_info->ce_tx_hdl);
374 ret = ce_enqueue_desc(tx_ep_info->ce_tx_hdl, nbuf,
375 tx_ep_info->tx_endpoint, download_len);
376 if (ret) {
377 ce_ring_release_lock(tx_ep_info->ce_tx_hdl);
378 dp_verbose_debug("CE tx ring full");
379 /* TODO: Should this be a separate ce_ring_full stat? */
380 DP_STATS_INC(soc, tx.tcl_ring_full[0], 1);
381 DP_STATS_INC(vdev, tx_i[DP_XMIT_LINK].dropped.enqueue_fail, 1);
382 goto enqueue_fail;
383 }
384
385 coalesce = dp_tx_attempt_coalescing(soc, vdev, tx_desc, tid,
386 msdu_info, 0);
387
388 dp_tx_update_write_index(soc, tx_ep_info, coalesce);
389 ce_ring_release_lock(tx_ep_info->ce_tx_hdl);
390
391 tx_desc->flags |= DP_TX_DESC_FLAG_QUEUED_TX;
392 dp_vdev_peer_stats_update_protocol_cnt_tx(vdev, nbuf);
393 DP_STATS_INC_PKT(vdev, tx_i[DP_XMIT_LINK].processed, 1,
394 tx_desc->length);
395 DP_STATS_INC(soc, tx.tcl_enq[0], 1);
396
397 dp_tx_update_stats(soc, tx_desc, 0);
398 status = QDF_STATUS_SUCCESS;
399
400 dp_tx_record_hw_desc_rh((uint8_t *)hal_tx_desc_cached, soc);
401
402 enqueue_fail:
403 dp_pkt_add_timestamp(vdev, QDF_PKT_TX_DRIVER_EXIT,
404 qdf_get_log_timestamp(), tx_desc->nbuf);
405
406 return status;
407 }
408
409 /**
410 * dp_tx_tcl_desc_pool_alloc_rh() - Allocate the tcl descriptor pool
411 * based on pool_id
412 * @soc: Handle to DP SoC structure
413 * @num_elem: Number of descriptor elements per pool
414 * @pool_id: Pool to allocate
415 *
416 * Return: QDF_STATUS_SUCCESS
417 * QDF_STATUS_E_NOMEM
418 */
419 static QDF_STATUS
dp_tx_tcl_desc_pool_alloc_rh(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)420 dp_tx_tcl_desc_pool_alloc_rh(struct dp_soc *soc, uint32_t num_elem,
421 uint8_t pool_id)
422 {
423 struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
424 struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
425 uint16_t elem_size = DP_RH_TX_TCL_DESC_SIZE;
426 QDF_STATUS status = QDF_STATUS_SUCCESS;
427 qdf_dma_context_t memctx = 0;
428
429 if (pool_id > MAX_TXDESC_POOLS - 1)
430 return QDF_STATUS_E_INVAL;
431
432 /* Allocate tcl descriptors in coherent memory */
433 tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
434 memctx = qdf_get_dma_mem_context(tcl_desc_pool, memctx);
435 dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_TCL_DESC_TYPE,
436 &tcl_desc_pool->desc_pages,
437 elem_size, num_elem, memctx, false);
438
439 if (!tcl_desc_pool->desc_pages.num_pages) {
440 dp_err("failed to allocate tcl desc Pages");
441 status = QDF_STATUS_E_NOMEM;
442 goto err_alloc_fail;
443 }
444
445 return status;
446
447 err_alloc_fail:
448 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_TCL_DESC_TYPE,
449 &tcl_desc_pool->desc_pages,
450 memctx, false);
451 return status;
452 }
453
454 /**
455 * dp_tx_tcl_desc_pool_free_rh() - Free the tcl descriptor pool
456 * @soc: Handle to DP SoC structure
457 * @pool_id: pool to free
458 *
459 */
dp_tx_tcl_desc_pool_free_rh(struct dp_soc * soc,uint8_t pool_id)460 static void dp_tx_tcl_desc_pool_free_rh(struct dp_soc *soc, uint8_t pool_id)
461 {
462 struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
463 struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
464 qdf_dma_context_t memctx = 0;
465
466 if (pool_id > MAX_TXDESC_POOLS - 1)
467 return;
468
469 tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
470 memctx = qdf_get_dma_mem_context(tcl_desc_pool, memctx);
471
472 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_TCL_DESC_TYPE,
473 &tcl_desc_pool->desc_pages,
474 memctx, false);
475 }
476
477 /**
478 * dp_tx_tcl_desc_pool_init_rh() - Initialize tcl descriptor pool
479 * based on pool_id
480 * @soc: Handle to DP SoC structure
481 * @num_elem: Number of descriptor elements per pool
482 * @pool_id: pool to initialize
483 *
484 * Return: QDF_STATUS_SUCCESS
485 * QDF_STATUS_E_FAULT
486 */
487 static QDF_STATUS
dp_tx_tcl_desc_pool_init_rh(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)488 dp_tx_tcl_desc_pool_init_rh(struct dp_soc *soc, uint32_t num_elem,
489 uint8_t pool_id)
490 {
491 struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
492 struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
493 struct qdf_mem_dma_page_t *page_info;
494 QDF_STATUS status;
495
496 tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
497 tcl_desc_pool->elem_size = DP_RH_TX_TCL_DESC_SIZE;
498 tcl_desc_pool->elem_count = num_elem;
499
500 /* Link tcl descriptors into a freelist */
501 if (qdf_mem_multi_page_link(soc->osdev, &tcl_desc_pool->desc_pages,
502 tcl_desc_pool->elem_size,
503 tcl_desc_pool->elem_count,
504 false)) {
505 dp_err("failed to link tcl desc Pages");
506 status = QDF_STATUS_E_FAULT;
507 goto err_link_fail;
508 }
509
510 page_info = tcl_desc_pool->desc_pages.dma_pages;
511 tcl_desc_pool->freelist = (uint32_t *)page_info->page_v_addr_start;
512
513 return QDF_STATUS_SUCCESS;
514
515 err_link_fail:
516 return status;
517 }
518
519 /**
520 * dp_tx_tcl_desc_pool_deinit_rh() - De-initialize tcl descriptor pool
521 * based on pool_id
522 * @soc: Handle to DP SoC structure
523 * @pool_id: pool to de-initialize
524 *
525 */
dp_tx_tcl_desc_pool_deinit_rh(struct dp_soc * soc,uint8_t pool_id)526 static void dp_tx_tcl_desc_pool_deinit_rh(struct dp_soc *soc, uint8_t pool_id)
527 {
528 }
529
530 /**
531 * dp_tx_alloc_tcl_desc_rh() - Allocate a tcl descriptor from the pool
532 * @tcl_desc_pool: Tcl descriptor pool
533 * @tx_desc: SW TX descriptor
534 * @index: Index into the tcl descriptor pool
535 */
dp_tx_alloc_tcl_desc_rh(struct dp_tx_tcl_desc_pool_s * tcl_desc_pool,struct dp_tx_desc_s * tx_desc,uint32_t index)536 static void dp_tx_alloc_tcl_desc_rh(struct dp_tx_tcl_desc_pool_s *tcl_desc_pool,
537 struct dp_tx_desc_s *tx_desc,
538 uint32_t index)
539 {
540 struct qdf_mem_dma_page_t *dma_page;
541 uint32_t page_id;
542 uint32_t offset;
543
544 tx_desc->tcl_cmd_vaddr = (void *)tcl_desc_pool->freelist;
545
546 if (tcl_desc_pool->freelist)
547 tcl_desc_pool->freelist =
548 *((uint32_t **)tcl_desc_pool->freelist);
549
550 page_id = index / tcl_desc_pool->desc_pages.num_element_per_page;
551 offset = index % tcl_desc_pool->desc_pages.num_element_per_page;
552 dma_page = &tcl_desc_pool->desc_pages.dma_pages[page_id];
553
554 tx_desc->tcl_cmd_paddr =
555 dma_page->page_p_addr + offset * tcl_desc_pool->elem_size;
556 }
557
dp_tx_desc_pool_init_rh(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id,bool spcl_tx_desc)558 QDF_STATUS dp_tx_desc_pool_init_rh(struct dp_soc *soc,
559 uint32_t num_elem,
560 uint8_t pool_id,
561 bool spcl_tx_desc)
562 {
563 struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc);
564 uint32_t id, count, page_id, offset, pool_id_32;
565 struct dp_tx_desc_s *tx_desc;
566 struct dp_tx_tcl_desc_pool_s *tcl_desc_pool;
567 struct dp_tx_desc_pool_s *tx_desc_pool;
568 uint16_t num_desc_per_page;
569 QDF_STATUS status;
570
571 status = dp_tx_tcl_desc_pool_init_rh(soc, num_elem, pool_id);
572 if (QDF_IS_STATUS_ERROR(status)) {
573 dp_err("failed to initialise tcl desc pool %d", pool_id);
574 goto err_out;
575 }
576
577 status = dp_tx_ext_desc_pool_init_by_id(soc, num_elem, pool_id);
578 if (QDF_IS_STATUS_ERROR(status)) {
579 dp_err("failed to initialise tx ext desc pool %d", pool_id);
580 goto err_deinit_tcl_pool;
581 }
582
583 status = dp_tx_tso_desc_pool_init_by_id(soc, num_elem, pool_id);
584 if (QDF_IS_STATUS_ERROR(status)) {
585 dp_err("failed to initialise tso desc pool %d", pool_id);
586 goto err_deinit_tx_ext_pool;
587 }
588
589 status = dp_tx_tso_num_seg_pool_init_by_id(soc, num_elem, pool_id);
590 if (QDF_IS_STATUS_ERROR(status)) {
591 dp_err("failed to initialise tso num seg pool %d", pool_id);
592 goto err_deinit_tso_pool;
593 }
594
595 tx_desc_pool = &soc->tx_desc[pool_id];
596 tcl_desc_pool = &rh_soc->tcl_desc_pool[pool_id];
597 tx_desc = tx_desc_pool->freelist;
598 count = 0;
599 pool_id_32 = (uint32_t)pool_id;
600 num_desc_per_page = tx_desc_pool->desc_pages.num_element_per_page;
601 while (tx_desc) {
602 page_id = count / num_desc_per_page;
603 offset = count % num_desc_per_page;
604 id = ((pool_id_32 << DP_TX_DESC_ID_POOL_OS) |
605 (page_id << DP_TX_DESC_ID_PAGE_OS) | offset);
606
607 tx_desc->id = id;
608 tx_desc->pool_id = pool_id;
609 dp_tx_desc_set_magic(tx_desc, DP_TX_MAGIC_PATTERN_FREE);
610 dp_tx_alloc_tcl_desc_rh(tcl_desc_pool, tx_desc, count);
611 tx_desc = tx_desc->next;
612 count++;
613 }
614
615 return QDF_STATUS_SUCCESS;
616
617 err_deinit_tso_pool:
618 dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);
619 err_deinit_tx_ext_pool:
620 dp_tx_ext_desc_pool_deinit_by_id(soc, pool_id);
621 err_deinit_tcl_pool:
622 dp_tx_tcl_desc_pool_deinit_rh(soc, pool_id);
623 err_out:
624 /* TODO: is assert needed ? */
625 qdf_assert_always(0);
626 return status;
627 }
628
dp_tx_desc_pool_deinit_rh(struct dp_soc * soc,struct dp_tx_desc_pool_s * tx_desc_pool,uint8_t pool_id,bool spcl_tx_desc)629 void dp_tx_desc_pool_deinit_rh(struct dp_soc *soc,
630 struct dp_tx_desc_pool_s *tx_desc_pool,
631 uint8_t pool_id, bool spcl_tx_desc)
632 {
633 dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
634 dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);
635 dp_tx_ext_desc_pool_deinit_by_id(soc, pool_id);
636 dp_tx_tcl_desc_pool_deinit_rh(soc, pool_id);
637 }
638
dp_tx_compute_tx_delay_rh(struct dp_soc * soc,struct dp_vdev * vdev,struct hal_tx_completion_status * ts,uint32_t * delay_us)639 QDF_STATUS dp_tx_compute_tx_delay_rh(struct dp_soc *soc,
640 struct dp_vdev *vdev,
641 struct hal_tx_completion_status *ts,
642 uint32_t *delay_us)
643 {
644 return QDF_STATUS_SUCCESS;
645 }
646
dp_tx_desc_pool_alloc_rh(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)647 QDF_STATUS dp_tx_desc_pool_alloc_rh(struct dp_soc *soc, uint32_t num_elem,
648 uint8_t pool_id)
649 {
650 QDF_STATUS status;
651
652 status = dp_tx_tcl_desc_pool_alloc_rh(soc, num_elem, pool_id);
653 if (QDF_IS_STATUS_ERROR(status)) {
654 dp_err("failed to allocate tcl desc pool %d", pool_id);
655 goto err_tcl_desc_pool;
656 }
657
658 status = dp_tx_ext_desc_pool_alloc_by_id(soc, num_elem, pool_id);
659 if (QDF_IS_STATUS_ERROR(status)) {
660 dp_err("failed to allocate tx ext desc pool %d", pool_id);
661 goto err_free_tcl_pool;
662 }
663
664 status = dp_tx_tso_desc_pool_alloc_by_id(soc, num_elem, pool_id);
665 if (QDF_IS_STATUS_ERROR(status)) {
666 dp_err("failed to allocate tso desc pool %d", pool_id);
667 goto err_free_tx_ext_pool;
668 }
669
670 status = dp_tx_tso_num_seg_pool_alloc_by_id(soc, num_elem, pool_id);
671 if (QDF_IS_STATUS_ERROR(status)) {
672 dp_err("failed to allocate tso num seg pool %d", pool_id);
673 goto err_free_tso_pool;
674 }
675
676 return status;
677
678 err_free_tso_pool:
679 dp_tx_tso_desc_pool_free_by_id(soc, pool_id);
680 err_free_tx_ext_pool:
681 dp_tx_ext_desc_pool_free_by_id(soc, pool_id);
682 err_free_tcl_pool:
683 dp_tx_tcl_desc_pool_free_rh(soc, pool_id);
684 err_tcl_desc_pool:
685 /* TODO: is assert needed ? */
686 qdf_assert_always(0);
687 return status;
688 }
689
dp_tx_desc_pool_free_rh(struct dp_soc * soc,uint8_t pool_id)690 void dp_tx_desc_pool_free_rh(struct dp_soc *soc, uint8_t pool_id)
691 {
692 dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
693 dp_tx_tso_desc_pool_free_by_id(soc, pool_id);
694 dp_tx_ext_desc_pool_free_by_id(soc, pool_id);
695 dp_tx_tcl_desc_pool_free_rh(soc, pool_id);
696 }
697
dp_tx_compl_handler_rh(struct dp_soc * soc,qdf_nbuf_t htt_msg)698 void dp_tx_compl_handler_rh(struct dp_soc *soc, qdf_nbuf_t htt_msg)
699 {
700 struct dp_tx_desc_s *tx_desc = NULL;
701 struct dp_tx_desc_s *head_desc = NULL;
702 struct dp_tx_desc_s *tail_desc = NULL;
703 uint32_t sw_cookie;
704 uint32_t num_msdus;
705 uint32_t *msg_word;
706 uint8_t ring_id;
707 uint8_t tx_status;
708 int i;
709
710 DP_HIST_INIT();
711
712 msg_word = (uint32_t *)qdf_nbuf_data(htt_msg);
713 num_msdus = HTT_SOFT_UMAC_TX_COMP_IND_MSDU_COUNT_GET(*msg_word);
714 msg_word += HTT_SOFT_UMAC_TX_COMPL_IND_SIZE >> 2;
715
716 for (i = 0; i < num_msdus; i++) {
717 sw_cookie = HTT_TX_BUFFER_ADDR_INFO_SW_BUFFER_COOKIE_GET(*(msg_word + 1));
718
719 tx_desc = dp_tx_comp_find_tx_desc_rh(soc, sw_cookie);
720 if (!tx_desc) {
721 dp_err("failed to find tx desc");
722 qdf_assert_always(0);
723 }
724
725 /*
726 * If the descriptor is already freed in vdev_detach,
727 * continue to next descriptor
728 */
729 if (qdf_unlikely((tx_desc->vdev_id == DP_INVALID_VDEV_ID) &&
730 !tx_desc->flags)) {
731 dp_tx_comp_info_rl("Descriptor freed in vdev_detach %d",
732 tx_desc->id);
733 DP_STATS_INC(soc, tx.tx_comp_exception, 1);
734 dp_tx_desc_check_corruption(tx_desc);
735 goto next_msdu;
736 }
737
738 if (qdf_unlikely(tx_desc->pdev->is_pdev_down)) {
739 dp_tx_comp_info_rl("pdev in down state %d",
740 tx_desc->id);
741 tx_desc->flags |= DP_TX_DESC_FLAG_TX_COMP_ERR;
742 dp_tx_comp_free_buf(soc, tx_desc, false);
743 dp_tx_desc_release(soc, tx_desc, tx_desc->pool_id);
744 goto next_msdu;
745 }
746
747 if (!(tx_desc->flags & DP_TX_DESC_FLAG_ALLOCATED) ||
748 !(tx_desc->flags & DP_TX_DESC_FLAG_QUEUED_TX)) {
749 dp_tx_comp_alert("Txdesc invalid, flgs = %x,id = %d",
750 tx_desc->flags, tx_desc->id);
751 qdf_assert_always(0);
752 }
753
754 if (HTT_TX_BUFFER_ADDR_INFO_RELEASE_SOURCE_GET(*(msg_word + 1)) ==
755 HTT_TX_MSDU_RELEASE_SOURCE_FW)
756 tx_desc->buffer_src = HAL_TX_COMP_RELEASE_SOURCE_FW;
757 else
758 tx_desc->buffer_src = HAL_TX_COMP_RELEASE_SOURCE_TQM;
759
760 tx_desc->peer_id = HTT_TX_MSDU_INFO_SW_PEER_ID_GET(*(msg_word + 2));
761 tx_status = HTT_TX_MSDU_INFO_RELEASE_REASON_GET(*(msg_word + 3));
762
763 tx_desc->tx_status =
764 (tx_status == HTT_TX_MSDU_RELEASE_REASON_FRAME_ACKED ?
765 HAL_TX_TQM_RR_FRAME_ACKED : HAL_TX_TQM_RR_REM_CMD_REM);
766
767 qdf_mem_copy(&tx_desc->comp, msg_word, HTT_TX_MSDU_INFO_SIZE);
768
769 DP_HIST_PACKET_COUNT_INC(tx_desc->pdev->pdev_id);
770
771 /* First ring descriptor on the cycle */
772 if (!head_desc) {
773 head_desc = tx_desc;
774 tail_desc = tx_desc;
775 }
776
777 tail_desc->next = tx_desc;
778 tx_desc->next = NULL;
779 tail_desc = tx_desc;
780 next_msdu:
781 msg_word += HTT_TX_MSDU_INFO_SIZE >> 2;
782 }
783
784 /* For now, pass ring_id as 0 (zero) as WCN6450 only
785 * supports one TX ring.
786 */
787 ring_id = 0;
788
789 if (head_desc)
790 dp_tx_comp_process_desc_list(soc, head_desc, ring_id);
791
792 DP_STATS_INC(soc, tx.tx_comp[ring_id], num_msdus);
793 DP_TX_HIST_STATS_PER_PDEV();
794 }
795