1 /*
2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include "hal_hw_headers.h"
21 #include "dp_types.h"
22 #include "dp_tx_desc.h"
23
24 #ifndef DESC_PARTITION
25 #define DP_TX_DESC_SIZE(a) qdf_get_pwr2(a)
26 #define DP_TX_DESC_PAGE_DIVIDER(soc, num_desc_per_page, pool_id) \
27 do { \
28 uint8_t sig_bit; \
29 soc->tx_desc[pool_id].offset_filter = num_desc_per_page - 1; \
30 /* Calculate page divider to find page number */ \
31 sig_bit = 0; \
32 while (num_desc_per_page) { \
33 sig_bit++; \
34 num_desc_per_page = num_desc_per_page >> 1; \
35 } \
36 soc->tx_desc[pool_id].page_divider = (sig_bit - 1); \
37 } while (0)
38 #else
39 #define DP_TX_DESC_SIZE(a) a
40 #define DP_TX_DESC_PAGE_DIVIDER(soc, num_desc_per_page, pool_id) {}
41 #endif /* DESC_PARTITION */
42
43 /**
44 * dp_tx_desc_pool_counter_initialize() - Initialize counters
45 * @tx_desc_pool: Handle to DP tx_desc_pool structure
46 * @num_elem: Number of descriptor elements per pool
47 *
48 * Return: None
49 */
50 #ifdef QCA_LL_TX_FLOW_CONTROL_V2
51 static void
dp_tx_desc_pool_counter_initialize(struct dp_tx_desc_pool_s * tx_desc_pool,uint16_t num_elem)52 dp_tx_desc_pool_counter_initialize(struct dp_tx_desc_pool_s *tx_desc_pool,
53 uint16_t num_elem)
54 {
55 }
56 #else
57 static void
dp_tx_desc_pool_counter_initialize(struct dp_tx_desc_pool_s * tx_desc_pool,uint16_t num_elem)58 dp_tx_desc_pool_counter_initialize(struct dp_tx_desc_pool_s *tx_desc_pool,
59 uint16_t num_elem)
60 {
61 tx_desc_pool->elem_count = num_elem;
62 tx_desc_pool->num_free = num_elem;
63 tx_desc_pool->num_allocated = 0;
64 }
65 #endif
66
67 #ifdef DP_UMAC_HW_RESET_SUPPORT
68 /**
69 * dp_tx_desc_clean_up() - Clean up the tx descriptors
70 * @ctxt: context passed
71 * @elem: element to be cleaned up
72 * @elem_list: element list
73 *
74 */
dp_tx_desc_clean_up(void * ctxt,void * elem,void * elem_list)75 static void dp_tx_desc_clean_up(void *ctxt, void *elem, void *elem_list)
76 {
77 struct dp_soc *soc = (struct dp_soc *)ctxt;
78 struct dp_tx_desc_s *tx_desc = (struct dp_tx_desc_s *)elem;
79 qdf_nbuf_t *nbuf_list = (qdf_nbuf_t *)elem_list;
80 qdf_nbuf_t nbuf = NULL;
81
82 if (tx_desc->nbuf) {
83 nbuf = dp_tx_comp_free_buf(soc, tx_desc, true);
84 dp_tx_desc_release(soc, tx_desc, tx_desc->pool_id);
85
86 if (nbuf) {
87 if (!nbuf_list) {
88 dp_err("potential memory leak");
89 qdf_assert_always(0);
90 }
91
92 nbuf->next = *nbuf_list;
93 *nbuf_list = nbuf;
94 }
95 }
96 }
97
dp_tx_desc_pool_cleanup(struct dp_soc * soc,qdf_nbuf_t * nbuf_list,bool cleanup)98 void dp_tx_desc_pool_cleanup(struct dp_soc *soc, qdf_nbuf_t *nbuf_list,
99 bool cleanup)
100 {
101 int i;
102 struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
103 uint8_t num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
104
105 if (!cleanup)
106 return;
107
108 for (i = 0; i < num_pool; i++) {
109 tx_desc_pool = dp_get_tx_desc_pool(soc, i);
110
111 TX_DESC_LOCK_LOCK(&tx_desc_pool->lock);
112 if (tx_desc_pool)
113 qdf_tx_desc_pool_free_bufs(soc,
114 &tx_desc_pool->desc_pages,
115 tx_desc_pool->elem_size,
116 tx_desc_pool->elem_count,
117 true, &dp_tx_desc_clean_up,
118 nbuf_list);
119
120 TX_DESC_LOCK_UNLOCK(&tx_desc_pool->lock);
121
122 tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, i);
123 TX_DESC_LOCK_LOCK(&tx_desc_pool->lock);
124
125 if (tx_desc_pool)
126 qdf_tx_desc_pool_free_bufs(soc,
127 &tx_desc_pool->desc_pages,
128 tx_desc_pool->elem_size,
129 tx_desc_pool->elem_count,
130 true, &dp_tx_desc_clean_up,
131 nbuf_list);
132
133 TX_DESC_LOCK_UNLOCK(&tx_desc_pool->lock);
134 }
135 }
136 #endif
137
138 #ifdef QCA_SUPPORT_DP_GLOBAL_CTX
dp_tx_desc_pool_alloc_mem(struct dp_soc * soc,int8_t pool_id,bool spcl_tx_desc)139 static void dp_tx_desc_pool_alloc_mem(struct dp_soc *soc, int8_t pool_id,
140 bool spcl_tx_desc)
141 {
142 struct dp_global_context *dp_global = NULL;
143
144 dp_global = wlan_objmgr_get_global_ctx();
145
146 if (spcl_tx_desc) {
147 dp_global->spcl_tx_desc[soc->arch_id][pool_id] =
148 qdf_mem_malloc(sizeof(struct dp_tx_desc_pool_s));
149 } else {
150 dp_global->tx_desc[soc->arch_id][pool_id] =
151 qdf_mem_malloc(sizeof(struct dp_tx_desc_pool_s));
152 }
153 }
154
dp_tx_desc_pool_free_mem(struct dp_soc * soc,int8_t pool_id,bool spcl_tx_desc)155 static void dp_tx_desc_pool_free_mem(struct dp_soc *soc, int8_t pool_id,
156 bool spcl_tx_desc)
157 {
158 struct dp_global_context *dp_global = NULL;
159
160 dp_global = wlan_objmgr_get_global_ctx();
161 if (spcl_tx_desc) {
162 if (!dp_global->spcl_tx_desc[soc->arch_id][pool_id])
163 return;
164
165 qdf_mem_free(dp_global->spcl_tx_desc[soc->arch_id][pool_id]);
166 dp_global->spcl_tx_desc[soc->arch_id][pool_id] = NULL;
167 } else {
168 if (!dp_global->tx_desc[soc->arch_id][pool_id])
169 return;
170
171 qdf_mem_free(dp_global->tx_desc[soc->arch_id][pool_id]);
172 dp_global->tx_desc[soc->arch_id][pool_id] = NULL;
173 }
174 }
175 #else
dp_tx_desc_pool_alloc_mem(struct dp_soc * soc,int8_t pool_id,bool spcl_tx_desc)176 static void dp_tx_desc_pool_alloc_mem(struct dp_soc *soc, int8_t pool_id,
177 bool spcl_tx_desc)
178 {
179 }
180
dp_tx_desc_pool_free_mem(struct dp_soc * soc,int8_t pool_id,bool spcl_tx_desc)181 static void dp_tx_desc_pool_free_mem(struct dp_soc *soc, int8_t pool_id,
182 bool spcl_tx_desc)
183 {
184 }
185 #endif
186
dp_tx_desc_pool_alloc(struct dp_soc * soc,uint8_t pool_id,uint32_t num_elem,bool spcl_tx_desc)187 QDF_STATUS dp_tx_desc_pool_alloc(struct dp_soc *soc, uint8_t pool_id,
188 uint32_t num_elem, bool spcl_tx_desc)
189 {
190 uint32_t desc_size, num_elem_t;
191 struct dp_tx_desc_pool_s *tx_desc_pool;
192 QDF_STATUS status;
193 enum qdf_dp_desc_type desc_type = QDF_DP_TX_DESC_TYPE;
194
195 desc_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
196
197 dp_tx_desc_pool_alloc_mem(soc, pool_id, spcl_tx_desc);
198 if (spcl_tx_desc) {
199 tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
200 desc_type = QDF_DP_TX_SPCL_DESC_TYPE;
201 num_elem_t = num_elem;
202 } else {
203 tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
204 desc_type = QDF_DP_TX_DESC_TYPE;
205 num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
206 }
207
208 tx_desc_pool->desc_pages.page_size = DP_BLOCKMEM_SIZE;
209 dp_desc_multi_pages_mem_alloc(soc, desc_type,
210 &tx_desc_pool->desc_pages,
211 desc_size, num_elem_t,
212 0, true);
213
214 if (!tx_desc_pool->desc_pages.num_pages) {
215 dp_err("Multi page alloc fail, tx desc");
216 return QDF_STATUS_E_NOMEM;
217 }
218
219 /* Arch specific TX descriptor allocation */
220 status = soc->arch_ops.dp_tx_desc_pool_alloc(soc, num_elem_t, pool_id);
221 if (QDF_IS_STATUS_ERROR(status)) {
222 dp_err("failed to allocate arch specific descriptors");
223 return QDF_STATUS_E_NOMEM;
224 }
225
226 return QDF_STATUS_SUCCESS;
227 }
228
dp_tx_desc_pool_free(struct dp_soc * soc,uint8_t pool_id,bool spcl_tx_desc)229 void dp_tx_desc_pool_free(struct dp_soc *soc, uint8_t pool_id,
230 bool spcl_tx_desc)
231 {
232 struct dp_tx_desc_pool_s *tx_desc_pool;
233 enum qdf_dp_desc_type desc_type = QDF_DP_TX_DESC_TYPE;
234
235 if (spcl_tx_desc) {
236 tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
237 desc_type = QDF_DP_TX_SPCL_DESC_TYPE;
238 } else {
239 tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
240 desc_type = QDF_DP_TX_DESC_TYPE;
241 }
242
243 if (tx_desc_pool->desc_pages.num_pages)
244 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_DESC_TYPE,
245 &tx_desc_pool->desc_pages, 0,
246 true);
247
248 /* Free arch specific TX descriptor */
249 soc->arch_ops.dp_tx_desc_pool_free(soc, pool_id);
250 dp_tx_desc_pool_free_mem(soc, pool_id, spcl_tx_desc);
251 }
252
dp_tx_desc_pool_init(struct dp_soc * soc,uint8_t pool_id,uint32_t num_elem,bool spcl_tx_desc)253 QDF_STATUS dp_tx_desc_pool_init(struct dp_soc *soc, uint8_t pool_id,
254 uint32_t num_elem, bool spcl_tx_desc)
255 {
256 struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
257 uint32_t desc_size, num_elem_t;
258
259 desc_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
260
261 if (spcl_tx_desc) {
262 tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
263 num_elem_t = num_elem;
264 } else {
265 tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
266 num_elem_t = dp_get_updated_tx_desc(soc->ctrl_psoc, pool_id, num_elem);
267 }
268 if (qdf_mem_multi_page_link(soc->osdev,
269 &tx_desc_pool->desc_pages,
270 desc_size, num_elem_t, true)) {
271 dp_err("invalid tx desc allocation -overflow num link");
272 return QDF_STATUS_E_FAULT;
273 }
274
275 tx_desc_pool->freelist = (struct dp_tx_desc_s *)
276 *tx_desc_pool->desc_pages.cacheable_pages;
277 /* Set unique IDs for each Tx descriptor */
278 if (QDF_STATUS_SUCCESS != soc->arch_ops.dp_tx_desc_pool_init(
279 soc, num_elem_t,
280 pool_id, spcl_tx_desc)) {
281 dp_err("initialization per target failed");
282 return QDF_STATUS_E_FAULT;
283 }
284
285 tx_desc_pool->elem_size = DP_TX_DESC_SIZE(sizeof(struct dp_tx_desc_s));
286
287 dp_tx_desc_pool_counter_initialize(tx_desc_pool, num_elem_t);
288 TX_DESC_LOCK_CREATE(&tx_desc_pool->lock);
289
290 return QDF_STATUS_SUCCESS;
291 }
292
dp_tx_desc_pool_deinit(struct dp_soc * soc,uint8_t pool_id,bool spcl_tx_desc)293 void dp_tx_desc_pool_deinit(struct dp_soc *soc, uint8_t pool_id,
294 bool spcl_tx_desc)
295 {
296 struct dp_tx_desc_pool_s *tx_desc_pool;
297
298 if (spcl_tx_desc)
299 tx_desc_pool = dp_get_spcl_tx_desc_pool(soc, pool_id);
300 else
301 tx_desc_pool = dp_get_tx_desc_pool(soc, pool_id);
302 soc->arch_ops.dp_tx_desc_pool_deinit(soc, tx_desc_pool,
303 pool_id, spcl_tx_desc);
304 TX_DESC_POOL_MEMBER_CLEAN(tx_desc_pool);
305 TX_DESC_LOCK_DESTROY(&tx_desc_pool->lock);
306 }
307
308 QDF_STATUS
dp_tx_ext_desc_pool_alloc_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)309 dp_tx_ext_desc_pool_alloc_by_id(struct dp_soc *soc, uint32_t num_elem,
310 uint8_t pool_id)
311 {
312 QDF_STATUS status;
313 qdf_dma_context_t memctx = 0;
314 uint16_t elem_size = HAL_TX_EXT_DESC_WITH_META_DATA;
315 struct dp_tx_ext_desc_pool_s *dp_tx_ext_desc_pool;
316 uint16_t link_elem_size = sizeof(struct dp_tx_ext_desc_elem_s);
317
318 dp_tx_ext_desc_pool = &((soc)->tx_ext_desc[pool_id]);
319 memctx = qdf_get_dma_mem_context(dp_tx_ext_desc_pool, memctx);
320
321 /* Coherent tx extension descriptor alloc */
322 dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_EXT_DESC_TYPE,
323 &dp_tx_ext_desc_pool->desc_pages,
324 elem_size, num_elem, memctx, false);
325
326 if (!dp_tx_ext_desc_pool->desc_pages.num_pages) {
327 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
328 "ext desc page alloc fail");
329 return QDF_STATUS_E_NOMEM;
330 }
331
332 /*
333 * Cacheable ext descriptor link alloc
334 * This structure also large size already
335 * single element is 24bytes, 2K elements are 48Kbytes
336 * Have to alloc multi page cacheable memory
337 */
338 dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_EXT_DESC_LINK_TYPE,
339 &dp_tx_ext_desc_pool->desc_link_pages,
340 link_elem_size, num_elem, 0, true);
341
342 if (!dp_tx_ext_desc_pool->desc_link_pages.num_pages) {
343 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
344 "ext link desc page alloc fail");
345 status = QDF_STATUS_E_NOMEM;
346 goto free_ext_desc;
347 }
348
349 return QDF_STATUS_SUCCESS;
350
351 free_ext_desc:
352 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_EXT_DESC_TYPE,
353 &dp_tx_ext_desc_pool->desc_pages,
354 memctx, false);
355 return status;
356 }
357
dp_tx_ext_desc_pool_alloc(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)358 QDF_STATUS dp_tx_ext_desc_pool_alloc(struct dp_soc *soc, uint8_t num_pool,
359 uint32_t num_elem)
360 {
361 QDF_STATUS status;
362 uint8_t pool_id, count;
363
364 for (pool_id = 0; pool_id < num_pool; pool_id++) {
365 status = dp_tx_ext_desc_pool_alloc_by_id(soc, num_elem, pool_id);
366 if (QDF_IS_STATUS_ERROR(status)) {
367 dp_err("failed to allocate tx ext desc pool %d", pool_id);
368 goto free_ext_desc_pool;
369 }
370 }
371
372 return QDF_STATUS_SUCCESS;
373
374 free_ext_desc_pool:
375 for (count = 0; count < pool_id; count++)
376 dp_tx_ext_desc_pool_free_by_id(soc, count);
377
378 return status;
379 }
380
dp_tx_ext_desc_pool_init_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)381 QDF_STATUS dp_tx_ext_desc_pool_init_by_id(struct dp_soc *soc, uint32_t num_elem,
382 uint8_t pool_id)
383 {
384 uint32_t i;
385 struct dp_tx_ext_desc_elem_s *c_elem, *p_elem;
386 struct qdf_mem_dma_page_t *page_info;
387 struct qdf_mem_multi_page_t *pages;
388 struct dp_tx_ext_desc_pool_s *dp_tx_ext_desc_pool;
389 QDF_STATUS status;
390
391 /* link tx descriptors into a freelist */
392 dp_tx_ext_desc_pool = &((soc)->tx_ext_desc[pool_id]);
393 soc->tx_ext_desc[pool_id].elem_size =
394 HAL_TX_EXT_DESC_WITH_META_DATA;
395 soc->tx_ext_desc[pool_id].link_elem_size =
396 sizeof(struct dp_tx_ext_desc_elem_s);
397 soc->tx_ext_desc[pool_id].elem_count = num_elem;
398
399 dp_tx_ext_desc_pool->freelist = (struct dp_tx_ext_desc_elem_s *)
400 *dp_tx_ext_desc_pool->desc_link_pages.cacheable_pages;
401
402 if (qdf_mem_multi_page_link(soc->osdev,
403 &dp_tx_ext_desc_pool->desc_link_pages,
404 dp_tx_ext_desc_pool->link_elem_size,
405 dp_tx_ext_desc_pool->elem_count,
406 true)) {
407 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
408 "ext link desc page linking fail");
409 status = QDF_STATUS_E_FAULT;
410 goto fail;
411 }
412
413 /* Assign coherent memory pointer into linked free list */
414 pages = &dp_tx_ext_desc_pool->desc_pages;
415 page_info = dp_tx_ext_desc_pool->desc_pages.dma_pages;
416 c_elem = dp_tx_ext_desc_pool->freelist;
417 p_elem = c_elem;
418 for (i = 0; i < dp_tx_ext_desc_pool->elem_count; i++) {
419 if (!(i % pages->num_element_per_page)) {
420 /**
421 * First element for new page,
422 * should point next page
423 */
424 if (!pages->dma_pages->page_v_addr_start) {
425 QDF_TRACE(QDF_MODULE_ID_DP,
426 QDF_TRACE_LEVEL_ERROR,
427 "link over flow");
428 status = QDF_STATUS_E_FAULT;
429 goto fail;
430 }
431
432 c_elem->vaddr =
433 (void *)page_info->page_v_addr_start;
434 c_elem->paddr = page_info->page_p_addr;
435 page_info++;
436 } else {
437 c_elem->vaddr = (void *)(p_elem->vaddr +
438 dp_tx_ext_desc_pool->elem_size);
439 c_elem->paddr = (p_elem->paddr +
440 dp_tx_ext_desc_pool->elem_size);
441 }
442 p_elem = c_elem;
443 c_elem = c_elem->next;
444 if (!c_elem)
445 break;
446 }
447 dp_tx_ext_desc_pool->num_free = num_elem;
448 qdf_spinlock_create(&dp_tx_ext_desc_pool->lock);
449
450 return QDF_STATUS_SUCCESS;
451
452 fail:
453 return status;
454 }
455
dp_tx_ext_desc_pool_init(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)456 QDF_STATUS dp_tx_ext_desc_pool_init(struct dp_soc *soc, uint8_t num_pool,
457 uint32_t num_elem)
458 {
459 uint8_t pool_id;
460 QDF_STATUS status;
461
462 for (pool_id = 0; pool_id < num_pool; pool_id++) {
463 status = dp_tx_ext_desc_pool_init_by_id(soc, num_elem, pool_id);
464 if (QDF_IS_STATUS_ERROR(status)) {
465 dp_err("failed to init ext desc pool %d", pool_id);
466 goto fail;
467 }
468 }
469
470 return QDF_STATUS_SUCCESS;
471 fail:
472 return status;
473 }
474
dp_tx_ext_desc_pool_free_by_id(struct dp_soc * soc,uint8_t pool_id)475 void dp_tx_ext_desc_pool_free_by_id(struct dp_soc *soc, uint8_t pool_id)
476 {
477 struct dp_tx_ext_desc_pool_s *dp_tx_ext_desc_pool;
478 qdf_dma_context_t memctx = 0;
479
480 dp_tx_ext_desc_pool = &((soc)->tx_ext_desc[pool_id]);
481 memctx = qdf_get_dma_mem_context(dp_tx_ext_desc_pool, memctx);
482
483 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_EXT_DESC_LINK_TYPE,
484 &dp_tx_ext_desc_pool->desc_link_pages,
485 0, true);
486
487 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_EXT_DESC_TYPE,
488 &dp_tx_ext_desc_pool->desc_pages,
489 memctx, false);
490 }
491
dp_tx_ext_desc_pool_free(struct dp_soc * soc,uint8_t num_pool)492 void dp_tx_ext_desc_pool_free(struct dp_soc *soc, uint8_t num_pool)
493 {
494 uint8_t pool_id;
495
496 for (pool_id = 0; pool_id < num_pool; pool_id++)
497 dp_tx_ext_desc_pool_free_by_id(soc, pool_id);
498 }
499
dp_tx_ext_desc_pool_deinit_by_id(struct dp_soc * soc,uint8_t pool_id)500 void dp_tx_ext_desc_pool_deinit_by_id(struct dp_soc *soc, uint8_t pool_id)
501 {
502 struct dp_tx_ext_desc_pool_s *dp_tx_ext_desc_pool;
503
504 dp_tx_ext_desc_pool = &((soc)->tx_ext_desc[pool_id]);
505 qdf_spinlock_destroy(&dp_tx_ext_desc_pool->lock);
506 }
507
dp_tx_ext_desc_pool_deinit(struct dp_soc * soc,uint8_t num_pool)508 void dp_tx_ext_desc_pool_deinit(struct dp_soc *soc, uint8_t num_pool)
509 {
510 uint8_t pool_id;
511
512 for (pool_id = 0; pool_id < num_pool; pool_id++)
513 dp_tx_ext_desc_pool_deinit_by_id(soc, pool_id);
514 }
515
516 #if defined(FEATURE_TSO)
dp_tx_tso_desc_pool_alloc_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)517 QDF_STATUS dp_tx_tso_desc_pool_alloc_by_id(struct dp_soc *soc, uint32_t num_elem,
518 uint8_t pool_id)
519 {
520 struct dp_tx_tso_seg_pool_s *tso_desc_pool;
521 uint32_t desc_size;
522
523 desc_size = DP_TX_DESC_SIZE(sizeof(struct qdf_tso_seg_elem_t));
524
525 tso_desc_pool = &soc->tx_tso_desc[pool_id];
526 tso_desc_pool->num_free = 0;
527 dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_TSO_DESC_TYPE,
528 &tso_desc_pool->desc_pages,
529 desc_size, num_elem, 0, true);
530 if (!tso_desc_pool->desc_pages.num_pages) {
531 dp_err("Multi page alloc fail, tx desc");
532 return QDF_STATUS_E_NOMEM;
533 }
534
535 return QDF_STATUS_SUCCESS;
536 }
537
dp_tx_tso_desc_pool_alloc(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)538 QDF_STATUS dp_tx_tso_desc_pool_alloc(struct dp_soc *soc, uint8_t num_pool,
539 uint32_t num_elem)
540 {
541 uint32_t pool_id, i;
542 QDF_STATUS status;
543
544 for (pool_id = 0; pool_id < num_pool; pool_id++) {
545 status = dp_tx_tso_desc_pool_alloc_by_id(soc, num_elem,
546 pool_id);
547 if (QDF_IS_STATUS_ERROR(status)) {
548 dp_err("failed to allocate TSO desc pool %d", pool_id);
549 goto fail;
550 }
551 }
552
553 return QDF_STATUS_SUCCESS;
554
555 fail:
556 for (i = 0; i < pool_id; i++)
557 dp_tx_tso_desc_pool_free_by_id(soc, i);
558
559 return QDF_STATUS_E_NOMEM;
560 }
561
dp_tx_tso_desc_pool_free_by_id(struct dp_soc * soc,uint8_t pool_id)562 void dp_tx_tso_desc_pool_free_by_id(struct dp_soc *soc, uint8_t pool_id)
563 {
564 struct dp_tx_tso_seg_pool_s *tso_desc_pool;
565
566 tso_desc_pool = &soc->tx_tso_desc[pool_id];
567 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_TSO_DESC_TYPE,
568 &tso_desc_pool->desc_pages,
569 0, true);
570 }
571
dp_tx_tso_desc_pool_free(struct dp_soc * soc,uint8_t num_pool)572 void dp_tx_tso_desc_pool_free(struct dp_soc *soc, uint8_t num_pool)
573 {
574 uint32_t pool_id;
575
576 for (pool_id = 0; pool_id < num_pool; pool_id++)
577 dp_tx_tso_desc_pool_free_by_id(soc, pool_id);
578 }
579
dp_tx_tso_desc_pool_init_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)580 QDF_STATUS dp_tx_tso_desc_pool_init_by_id(struct dp_soc *soc, uint32_t num_elem,
581 uint8_t pool_id)
582 {
583 struct dp_tx_tso_seg_pool_s *tso_desc_pool;
584 uint32_t desc_size;
585
586 desc_size = DP_TX_DESC_SIZE(sizeof(struct qdf_tso_seg_elem_t));
587
588 tso_desc_pool = &soc->tx_tso_desc[pool_id];
589
590 if (qdf_mem_multi_page_link(soc->osdev,
591 &tso_desc_pool->desc_pages,
592 desc_size,
593 num_elem, true)) {
594 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
595 "invalid tso desc allocation - overflow num link");
596 return QDF_STATUS_E_FAULT;
597 }
598
599 tso_desc_pool->freelist = (struct qdf_tso_seg_elem_t *)
600 *tso_desc_pool->desc_pages.cacheable_pages;
601 tso_desc_pool->num_free = num_elem;
602
603 TSO_DEBUG("Number of free descriptors: %u\n",
604 tso_desc_pool->num_free);
605 tso_desc_pool->pool_size = num_elem;
606 qdf_spinlock_create(&tso_desc_pool->lock);
607
608 return QDF_STATUS_SUCCESS;
609 }
610
dp_tx_tso_desc_pool_init(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)611 QDF_STATUS dp_tx_tso_desc_pool_init(struct dp_soc *soc, uint8_t num_pool,
612 uint32_t num_elem)
613 {
614 QDF_STATUS status;
615 uint32_t pool_id;
616
617 for (pool_id = 0; pool_id < num_pool; pool_id++) {
618 status = dp_tx_tso_desc_pool_init_by_id(soc, num_elem,
619 pool_id);
620 if (QDF_IS_STATUS_ERROR(status)) {
621 dp_err("failed to initialise TSO desc pool %d", pool_id);
622 return status;
623 }
624 }
625
626 return QDF_STATUS_SUCCESS;
627 }
628
dp_tx_tso_desc_pool_deinit_by_id(struct dp_soc * soc,uint8_t pool_id)629 void dp_tx_tso_desc_pool_deinit_by_id(struct dp_soc *soc, uint8_t pool_id)
630 {
631 struct dp_tx_tso_seg_pool_s *tso_desc_pool;
632
633 tso_desc_pool = &soc->tx_tso_desc[pool_id];
634
635 if (tso_desc_pool->pool_size) {
636 qdf_spin_lock_bh(&tso_desc_pool->lock);
637 tso_desc_pool->freelist = NULL;
638 tso_desc_pool->num_free = 0;
639 tso_desc_pool->pool_size = 0;
640 qdf_spin_unlock_bh(&tso_desc_pool->lock);
641 qdf_spinlock_destroy(&tso_desc_pool->lock);
642 }
643 }
644
dp_tx_tso_desc_pool_deinit(struct dp_soc * soc,uint8_t num_pool)645 void dp_tx_tso_desc_pool_deinit(struct dp_soc *soc, uint8_t num_pool)
646 {
647 uint32_t pool_id;
648
649 for (pool_id = 0; pool_id < num_pool; pool_id++)
650 dp_tx_tso_desc_pool_deinit_by_id(soc, pool_id);
651 }
652
dp_tx_tso_num_seg_pool_alloc_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)653 QDF_STATUS dp_tx_tso_num_seg_pool_alloc_by_id(struct dp_soc *soc,
654 uint32_t num_elem,
655 uint8_t pool_id)
656 {
657 struct dp_tx_tso_num_seg_pool_s *tso_num_seg_pool;
658 uint32_t desc_size;
659
660 desc_size = DP_TX_DESC_SIZE(sizeof(struct qdf_tso_num_seg_elem_t));
661
662 tso_num_seg_pool = &soc->tx_tso_num_seg[pool_id];
663 tso_num_seg_pool->num_free = 0;
664 dp_desc_multi_pages_mem_alloc(soc, QDF_DP_TX_TSO_NUM_SEG_TYPE,
665 &tso_num_seg_pool->desc_pages,
666 desc_size,
667 num_elem, 0, true);
668
669 if (!tso_num_seg_pool->desc_pages.num_pages) {
670 dp_err("Multi page alloc fail, tso_num_seg_pool");
671 return QDF_STATUS_E_NOMEM;
672 }
673
674 return QDF_STATUS_SUCCESS;
675 }
676
dp_tx_tso_num_seg_pool_alloc(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)677 QDF_STATUS dp_tx_tso_num_seg_pool_alloc(struct dp_soc *soc, uint8_t num_pool,
678 uint32_t num_elem)
679 {
680 uint32_t pool_id, i;
681 QDF_STATUS status;
682
683 for (pool_id = 0; pool_id < num_pool; pool_id++) {
684 status = dp_tx_tso_num_seg_pool_alloc_by_id(soc, num_elem,
685 pool_id);
686 if (QDF_IS_STATUS_ERROR(status)) {
687 dp_err("failed to allocate TSO num seg pool %d", pool_id);
688 goto fail;
689 }
690 }
691
692 return QDF_STATUS_SUCCESS;
693
694 fail:
695 for (i = 0; i < pool_id; i++)
696 dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
697
698 return QDF_STATUS_E_NOMEM;
699 }
700
dp_tx_tso_num_seg_pool_free_by_id(struct dp_soc * soc,uint8_t pool_id)701 void dp_tx_tso_num_seg_pool_free_by_id(struct dp_soc *soc, uint8_t pool_id)
702 {
703 struct dp_tx_tso_num_seg_pool_s *tso_num_seg_pool;
704
705 tso_num_seg_pool = &soc->tx_tso_num_seg[pool_id];
706 dp_desc_multi_pages_mem_free(soc, QDF_DP_TX_TSO_NUM_SEG_TYPE,
707 &tso_num_seg_pool->desc_pages,
708 0, true);
709 }
710
dp_tx_tso_num_seg_pool_free(struct dp_soc * soc,uint8_t num_pool)711 void dp_tx_tso_num_seg_pool_free(struct dp_soc *soc, uint8_t num_pool)
712 {
713 uint32_t pool_id;
714
715 for (pool_id = 0; pool_id < num_pool; pool_id++)
716 dp_tx_tso_num_seg_pool_free_by_id(soc, pool_id);
717 }
718
719 QDF_STATUS
dp_tx_tso_num_seg_pool_init_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)720 dp_tx_tso_num_seg_pool_init_by_id(struct dp_soc *soc, uint32_t num_elem,
721 uint8_t pool_id)
722 {
723 struct dp_tx_tso_num_seg_pool_s *tso_num_seg_pool;
724 uint32_t desc_size;
725
726 desc_size = DP_TX_DESC_SIZE(sizeof(struct qdf_tso_num_seg_elem_t));
727 tso_num_seg_pool = &soc->tx_tso_num_seg[pool_id];
728
729 if (qdf_mem_multi_page_link(soc->osdev,
730 &tso_num_seg_pool->desc_pages,
731 desc_size,
732 num_elem, true)) {
733 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
734 "invalid tso desc allocation - overflow num link");
735 return QDF_STATUS_E_FAULT;
736 }
737
738 tso_num_seg_pool->freelist = (struct qdf_tso_num_seg_elem_t *)
739 *tso_num_seg_pool->desc_pages.cacheable_pages;
740 tso_num_seg_pool->num_free = num_elem;
741 tso_num_seg_pool->num_seg_pool_size = num_elem;
742
743 qdf_spinlock_create(&tso_num_seg_pool->lock);
744
745 return QDF_STATUS_SUCCESS;
746 }
747
dp_tx_tso_num_seg_pool_init(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)748 QDF_STATUS dp_tx_tso_num_seg_pool_init(struct dp_soc *soc, uint8_t num_pool,
749 uint32_t num_elem)
750 {
751 uint32_t pool_id;
752 QDF_STATUS status;
753
754 for (pool_id = 0; pool_id < num_pool; pool_id++) {
755 status = dp_tx_tso_num_seg_pool_init_by_id(soc, num_elem,
756 pool_id);
757 if (QDF_IS_STATUS_ERROR(status)) {
758 dp_err("failed to initialise TSO num seg pool %d", pool_id);
759 return status;
760 }
761 }
762
763 return QDF_STATUS_SUCCESS;
764 }
765
dp_tx_tso_num_seg_pool_deinit_by_id(struct dp_soc * soc,uint8_t pool_id)766 void dp_tx_tso_num_seg_pool_deinit_by_id(struct dp_soc *soc, uint8_t pool_id)
767 {
768 struct dp_tx_tso_num_seg_pool_s *tso_num_seg_pool;
769
770 tso_num_seg_pool = &soc->tx_tso_num_seg[pool_id];
771
772 if (tso_num_seg_pool->num_seg_pool_size) {
773 qdf_spin_lock_bh(&tso_num_seg_pool->lock);
774 tso_num_seg_pool->freelist = NULL;
775 tso_num_seg_pool->num_free = 0;
776 tso_num_seg_pool->num_seg_pool_size = 0;
777 qdf_spin_unlock_bh(&tso_num_seg_pool->lock);
778 qdf_spinlock_destroy(&tso_num_seg_pool->lock);
779 }
780 }
781
dp_tx_tso_num_seg_pool_deinit(struct dp_soc * soc,uint8_t num_pool)782 void dp_tx_tso_num_seg_pool_deinit(struct dp_soc *soc, uint8_t num_pool)
783 {
784 uint32_t pool_id;
785
786 for (pool_id = 0; pool_id < num_pool; pool_id++)
787 dp_tx_tso_num_seg_pool_deinit_by_id(soc, pool_id);
788 }
789 #else
dp_tx_tso_desc_pool_alloc_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)790 QDF_STATUS dp_tx_tso_desc_pool_alloc_by_id(struct dp_soc *soc, uint32_t num_elem,
791 uint8_t pool_id)
792 {
793 return QDF_STATUS_SUCCESS;
794 }
795
dp_tx_tso_desc_pool_alloc(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)796 QDF_STATUS dp_tx_tso_desc_pool_alloc(struct dp_soc *soc, uint8_t num_pool,
797 uint32_t num_elem)
798 {
799 return QDF_STATUS_SUCCESS;
800 }
801
dp_tx_tso_desc_pool_init_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)802 QDF_STATUS dp_tx_tso_desc_pool_init_by_id(struct dp_soc *soc, uint32_t num_elem,
803 uint8_t pool_id)
804 {
805 return QDF_STATUS_SUCCESS;
806 }
807
dp_tx_tso_desc_pool_init(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)808 QDF_STATUS dp_tx_tso_desc_pool_init(struct dp_soc *soc, uint8_t num_pool,
809 uint32_t num_elem)
810 {
811 return QDF_STATUS_SUCCESS;
812 }
813
dp_tx_tso_desc_pool_free_by_id(struct dp_soc * soc,uint8_t pool_id)814 void dp_tx_tso_desc_pool_free_by_id(struct dp_soc *soc, uint8_t pool_id)
815 {
816 }
817
dp_tx_tso_desc_pool_free(struct dp_soc * soc,uint8_t num_pool)818 void dp_tx_tso_desc_pool_free(struct dp_soc *soc, uint8_t num_pool)
819 {
820 }
821
dp_tx_tso_desc_pool_deinit_by_id(struct dp_soc * soc,uint8_t pool_id)822 void dp_tx_tso_desc_pool_deinit_by_id(struct dp_soc *soc, uint8_t pool_id)
823 {
824 }
825
dp_tx_tso_desc_pool_deinit(struct dp_soc * soc,uint8_t num_pool)826 void dp_tx_tso_desc_pool_deinit(struct dp_soc *soc, uint8_t num_pool)
827 {
828 }
829
dp_tx_tso_num_seg_pool_alloc_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)830 QDF_STATUS dp_tx_tso_num_seg_pool_alloc_by_id(struct dp_soc *soc,
831 uint32_t num_elem,
832 uint8_t pool_id)
833 {
834 return QDF_STATUS_SUCCESS;
835 }
836
dp_tx_tso_num_seg_pool_alloc(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)837 QDF_STATUS dp_tx_tso_num_seg_pool_alloc(struct dp_soc *soc, uint8_t num_pool,
838 uint32_t num_elem)
839 {
840 return QDF_STATUS_SUCCESS;
841 }
842
dp_tx_tso_num_seg_pool_free_by_id(struct dp_soc * soc,uint8_t pool_id)843 void dp_tx_tso_num_seg_pool_free_by_id(struct dp_soc *soc, uint8_t pool_id)
844 {
845 }
846
dp_tx_tso_num_seg_pool_free(struct dp_soc * soc,uint8_t num_pool)847 void dp_tx_tso_num_seg_pool_free(struct dp_soc *soc, uint8_t num_pool)
848 {
849 }
850
851 QDF_STATUS
dp_tx_tso_num_seg_pool_init_by_id(struct dp_soc * soc,uint32_t num_elem,uint8_t pool_id)852 dp_tx_tso_num_seg_pool_init_by_id(struct dp_soc *soc, uint32_t num_elem,
853 uint8_t pool_id)
854 {
855 return QDF_STATUS_SUCCESS;
856 }
857
dp_tx_tso_num_seg_pool_init(struct dp_soc * soc,uint8_t num_pool,uint32_t num_elem)858 QDF_STATUS dp_tx_tso_num_seg_pool_init(struct dp_soc *soc, uint8_t num_pool,
859 uint32_t num_elem)
860 {
861 return QDF_STATUS_SUCCESS;
862 }
863
dp_tx_tso_num_seg_pool_deinit_by_id(struct dp_soc * soc,uint8_t pool_id)864 void dp_tx_tso_num_seg_pool_deinit_by_id(struct dp_soc *soc, uint8_t pool_id)
865 {
866 }
867
dp_tx_tso_num_seg_pool_deinit(struct dp_soc * soc,uint8_t num_pool)868 void dp_tx_tso_num_seg_pool_deinit(struct dp_soc *soc, uint8_t num_pool)
869 {
870 }
871 #endif
872