1/*
2 * osmemapi.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *  * Neither the name Texas Instruments nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35/*
36 * src/osmemapi.c
37 *
38 */
39
40#include "arch_ti.h"
41
42#include <linux/stddef.h>
43#include <linux/string.h>
44#include <linux/time.h>
45#include <linux/timer.h>
46
47#include <linux/module.h>
48#include <linux/kernel.h>
49#include <linux/netdevice.h>
50#include <linux/etherdevice.h>
51#include <linux/vmalloc.h>
52#include <linux/string.h>
53#include <linux/delay.h>
54#include <linux/time.h>
55#include <linux/list.h>
56
57#include "osApi.h"
58#include "tidef.h"
59#include "WlanDrvIf.h"
60
61typedef void (*os_free)(void *);
62struct os_mem_block
63{
64	struct list_head blk_list;
65	os_free f_free;
66	__u32 size;
67	__u32 signature;
68};
69#define MEM_BLOCK_START  (('m'<<24) | ('e'<<16) | ('m'<<8) | 's')
70#define MEM_BLOCK_END    (('m'<<24) | ('e'<<16) | ('m'<<8) | 'e')
71
72/****************************************************************************************
73 *                        																*
74 *						OS Memory API													*
75 *																						*
76 ****************************************************************************************/
77
78/****************************************************************************************
79 *                        os_memoryAlloc()
80 ****************************************************************************************
81DESCRIPTION:    Allocates resident (nonpaged) system-space memory.
82
83ARGUMENTS:		OsContext	- our adapter context.
84				Size		- Specifies the size, in bytes, to be allocated.
85
86RETURN:			Pointer to the allocated memory.
87				NULL if there is insufficient memory available.
88
89NOTES:         	With the call to vmalloc it is assumed that this function will
90				never be called in an interrupt context. vmalloc has the potential to
91				sleep the caller while waiting for memory to become available.
92
93*****************************************************************************************/
94void*
95os_memoryAlloc(
96        TI_HANDLE OsContext,
97        TI_UINT32 Size
98        )
99{
100	struct os_mem_block *blk;
101	__u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);
102	gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
103
104#ifdef TI_MEM_ALLOC_TRACE
105	os_printf("MTT:%s:%d ::os_memoryAlloc(0x%p, %lu) : %lu\n",__FUNCTION__, __LINE__,OsContext,Size,total_size);
106#endif
107	/*
108	Memory optimization issue. Allocate up to 2 pages (8k) from the SLAB
109	    allocator (2^n), otherwise allocate from virtual pool.
110	If full Async mode is used, allow up to 6 pages (24k) for DMA-able
111	  memory, so the TxCtrlBlk table can be transacted over DMA.
112	*/
113#ifdef FULL_ASYNC_MODE
114	if (total_size < 6 * 4096)
115#else
116	if (total_size < 2 * 4096)
117#endif
118	{
119		blk = kmalloc(total_size, flags);
120		if (!blk)
121		{
122			printk("%s: NULL\n",__func__);
123			return NULL;
124		}
125		blk->f_free = (os_free)kfree;
126	}
127	else
128	{
129		/* We expect that the big allocations should be made outside
130		     the interrupt, otherwise fail
131		*/
132		if (in_interrupt()) {
133			printk("%s: NULL\n",__func__);
134			return NULL;
135		}
136	        blk = vmalloc(total_size);
137	        if (!blk) {
138			printk("%s: NULL\n",__func__);
139			return NULL;
140		}
141		blk->f_free = (os_free)vfree;
142	}
143
144	os_profile (OsContext, 4, total_size);
145
146	/*list_add(&blk->blk_list, &drv->mem_blocks);*/
147	blk->size = Size;
148	blk->signature = MEM_BLOCK_START;
149	*(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
150	return (void *)((char *)blk + sizeof(struct os_mem_block));
151}
152
153
154/****************************************************************************************
155 *                        os_memoryCAlloc()
156 ****************************************************************************************
157DESCRIPTION:    Allocates an array in memory with elements initialized to 0.
158
159ARGUMENTS:		OsContext	-	our adapter context.
160				Number		-	Number of elements
161				Size		-	Length in bytes of each element
162
163RETURN:			None
164
165NOTES:
166*****************************************************************************************/
167void*
168os_memoryCAlloc(
169        TI_HANDLE OsContext,
170        TI_UINT32 Number,
171        TI_UINT32 Size
172        )
173{
174	void* pAllocatedMem;
175	TI_UINT32 MemSize;
176
177#ifdef TI_MEM_ALLOC_TRACE
178	os_printf("MTT:%s:%d ::os_memoryCAlloc(0x%p, %lu, %lu) : %lu\n",__FUNCTION__,__LINE__,OsContext,Number,Size,Number*Size);
179#endif
180	MemSize = Number * Size;
181
182	pAllocatedMem = os_memoryAlloc(OsContext, MemSize);
183
184	if (!pAllocatedMem)
185		return NULL;
186
187	memset(pAllocatedMem,0,MemSize);
188
189	return pAllocatedMem;
190}
191
192
193
194/****************************************************************************************
195 *                        os_memoryFree()
196 ****************************************************************************************
197DESCRIPTION:    This function releases a block of memory previously allocated with the
198				os_memoryAlloc function.
199
200
201ARGUMENTS:		OsContext	-	our adapter context.
202				pMemPtr		-	Pointer to the base virtual address of the allocated memory.
203								This address was returned by the os_memoryAlloc function.
204				Size		-	Specifies the size, in bytes, of the memory block to be released.
205								This parameter must be identical to the Length that was passed to
206								os_memoryAlloc.
207
208RETURN:			None
209
210NOTES:
211*****************************************************************************************/
212void
213os_memoryFree(
214        TI_HANDLE OsContext,
215        void* pMemPtr,
216        TI_UINT32 Size
217        )
218{
219	struct os_mem_block *blk;
220
221	if (!pMemPtr) {
222		printk("%s: NULL\n",__func__);
223		return;
224	}
225	blk = (struct os_mem_block *)((char *)pMemPtr - sizeof(struct os_mem_block));
226
227#ifdef TI_MEM_ALLOC_TRACE
228	os_printf("MTT:%s:%d ::os_memoryFree(0x%p, 0x%p, %lu) : %d\n",__FUNCTION__,__LINE__,OsContext,pMemPtr,Size,-Size);
229#endif
230	if (blk->signature != MEM_BLOCK_START)
231	{
232		printk("\n\n%s: memory block signature is incorrect - 0x%x\n\n\n",
233			__FUNCTION__, blk->signature);
234		return;
235	}
236	*(char *)(&blk->signature) = '~';
237	if (*(__u32 *)((unsigned char *)blk + blk->size + sizeof(struct os_mem_block))
238		!= MEM_BLOCK_END)
239	{
240		printk("\n\n%s: memory block corruption. Size=%u\n\n\n",
241			__FUNCTION__, blk->size);
242	}
243
244	os_profile (OsContext, 5, blk->size + sizeof(struct os_mem_block) + sizeof(__u32));
245	blk->f_free(blk);
246}
247
248
249/****************************************************************************************
250 *                        os_memorySet()
251 ****************************************************************************************
252DESCRIPTION:    This function fills a block of memory with given value.
253
254ARGUMENTS:		OsContext	- our adapter context.
255				pMemPtr		- Specifies the base address of a block of memory
256				Value		- Specifies the value to set
257				Length		- Specifies the size, in bytes, to copy.
258
259RETURN:			None
260
261NOTES:
262*****************************************************************************************/
263void
264os_memorySet(
265    TI_HANDLE OsContext,
266    void* pMemPtr,
267    TI_INT32 Value,
268    TI_UINT32 Length
269    )
270{
271	if (!pMemPtr) {
272		printk("%s: NULL\n",__func__);
273		return;
274	}
275	memset(pMemPtr,Value,Length);
276}
277
278/****************************************************************************************
279 *                        _os_memoryAlloc4HwDma()
280 ****************************************************************************************
281DESCRIPTION:    Allocates resident (nonpaged) system-space memory for DMA operations.
282
283ARGUMENTS:		OsContext	- our adapter context.
284				Size		- Specifies the size, in bytes, to be allocated.
285
286RETURN:			Pointer to the allocated memory.
287				NULL if there is insufficient memory available.
288
289NOTES:
290
291*****************************************************************************************/
292void*
293os_memoryAlloc4HwDma(
294    TI_HANDLE pOsContext,
295    TI_UINT32 Size
296    )
297{
298	struct os_mem_block *blk;
299	__u32 total_size = Size + sizeof(struct os_mem_block) + sizeof(__u32);
300	gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
301
302	/*
303	if the size is greater than 2 pages then we cant allocate the memory
304	    through kmalloc so the function fails
305	*/
306	if (Size < 2 * OS_PAGE_SIZE)
307	{
308		blk = kmalloc(total_size, flags | GFP_DMA);
309		if (!blk) {
310			printk("%s: NULL\n",__func__);
311			return NULL;
312		}
313		blk->f_free = (os_free)kfree;
314	}
315	else
316	{
317		printk("\n\n%s: memory cant be allocated-Size = %d\n\n\n",
318			__FUNCTION__, Size);
319		return NULL;
320	}
321	blk->size = Size;
322	blk->signature = MEM_BLOCK_START;
323	*(__u32 *)((unsigned char *)blk + total_size - sizeof(__u32)) = MEM_BLOCK_END;
324
325	return (void *)((char *)blk + sizeof(struct os_mem_block));
326}
327
328/****************************************************************************************
329 *                        _os_memory4HwDmaFree()
330 ****************************************************************************************
331DESCRIPTION:    This function releases a block of memory previously allocated with the
332				_os_memoryAlloc4HwDma function.
333
334
335ARGUMENTS:		OsContext	-	our adapter context.
336				pMemPtr		-	Pointer to the base virtual address of the allocated memory.
337								This address was returned by the os_memoryAlloc function.
338				Size		-	Specifies the size, in bytes, of the memory block to be released.
339								This parameter must be identical to the Length that was passed to
340								os_memoryAlloc.
341
342RETURN:			None
343
344NOTES:
345*****************************************************************************************/
346void
347os_memory4HwDmaFree(
348    TI_HANDLE pOsContext,
349    void* pMem_ptr,
350    TI_UINT32 Size
351    )
352{
353	struct os_mem_block *blk;
354
355	if (!pMem_ptr) {
356		printk("%s: NULL\n",__func__);
357		return;
358	}
359	blk = (struct os_mem_block *)((char *)pMem_ptr - sizeof(struct os_mem_block));
360
361	if (blk->signature != MEM_BLOCK_START)
362	{
363		printk("\n\n%s: memory block signature is incorrect - 0x%x\n\n\n",
364			__FUNCTION__, blk->signature);
365		return;
366	}
367	*(char *)(&blk->signature) = '~';
368	if (*(__u32 *)((unsigned char *)blk + blk->size + sizeof(struct os_mem_block))
369		!= MEM_BLOCK_END)
370	{
371		printk("\n\n%s: memory block corruption. Size=%u\n\n\n",
372			__FUNCTION__, blk->size);
373	}
374
375	blk->f_free(blk);
376}
377
378/****************************************************************************************
379 *                        os_memoryZero()
380 ****************************************************************************************
381DESCRIPTION:    This function fills a block of memory with 0s.
382
383ARGUMENTS:		OsContext	- our adapter context.
384				pMemPtr		- Specifies the base address of a block of memory
385				Length		- Specifies how many bytes to fill with 0s.
386
387RETURN:			None
388
389NOTES:
390*****************************************************************************************/
391void
392os_memoryZero(
393    TI_HANDLE OsContext,
394    void* pMemPtr,
395    TI_UINT32 Length
396    )
397{
398	if (!pMemPtr) {
399		printk("%s: NULL\n",__func__);
400		return;
401	}
402	memset(pMemPtr,0,Length);
403}
404
405
406/****************************************************************************************
407 *                        os_memoryCopy()
408 ****************************************************************************************
409DESCRIPTION:    This function copies a specified number of bytes from one caller-supplied
410				location to another.
411
412ARGUMENTS:		OsContext	- our adapter context.
413				pDstPtr		- Destination buffer
414				pSrcPtr		- Source buffer
415				Size		- Specifies the size, in bytes, to copy.
416
417RETURN:			None
418
419NOTES:
420*****************************************************************************************/
421void
422os_memoryCopy(
423    TI_HANDLE OsContext,
424    void* pDstPtr,
425    void* pSrcPtr,
426    TI_UINT32 Size
427    )
428{
429
430	memcpy(pDstPtr,pSrcPtr,Size);
431}
432
433/****************************************************************************************
434 *                        os_memoryCompare()
435 ****************************************************************************************
436DESCRIPTION:    Compare characters in two buffers.
437
438ARGUMENTS:		OsContext	- our adapter context.
439				Buf1		- First buffer
440				Buf2		- Second buffer
441				Count		- Number of characters
442
443RETURN:			The return value indicates the relationship between the buffers:
444                < 0 Buf1 less than Buf2
445                0 Buf1 identical to Buf2
446                > 0 Buf1 greater than Buf2
447
448NOTES:
449*****************************************************************************************/
450TI_INT32
451os_memoryCompare(
452        TI_HANDLE OsContext,
453        TI_UINT8* Buf1,
454        TI_UINT8* Buf2,
455        TI_INT32 Count
456        )
457{
458	return memcmp(Buf1, Buf2, Count);
459}
460
461
462
463
464/****************************************************************************************
465 *                        os_memoryCopyFromUser()
466 ****************************************************************************************
467DESCRIPTION:    This function copies a specified number of bytes from one caller-supplied
468				location to another. source buffer is in USER-MODE address space
469
470ARGUMENTS:		OsContext	- our adapter context.
471				pDstPtr		- Destination buffer
472				pSrcPtr		- Source buffer
473				Size		- Specifies the size, in bytes, to copy.
474
475RETURN:			None
476
477NOTES:
478*****************************************************************************************/
479int
480os_memoryCopyFromUser(
481    TI_HANDLE OsContext,
482    void* pDstPtr,
483    void* pSrcPtr,
484    TI_UINT32 Size
485    )
486{
487	return copy_from_user(pDstPtr,pSrcPtr,Size);
488}
489
490/****************************************************************************************
491 *                        os_memoryCopyToUser()
492 ****************************************************************************************
493DESCRIPTION:    This function copies a specified number of bytes from one caller-supplied
494				location to another. desination buffer is in USER-MODE address space
495
496ARGUMENTS:		OsContext	- our adapter context.
497				pDstPtr		- Destination buffer
498				pSrcPtr		- Source buffer
499				Size		- Specifies the size, in bytes, to copy.
500
501RETURN:			None
502
503NOTES:
504*****************************************************************************************/
505int
506os_memoryCopyToUser(
507    TI_HANDLE OsContext,
508    void* pDstPtr,
509    void* pSrcPtr,
510    TI_UINT32 Size
511    )
512{
513	return copy_to_user(pDstPtr,pSrcPtr,Size);
514}
515