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