xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/dp_rx_desc.c (revision d97a5912d37f3ed3ec22e5ea3d41a9537ae60ae6)
1 /*
2  * Copyright (c) 2016-2019 The Linux Foundation. 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 
19 #include "dp_types.h"
20 #include "dp_rx.h"
21 
22 /*
23  * dp_rx_desc_pool_alloc() - create a pool of software rx_descs
24  *			     at the time of dp rx initialization
25  *
26  * @soc: core txrx main context
27  * @pool_id: pool_id which is one of 3 mac_ids
28  * @pool_size: number of Rx descriptor in the pool
29  * @rx_desc_pool: rx descriptor pool pointer
30  *
31  * return success or failure
32  */
33 QDF_STATUS dp_rx_desc_pool_alloc(struct dp_soc *soc, uint32_t pool_id,
34 	uint32_t pool_size, struct rx_desc_pool *rx_desc_pool)
35 {
36 	uint32_t i;
37 
38 	if (!dp_is_soc_reinit(soc)) {
39 		rx_desc_pool->array =
40 		qdf_mem_malloc(pool_size *
41 		sizeof(union dp_rx_desc_list_elem_t));
42 
43 		if (!(rx_desc_pool->array)) {
44 			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
45 				  "%s: RX Desc Pool[%d] allocation failed",
46 				  __func__, pool_id);
47 			return QDF_STATUS_E_NOMEM;
48 		}
49 	}
50 
51 	/* Initialize the lock */
52 	qdf_spinlock_create(&rx_desc_pool->lock);
53 
54 	qdf_spin_lock_bh(&rx_desc_pool->lock);
55 	rx_desc_pool->pool_size = pool_size;
56 
57 	/* link SW rx descs into a freelist */
58 	rx_desc_pool->freelist = &rx_desc_pool->array[0];
59 	for (i = 0; i < rx_desc_pool->pool_size-1; i++) {
60 		rx_desc_pool->array[i].next = &rx_desc_pool->array[i+1];
61 		rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18);
62 		rx_desc_pool->array[i].rx_desc.pool_id = pool_id;
63 		rx_desc_pool->array[i].rx_desc.in_use = 0;
64 	}
65 
66 	rx_desc_pool->array[i].next = NULL;
67 	rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18);
68 	rx_desc_pool->array[i].rx_desc.pool_id = pool_id;
69 	qdf_spin_unlock_bh(&rx_desc_pool->lock);
70 	return QDF_STATUS_SUCCESS;
71 }
72 
73 /*
74  * dp_rx_desc_pool_free() - free the sw rx desc pool called during
75  *			    de-initialization of wifi module.
76  *
77  * @soc: core txrx main context
78  * @pool_id: pool_id which is one of 3 mac_ids
79  * @rx_desc_pool: rx descriptor pool pointer
80  */
81 void dp_rx_desc_pool_free(struct dp_soc *soc, uint32_t pool_id,
82 	struct rx_desc_pool *rx_desc_pool)
83 {
84 	int i;
85 
86 	qdf_spin_lock_bh(&rx_desc_pool->lock);
87 	for (i = 0; i < rx_desc_pool->pool_size; i++) {
88 		if (rx_desc_pool->array[i].rx_desc.in_use) {
89 			if (!(rx_desc_pool->array[i].rx_desc.unmapped))
90 				qdf_nbuf_unmap_single(soc->osdev,
91 					rx_desc_pool->array[i].rx_desc.nbuf,
92 					QDF_DMA_BIDIRECTIONAL);
93 			qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf);
94 		}
95 	}
96 	qdf_mem_free(rx_desc_pool->array);
97 	qdf_spin_unlock_bh(&rx_desc_pool->lock);
98 	qdf_spinlock_destroy(&rx_desc_pool->lock);
99 }
100 
101 /*
102  * dp_rx_desc_pool_free_nbuf() - free the sw rx desc nbufs called during
103  *			         de-initialization of wifi module.
104  *
105  * @soc: core txrx main context
106  * @pool_id: pool_id which is one of 3 mac_ids
107  * @rx_desc_pool: rx descriptor pool pointer
108  */
109 void dp_rx_desc_nbuf_pool_free(struct dp_soc *soc,
110 			       struct rx_desc_pool *rx_desc_pool)
111 {
112 	int i;
113 
114 	qdf_spin_lock_bh(&rx_desc_pool->lock);
115 	for (i = 0; i < rx_desc_pool->pool_size; i++) {
116 		if (rx_desc_pool->array[i].rx_desc.in_use) {
117 			if (!(rx_desc_pool->array[i].rx_desc.unmapped))
118 				qdf_nbuf_unmap_single(soc->osdev,
119 					rx_desc_pool->array[i].rx_desc.nbuf,
120 					QDF_DMA_BIDIRECTIONAL);
121 			qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf);
122 		}
123 	}
124 	qdf_spin_unlock_bh(&rx_desc_pool->lock);
125 	qdf_spinlock_destroy(&rx_desc_pool->lock);
126 }
127 
128 /*
129  * dp_rx_get_free_desc_list() - provide a list of descriptors from
130  *				the free rx desc pool.
131  *
132  * @soc: core txrx main context
133  * @pool_id: pool_id which is one of 3 mac_ids
134  * @rx_desc_pool: rx descriptor pool pointer
135  * @num_descs: number of descs requested from freelist
136  * @desc_list: attach the descs to this list (output parameter)
137  * @tail: attach the point to last desc of free list (output parameter)
138  *
139  * Return: number of descs allocated from free list.
140  */
141 uint16_t dp_rx_get_free_desc_list(struct dp_soc *soc, uint32_t pool_id,
142 				struct rx_desc_pool *rx_desc_pool,
143 				uint16_t num_descs,
144 				union dp_rx_desc_list_elem_t **desc_list,
145 				union dp_rx_desc_list_elem_t **tail)
146 {
147 	uint16_t count;
148 
149 	qdf_spin_lock_bh(&rx_desc_pool->lock);
150 
151 	*desc_list = *tail = rx_desc_pool->freelist;
152 
153 	for (count = 0; count < num_descs; count++) {
154 
155 		if (qdf_unlikely(!rx_desc_pool->freelist)) {
156 			qdf_spin_unlock_bh(&rx_desc_pool->lock);
157 			return count;
158 		}
159 		*tail = rx_desc_pool->freelist;
160 		rx_desc_pool->freelist = rx_desc_pool->freelist->next;
161 	}
162 	(*tail)->next = NULL;
163 	qdf_spin_unlock_bh(&rx_desc_pool->lock);
164 	return count;
165 }
166 
167 /*
168  * dp_rx_add_desc_list_to_free_list() - append unused desc_list back to
169  *					freelist.
170  *
171  * @soc: core txrx main context
172  * @local_desc_list: local desc list provided by the caller
173  * @tail: attach the point to last desc of local desc list
174  * @pool_id: pool_id which is one of 3 mac_ids
175  * @rx_desc_pool: rx descriptor pool pointer
176  */
177 void dp_rx_add_desc_list_to_free_list(struct dp_soc *soc,
178 				union dp_rx_desc_list_elem_t **local_desc_list,
179 				union dp_rx_desc_list_elem_t **tail,
180 				uint16_t pool_id,
181 				struct rx_desc_pool *rx_desc_pool)
182 {
183 	union dp_rx_desc_list_elem_t *temp_list = NULL;
184 
185 	qdf_spin_lock_bh(&rx_desc_pool->lock);
186 
187 
188 	temp_list = rx_desc_pool->freelist;
189 	QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
190 	"temp_list: %pK, *local_desc_list: %pK, *tail: %pK (*tail)->next: %pK",
191 	temp_list, *local_desc_list, *tail, (*tail)->next);
192 	rx_desc_pool->freelist = *local_desc_list;
193 	(*tail)->next = temp_list;
194 
195 	qdf_spin_unlock_bh(&rx_desc_pool->lock);
196 }
197