xref: /wlan-driver/qca-wifi-host-cmn/qdf/linux/src/qdf_nbuf_frag.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: qdf_nbuf_frag.c
22*5113495bSYour Name  * QCA driver framework(QDF) network nbuf frag management APIs
23*5113495bSYour Name  */
24*5113495bSYour Name 
25*5113495bSYour Name #include <qdf_atomic.h>
26*5113495bSYour Name #include <qdf_list.h>
27*5113495bSYour Name #include <qdf_debugfs.h>
28*5113495bSYour Name #include <qdf_module.h>
29*5113495bSYour Name #include <qdf_nbuf_frag.h>
30*5113495bSYour Name #include <qdf_trace.h>
31*5113495bSYour Name #include "qdf_str.h"
32*5113495bSYour Name 
33*5113495bSYour Name #ifdef QDF_NBUF_FRAG_GLOBAL_COUNT
34*5113495bSYour Name #define FRAG_DEBUGFS_NAME    "frag_counters"
35*5113495bSYour Name static qdf_atomic_t frag_count;
36*5113495bSYour Name #endif
37*5113495bSYour Name 
38*5113495bSYour Name #if defined(NBUF_FRAG_MEMORY_DEBUG) || defined(QDF_NBUF_FRAG_GLOBAL_COUNT)
39*5113495bSYour Name static bool is_initial_mem_debug_disabled;
40*5113495bSYour Name #endif
41*5113495bSYour Name 
42*5113495bSYour Name #ifdef QDF_NBUF_FRAG_GLOBAL_COUNT
43*5113495bSYour Name 
__qdf_frag_count_get(void)44*5113495bSYour Name uint32_t __qdf_frag_count_get(void)
45*5113495bSYour Name {
46*5113495bSYour Name 	return qdf_atomic_read(&frag_count);
47*5113495bSYour Name }
48*5113495bSYour Name 
49*5113495bSYour Name qdf_export_symbol(__qdf_frag_count_get);
50*5113495bSYour Name 
__qdf_frag_count_inc(uint32_t value)51*5113495bSYour Name void __qdf_frag_count_inc(uint32_t value)
52*5113495bSYour Name {
53*5113495bSYour Name 	if (qdf_likely(is_initial_mem_debug_disabled))
54*5113495bSYour Name 		return;
55*5113495bSYour Name 
56*5113495bSYour Name 	qdf_atomic_add(value, &frag_count);
57*5113495bSYour Name }
58*5113495bSYour Name 
59*5113495bSYour Name qdf_export_symbol(__qdf_frag_count_inc);
60*5113495bSYour Name 
__qdf_frag_count_dec(uint32_t value)61*5113495bSYour Name void __qdf_frag_count_dec(uint32_t value)
62*5113495bSYour Name {
63*5113495bSYour Name 	if (qdf_likely(is_initial_mem_debug_disabled))
64*5113495bSYour Name 		return;
65*5113495bSYour Name 
66*5113495bSYour Name 	qdf_atomic_sub(value, &frag_count);
67*5113495bSYour Name }
68*5113495bSYour Name 
69*5113495bSYour Name qdf_export_symbol(__qdf_frag_count_dec);
70*5113495bSYour Name 
__qdf_frag_mod_init(void)71*5113495bSYour Name void __qdf_frag_mod_init(void)
72*5113495bSYour Name {
73*5113495bSYour Name 	is_initial_mem_debug_disabled = qdf_mem_debug_config_get();
74*5113495bSYour Name 	qdf_atomic_init(&frag_count);
75*5113495bSYour Name 	qdf_debugfs_create_atomic(FRAG_DEBUGFS_NAME, S_IRUSR, NULL,
76*5113495bSYour Name 				  &frag_count);
77*5113495bSYour Name }
78*5113495bSYour Name 
__qdf_frag_mod_exit(void)79*5113495bSYour Name void __qdf_frag_mod_exit(void)
80*5113495bSYour Name {
81*5113495bSYour Name }
82*5113495bSYour Name #endif /* QDF_NBUF_FRAG_GLOBAL_COUNT */
83*5113495bSYour Name 
84*5113495bSYour Name #ifdef NBUF_FRAG_MEMORY_DEBUG
85*5113495bSYour Name 
86*5113495bSYour Name #define QDF_FRAG_TRACK_MAX_SIZE    1024
87*5113495bSYour Name 
88*5113495bSYour Name /**
89*5113495bSYour Name  * struct qdf_frag_track_node_t - Network frag tracking node structure
90*5113495bSYour Name  * @hnode: list_head for next and prev pointers
91*5113495bSYour Name  * @p_frag: Pointer to frag
92*5113495bSYour Name  * @alloc_func_name: Function where frag is allocated
93*5113495bSYour Name  * @alloc_func_line: Allocation function line no.
94*5113495bSYour Name  * @refcount: No. of references to the frag
95*5113495bSYour Name  * @last_func_name: Function where frag recently accessed
96*5113495bSYour Name  * @last_func_line: Line number of last function
97*5113495bSYour Name  *
98*5113495bSYour Name  **/
99*5113495bSYour Name struct qdf_frag_track_node_t {
100*5113495bSYour Name 	qdf_list_node_t hnode;
101*5113495bSYour Name 	qdf_frag_t p_frag;
102*5113495bSYour Name 	char alloc_func_name[QDF_MEM_FUNC_NAME_SIZE];
103*5113495bSYour Name 	uint32_t alloc_func_line;
104*5113495bSYour Name 	uint8_t refcount;
105*5113495bSYour Name 	char last_func_name[QDF_MEM_FUNC_NAME_SIZE];
106*5113495bSYour Name 	uint32_t last_func_line;
107*5113495bSYour Name };
108*5113495bSYour Name 
109*5113495bSYour Name /**
110*5113495bSYour Name  * struct qdf_frag_tracking_list_t - Frag node tracking list
111*5113495bSYour Name  * @track_list: qdf_list_t for maintaining the list
112*5113495bSYour Name  * @list_lock: Lock over the list
113*5113495bSYour Name  *
114*5113495bSYour Name  */
115*5113495bSYour Name typedef struct qdf_frag_tracking_list_t {
116*5113495bSYour Name 	qdf_list_t track_list;
117*5113495bSYour Name 	qdf_spinlock_t list_lock;
118*5113495bSYour Name } qdf_frag_tracking_list;
119*5113495bSYour Name 
120*5113495bSYour Name typedef struct qdf_frag_track_node_t QDF_FRAG_TRACK;
121*5113495bSYour Name 
122*5113495bSYour Name /*
123*5113495bSYour Name  * Array of tracking list for maintaining
124*5113495bSYour Name  * allocated debug frag nodes as per the calculated
125*5113495bSYour Name  * hash value.
126*5113495bSYour Name  */
127*5113495bSYour Name static qdf_frag_tracking_list gp_qdf_frag_track_tbl[QDF_FRAG_TRACK_MAX_SIZE];
128*5113495bSYour Name 
129*5113495bSYour Name static struct kmem_cache *frag_tracking_cache;
130*5113495bSYour Name 
131*5113495bSYour Name /* Tracking list for maintaining the free debug frag nodes */
132*5113495bSYour Name static qdf_frag_tracking_list qdf_frag_track_free_list;
133*5113495bSYour Name 
134*5113495bSYour Name /*
135*5113495bSYour Name  * Parameters for statistics
136*5113495bSYour Name  * qdf_frag_track_free_list_count: No. of free nodes
137*5113495bSYour Name  * qdf_frag_track_used_list_count : No. of nodes used
138*5113495bSYour Name  * qdf_frag_track_max_used : Max no. of nodes used during execution
139*5113495bSYour Name  * qdf_frag_track_max_free : Max free nodes observed during execution
140*5113495bSYour Name  * qdf_frag_track_max_allocated: Max no. of allocated nodes
141*5113495bSYour Name  */
142*5113495bSYour Name static uint32_t qdf_frag_track_free_list_count;
143*5113495bSYour Name static uint32_t qdf_frag_track_used_list_count;
144*5113495bSYour Name static uint32_t qdf_frag_track_max_used;
145*5113495bSYour Name static uint32_t qdf_frag_track_max_free;
146*5113495bSYour Name static uint32_t qdf_frag_track_max_allocated;
147*5113495bSYour Name 
148*5113495bSYour Name /**
149*5113495bSYour Name  * qdf_frag_update_max_used() - Update qdf_frag_track_max_used tracking variable
150*5113495bSYour Name  *
151*5113495bSYour Name  * Tracks the max number of frags that the wlan driver was tracking at any one
152*5113495bSYour Name  * time
153*5113495bSYour Name  *
154*5113495bSYour Name  * Return: none
155*5113495bSYour Name  **/
qdf_frag_update_max_used(void)156*5113495bSYour Name static inline void qdf_frag_update_max_used(void)
157*5113495bSYour Name {
158*5113495bSYour Name 	int sum;
159*5113495bSYour Name 
160*5113495bSYour Name 	/* Update max_used if it is less than used list count */
161*5113495bSYour Name 	if (qdf_frag_track_max_used < qdf_frag_track_used_list_count)
162*5113495bSYour Name 		qdf_frag_track_max_used = qdf_frag_track_used_list_count;
163*5113495bSYour Name 
164*5113495bSYour Name 	/* Calculate no. of allocated nodes */
165*5113495bSYour Name 	sum = qdf_frag_track_used_list_count + qdf_frag_track_free_list_count;
166*5113495bSYour Name 
167*5113495bSYour Name 	/* Update max allocated if less then no. of allocated nodes */
168*5113495bSYour Name 	if (qdf_frag_track_max_allocated < sum)
169*5113495bSYour Name 		qdf_frag_track_max_allocated = sum;
170*5113495bSYour Name }
171*5113495bSYour Name 
172*5113495bSYour Name /**
173*5113495bSYour Name  * qdf_frag_update_max_free() - Update qdf_frag_track_max_free
174*5113495bSYour Name  *
175*5113495bSYour Name  * Tracks the max number tracking buffers kept in the freelist.
176*5113495bSYour Name  *
177*5113495bSYour Name  * Return: none
178*5113495bSYour Name  */
qdf_frag_update_max_free(void)179*5113495bSYour Name static inline void qdf_frag_update_max_free(void)
180*5113495bSYour Name {
181*5113495bSYour Name 	if (qdf_frag_track_max_free < qdf_frag_track_free_list_count)
182*5113495bSYour Name 		qdf_frag_track_max_free = qdf_frag_track_free_list_count;
183*5113495bSYour Name }
184*5113495bSYour Name 
185*5113495bSYour Name /**
186*5113495bSYour Name  * qdf_frag_track_alloc() - Allocate a cookie to track frags allocated by wlan
187*5113495bSYour Name  *
188*5113495bSYour Name  * This function pulls from freelist if possible,otherwise uses kmem_cache_alloc
189*5113495bSYour Name  * This function also adds fexibility to adjust the allocation and freelist
190*5113495bSYour Name  * schemes.
191*5113495bSYour Name  *
192*5113495bSYour Name  * Return: Pointer to an unused QDF_FRAG_TRACK structure which may not be zeroed
193*5113495bSYour Name  */
qdf_frag_track_alloc(void)194*5113495bSYour Name static QDF_FRAG_TRACK *qdf_frag_track_alloc(void)
195*5113495bSYour Name {
196*5113495bSYour Name 	int flags = GFP_KERNEL;
197*5113495bSYour Name 	QDF_FRAG_TRACK *frag_track_node = NULL;
198*5113495bSYour Name 	qdf_list_node_t *temp_list_node;
199*5113495bSYour Name 
200*5113495bSYour Name 	qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock);
201*5113495bSYour Name 	qdf_frag_track_used_list_count++;
202*5113495bSYour Name 
203*5113495bSYour Name 	if (!qdf_list_empty(&qdf_frag_track_free_list.track_list)) {
204*5113495bSYour Name 		qdf_list_remove_front(&qdf_frag_track_free_list.track_list,
205*5113495bSYour Name 				      &temp_list_node);
206*5113495bSYour Name 		frag_track_node = qdf_container_of(temp_list_node,
207*5113495bSYour Name 						   struct qdf_frag_track_node_t,
208*5113495bSYour Name 						   hnode);
209*5113495bSYour Name 		qdf_frag_track_free_list_count--;
210*5113495bSYour Name 	}
211*5113495bSYour Name 
212*5113495bSYour Name 	qdf_frag_update_max_used();
213*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock);
214*5113495bSYour Name 
215*5113495bSYour Name 	if (frag_track_node)
216*5113495bSYour Name 		return frag_track_node;
217*5113495bSYour Name 
218*5113495bSYour Name 	if (in_interrupt() || irqs_disabled() || in_atomic())
219*5113495bSYour Name 		flags = GFP_ATOMIC;
220*5113495bSYour Name 
221*5113495bSYour Name 	frag_track_node = kmem_cache_alloc(frag_tracking_cache, flags);
222*5113495bSYour Name 	if (frag_track_node)
223*5113495bSYour Name 		qdf_init_list_head(&frag_track_node->hnode);
224*5113495bSYour Name 
225*5113495bSYour Name 	return frag_track_node;
226*5113495bSYour Name }
227*5113495bSYour Name 
228*5113495bSYour Name /* FREEQ_POOLSIZE initial and minimum desired freelist poolsize */
229*5113495bSYour Name #define FREEQ_POOLSIZE    2048
230*5113495bSYour Name 
231*5113495bSYour Name /**
232*5113495bSYour Name  * qdf_frag_track_free() - Free the frag tracking cookie.
233*5113495bSYour Name  * @frag_track_node : Debug frag node address
234*5113495bSYour Name  *
235*5113495bSYour Name  * Matches calls to qdf_frag_track_alloc.
236*5113495bSYour Name  * Either frees the tracking cookie to kernel or an internal
237*5113495bSYour Name  * freelist based on the size of the freelist.
238*5113495bSYour Name  *
239*5113495bSYour Name  * Return: none
240*5113495bSYour Name  */
qdf_frag_track_free(QDF_FRAG_TRACK * frag_track_node)241*5113495bSYour Name static void qdf_frag_track_free(QDF_FRAG_TRACK *frag_track_node)
242*5113495bSYour Name {
243*5113495bSYour Name 	if (!frag_track_node)
244*5113495bSYour Name 		return;
245*5113495bSYour Name 
246*5113495bSYour Name 	/*
247*5113495bSYour Name 	 * Try to shrink the freelist if free_list_count > than FREEQ_POOLSIZE
248*5113495bSYour Name 	 * only shrink the freelist if it is bigger than twice the number of
249*5113495bSYour Name 	 * frags in use. Otherwise add the frag debug track node to the front
250*5113495bSYour Name 	 * of qdf_frag_track_free_list.
251*5113495bSYour Name 	 */
252*5113495bSYour Name 
253*5113495bSYour Name 	qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock);
254*5113495bSYour Name 
255*5113495bSYour Name 	qdf_frag_track_used_list_count--;
256*5113495bSYour Name 	if (qdf_frag_track_free_list_count > FREEQ_POOLSIZE &&
257*5113495bSYour Name 	    (qdf_frag_track_free_list_count >
258*5113495bSYour Name 	    qdf_frag_track_used_list_count << 1)) {
259*5113495bSYour Name 		kmem_cache_free(frag_tracking_cache, frag_track_node);
260*5113495bSYour Name 	} else {
261*5113495bSYour Name 		qdf_list_insert_front(&qdf_frag_track_free_list.track_list,
262*5113495bSYour Name 				      &frag_track_node->hnode);
263*5113495bSYour Name 		qdf_frag_track_free_list_count++;
264*5113495bSYour Name 	}
265*5113495bSYour Name 	qdf_frag_update_max_free();
266*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock);
267*5113495bSYour Name }
268*5113495bSYour Name 
269*5113495bSYour Name /**
270*5113495bSYour Name  * qdf_frag_track_prefill() - Prefill the frag tracking cookie freelist
271*5113495bSYour Name  *
272*5113495bSYour Name  * Return: none
273*5113495bSYour Name  */
qdf_frag_track_prefill(void)274*5113495bSYour Name static void qdf_frag_track_prefill(void)
275*5113495bSYour Name {
276*5113495bSYour Name 	int index;
277*5113495bSYour Name 	QDF_FRAG_TRACK *curr_node, *next_node;
278*5113495bSYour Name 	qdf_list_t temp_list;
279*5113495bSYour Name 
280*5113495bSYour Name 	qdf_list_create(&temp_list, 0);
281*5113495bSYour Name 
282*5113495bSYour Name 	/* Prepopulate the freelist */
283*5113495bSYour Name 	for (index = 0; index < FREEQ_POOLSIZE; index++) {
284*5113495bSYour Name 		curr_node = qdf_frag_track_alloc();
285*5113495bSYour Name 		if (!curr_node)
286*5113495bSYour Name 			continue;
287*5113495bSYour Name 		qdf_list_insert_front(&temp_list, &curr_node->hnode);
288*5113495bSYour Name 	}
289*5113495bSYour Name 
290*5113495bSYour Name 	curr_node = NULL;
291*5113495bSYour Name 	next_node = NULL;
292*5113495bSYour Name 
293*5113495bSYour Name 	qdf_list_for_each_del(&temp_list, curr_node, next_node, hnode) {
294*5113495bSYour Name 		qdf_list_remove_node(&temp_list, &curr_node->hnode);
295*5113495bSYour Name 		qdf_frag_track_free(curr_node);
296*5113495bSYour Name 	}
297*5113495bSYour Name 
298*5113495bSYour Name 	/* prefilled buffers should not count as used */
299*5113495bSYour Name 	qdf_frag_track_max_used = 0;
300*5113495bSYour Name 
301*5113495bSYour Name 	qdf_list_destroy(&temp_list);
302*5113495bSYour Name }
303*5113495bSYour Name 
304*5113495bSYour Name /**
305*5113495bSYour Name  * qdf_frag_track_memory_manager_create() - Manager for frag tracking cookies
306*5113495bSYour Name  *
307*5113495bSYour Name  * This initializes the memory manager for the frag tracking cookies. Because
308*5113495bSYour Name  * these cookies are all the same size and only used in this feature, we can
309*5113495bSYour Name  * use a kmem_cache to provide tracking as well as to speed up allocations.
310*5113495bSYour Name  * To avoid the overhead of allocating and freeing the buffers (including SLUB
311*5113495bSYour Name  * features) a freelist is prepopulated here.
312*5113495bSYour Name  *
313*5113495bSYour Name  * Return: none
314*5113495bSYour Name  */
qdf_frag_track_memory_manager_create(void)315*5113495bSYour Name static void qdf_frag_track_memory_manager_create(void)
316*5113495bSYour Name {
317*5113495bSYour Name 	qdf_spinlock_create(&qdf_frag_track_free_list.list_lock);
318*5113495bSYour Name 	qdf_list_create(&qdf_frag_track_free_list.track_list, 0);
319*5113495bSYour Name 	frag_tracking_cache = kmem_cache_create("qdf_frag_tracking_cache",
320*5113495bSYour Name 						sizeof(QDF_FRAG_TRACK),
321*5113495bSYour Name 						0, 0, NULL);
322*5113495bSYour Name 
323*5113495bSYour Name 	qdf_frag_track_prefill();
324*5113495bSYour Name }
325*5113495bSYour Name 
326*5113495bSYour Name /**
327*5113495bSYour Name  * qdf_frag_track_memory_manager_destroy() - Manager for frag tracking cookies
328*5113495bSYour Name  *
329*5113495bSYour Name  * Empty the freelist and print out usage statistics when it is no longer
330*5113495bSYour Name  * needed. Also the kmem_cache should be destroyed here so that it can warn if
331*5113495bSYour Name  * any frag tracking cookies were leaked.
332*5113495bSYour Name  *
333*5113495bSYour Name  * Return: none
334*5113495bSYour Name  */
qdf_frag_track_memory_manager_destroy(void)335*5113495bSYour Name static void qdf_frag_track_memory_manager_destroy(void)
336*5113495bSYour Name {
337*5113495bSYour Name 	QDF_FRAG_TRACK *curr_node, *next_node;
338*5113495bSYour Name 
339*5113495bSYour Name 	curr_node = next_node = NULL;
340*5113495bSYour Name 
341*5113495bSYour Name 	qdf_spin_lock_irqsave(&qdf_frag_track_free_list.list_lock);
342*5113495bSYour Name 
343*5113495bSYour Name 	if (qdf_frag_track_max_used > FREEQ_POOLSIZE * 4)
344*5113495bSYour Name 		qdf_info("Unexpectedly large max_used count %d",
345*5113495bSYour Name 			  qdf_frag_track_max_used);
346*5113495bSYour Name 
347*5113495bSYour Name 	if (qdf_frag_track_max_used < qdf_frag_track_max_allocated)
348*5113495bSYour Name 		qdf_info("%d Unused trackers were allocated",
349*5113495bSYour Name 			  qdf_frag_track_max_allocated -
350*5113495bSYour Name 			  qdf_frag_track_max_used);
351*5113495bSYour Name 
352*5113495bSYour Name 	if (qdf_frag_track_free_list_count > FREEQ_POOLSIZE &&
353*5113495bSYour Name 	    qdf_frag_track_free_list_count > 3 * qdf_frag_track_max_used / 4)
354*5113495bSYour Name 		qdf_info("Check freelist shrinking functionality");
355*5113495bSYour Name 
356*5113495bSYour Name 	qdf_info("%d Residual freelist size", qdf_frag_track_free_list_count);
357*5113495bSYour Name 
358*5113495bSYour Name 	qdf_info("%d Max freelist size observed", qdf_frag_track_max_free);
359*5113495bSYour Name 
360*5113495bSYour Name 	qdf_info("%d Max buffers used observed", qdf_frag_track_max_used);
361*5113495bSYour Name 
362*5113495bSYour Name 	qdf_info("%d Max buffers allocated observed",
363*5113495bSYour Name 		  qdf_frag_track_max_allocated);
364*5113495bSYour Name 
365*5113495bSYour Name 	qdf_list_for_each_del(&qdf_frag_track_free_list.track_list,
366*5113495bSYour Name 			      curr_node, next_node, hnode) {
367*5113495bSYour Name 		qdf_list_remove_node(&qdf_frag_track_free_list.track_list,
368*5113495bSYour Name 				     &curr_node->hnode);
369*5113495bSYour Name 		kmem_cache_free(frag_tracking_cache, curr_node);
370*5113495bSYour Name 		qdf_frag_track_free_list_count--;
371*5113495bSYour Name 	}
372*5113495bSYour Name 
373*5113495bSYour Name 	if (qdf_frag_track_free_list_count != 0)
374*5113495bSYour Name 		qdf_info("%d Unfreed tracking memory lost in freelist",
375*5113495bSYour Name 			 qdf_frag_track_free_list_count);
376*5113495bSYour Name 
377*5113495bSYour Name 	if (qdf_frag_track_used_list_count != 0)
378*5113495bSYour Name 		qdf_info("%d Unfreed tracking memory still in use",
379*5113495bSYour Name 			 qdf_frag_track_used_list_count);
380*5113495bSYour Name 
381*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&qdf_frag_track_free_list.list_lock);
382*5113495bSYour Name 	kmem_cache_destroy(frag_tracking_cache);
383*5113495bSYour Name 
384*5113495bSYour Name 	qdf_list_destroy(&qdf_frag_track_free_list.track_list);
385*5113495bSYour Name 	qdf_spinlock_destroy(&qdf_frag_track_free_list.list_lock);
386*5113495bSYour Name }
387*5113495bSYour Name 
388*5113495bSYour Name /**
389*5113495bSYour Name  * qdf_frag_debug_init() - Initialize network frag debug functionality
390*5113495bSYour Name  *
391*5113495bSYour Name  * QDF frag buffer debug feature tracks all frags allocated by WLAN driver
392*5113495bSYour Name  * in a hash table and when driver is unloaded it reports about leaked frags.
393*5113495bSYour Name  *
394*5113495bSYour Name  * Return: none
395*5113495bSYour Name  */
qdf_frag_debug_init(void)396*5113495bSYour Name void qdf_frag_debug_init(void)
397*5113495bSYour Name {
398*5113495bSYour Name 	uint32_t index;
399*5113495bSYour Name 
400*5113495bSYour Name 	is_initial_mem_debug_disabled = qdf_mem_debug_config_get();
401*5113495bSYour Name 
402*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
403*5113495bSYour Name 		return;
404*5113495bSYour Name 
405*5113495bSYour Name 	qdf_frag_track_memory_manager_create();
406*5113495bSYour Name 
407*5113495bSYour Name 	for (index = 0; index < QDF_FRAG_TRACK_MAX_SIZE; index++) {
408*5113495bSYour Name 		qdf_list_create(&gp_qdf_frag_track_tbl[index].track_list, 0);
409*5113495bSYour Name 		qdf_spinlock_create(&gp_qdf_frag_track_tbl[index].list_lock);
410*5113495bSYour Name 	}
411*5113495bSYour Name }
412*5113495bSYour Name 
413*5113495bSYour Name qdf_export_symbol(qdf_frag_debug_init);
414*5113495bSYour Name 
qdf_frag_debug_exit(void)415*5113495bSYour Name void qdf_frag_debug_exit(void)
416*5113495bSYour Name {
417*5113495bSYour Name 	uint32_t index;
418*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
419*5113495bSYour Name 	QDF_FRAG_TRACK *p_prev;
420*5113495bSYour Name 
421*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
422*5113495bSYour Name 		return;
423*5113495bSYour Name 
424*5113495bSYour Name 	for (index = 0; index < QDF_FRAG_TRACK_MAX_SIZE; index++) {
425*5113495bSYour Name 		qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock);
426*5113495bSYour Name 		qdf_list_for_each_del(&gp_qdf_frag_track_tbl[index].track_list,
427*5113495bSYour Name 				      p_prev, p_node, hnode) {
428*5113495bSYour Name 			qdf_list_remove_node(
429*5113495bSYour Name 				&gp_qdf_frag_track_tbl[index].track_list,
430*5113495bSYour Name 				&p_prev->hnode);
431*5113495bSYour Name 			qdf_info("******Frag Memory Leak******");
432*5113495bSYour Name 			qdf_info("@Frag Address: %pK", p_prev->p_frag);
433*5113495bSYour Name 			qdf_info("@Refcount: %u", p_prev->refcount);
434*5113495bSYour Name 			qdf_info("@Alloc Func Name: %s, @Alloc Func Line: %d",
435*5113495bSYour Name 				 p_prev->alloc_func_name,
436*5113495bSYour Name 				 p_prev->alloc_func_line);
437*5113495bSYour Name 			qdf_info("@Last Func Name: %s, @Last Func Line: %d",
438*5113495bSYour Name 				 p_prev->last_func_name,
439*5113495bSYour Name 				 p_prev->last_func_line);
440*5113495bSYour Name 			qdf_info("****************************");
441*5113495bSYour Name 
442*5113495bSYour Name 			qdf_frag_track_free(p_prev);
443*5113495bSYour Name 		}
444*5113495bSYour Name 		qdf_list_destroy(&gp_qdf_frag_track_tbl[index].track_list);
445*5113495bSYour Name 		qdf_spin_unlock_irqrestore(
446*5113495bSYour Name 				&gp_qdf_frag_track_tbl[index].list_lock);
447*5113495bSYour Name 		qdf_spinlock_destroy(&gp_qdf_frag_track_tbl[index].list_lock);
448*5113495bSYour Name 	}
449*5113495bSYour Name 
450*5113495bSYour Name 	qdf_frag_track_memory_manager_destroy();
451*5113495bSYour Name }
452*5113495bSYour Name 
453*5113495bSYour Name qdf_export_symbol(qdf_frag_debug_exit);
454*5113495bSYour Name 
455*5113495bSYour Name /**
456*5113495bSYour Name  * qdf_frag_debug_hash() - Hash network frag pointer
457*5113495bSYour Name  * @p_frag: Frag address
458*5113495bSYour Name  *
459*5113495bSYour Name  * Return: hash value
460*5113495bSYour Name  */
qdf_frag_debug_hash(qdf_frag_t p_frag)461*5113495bSYour Name static uint32_t qdf_frag_debug_hash(qdf_frag_t p_frag)
462*5113495bSYour Name {
463*5113495bSYour Name 	uint32_t index;
464*5113495bSYour Name 
465*5113495bSYour Name 	index = (uint32_t)(((uintptr_t)p_frag) >> 4);
466*5113495bSYour Name 	index += (uint32_t)(((uintptr_t)p_frag) >> 14);
467*5113495bSYour Name 	index &= (QDF_FRAG_TRACK_MAX_SIZE - 1);
468*5113495bSYour Name 
469*5113495bSYour Name 	return index;
470*5113495bSYour Name }
471*5113495bSYour Name 
472*5113495bSYour Name /**
473*5113495bSYour Name  * qdf_frag_debug_look_up() - Look up network frag in debug hash table
474*5113495bSYour Name  * @p_frag: Frag address
475*5113495bSYour Name  *
476*5113495bSYour Name  * Return: If frag is found in hash table then return pointer to network frag
477*5113495bSYour Name  *	else return NULL
478*5113495bSYour Name  */
qdf_frag_debug_look_up(qdf_frag_t p_frag)479*5113495bSYour Name static QDF_FRAG_TRACK *qdf_frag_debug_look_up(qdf_frag_t p_frag)
480*5113495bSYour Name {
481*5113495bSYour Name 	uint32_t index;
482*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
483*5113495bSYour Name 
484*5113495bSYour Name 	index = qdf_frag_debug_hash(p_frag);
485*5113495bSYour Name 
486*5113495bSYour Name 	qdf_list_for_each(&gp_qdf_frag_track_tbl[index].track_list, p_node,
487*5113495bSYour Name 			  hnode) {
488*5113495bSYour Name 		if (p_node->p_frag == p_frag)
489*5113495bSYour Name 			return p_node;
490*5113495bSYour Name 	}
491*5113495bSYour Name 
492*5113495bSYour Name 	return NULL;
493*5113495bSYour Name }
494*5113495bSYour Name 
495*5113495bSYour Name /**
496*5113495bSYour Name  * __qdf_frag_debug_add_node()- Add frag node to debug tracker
497*5113495bSYour Name  * @fragp: Frag Pointer
498*5113495bSYour Name  * @idx: Index
499*5113495bSYour Name  * @func_name: Caller function name
500*5113495bSYour Name  * @line_num: Caller function line no.
501*5113495bSYour Name  *
502*5113495bSYour Name  * Return: Allocated frag tracker node address
503*5113495bSYour Name  */
__qdf_frag_debug_add_node(qdf_frag_t fragp,uint32_t idx,const char * func_name,uint32_t line_num)504*5113495bSYour Name static QDF_FRAG_TRACK *__qdf_frag_debug_add_node(qdf_frag_t fragp,
505*5113495bSYour Name 						 uint32_t idx,
506*5113495bSYour Name 						 const char *func_name,
507*5113495bSYour Name 						 uint32_t line_num)
508*5113495bSYour Name {
509*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
510*5113495bSYour Name 
511*5113495bSYour Name 	p_node = qdf_frag_track_alloc();
512*5113495bSYour Name 
513*5113495bSYour Name 	if (p_node) {
514*5113495bSYour Name 		p_node->p_frag = fragp;
515*5113495bSYour Name 		qdf_str_lcopy(p_node->alloc_func_name, func_name,
516*5113495bSYour Name 			      QDF_MEM_FUNC_NAME_SIZE);
517*5113495bSYour Name 		p_node->alloc_func_line = line_num;
518*5113495bSYour Name 		p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ZERO;
519*5113495bSYour Name 
520*5113495bSYour Name 		qdf_str_lcopy(p_node->last_func_name, func_name,
521*5113495bSYour Name 			      QDF_MEM_FUNC_NAME_SIZE);
522*5113495bSYour Name 		p_node->last_func_line = line_num;
523*5113495bSYour Name 
524*5113495bSYour Name 		qdf_list_insert_front(&gp_qdf_frag_track_tbl[idx].track_list,
525*5113495bSYour Name 				      &p_node->hnode);
526*5113495bSYour Name 	}
527*5113495bSYour Name 	return p_node;
528*5113495bSYour Name }
529*5113495bSYour Name 
530*5113495bSYour Name /**
531*5113495bSYour Name  * __qdf_frag_debug_delete_node()- Remove frag node from debug tracker
532*5113495bSYour Name  * @p_node: Frag node address in debug tracker
533*5113495bSYour Name  * @idx: Index
534*5113495bSYour Name  *
535*5113495bSYour Name  * Return: none
536*5113495bSYour Name  */
__qdf_frag_debug_delete_node(QDF_FRAG_TRACK * p_node,uint32_t idx)537*5113495bSYour Name static void __qdf_frag_debug_delete_node(QDF_FRAG_TRACK *p_node, uint32_t idx)
538*5113495bSYour Name {
539*5113495bSYour Name 	if (idx < QDF_FRAG_TRACK_MAX_SIZE) {
540*5113495bSYour Name 		qdf_list_remove_node(&gp_qdf_frag_track_tbl[idx].track_list,
541*5113495bSYour Name 				     &p_node->hnode);
542*5113495bSYour Name 		qdf_frag_track_free(p_node);
543*5113495bSYour Name 	} else {
544*5113495bSYour Name 		qdf_info("Index value exceeds %d for delete node operation",
545*5113495bSYour Name 			  QDF_FRAG_TRACK_MAX_SIZE);
546*5113495bSYour Name 	}
547*5113495bSYour Name }
548*5113495bSYour Name 
qdf_frag_debug_add_node(qdf_frag_t fragp,const char * func_name,uint32_t line_num)549*5113495bSYour Name void qdf_frag_debug_add_node(qdf_frag_t fragp, const char *func_name,
550*5113495bSYour Name 			     uint32_t line_num)
551*5113495bSYour Name {
552*5113495bSYour Name 	uint32_t index;
553*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
554*5113495bSYour Name 
555*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
556*5113495bSYour Name 		return;
557*5113495bSYour Name 
558*5113495bSYour Name 	index = qdf_frag_debug_hash(fragp);
559*5113495bSYour Name 
560*5113495bSYour Name 	qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock);
561*5113495bSYour Name 
562*5113495bSYour Name 	p_node = qdf_frag_debug_look_up(fragp);
563*5113495bSYour Name 
564*5113495bSYour Name 	if (p_node) {
565*5113495bSYour Name 		qdf_info("Double addition of frag %pK to debug tracker!!",
566*5113495bSYour Name 			 fragp);
567*5113495bSYour Name 		qdf_info("Already added from %s %d Current addition from %s %d",
568*5113495bSYour Name 			  p_node->alloc_func_name,
569*5113495bSYour Name 			  p_node->alloc_func_line, func_name, line_num);
570*5113495bSYour Name 	} else {
571*5113495bSYour Name 		p_node = __qdf_frag_debug_add_node(fragp, index, func_name,
572*5113495bSYour Name 						   line_num);
573*5113495bSYour Name 		if (!p_node)
574*5113495bSYour Name 			qdf_info("Memory allocation failed !! "
575*5113495bSYour Name 				 "Add node oprt failed for frag %pK from %s %d",
576*5113495bSYour Name 				 fragp, func_name, line_num);
577*5113495bSYour Name 	}
578*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock);
579*5113495bSYour Name }
580*5113495bSYour Name 
qdf_frag_debug_refcount_inc(qdf_frag_t fragp,const char * func_name,uint32_t line_num)581*5113495bSYour Name void qdf_frag_debug_refcount_inc(qdf_frag_t fragp, const char *func_name,
582*5113495bSYour Name 				 uint32_t line_num)
583*5113495bSYour Name {
584*5113495bSYour Name 	uint32_t index;
585*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
586*5113495bSYour Name 
587*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
588*5113495bSYour Name 		return;
589*5113495bSYour Name 
590*5113495bSYour Name 	index = qdf_frag_debug_hash(fragp);
591*5113495bSYour Name 
592*5113495bSYour Name 	qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock);
593*5113495bSYour Name 
594*5113495bSYour Name 	p_node = qdf_frag_debug_look_up(fragp);
595*5113495bSYour Name 
596*5113495bSYour Name 	if (p_node) {
597*5113495bSYour Name 		(p_node->refcount)++;
598*5113495bSYour Name 
599*5113495bSYour Name 		qdf_str_lcopy(p_node->last_func_name, func_name,
600*5113495bSYour Name 			      QDF_MEM_FUNC_NAME_SIZE);
601*5113495bSYour Name 		p_node->last_func_line = line_num;
602*5113495bSYour Name 	} else {
603*5113495bSYour Name 		p_node = __qdf_frag_debug_add_node(fragp, index, func_name,
604*5113495bSYour Name 						   line_num);
605*5113495bSYour Name 		if (p_node)
606*5113495bSYour Name 			p_node->refcount = QDF_NBUF_FRAG_DEBUG_COUNT_ONE;
607*5113495bSYour Name 		else
608*5113495bSYour Name 			qdf_info("Memory allocation failed !! "
609*5113495bSYour Name 				 "Refcount inc failed for frag %pK from %s %d",
610*5113495bSYour Name 				 fragp, func_name, line_num);
611*5113495bSYour Name 	}
612*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock);
613*5113495bSYour Name }
614*5113495bSYour Name 
qdf_frag_debug_refcount_dec(qdf_frag_t fragp,const char * func_name,uint32_t line_num)615*5113495bSYour Name void qdf_frag_debug_refcount_dec(qdf_frag_t fragp, const char *func_name,
616*5113495bSYour Name 				 uint32_t line_num)
617*5113495bSYour Name {
618*5113495bSYour Name 	uint32_t index;
619*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
620*5113495bSYour Name 
621*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
622*5113495bSYour Name 		return;
623*5113495bSYour Name 
624*5113495bSYour Name 	index = qdf_frag_debug_hash(fragp);
625*5113495bSYour Name 
626*5113495bSYour Name 	qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock);
627*5113495bSYour Name 
628*5113495bSYour Name 	p_node = qdf_frag_debug_look_up(fragp);
629*5113495bSYour Name 
630*5113495bSYour Name 	if (p_node) {
631*5113495bSYour Name 		if (!(p_node->refcount)) {
632*5113495bSYour Name 			qdf_info("Refcount dec oprt for frag %pK not permitted "
633*5113495bSYour Name 				 "as refcount=0", fragp);
634*5113495bSYour Name 			goto done;
635*5113495bSYour Name 		}
636*5113495bSYour Name 		(p_node->refcount)--;
637*5113495bSYour Name 
638*5113495bSYour Name 		if (!(p_node->refcount)) {
639*5113495bSYour Name 			/* Remove frag debug node when refcount reaches 0 */
640*5113495bSYour Name 			__qdf_frag_debug_delete_node(p_node, index);
641*5113495bSYour Name 		} else {
642*5113495bSYour Name 			qdf_str_lcopy(p_node->last_func_name, func_name,
643*5113495bSYour Name 				      QDF_MEM_FUNC_NAME_SIZE);
644*5113495bSYour Name 			p_node->last_func_line = line_num;
645*5113495bSYour Name 		}
646*5113495bSYour Name 	} else {
647*5113495bSYour Name 		qdf_info("Unallocated frag !! Could not track frag %pK", fragp);
648*5113495bSYour Name 		qdf_info("Refcount dec oprt failed for frag %pK from %s %d",
649*5113495bSYour Name 			 fragp, func_name, line_num);
650*5113495bSYour Name 	}
651*5113495bSYour Name done:
652*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock);
653*5113495bSYour Name }
654*5113495bSYour Name 
qdf_frag_debug_delete_node(qdf_frag_t fragp,const char * func_name,uint32_t line_num)655*5113495bSYour Name void qdf_frag_debug_delete_node(qdf_frag_t fragp, const char *func_name,
656*5113495bSYour Name 				uint32_t line_num)
657*5113495bSYour Name {
658*5113495bSYour Name 	uint32_t index;
659*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
660*5113495bSYour Name 
661*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
662*5113495bSYour Name 		return;
663*5113495bSYour Name 
664*5113495bSYour Name 	index = qdf_frag_debug_hash(fragp);
665*5113495bSYour Name 
666*5113495bSYour Name 	qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[index].list_lock);
667*5113495bSYour Name 
668*5113495bSYour Name 	p_node = qdf_frag_debug_look_up(fragp);
669*5113495bSYour Name 
670*5113495bSYour Name 	if (p_node) {
671*5113495bSYour Name 		if (p_node->refcount) {
672*5113495bSYour Name 			qdf_info("Frag %pK has refcount %d", fragp,
673*5113495bSYour Name 				 p_node->refcount);
674*5113495bSYour Name 			qdf_info("Delete oprt failed for frag %pK from %s %d",
675*5113495bSYour Name 				 fragp, func_name, line_num);
676*5113495bSYour Name 		} else {
677*5113495bSYour Name 			/* Remove node from tracker as refcount=0 */
678*5113495bSYour Name 			__qdf_frag_debug_delete_node(p_node, index);
679*5113495bSYour Name 		}
680*5113495bSYour Name 	} else {
681*5113495bSYour Name 		qdf_info("Unallocated frag !! Double free of frag %pK", fragp);
682*5113495bSYour Name 		qdf_info("Could not track frag %pK for delete oprt from %s %d",
683*5113495bSYour Name 			 fragp, func_name, line_num);
684*5113495bSYour Name 	}
685*5113495bSYour Name 
686*5113495bSYour Name 	qdf_spin_unlock_irqrestore(&gp_qdf_frag_track_tbl[index].list_lock);
687*5113495bSYour Name }
688*5113495bSYour Name 
qdf_frag_debug_update_addr(qdf_frag_t p_fragp,qdf_frag_t n_fragp,const char * func_name,uint32_t line_num)689*5113495bSYour Name void qdf_frag_debug_update_addr(qdf_frag_t p_fragp, qdf_frag_t n_fragp,
690*5113495bSYour Name 				const char *func_name, uint32_t line_num)
691*5113495bSYour Name {
692*5113495bSYour Name 	uint32_t prev_index, new_index;
693*5113495bSYour Name 	QDF_FRAG_TRACK *p_node;
694*5113495bSYour Name 
695*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
696*5113495bSYour Name 		return;
697*5113495bSYour Name 
698*5113495bSYour Name 	prev_index = qdf_frag_debug_hash(p_fragp);
699*5113495bSYour Name 
700*5113495bSYour Name 	new_index = qdf_frag_debug_hash(n_fragp);
701*5113495bSYour Name 
702*5113495bSYour Name 	qdf_spin_lock_irqsave(&gp_qdf_frag_track_tbl[prev_index].list_lock);
703*5113495bSYour Name 
704*5113495bSYour Name 	p_node = qdf_frag_debug_look_up(p_fragp);
705*5113495bSYour Name 
706*5113495bSYour Name 	if (!p_node) {
707*5113495bSYour Name 		qdf_info("Unallocated frag !! Could not track frag %pK",
708*5113495bSYour Name 			 p_fragp);
709*5113495bSYour Name 		qdf_info("Update address oprt failed for frag %pK from %s %d",
710*5113495bSYour Name 			 p_fragp, func_name, line_num);
711*5113495bSYour Name 		qdf_spin_unlock_irqrestore(
712*5113495bSYour Name 				&gp_qdf_frag_track_tbl[prev_index].list_lock);
713*5113495bSYour Name 	} else {
714*5113495bSYour Name 		/* Update frag address */
715*5113495bSYour Name 		p_node->p_frag = n_fragp;
716*5113495bSYour Name 
717*5113495bSYour Name 		qdf_str_lcopy(p_node->last_func_name, func_name,
718*5113495bSYour Name 			      QDF_MEM_FUNC_NAME_SIZE);
719*5113495bSYour Name 		p_node->last_func_line = line_num;
720*5113495bSYour Name 
721*5113495bSYour Name 		if (prev_index != new_index) {
722*5113495bSYour Name 			qdf_list_remove_node(
723*5113495bSYour Name 				&gp_qdf_frag_track_tbl[prev_index].track_list,
724*5113495bSYour Name 				&p_node->hnode);
725*5113495bSYour Name 
726*5113495bSYour Name 			qdf_spin_unlock_irqrestore(
727*5113495bSYour Name 				&gp_qdf_frag_track_tbl[prev_index].list_lock);
728*5113495bSYour Name 
729*5113495bSYour Name 			qdf_spin_lock_irqsave(
730*5113495bSYour Name 				&gp_qdf_frag_track_tbl[new_index].list_lock);
731*5113495bSYour Name 
732*5113495bSYour Name 			qdf_list_insert_front(
733*5113495bSYour Name 				&gp_qdf_frag_track_tbl[new_index].track_list,
734*5113495bSYour Name 				&p_node->hnode);
735*5113495bSYour Name 
736*5113495bSYour Name 			qdf_spin_unlock_irqrestore(
737*5113495bSYour Name 				&gp_qdf_frag_track_tbl[new_index].list_lock);
738*5113495bSYour Name 		} else {
739*5113495bSYour Name 			qdf_spin_unlock_irqrestore(
740*5113495bSYour Name 				&gp_qdf_frag_track_tbl[prev_index].list_lock);
741*5113495bSYour Name 		}
742*5113495bSYour Name 	}
743*5113495bSYour Name }
744*5113495bSYour Name 
qdf_frag_alloc_debug(qdf_frag_cache_t * pf_cache,unsigned int frag_size,const char * func_name,uint32_t line_num)745*5113495bSYour Name qdf_frag_t qdf_frag_alloc_debug(qdf_frag_cache_t *pf_cache,
746*5113495bSYour Name 				unsigned int frag_size,
747*5113495bSYour Name 				const char *func_name,
748*5113495bSYour Name 				uint32_t line_num)
749*5113495bSYour Name {
750*5113495bSYour Name 	qdf_frag_t p_frag;
751*5113495bSYour Name 
752*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
753*5113495bSYour Name 		return __qdf_frag_alloc(pf_cache, frag_size);
754*5113495bSYour Name 
755*5113495bSYour Name 	p_frag =  __qdf_frag_alloc(pf_cache, frag_size);
756*5113495bSYour Name 
757*5113495bSYour Name 	/* Store frag in QDF Frag Tracking Table */
758*5113495bSYour Name 	if (qdf_likely(p_frag))
759*5113495bSYour Name 		qdf_frag_debug_add_node(p_frag, func_name, line_num);
760*5113495bSYour Name 
761*5113495bSYour Name 	return p_frag;
762*5113495bSYour Name }
763*5113495bSYour Name 
764*5113495bSYour Name qdf_export_symbol(qdf_frag_alloc_debug);
765*5113495bSYour Name 
qdf_frag_free_debug(qdf_frag_t vaddr,const char * func_name,uint32_t line_num)766*5113495bSYour Name void qdf_frag_free_debug(qdf_frag_t vaddr, const char *func_name,
767*5113495bSYour Name 			 uint32_t line_num)
768*5113495bSYour Name {
769*5113495bSYour Name 	if (qdf_unlikely(!vaddr))
770*5113495bSYour Name 		return;
771*5113495bSYour Name 
772*5113495bSYour Name 	if (is_initial_mem_debug_disabled)
773*5113495bSYour Name 		goto free_frag;
774*5113495bSYour Name 
775*5113495bSYour Name 	qdf_frag_debug_delete_node(vaddr, func_name, line_num);
776*5113495bSYour Name free_frag:
777*5113495bSYour Name 	__qdf_frag_free(vaddr);
778*5113495bSYour Name }
779*5113495bSYour Name 
780*5113495bSYour Name qdf_export_symbol(qdf_frag_free_debug);
781*5113495bSYour Name 
782*5113495bSYour Name #endif /* NBUF_FRAG_MEMORY_DEBUG */
783*5113495bSYour Name 
784*5113495bSYour Name #if defined(HIF_PCI)
__qdf_mem_map_page(qdf_device_t osdev,__qdf_frag_t buf,qdf_dma_dir_t dir,size_t nbytes,qdf_dma_addr_t * phy_addr)785*5113495bSYour Name QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf,
786*5113495bSYour Name 			      qdf_dma_dir_t dir, size_t nbytes,
787*5113495bSYour Name 			      qdf_dma_addr_t *phy_addr)
788*5113495bSYour Name {
789*5113495bSYour Name 	struct page *page;
790*5113495bSYour Name 	unsigned long offset;
791*5113495bSYour Name 
792*5113495bSYour Name 	page = virt_to_head_page(buf);
793*5113495bSYour Name 	offset = buf - page_address(page);
794*5113495bSYour Name 	*phy_addr = dma_map_page(osdev->dev, page, offset, nbytes,
795*5113495bSYour Name 				 __qdf_dma_dir_to_os(dir));
796*5113495bSYour Name 
797*5113495bSYour Name 	return dma_mapping_error(osdev->dev, *phy_addr) ?
798*5113495bSYour Name 		QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS;
799*5113495bSYour Name }
800*5113495bSYour Name #else
__qdf_mem_map_page(qdf_device_t osdev,__qdf_frag_t buf,qdf_dma_dir_t dir,size_t nbytes,qdf_dma_addr_t * phy_addr)801*5113495bSYour Name QDF_STATUS __qdf_mem_map_page(qdf_device_t osdev, __qdf_frag_t buf,
802*5113495bSYour Name 			      qdf_dma_dir_t dir, size_t nbytes,
803*5113495bSYour Name 			      qdf_dma_addr_t *phy_addr)
804*5113495bSYour Name {
805*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
806*5113495bSYour Name }
807*5113495bSYour Name #endif
808*5113495bSYour Name 
809*5113495bSYour Name qdf_export_symbol(__qdf_mem_map_page);
810*5113495bSYour Name 
811*5113495bSYour Name #if defined(HIF_PCI)
__qdf_mem_unmap_page(qdf_device_t osdev,qdf_dma_addr_t paddr,size_t nbytes,qdf_dma_dir_t dir)812*5113495bSYour Name void __qdf_mem_unmap_page(qdf_device_t osdev, qdf_dma_addr_t paddr,
813*5113495bSYour Name 			  size_t nbytes, qdf_dma_dir_t dir)
814*5113495bSYour Name {
815*5113495bSYour Name 	dma_unmap_page(osdev->dev, paddr, nbytes,
816*5113495bSYour Name 		       __qdf_dma_dir_to_os(dir));
817*5113495bSYour Name }
818*5113495bSYour Name #else
__qdf_mem_unmap_page(qdf_device_t osdev,qdf_dma_addr_t paddr,size_t nbytes,qdf_dma_dir_t dir)819*5113495bSYour Name void __qdf_mem_unmap_page(qdf_device_t osdev, qdf_dma_addr_t paddr,
820*5113495bSYour Name 			  size_t nbytes, qdf_dma_dir_t dir)
821*5113495bSYour Name {
822*5113495bSYour Name }
823*5113495bSYour Name #endif
824*5113495bSYour Name 
825*5113495bSYour Name qdf_export_symbol(__qdf_mem_unmap_page);
826*5113495bSYour Name 
827*5113495bSYour Name #if defined(QDF_FRAG_CACHE_SUPPORT)
__qdf_frag_cache_drain(qdf_frag_cache_t * pf_cache)828*5113495bSYour Name void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache)
829*5113495bSYour Name {
830*5113495bSYour Name 	struct page *page;
831*5113495bSYour Name 
832*5113495bSYour Name 	if (!pf_cache->va)
833*5113495bSYour Name 		return;
834*5113495bSYour Name 
835*5113495bSYour Name 	page  = virt_to_page(pf_cache->va);
836*5113495bSYour Name 	__page_frag_cache_drain(page, pf_cache->pagecnt_bias);
837*5113495bSYour Name 	memset(pf_cache, 0, sizeof(*pf_cache));
838*5113495bSYour Name }
839*5113495bSYour Name #else
__qdf_frag_cache_drain(qdf_frag_cache_t * pf_cache)840*5113495bSYour Name void __qdf_frag_cache_drain(qdf_frag_cache_t *pf_cache)
841*5113495bSYour Name {
842*5113495bSYour Name }
843*5113495bSYour Name #endif
844*5113495bSYour Name 
845*5113495bSYour Name qdf_export_symbol(__qdf_frag_cache_drain);
846