static IMG_RESULT AllocPages( SYSMEM_Heap * heap, IMG_UINT32 ui32Size, SYSMEMU_sPages * psPages, SYS_eMemAttrib eMemAttrib ) { IMG_UINT32 ui32NoPages; IMG_UINT32 ui32ExamPages; IMG_UINT32 i; IMG_UINT64 ui64DeviceMemoryBase; IMG_PHYSADDR paCpuPhysAddr; IMG_UINT32 ui32Result; size_t physAddrArrSize; struct priv_params * prv = (struct priv_params *)heap->priv; /* If we don't know where the memory is...*/ SYSOSKM_DisableInt(); /* Calculate required no. of pages...*/ ui32NoPages = (ui32Size + (HOST_MMU_PAGE_SIZE-1)) / HOST_MMU_PAGE_SIZE; /* Loop over allocated pages until we find an unallocated slot big enough for this allocation...*/ ui32ExamPages = 0; while (ui32ExamPages < prv->npages) { /* If the current page is not allocated and we might have enough remaining to make this allocation...*/ if ( (!prv->alloc_pool[prv->cur_index]) && ((prv->cur_index + ui32NoPages) <= prv->npages) ) { /* Can we make this allocation...*/ for (i=0; i<ui32NoPages; i++) { if (prv->alloc_pool[prv->cur_index+i]) { break; } } if (i == ui32NoPages) { /* Yes, mark pages as allocated...*/ for (i=0; i<ui32NoPages; i++) { prv->alloc_pool[prv->cur_index+i] = IMG_TRUE; } /* Calculate the memory address of the start of the allocation...*/ //psPages->pvCpuKmAddr = (IMG_VOID *)((IMG_UINTPTR)prv->vstart + (prv->cur_index * HOST_MMU_PAGE_SIZE)); psPages->pvImplData = (IMG_VOID *)(prv->vstart + (prv->cur_index * HOST_MMU_PAGE_SIZE)); /* Update the current page index....*/ prv->cur_index += ui32NoPages; if (prv->cur_index >= prv->npages) { prv->cur_index = 0; } break; } } /* Update examined pages and page index...*/ ui32ExamPages++; prv->cur_index++; if (prv->cur_index >= prv->npages) { prv->cur_index = 0; } } SYSOSKM_EnableInt(); /* Check if allocation failed....*/ IMG_ASSERT(ui32ExamPages < prv->npages); if (ui32ExamPages >= prv->npages) { /* Failed...*/ /* dump some fragmentation information */ int i = 0; int nAllocated = 0; int n64kBlocks = 0; // number of blocks of <16 consecutive pages int n128kBlocks = 0; int n256kBlocks = 0; int nBigBlocks = 0; // number of blocks of >=64 consecutive pages int nMaxBlocks = 0; int nPages = 0; for(i = 0; i < (int)prv->npages; i++) { IMG_UINT8 isallocated = prv->alloc_pool[i]; nPages++; if(i == prv->npages-1 || isallocated != prv->alloc_pool[i+1]) { if(isallocated) nAllocated += nPages; else if(nPages < 16) n64kBlocks++; else if(nPages < 32) n128kBlocks++; else if(nPages < 64) n256kBlocks++; else nBigBlocks++; if(nMaxBlocks < nPages) nMaxBlocks = nPages; isallocated = prv->alloc_pool[i]; nPages = 0; } } #ifdef printk /* hopefully, this will give some idea of the fragmentation of the memory */ printk("AllocPages not able to allocate memory \n"); printk(" number available memory areas under 64k:%d\n", n64kBlocks); printk(" number available memory areas under 128k:%d\n", n128kBlocks); printk(" number available memory areas under 256k:%d\n", n256kBlocks); printk(" number available memory areas over 256k:%d\n", nBigBlocks); printk(" total allocated memory:%dk/%dk\n", nAllocated*4, prv->npages*4); #endif return IMG_ERROR_OUT_OF_MEMORY; } paCpuPhysAddr = CpuKmAddrToCpuPAddr(heap, psPages->pvImplData); IMG_ASSERT(paCpuPhysAddr != 0); if (paCpuPhysAddr == 0) { return IMG_ERROR_GENERIC_FAILURE; } #ifdef CONFIG_ARM /* This flushes the outer cache in ARM, so we avoid memory corruption by late flushes of memory previously marked as cached. */ if ((eMemAttrib & SYS_MEMATTRIB_CACHED) == 0) { mb(); /* the following two calls are somewhat expensive, but are there for defensive reasons */ flush_cache_all(); outer_flush_all(); } #endif { IMG_PHYSADDR * ppaCpuPhysAddrs; size_t numPages, pg_i, offset; // Memory for physical addresses numPages = (ui32Size + HOST_MMU_PAGE_SIZE - 1)/HOST_MMU_PAGE_SIZE; physAddrArrSize = sizeof(*ppaCpuPhysAddrs) * numPages; ppaCpuPhysAddrs = IMG_BIGORSMALL_ALLOC(physAddrArrSize); if (!ppaCpuPhysAddrs) { return IMG_ERROR_OUT_OF_MEMORY; } for (pg_i = 0, offset = 0; pg_i < numPages; offset += HOST_MMU_PAGE_SIZE, ++pg_i) { ppaCpuPhysAddrs[pg_i] = paCpuPhysAddr + offset; } // Set pointer to physical address in structure psPages->ppaPhysAddr = ppaCpuPhysAddrs; } /* Add this to the list of mappable regions...*/ ui32Result = SYSBRGU_CreateMappableRegion(paCpuPhysAddr, ui32Size, eMemAttrib, psPages, &psPages->hRegHandle); IMG_ASSERT(ui32Result == IMG_SUCCESS); if (ui32Result != IMG_SUCCESS) { goto error_mappable_region; } #if defined (CLEAR_PAGES) if (psPages->pvImplData) IMG_MEMSET( psPages->pvImplData, 0, ui32Size); #endif return IMG_SUCCESS; /* Error handling. */ error_mappable_region: IMG_BIGORSMALL_FREE(physAddrArrSize, psPages->ppaPhysAddr); psPages->ppaPhysAddr = IMG_NULL; return ui32Result; }
/*! ****************************************************************************** @Function SYSMEMKM_AllocPages ******************************************************************************/ static IMG_RESULT AllocPages( SYSMEM_Heap * heap, IMG_UINT32 ui32Size, SYSMEMU_sPages * psPages, SYS_eMemAttrib eMemAttrib ) { struct priv_params * prv = (struct priv_params *)heap->priv; IMG_PHYSADDR paCpuPhysAddr, paOffset; IMG_RESULT ui32Result; IMG_PHYSADDR * ppaCpuPhysAddrs; size_t numPages, pg_i; size_t physAddrArrSize; /* Calculate required no. of pages...*/ psPages->pvImplData = (IMG_VOID *)gen_pool_alloc(prv->pool, ui32Size); if(psPages->pvImplData == IMG_NULL) { return IMG_ERROR_OUT_OF_MEMORY; } paCpuPhysAddr = CpuKmAddrToCpuPAddr(heap, psPages->pvImplData); IMG_ASSERT(paCpuPhysAddr != 0); if (paCpuPhysAddr == 0) { ui32Result = IMG_ERROR_GENERIC_FAILURE; goto error_map; } numPages = (ui32Size + HOST_MMU_PAGE_SIZE - 1)/HOST_MMU_PAGE_SIZE; physAddrArrSize = sizeof(*ppaCpuPhysAddrs) * numPages; ppaCpuPhysAddrs = IMG_BIGORSMALL_ALLOC(physAddrArrSize); if (!ppaCpuPhysAddrs) { ui32Result = IMG_ERROR_OUT_OF_MEMORY; goto error_array_alloc; } for (pg_i = 0, paOffset = 0; pg_i < numPages; paOffset += HOST_MMU_PAGE_SIZE, ++pg_i) { ppaCpuPhysAddrs[pg_i] = paCpuPhysAddr + paOffset; } psPages->ppaPhysAddr = ppaCpuPhysAddrs; /* Add this to the list of mappable regions...*/ ui32Result = SYSBRGU_CreateMappableRegion(psPages->ppaPhysAddr[0], ui32Size, eMemAttrib, IMG_FALSE, psPages, &psPages->hRegHandle); IMG_ASSERT(ui32Result == IMG_SUCCESS); if (ui32Result != IMG_SUCCESS) { goto error_region_create; } #if defined (CLEAR_PAGES) IMG_MEMSET( psPages->pvImplData, 0, ui32Size); #endif return IMG_SUCCESS; /* Error handling. */ error_region_create: IMG_BIGORSMALL_FREE(physAddrArrSize, psPages->ppaPhysAddr); error_array_alloc: error_map: gen_pool_free(prv->pool, (unsigned long)psPages->pvImplData, ui32Size); psPages->ppaPhysAddr = IMG_NULL; psPages->hRegHandle = IMG_NULL; return ui32Result; }