blob: a01dc919881dd6a5473dd14c5fb306c8e65c42e8 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*===========================================================================
23 @file vos_memory.c
24
25 @brief Virtual Operating System Services Memory API
26
27
28 Copyright (c) 2008 QUALCOMM Incorporated.
29 All Rights Reserved.
30 Qualcomm Confidential and Proprietary
31===========================================================================*/
32
33/*===========================================================================
34
35 EDIT HISTORY FOR FILE
36
37
38 This section contains comments describing changes made to the module.
39 Notice that changes are listed in reverse chronological order.
40
41
42 $Header:$ $DateTime: $ $Author: $
43
44
45 when who what, where, why
46 -------- --- --------------------------------------------------------
47
48===========================================================================*/
49
50/*---------------------------------------------------------------------------
51 * Include Files
52 * ------------------------------------------------------------------------*/
53
54#include "vos_memory.h"
55#include "vos_trace.h"
56
57#ifdef MEMORY_DEBUG
58#include "wlan_hdd_dp_utils.h"
59
60hdd_list_t vosMemList;
61
62static v_U8_t WLAN_MEM_HEADER[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68 };
63static v_U8_t WLAN_MEM_TAIL[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87};
64
65struct s_vos_mem_struct
66{
67 hdd_list_node_t pNode;
68 char* fileName;
69 unsigned int lineNum;
70 unsigned int size;
71 v_U8_t header[8];
72};
73#endif
74
75/*---------------------------------------------------------------------------
76 * Preprocessor Definitions and Constants
77 * ------------------------------------------------------------------------*/
78
79/*---------------------------------------------------------------------------
80 * Type Declarations
81 * ------------------------------------------------------------------------*/
82
83/*---------------------------------------------------------------------------
84 * Data definitions
85 * ------------------------------------------------------------------------*/
86
87/*---------------------------------------------------------------------------
88 * External Function implementation
89 * ------------------------------------------------------------------------*/
90#ifdef MEMORY_DEBUG
91void vos_mem_init()
92{
93 /* Initalizing the list with maximum size of 60000 */
94 hdd_list_init(&vosMemList, 60000);
95 return;
96}
97
98void vos_mem_clean()
99{
100 v_SIZE_t listSize;
101 hdd_list_size(&vosMemList, &listSize);
102
103 if(listSize)
104 {
105 hdd_list_node_t* pNode;
106 VOS_STATUS vosStatus;
107
108 struct s_vos_mem_struct* memStruct;
109
110 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
111 "%s: List is not Empty. listSize %d ", __FUNCTION__, (int)listSize);
112
113 do
114 {
115 spin_lock(&vosMemList.lock);
116 vosStatus = hdd_list_remove_front(&vosMemList, &pNode);
117 spin_unlock(&vosMemList.lock);
118 if(VOS_STATUS_SUCCESS == vosStatus)
119 {
120 memStruct = (struct s_vos_mem_struct*)pNode;
121 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
122 "Memory Leak@ File %s, @Line %d, size %d",
123 memStruct->fileName, (int)memStruct->lineNum, memStruct->size);
124 kfree((v_VOID_t*)memStruct);
125 }
126 }while(vosStatus == VOS_STATUS_SUCCESS);
127 }
128}
129
130void vos_mem_exit()
131{
132 vos_mem_clean();
133 hdd_list_destroy(&vosMemList);
134}
135
136v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum)
137{
138 struct s_vos_mem_struct* memStruct;
139 v_VOID_t* memPtr = NULL;
140 v_SIZE_t new_size;
141
142 if (size > (1024*1024))
143 {
144 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
145 "%s: called with arg > 1024K; passed in %d !!!", __FUNCTION__,size);
146 return NULL;
147 }
148 if (in_interrupt())
149 {
150 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
151 "%s is being called in interrupt context, using GPF_ATOMIC.", __FUNCTION__);
152 return kmalloc(size, GFP_ATOMIC);
153
154 }
155
156 new_size = size + sizeof(struct s_vos_mem_struct) + 8;
157
158 memStruct = (struct s_vos_mem_struct*)kmalloc(new_size,GFP_KERNEL);
159
160 if(memStruct != NULL)
161 {
162 VOS_STATUS vosStatus;
163
164 memStruct->fileName = fileName;
165 memStruct->lineNum = lineNum;
166 memStruct->size = size;
167
168 vos_mem_copy(&memStruct->header[0], &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER));
169 vos_mem_copy( (v_U8_t*)(memStruct + 1) + size, &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL));
170
171 spin_lock(&vosMemList.lock);
172 vosStatus = hdd_list_insert_front(&vosMemList, &memStruct->pNode);
173 spin_unlock(&vosMemList.lock);
174 if(VOS_STATUS_SUCCESS != vosStatus)
175 {
176 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
177 "%s: Unable to insert node into List vosStatus %d\n", __FUNCTION__, vosStatus);
178 }
179
180 memPtr = (v_VOID_t*)(memStruct + 1);
181 }
182 return memPtr;
183}
184
185v_VOID_t vos_mem_free( v_VOID_t *ptr )
186{
187 if (ptr != NULL)
188 {
189 VOS_STATUS vosStatus;
190 struct s_vos_mem_struct* memStruct = ((struct s_vos_mem_struct*)ptr) - 1;
191
192 spin_lock(&vosMemList.lock);
193 vosStatus = hdd_list_remove_node(&vosMemList, &memStruct->pNode);
194 spin_unlock(&vosMemList.lock);
195
196 if(VOS_STATUS_SUCCESS == vosStatus)
197 {
198 if(0 == vos_mem_compare(memStruct->header, &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER)) )
199 {
200 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
201 "Memory Header is corrupted. MemInfo: Filename %s, LineNum %d",
202 memStruct->fileName, (int)memStruct->lineNum);
203 }
204 if(0 == vos_mem_compare( (v_U8_t*)ptr + memStruct->size, &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL ) ) )
205 {
206 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
207 "Memory Trailer is corrupted. MemInfo: Filename %s, LineNum %d",
208 memStruct->fileName, (int)memStruct->lineNum);
209 }
210 kfree((v_VOID_t*)memStruct);
211 }
212 else
213 {
214 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
215 "%s: Unallocated memory (double free?)", __FUNCTION__);
216 VOS_ASSERT(0);
217 }
218 }
219}
220#else
221v_VOID_t * vos_mem_malloc( v_SIZE_t size )
222{
223 if (size > (1024*1024))
224 {
225 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: called with arg > 1024K; passed in %d !!!", __FUNCTION__,size);
226 return NULL;
227 }
228 if (in_interrupt())
229 {
230 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __FUNCTION__);
231 return NULL;
232 }
233 return kmalloc(size, GFP_KERNEL);
234}
235
236v_VOID_t vos_mem_free( v_VOID_t *ptr )
237{
238 if (ptr == NULL)
239 return;
240 kfree(ptr);
241}
242#endif
243
244v_VOID_t vos_mem_set( v_VOID_t *ptr, v_SIZE_t numBytes, v_BYTE_t value )
245{
246 if (ptr == NULL)
247 {
248 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s called with NULL parameter ptr", __FUNCTION__);
249 return;
250 }
251 memset(ptr, value, numBytes);
252}
253
254v_VOID_t vos_mem_zero( v_VOID_t *ptr, v_SIZE_t numBytes )
255{
256 if (0 == numBytes)
257 {
258 // special case where ptr can be NULL
259 return;
260 }
261
262 if (ptr == NULL)
263 {
264 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s called with NULL parameter ptr", __FUNCTION__);
265 return;
266 }
267 memset(ptr, 0, numBytes);
268
269}
270
271
272//This function is to validate one list in SME. We suspect someone corrupt te list. This code need to be removed
273//once the issue is fixed.
274extern int csrCheckValidateLists(void * dest, const void *src, v_SIZE_t num, int idx);
275
276v_VOID_t vos_mem_copy( v_VOID_t *pDst, const v_VOID_t *pSrc, v_SIZE_t numBytes )
277{
278 if (0 == numBytes)
279 {
280 // special case where pDst or pSrc can be NULL
281 return;
282 }
283
284 if ((pDst == NULL) || (pSrc==NULL))
285 {
286 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
287 "%s called with NULL parameter, source:%p destination:%p",
288 __FUNCTION__, pSrc, pDst);
289 VOS_ASSERT(0);
290 return;
291 }
292 //These two check function calls are to see if someone corrupt the list while doing mem copy.
293 csrCheckValidateLists(pDst, pSrc, numBytes, 1);
294 memcpy(pDst, pSrc, numBytes);
295 csrCheckValidateLists(pDst, pSrc, numBytes, 2);
296}
297
298v_VOID_t vos_mem_move( v_VOID_t *pDst, const v_VOID_t *pSrc, v_SIZE_t numBytes )
299{
300 if (0 == numBytes)
301 {
302 // special case where pDst or pSrc can be NULL
303 return;
304 }
305
306 if ((pDst == NULL) || (pSrc==NULL))
307 {
308 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
309 "%s called with NULL parameter, source:%p destination:%p",
310 __FUNCTION__, pSrc, pDst);
311 VOS_ASSERT(0);
312 return;
313 }
314 memmove(pDst, pSrc, numBytes);
315}
316
317v_BOOL_t vos_mem_compare( v_VOID_t *pMemory1, v_VOID_t *pMemory2, v_U32_t numBytes )
318{
319 if (0 == numBytes)
320 {
321 // special case where pMemory1 or pMemory2 can be NULL
322 return VOS_TRUE;
323 }
324
325 if ((pMemory1 == NULL) || (pMemory2==NULL))
326 {
327 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
328 "%s called with NULL parameter, p1:%p p2:%p",
329 __FUNCTION__, pMemory1, pMemory2);
330 VOS_ASSERT(0);
331 return VOS_FALSE;
332 }
333 return (memcmp(pMemory1, pMemory2, numBytes)?VOS_FALSE:VOS_TRUE);
334}
335
336
337v_SINT_t vos_mem_compare2( v_VOID_t *pMemory1, v_VOID_t *pMemory2, v_U32_t numBytes )
338
339{
340 return( (v_SINT_t) memcmp( pMemory1, pMemory2, numBytes ) );
341}
342
343/*----------------------------------------------------------------------------
344
345 \brief vos_mem_dma_malloc() - vOSS DMA Memory Allocation
346
347 This function will dynamicallly allocate the specified number of bytes of
348 memory. This memory will have special attributes making it DMA friendly i.e.
349 it will exist in contiguous, 32-byte aligned uncached memory. A normal
350 vos_mem_malloc does not yield memory with these attributes.
351
352 NOTE: the special DMA friendly memory is very scarce and this API must be
353 used sparingly
354
355 On WM, there is nothing special about this memory. SDHC allocates the
356 DMA friendly buffer and copies the data into it
357
358 \param size - the number of bytes of memory to allocate.
359
360 \return Upon successful allocate, returns a non-NULL pointer to the
361 allocated memory. If this function is unable to allocate the amount of
362 memory specified (for any reason) it returns NULL.
363
364 \sa
365
366 --------------------------------------------------------------------------*/
367#ifdef MEMORY_DEBUG
368v_VOID_t * vos_mem_dma_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum)
369{
370 struct s_vos_mem_struct* memStruct;
371 v_VOID_t* memPtr = NULL;
372 v_SIZE_t new_size;
373
374 if (in_interrupt())
375 {
376 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __FUNCTION__);
377 return NULL;
378 }
379
380 new_size = size + sizeof(struct s_vos_mem_struct) + 8;
381
382 memStruct = (struct s_vos_mem_struct*)kmalloc(new_size,GFP_KERNEL);
383
384 if(memStruct != NULL)
385 {
386 VOS_STATUS vosStatus;
387
388 memStruct->fileName = fileName;
389 memStruct->lineNum = lineNum;
390 memStruct->size = size;
391
392 vos_mem_copy(&memStruct->header[0], &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER));
393 vos_mem_copy( (v_U8_t*)(memStruct + 1) + size, &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL));
394
395 spin_lock(&vosMemList.lock);
396 vosStatus = hdd_list_insert_front(&vosMemList, &memStruct->pNode);
397 spin_unlock(&vosMemList.lock);
398 if(VOS_STATUS_SUCCESS != vosStatus)
399 {
400 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
401 "%s: Unable to insert node into List vosStatus %d\n", __FUNCTION__, vosStatus);
402 }
403
404 memPtr = (v_VOID_t*)(memStruct + 1);
405 }
406
407 return memPtr;
408}
409
410v_VOID_t vos_mem_dma_free( v_VOID_t *ptr )
411{
412 if (ptr != NULL)
413 {
414 VOS_STATUS vosStatus;
415 struct s_vos_mem_struct* memStruct = ((struct s_vos_mem_struct*)ptr) - 1;
416
417 spin_lock(&vosMemList.lock);
418 vosStatus = hdd_list_remove_node(&vosMemList, &memStruct->pNode);
419 spin_unlock(&vosMemList.lock);
420
421 if(VOS_STATUS_SUCCESS == vosStatus)
422 {
423 if(0 == vos_mem_compare(memStruct->header, &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER)) )
424 {
425 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
426 "Memory Header is corrupted. MemInfo: Filename %s, LineNum %d",
427 memStruct->fileName, (int)memStruct->lineNum);
428 }
429 if(0 == vos_mem_compare( (v_U8_t*)ptr + memStruct->size, &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL ) ) )
430 {
431 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
432 "Memory Trailer is corrupted. MemInfo: Filename %s, LineNum %d",
433 memStruct->fileName, (int)memStruct->lineNum);
434 }
435 kfree((v_VOID_t*)memStruct);
436 }
437 }
438}
439#else
440v_VOID_t* vos_mem_dma_malloc( v_SIZE_t size )
441{
442 if (in_interrupt())
443 {
444 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __FUNCTION__);
445 return NULL;
446 }
447 return kmalloc(size, GFP_KERNEL);
448}
449
450/*----------------------------------------------------------------------------
451
452 \brief vos_mem_dma_free() - vOSS DMA Free Memory
453
454 This function will free special DMA friendly memory pointed to by 'ptr'.
455
456 On WM, there is nothing special about the memory being free'd. SDHC will
457 take care of free'ing the DMA friendly buffer
458
459 \param ptr - pointer to the starting address of the memory to be
460 free'd.
461
462 \return Nothing
463
464 \sa
465
466 --------------------------------------------------------------------------*/
467v_VOID_t vos_mem_dma_free( v_VOID_t *ptr )
468{
469 if (ptr == NULL)
470 return;
471 kfree(ptr);
472}
473#endif