96003e0e9ac04f12165ed9b868888e9fd3cda6bd
1 /******************************************************************************
2 * FILE PURPOSE: Main Routines for HPLIB Virtual Memory Allocator
3 ******************************************************************************
4 * FILE NAME: hplib_vm.c
5 *
6 * DESCRIPTION: The virtual memory APIs provide the following functionality:
7 * Maps peripheral registers into user space for LLDs.
8 * QMSS
9 * CPPI
10 * SRIO
11 .* PASS
12 * Timer64 (Appleton)
13 * Memory allocation routines.
14 * Routines to perform address translations (physical to virtual, virtual to physical)
16 *
17 * REVISION HISTORY:
18 *
19 * Copyright (c) Texas Instruments Incorporated 2010-2012
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 *
25 * Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 *
28 * Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the
31 * distribution.
32 *
33 * Neither the name of Texas Instruments Incorporated nor the names of
34 * its contributors may be used to endorse or promote products derived
35 * from this software without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 *
49 */
51 #include <stdint.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #include <sys/mman.h>
58 #include <errno.h>
59 #include <unistd.h>
60 #include <sys/ioctl.h>
61 #include "hplibmod.h"
62 #include "hplib.h"
63 #include "ti/csl/cslr_device.h"
65 extern void* Osal_hplibCsEnter(void);
66 extern void Osal_hplibCsExit (void *CsHandle);
68 /***********************RAW MEMORY ALLOCATION & TRANSLATION*************************/
69 /* Macro to align x to y */
70 #define align(x,y) ((x + y) & (~(y-1)))
72 #define HPLIB_VM_BM_ALLOC_PAGE_SIZE 256
74 hplib_virtualMemPoolAddr_T memPoolAddr[HPLIB_MAX_MEM_POOLS];
75 uint8_t *hplib_VM_mem_start_phy = (uint8_t*)0;
76 uint8_t *hplib_VM_mem_start = (uint8_t*)0;
77 uint8_t *hplib_VM_mem_end = (uint8_t*)0;
78 uint8_t *hplib_VM_mem_end_phy = (uint8_t*)0;
79 static uint8_t *hplib_VM_mem_alloc_ptr = (uint8_t*)0;
80 static uint32_t hplib_VM_mem_size = 0;
81 uint32_t hplib_VM_virt_to_phy_mapping;
82 uint32_t hplib_VM_phy_to_virt_mapping;
84 /* File descriptor for /dev/mem */
85 static int dev_mem_fd;
87 /**************************************************************************
88 * FUNCTION PURPOSE: Maps the give physical address to virtual memory space
89 **************************************************************************/
90 void *hplib_VM_MemMap
91 (
92 void *addr, /* Physical address */
93 uint32_t size /* Size of block */
94 )
95 {
96 void *map_base,*virt_addr;
97 uint32_t page_sz;
98 long retval;
100 retval = sysconf(_SC_PAGE_SIZE);
101 if (retval == -1)
102 {
103 hplib_Log("hplib_VM_MemMap: Failed to get page size err=%s\n",
104 strerror(errno));
105 return (void *)0;
106 }
108 page_sz = (uint32_t)retval;
110 if (size%page_sz)
111 {
112 hplib_Log("hplib_VM_MemMap: error: block size not aligned to page size\n");
113 return (void *)0;
114 }
116 if ((uint32_t)addr%page_sz)
117 {
118 hplib_Log("hplib_VM_MemMap: error: addr not aligned to page size\n");
119 return (void *)0;
120 }
122 map_base = mmap(0, size, (PROT_READ|PROT_WRITE), MAP_SHARED, dev_mem_fd, (off_t)addr);
123 if(map_base == (void *) -1)
124 {
125 hplib_Log("hplib_VM_MemMap: Failed to mmap \"dev/mem\" err=%s\n",
126 strerror(errno));
127 return (void *)0;
128 }
129 virt_addr = map_base;
131 return(virt_addr);
132 }
134 unsigned long peek(unsigned long * p)
135 {
136 return *p;
137 }
139 /**************************************************************************
140 * FUNCTION PURPOSE: Initialize the allocated memory pool area
141 **************************************************************************/
142 HPLIB_BOOL_T hplib_VM_MemAllocInit
143 (
144 uint8_t *addr, /* Physical address */
145 uint32_t size, /* Size of block */
146 uint8_t i /* pool id */
147 )
148 {
149 void *map_base = NULL;
150 uint32_t mapSize = 0;
151 uint32_t virtPoolHdrSize = sizeof(hplib_VirtMemPoolheader_T);
153 /* Set up memory mapping for un-cached memory, this requires physical address and size of memory region to map*/
154 if ((addr != NULL ) && size)
155 {
156 map_base = hplib_VM_MemMap((void *)addr, size);
157 if (!map_base)
158 {
159 hplib_Log("hplib_VM_MemAllocInit(): Failed to memory map for uncached memory, addr (0x%x)",
160 (uint32_t)addr);
161 return HPLIB_FALSE;
162 }
164 memPoolAddr[i].memPoolHdr = (hplib_VirtMemPoolheader_T*)map_base;
165 memPoolAddr[i].memStart = (uint8_t*)map_base + virtPoolHdrSize;
167 memPoolAddr[i].memSize = size;
168 memPoolAddr[i].memEnd = (uint8_t*)map_base + size;
169 memPoolAddr[i].memStartPhy = addr + virtPoolHdrSize;
170 memPoolAddr[i].memEndPhy = addr + size;
171 mapSize = memPoolAddr[i].memSize / (HPLIB_VM_BM_ALLOC_PAGE_SIZE*32);
173 memPoolAddr[i].memAllocPtr = memPoolAddr[i].memStart +
174 mapSize +
175 virtPoolHdrSize;
176 memPoolAddr[i].memAllocPtr =
177 (uint8_t*)align((uint32_t)memPoolAddr[i].memAllocPtr,
178 HPLIB_VM_BM_ALLOC_PAGE_SIZE);
179 memPoolAddr[i].virtMapInfo =
180 (uint8_t*)bmAllocInit(memPoolAddr[i].memAllocPtr,
181 memPoolAddr[i].memSize - mapSize - virtPoolHdrSize,
182 (uint32_t*)&memPoolAddr[i].memPoolHdr->bmap,
183 HPLIB_VM_BM_ALLOC_PAGE_SIZE);
184 }
185 else if (addr == NULL)
186 {
187 addr= ( uint8_t *) hplib_utilGetPhysOfBufferArea();
188 size = hplib_utilGetSizeOfBufferArea();
189 map_base = (void *) hplib_utilGetVaOfBufferArea(HPLIBMOD_MMAP_DMA_MEM_OFFSET,
190 size); //mmap into our space, return va
191 memPoolAddr[i].memPoolHdr = (hplib_VirtMemPoolheader_T*)map_base;
192 memPoolAddr[i].memStart = (uint8_t*)map_base;
193 memPoolAddr[i].memSize =size;
194 memPoolAddr[i].memEnd = (uint8_t*)map_base + size;
195 memPoolAddr[i].memStartPhy = addr;
196 memPoolAddr[i].memEndPhy = addr + size;
197 mapSize = memPoolAddr[i].memSize / (HPLIB_VM_BM_ALLOC_PAGE_SIZE*32);
199 memPoolAddr[i].memAllocPtr = memPoolAddr[i].memStart +
200 mapSize +
201 virtPoolHdrSize;
203 memPoolAddr[i].memAllocPtr =
204 (uint8_t*)align((uint32_t)memPoolAddr[i].memAllocPtr,
205 HPLIB_VM_BM_ALLOC_PAGE_SIZE);
207 memPoolAddr[i].virtMapInfo=
208 (uint8_t*)bmAllocInit(memPoolAddr[i].memAllocPtr,
209 memPoolAddr[i].memSize - mapSize - virtPoolHdrSize,
210 (uint32_t*)&memPoolAddr[i].memPoolHdr->bmap,
211 HPLIB_VM_BM_ALLOC_PAGE_SIZE);
212 }
213 else
214 {
215 return HPLIB_FALSE;
216 }
217 if (i== 0)
218 {
219 hplib_VM_mem_size = size;
220 hplib_VM_mem_alloc_ptr = hplib_VM_mem_start = map_base +
221 mapSize +
222 virtPoolHdrSize;
223 hplib_VM_mem_end = map_base + hplib_VM_mem_size;
224 hplib_VM_mem_start_phy = addr + mapSize + virtPoolHdrSize;
225 hplib_VM_mem_end_phy = addr + hplib_VM_mem_size;
226 hplib_VM_virt_to_phy_mapping = (uint32_t) hplib_VM_mem_start_phy - (uint32_t)hplib_VM_mem_start;
227 hplib_VM_phy_to_virt_mapping = (uint32_t)hplib_VM_mem_start - (uint32_t)hplib_VM_mem_start_phy;
228 }
229 return HPLIB_TRUE;
230 }
234 /**************************************************************************
235 * FUNCTION PURPOSE: Returns the free amount of buffer/descriptor area
236 * for the memory pool specified.
237 **************************************************************************/
239 uint32_t hplib_vmGetMemPoolRemainder(int pool_id)
240 {
241 hplib_VirtMemPoolheader_T *poolHdr;
242 uint32_t remainder;
243 void* key;
244 uint32_t virtPoolHdrSize;
245 uint32_t mapSize;
247 if (pool_id > (HPLIB_MAX_MEM_POOLS -1))
248 return 0;
249 Osal_hplibCsEnter();
251 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
253 mapSize = memPoolAddr[pool_id].memSize / (HPLIB_VM_BM_ALLOC_PAGE_SIZE*32);
254 virtPoolHdrSize = sizeof(hplib_VirtMemPoolheader_T);
255 Osal_hplibCsExit(key);
257 return (memPoolAddr[pool_id].memEnd -
258 memPoolAddr[pool_id].memStart -
259 mapSize -
260 virtPoolHdrSize -
261 poolHdr->totalAllocated);
263 }
265 /*****************************************************************************
266 * FUNCTION PURPOSE: Free memory for Buffer/Descriptors from memory pool
267 * specified
268 *****************************************************************************/
269 void hplib_vmMemFree
270 (
271 void *ptr,
272 uint32_t size,
273 int pool_id
274 )
275 {
276 void* key = NULL;
277 hplib_VirtMemPoolheader_T *poolHdr;
279 if ((pool_id > (HPLIB_MAX_MEM_POOLS -1)) || (ptr == NULL))
280 return;
281 Osal_hplibCsEnter();
283 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
285 bmFree(memPoolAddr[pool_id].virtMapInfo,(unsigned char*)ptr, size);
286 poolHdr->totalAllocated -=size;
288 Osal_hplibCsExit(key);
289 return;
290 }
291 /*****************************************************************************
292 * FUNCTION PURPOSE: Allocates memory for Buffer/Descriptors from memory pool specified
293 *****************************************************************************/
294 void* hplib_vmMemAlloc
295 (
296 uint32_t size,
297 uint32_t alignment,
298 int pool_id
299 )
300 {
302 void* key = NULL;
303 hplib_VirtMemPoolheader_T *poolHdr;
304 void *pMalloc = NULL;
306 if (pool_id > (HPLIB_MAX_MEM_POOLS -1))
307 {
308 return NULL;
309 }
311 Osal_hplibCsEnter();
312 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
314 pMalloc = bmAlloc(memPoolAddr[pool_id].virtMapInfo,size);
315 if (pMalloc)
316 poolHdr->totalAllocated += size;
318 Osal_hplibCsExit(key);
319 return pMalloc;
320 }
323 /********************************************************************
324 *FUNCTION PURPOSE: The function API is used to release/unmap continuous
325 * block of memory allocated via hplib_VM_MemorySetup function,
326 * remove mapping of virtual memory for peripherals.
327 ********************************************************************/
328 void hplib_vmTeardown(void)
329 {
330 hplib_utilModClose();
331 close(dev_mem_fd);
332 }
334 hplib_RetValue hplib_checkMallocArea(int pool_id)
335 {
336 hplib_VirtMemPoolheader_T *poolHdr;
337 if (pool_id > (HPLIB_MAX_MEM_POOLS-1))
338 {
339 return hplib_FAILURE;
340 }
341 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
342 if(poolHdr->ref_count)
343 return hplib_OK;
344 else
345 return hplib_FAILURE;
346 }
348 hplib_RetValue hplib_resetMallocArea(int pool_id)
349 {
350 hplib_VirtMemPoolheader_T *poolHdr;
351 if (pool_id > (HPLIB_MAX_MEM_POOLS-1))
352 {
353 return hplib_FAILURE;
354 }
355 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
357 bmAllocClose(memPoolAddr[pool_id].virtMapInfo);
359 memset(poolHdr,
360 0,
361 memPoolAddr[pool_id].memAllocPtr - memPoolAddr[pool_id].memStart);
363 return hplib_OK;
364 }
366 hplib_RetValue hplib_initMallocArea(int pool_id)
367 {
368 hplib_VirtMemPoolheader_T *poolHdr;
370 if (pool_id > (HPLIB_MAX_MEM_POOLS -1))
371 {
372 return hplib_FAILURE;
373 }
375 poolHdr = (hplib_VirtMemPoolheader_T*) memPoolAddr[pool_id].memStart;
377 poolHdr->ref_count++;
378 poolHdr->totalAllocated = 0;
380 return hplib_OK;
382 }
383 /********************************************************************
384 * FUNCTION PURPOSE: Allocate continuous block of cached memory via CMA and
385 * optionally un-cached memory if specified, maps virtual memory for peripheral registers.
386 ********************************************************************/
387 hplib_RetValue hplib_vmInit(hplib_virtualAddrInfo_T *hplib_vmaddr,
388 int num_pools,
389 hplib_memPoolAttr_T *mempool_attr)
390 {
391 int i;
393 if (num_pools == 0)
394 {
395 hplib_Log("hplib_vmInit(): Error, invalid number of pools\n");
396 return -1;
397 }
400 /*Open dev/mem, since we need for QM, CPPI, etc */
401 if((dev_mem_fd = open("/dev/mem", (O_RDWR | O_SYNC))) == -1)
402 {
403 hplib_Log("hplib_vmInit: Failed to open \"dev/mem\" err=%s\n",
404 strerror(errno));
405 return HPLIB_FALSE;
406 }
408 /* Open kernel module since we need it for PA to VA mappings */
409 if (hplib_utilModOpen() == -1)
410 {
411 hplib_Log("hplib_vmInit:: failed to open /dev/netapi: '%s'\n", strerror(errno));
412 return HPLIB_FALSE;
413 }
414 for (i=0;i < num_pools; i++)
415 {
416 /* Initialize memory which was allocated from DDR via hplibmod CMA*/
417 if (mempool_attr[i].attr == HPLIB_ATTR_KM_CACHED0) {
418 if (hplib_VM_MemAllocInit( NULL, 0, i) == HPLIB_FALSE)
419 {
420 hplib_Log("hplib_vmInit: hplib_VM_MemAllocInit from DDR/CMA failed\n");
421 return hplib_ERR_NOMEM;
422 }
423 }
424 /* Intialize memory for un-cached memory, make sure size and phys_addr passed in and have valid values */
425 if ((mempool_attr[i].attr == HPLIB_ATTR_UN_CACHED) && mempool_attr[i].size && mempool_attr[i].phys_addr)
426 {
427 if (hplib_VM_MemAllocInit((uint8_t*)mempool_attr[i].phys_addr,
428 mempool_attr[i].size, i) == HPLIB_FALSE)
429 {
430 hplib_Log(" hplib_vmInit: hplib_VM_MemAllocInit from un-cached memory failed\n");
431 return hplib_ERR_NOMEM;
432 }
433 }
434 }
436 /* Create virtual memory maps for peripherals */
437 /* QMSS CFG Regs */
438 hplib_vmaddr->qmssCfgVaddr =
439 hplib_VM_MemMap((void*)CSL_QMSS_CFG_BASE, QMSS_CFG_BLK_SZ);
440 if (!hplib_vmaddr->qmssCfgVaddr)
441 {
442 hplib_Log("hplib_vmInit: Failed to map QMSS CFG registers\n");
443 return hplib_FAILURE;
444 }
446 /*QMSS DATA Regs */
447 hplib_vmaddr->qmssDataVaddr =
448 (void *) hplib_utilGetVaOfBufferArea(HPLIBMOD_MMAP_QM_DATA_REG_MEM_OFFSET,
449 QMSS_DATA_BLK_SZ);
451 if (!hplib_vmaddr->qmssDataVaddr)
452 {
453 hplib_Log("hplib_vmInit(): Failed to map QMSS DATA registers\n");
454 return hplib_FAILURE;
455 }
458 /* PASS CFG Regs */
459 hplib_vmaddr->passCfgVaddr =
460 hplib_VM_MemMap((void*)CSL_NETCP_CFG_REGS,
461 //p_device_cfg->netcpCfgBlkSz
462 PASS_CFG_BLK_SZ);
464 if (!hplib_vmaddr->passCfgVaddr)
465 {
466 hplib_Log("hplib_vmInit(): Failed to map PASS CFG registers\n");
467 return hplib_FAILURE;
468 }
470 #ifdef CORTEX_A8
471 /* (2f) Timer */
472 t64_memmap(dev_mem_fd);
473 #endif
475 return hplib_OK;
477 }