/*----------------------------------------------------------- * Name: HASH_FromArray() * Created: Thu Sep 8 23:53:36 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: converts an array to a hash table */ HASH_TABLE *HASH_FromArray(HASH_TABLE *h, DATA_PTR *array, unsigned size) { unsigned index; #ifdef HASH_DEBUG if (!array) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_FromArray()"); } } #endif if (!h) { h = HASH_Create(size, 0); /* create default hash table */ } else { HASH_ClearFn(h, NULL); } for (index = 0; index < size; index++) { HASH_Insert(h, array[index]); } #ifdef HASH_DEBUG if (h->attr & HASH_ReportChange) { printf("HASH TABLE: 0x%.8x FromArray(0x%.8x, %u) complete\n", h, array, h->count); } #endif #ifdef _HASH_INTERNAL_DEBUG HASH_Verify(h); #endif return(h); }
/*! ****************************************************************************** @Function PVRSRVTimeTraceBufferCreate @Description Create a trace buffer. Note: We assume that this will only be called once per process. @Input ui32PID : PID of the process that is creating the buffer @Return none ******************************************************************************/ PVRSRV_ERROR PVRSRVTimeTraceBufferCreate(IMG_UINT32 ui32PID) { sTimeTraceBuffer *psBuffer; PVRSRV_ERROR eError = PVRSRV_OK; eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT, sizeof(sTimeTraceBuffer) + TIME_TRACE_BUFFER_SIZE, (IMG_VOID **)&psBuffer, IMG_NULL, "Time Trace Buffer"); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceBufferCreate: Error allocating trace buffer")); return eError; } OSMemSet(psBuffer, 0, TIME_TRACE_BUFFER_SIZE); if (!HASH_Insert(g_psBufferTable, (IMG_UINTPTR_T) ui32PID, (IMG_UINTPTR_T) psBuffer)) { OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(sTimeTraceBuffer) + TIME_TRACE_BUFFER_SIZE, psBuffer, NULL); PVR_DPF((PVR_DBG_ERROR, "PVRSRVTimeTraceBufferCreate: Error adding trace buffer to hash table")); return PVRSRV_ERROR_OUT_OF_MEMORY; } return eError; }
hashTable_s* HASH_CloneTable (hashTable_s* source) { hashTable_s* t = HASH_NewTable(source->ownsKeys, source->ownsValues, source->duplicateOverwrite, source->hash, source->compare); hashItem_s* item = _iterator_first (source); while (item) { HASH_Insert (t, item->key, item->nkey, item->value, item->nvalue); item = _iterator_next (source, item); } return t; }
/** * @brief Registers a lua callback function with a key. * @param key A key for finding the callback function by name, usually the script name. * @param fnc A lua function registered in the lua registry index. */ void CL_RegisterCallback (const char* key, LUA_FUNCTION fnc) { int regvalue = (int) fnc; /* store regvalue into the list of handlers */ int len = strlen (key); if (len > 0) { HASH_Insert (cl_callback, key, len, ®value, sizeof(regvalue)); } else { Com_Printf("CL_RegisterCallback: lua callback registration error: script name has zero length!\n"); } }
/** * @brief Adds a lua based method to the list of available node methods for calling. * @param[in] node The node to extend. * @param[in] name The name of the new method to add * @param[in] fcn The lua based function reference. * @note If the method name is already defined, the new method is not added and a warning will be issued * in the log. * @note The method will be instance based, meaning that if a new node is created of the same behaviour, * it will not contain this method unless this node was specified as super. */ void UI_AddNodeMethod (uiNode_t* node, const char* name, LUA_METHOD fcn) { //Com_Printf ("UI_AddNodeMethod: registering node method [%s] on node [%s]\n", name, UI_GetPath(node)); /* the first method, so create a method table on this node */ if (!node->nodeMethods) { node->nodeMethods = HASH_NewTable(true, true, false); } /* add the method */ if (!HASH_Insert(node->nodeMethods, name, strlen(name), &fcn, sizeof(fcn))) { Com_Printf("UI_AddNodeMethod: method [%s] already defined on this behaviour [%s]\n", name, node->name); } }
/*----------------------------------------------------------- * Name: HASH_FromLinkedList() * Created: Fri Sep 9 00:04:37 1994 * Author: Jonathan DeKock <dekock@winter> * DESCR: converts a linked list into a hash table */ HASH_TABLE *HASH_FromLinkedList(HASH_TABLE *h, LINKED_LIST *ll) { DATA_PTR data; #ifdef HASH_DEBUG if (!ll) { if (HASH_Handler) { (HASH_Handler)(h, HASH_BadArgument, "HASH_FromLinkedList()"); } } #endif if (!h) { h = HASH_Create(ll->count, 0); /* create default hash table */ } else { HASH_ClearFn(h, NULL); } LL_Iterate(ll, data) { HASH_Insert(h, data); }
static inline enum PVRSRV_ERROR alloc_or_reuse_syncinfo(void *dev_cookie, void *mem_context_handle, struct PVRSRV_KERNEL_SYNC_INFO **syncinfo, struct IMG_SYS_PHYADDR *phys_addr) { enum PVRSRV_ERROR error; struct PVRSRV_DEVICE_NODE *dev; dev = (struct PVRSRV_DEVICE_NODE *) dev_cookie; *syncinfo = (struct PVRSRV_KERNEL_SYNC_INFO *) HASH_Retrieve(dev->sync_table, phys_addr->uiAddr); if (!*syncinfo) { /* Dont' have one so create one */ error = PVRSRVAllocSyncInfoKM(dev_cookie, mem_context_handle, syncinfo); if (error != PVRSRV_OK) return error; /* Setup our extra data */ (*syncinfo)->phys_addr.uiAddr = phys_addr->uiAddr; (*syncinfo)->dev_cookie = dev_cookie; (*syncinfo)->refcount = 1; if (!HASH_Insert(dev->sync_table, phys_addr->uiAddr, (u32) *syncinfo)) { PVR_DPF(PVR_DBG_ERROR, "alloc_or_reuse_syncinfo: " "Failed to add syncobject to hash table"); return PVRSRV_ERROR_GENERIC; } } else get_syncinfo(*syncinfo); return PVRSRV_OK; }
/*! ****************************************************************************** @Function PVRSRVPerProcessDataConnect @Description Allocate per-process data area, or increment refcount if one already exists for this PID. @Input ui32PID - process ID ppsPerProc - Pointer to per-process data area @Return PVRSRV_ERROR ******************************************************************************/ PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { PVRSRV_PER_PROCESS_DATA *psPerProc; IMG_HANDLE hBlockAlloc; PVRSRV_ERROR eError = PVRSRV_OK; if (psHashTab == IMG_NULL) { return PVRSRV_ERROR_INIT_FAILURE; } /* Look for existing per-process data area */ psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { /* Allocate per-process data area */ eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (IMG_PVOID *)&psPerProc, &hBlockAlloc, "Per Process Data"); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate per-process data (%d)", eError)); return eError; } OSMemSet(psPerProc, 0, sizeof(*psPerProc)); psPerProc->hBlockAlloc = hBlockAlloc; if (!HASH_Insert(psHashTab, (IMG_UINTPTR_T)ui32PID, (IMG_UINTPTR_T)psPerProc)) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't insert per-process data into hash table")); eError = PVRSRV_ERROR_INSERT_HASH_TABLE_DATA_FAILED; goto failure; } psPerProc->ui32PID = ui32PID; psPerProc->ui32RefCount = 0; #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if (ui32Flags == SRV_FLAGS_PDUMP_ACTIVE) { psPerProc->bPDumpActive = IMG_TRUE; } #else PVR_UNREFERENCED_PARAMETER(ui32Flags); #endif /* Call environment specific per process init function */ eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: OSPerProcessPrivateDataInit failed (%d)", eError)); goto failure; } /* Allocate a handle for the per-process data area */ eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psPerProc->hPerProcData, psPerProc, PVRSRV_HANDLE_TYPE_PERPROC_DATA, PVRSRV_HANDLE_ALLOC_FLAG_NONE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle for per-process data (%d)", eError)); goto failure; } /* Allocate handle base for this process */ eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle base for process (%d)", eError)); goto failure; } /* Set per-process handle options */ eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't set handle options (%d)", eError)); goto failure; } /* Create a resource manager context for the process */ eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't register with the resource manager")); goto failure; } #if defined (TTRACE) PVRSRVTimeTraceBufferCreate(ui32PID); #endif } psPerProc->ui32RefCount++; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", ui32PID, psPerProc->ui32RefCount)); return eError; failure: (IMG_VOID)FreePerProcessData(psPerProc); return eError; }
/** * @brief Unit test function. */ bool HASH_test () { // return value bool result = true; /* test 1: create the hash table, delete the hash table */ hashTable_s* table = HASH_NewTable(true, true, true); HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 2: create the hash table, insert 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); if (HASH_Count(table) != 3) return false; HASH_Clear (table); if (HASH_Count(table) != 0) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 3: create the hash table, insert/remove 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Remove (table, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Remove (table, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); HASH_Remove (table, "CCC", 4); HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 4: create the hash table, insert/count/search/delete 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); /* check count items */ if (HASH_Count(table) != 3) return false; char* aaa = (char*)HASH_Get(table, "AAA", 4); if (strncmp (aaa, "AAA", 4) != 0) return false; char* bbb = (char*)HASH_Get(table, "BBB", 4); if (strncmp (bbb, "BBB", 4) != 0) return false; char* ccc = (char*)HASH_Get(table, "CCC", 4); if (strncmp (ccc, "CCC", 4) != 0) return false; HASH_Remove (table, "AAA", 4); HASH_Remove (table, "BBB", 4); HASH_Remove (table, "CCC", 4); if (HASH_Count(table) != 0) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 5: hash function test */ const char AZ[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; char buffer[26]; /* compute the averag of the hash index of 400 random keys */ int total = 0; srand(time(NULL)); for(int i=0; i < 4000; i++) { /* create random key of random length between 4..23 charachters */ int len = 4 + (rand() % 20); memset (buffer, 0, sizeof(buffer)); for (int j=0; j < len; j++) { int v = rand() % sizeof(AZ); buffer[j]=AZ[v]; } /* compute the hash index */ int idx = default_hash (buffer, len); /* sum index */ total += idx; } /* now compute the average of the indices */ int avg = (total / 4000); /* the average idx should be somewhere halfway, allow a %10 error margin */ int idx_low = (HASH_TABLE_SIZE/2) - (HASH_TABLE_SIZE/10); int idx_high = (HASH_TABLE_SIZE/2) + (HASH_TABLE_SIZE/10); if ( !((idx_low <= avg) && (idx_high >= avg)) ) return false; /* test 6: hash table without ownership test */ table = HASH_NewTable(true, false, true); char item1[] = "AAA"; char item2[] = "BBB"; char item3[] = "CCC"; HASH_Insert (table, item1, 4, item1, 4); HASH_Insert (table, item2, 4, item2, 4); HASH_Insert (table, item3, 4, item3, 4); /* check if we get the correct value pointers */ aaa = (char*)HASH_Get(table, "AAA", 4); if (aaa != item1) return false; bbb = (char*)HASH_Get(table, "BBB", 4); if (bbb != item2) return false; ccc = (char*)HASH_Get(table, "CCC", 4); if (ccc != item3) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* end of unit test, everything OK */ return true; }
enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID) { struct PVRSRV_PER_PROCESS_DATA *psPerProc; void *hBlockAlloc; enum PVRSRV_ERROR eError = PVRSRV_OK; PVR_ASSERT(psHashTab != NULL); psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (u32)ui32PID); if (psPerProc == NULL) { eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (void **)&psPerProc, &hBlockAlloc); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't allocate per-process data (%d)", eError); return eError; } OSMemSet(psPerProc, 0, sizeof(*psPerProc)); psPerProc->hBlockAlloc = hBlockAlloc; if (!HASH_Insert(psHashTab, (u32) ui32PID, (u32)psPerProc)) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't insert per-process data into hash table"); eError = PVRSRV_ERROR_GENERIC; goto failure; } psPerProc->ui32PID = ui32PID; psPerProc->ui32RefCount = 0; eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "OSPerProcessPrivateDataInit failed (%d)", eError); goto failure; } eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psPerProc->hPerProcData, psPerProc, PVRSRV_HANDLE_TYPE_PERPROC_DATA, PVRSRV_HANDLE_ALLOC_FLAG_NONE); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't allocate handle for per-process data (%d)", eError); goto failure; } eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't allocate handle base for process (%d)", eError); goto failure; } eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't set handle options (%d)", eError); goto failure; } eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: " "Couldn't register with the resource manager"); goto failure; } } psPerProc->ui32RefCount++; PVR_DPF(PVR_DBG_MESSAGE, "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", ui32PID, psPerProc->ui32RefCount); return eError; failure: (void)FreePerProcessData(psPerProc); return eError; }
PVRSRV_ERROR PVRSRVPerProcessDataConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags) { PVRSRV_PER_PROCESS_DATA *psPerProc; IMG_HANDLE hBlockAlloc; PVRSRV_ERROR eError = PVRSRV_OK; PVR_ASSERT(psHashTab != IMG_NULL); psPerProc = (PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab, (IMG_UINTPTR_T)ui32PID); if (psPerProc == IMG_NULL) { eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), (IMG_PVOID *)&psPerProc, &hBlockAlloc, "Per Process Data"); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate per-process data (%d)", eError)); return eError; } OSMemSet(psPerProc, 0, sizeof(*psPerProc)); psPerProc->hBlockAlloc = hBlockAlloc; /* * FIXME: using a hash to retrieve psPerProc makes not much * sense. We always want to have this struct on the IOCTL path * for the current task, so it'd be just a matter of storing * it in the file private object. Until this is resolved and * we get rid of this pid specific lookup make sure the above * assumption holds. */ WARN_ON(OSGetCurrentProcessIDKM() != ui32PID); get_task_comm(psPerProc->name, current); if (!HASH_Insert(psHashTab, (IMG_UINTPTR_T)ui32PID, (IMG_UINTPTR_T)psPerProc)) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't insert per-process data into hash table")); eError = PVRSRV_ERROR_INSERT_HASH_TABLE_DATA_FAILED; goto failure; } psPerProc->ui32PID = ui32PID; psPerProc->ui32RefCount = 0; #if defined(PERPROC_LIST) List_PVRSRV_PER_PROCESS_DATA_Insert(&psPerProcList, psPerProc); /*PVR_LOG(("MarkTupsperproc %d\n", ui32PID));*/ #endif #if defined(SUPPORT_PDUMP_MULTI_PROCESS) if (ui32Flags == SRV_FLAGS_PDUMP_ACTIVE) { psPerProc->bPDumpActive = IMG_TRUE; } #else PVR_UNREFERENCED_PARAMETER(ui32Flags); #endif eError = OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: OSPerProcessPrivateDataInit failed (%d)", eError)); goto failure; } eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE, &psPerProc->hPerProcData, psPerProc, PVRSRV_HANDLE_TYPE_PERPROC_DATA, PVRSRV_HANDLE_ALLOC_FLAG_NONE); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle for per-process data (%d)", eError)); goto failure; } eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't allocate handle base for process (%d)", eError)); goto failure; } eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't set handle options (%d)", eError)); goto failure; } eError = PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext); if (eError != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: Couldn't register with the resource manager")); goto failure; } } psPerProc->ui32RefCount++; PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d", ui32PID, psPerProc->ui32RefCount)); return eError; failure: (IMG_VOID)FreePerProcessData(psPerProc); return eError; }
static int alloc_from_bt(struct RA_ARENA *arena, struct BT *bt, u32 start, size_t size, u32 align, struct BM_MAPPING **new_mapping, u32 *new_base) { _FreeListRemove(arena, bt); PVR_ASSERT(bt->type == btt_free); #ifdef RA_STATS arena->sStatistics.uLiveSegmentCount++; arena->sStatistics.uFreeSegmentCount--; arena->sStatistics.uFreeResourceCount -= bt->uSize; #endif if (start > bt->base) { struct BT *next_bt; next_bt = _SegmentSplit(arena, bt, start - bt->base); if (!next_bt) { PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: " "Front split failed"); _FreeListInsert(arena, bt); return -1; } _FreeListInsert(arena, bt); #ifdef RA_STATS arena->sStatistics.uFreeSegmentCount++; arena->sStatistics.uFreeResourceCount += bt->uSize; #endif bt = next_bt; } if (bt->uSize > size) { struct BT *next_bt; next_bt = _SegmentSplit(arena, bt, size); if (!next_bt) { PVR_DPF(PVR_DBG_ERROR, "_AttemptAllocAligned: " "Back split failed"); _FreeListInsert(arena, bt); return -1; } _FreeListInsert(arena, next_bt); #ifdef RA_STATS arena->sStatistics.uFreeSegmentCount++; arena->sStatistics.uFreeResourceCount += next_bt->uSize; #endif } bt->type = btt_live; if (!HASH_Insert(arena->pSegmentHash, bt->base, (u32)bt)) { _FreeBT(arena, bt, IMG_FALSE); return -1; } if (new_mapping) *new_mapping = bt->psMapping; *new_base = bt->base; return 0; }
IMG_BOOL BM_Wrap ( IMG_HANDLE hDevMemHeap, IMG_SIZE_T ui32Size, IMG_SIZE_T ui32Offset, IMG_BOOL bPhysContig, IMG_SYS_PHYADDR *psSysAddr, IMG_VOID *pvCPUVAddr, IMG_UINT32 *pui32Flags, BM_HANDLE *phBuf) { BM_BUF *pBuf; BM_CONTEXT *psBMContext; BM_HEAP *psBMHeap; SYS_DATA *psSysData; IMG_SYS_PHYADDR sHashAddress; IMG_UINT32 uFlags; psBMHeap = (BM_HEAP*)hDevMemHeap; psBMContext = psBMHeap->pBMContext; uFlags = psBMHeap->ui32Attribs & (PVRSRV_HAP_CACHETYPE_MASK | PVRSRV_HAP_MAPTYPE_MASK); if ((pui32Flags != IMG_NULL) && ((*pui32Flags & PVRSRV_HAP_CACHETYPE_MASK) != 0)) { uFlags &= ~PVRSRV_HAP_CACHETYPE_MASK; uFlags |= *pui32Flags & PVRSRV_HAP_CACHETYPE_MASK; } PVR_DPF ((PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uOffset=0x%x, bPhysContig=0x%x, pvCPUVAddr=0x%x, uFlags=0x%x)", ui32Size, ui32Offset, bPhysContig, (IMG_UINTPTR_T)pvCPUVAddr, uFlags)); SysAcquireData(&psSysData); #if defined(PVR_LMA) if (bPhysContig) { if (!ValidSysPAddrRangeForDev(psBMContext->psDeviceNode, *psSysAddr, WRAP_MAPPING_SIZE(ui32Size, ui32Offset))) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: System address range invalid for device")); return IMG_FALSE; } } else { IMG_SIZE_T ui32HostPageSize = HOST_PAGESIZE(); if (!ValidSysPAddrArrayForDev(psBMContext->psDeviceNode, psSysAddr, WRAP_PAGE_COUNT(ui32Size, ui32Offset, ui32HostPageSize), ui32HostPageSize)) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: Array of system addresses invalid for device")); return IMG_FALSE; } } #endif sHashAddress = psSysAddr[0]; sHashAddress.uiAddr += ui32Offset; pBuf = (BM_BUF *)HASH_Retrieve(psBMContext->pBufferHash, sHashAddress.uiAddr); if(pBuf) { IMG_SIZE_T ui32MappingSize = HOST_PAGEALIGN (ui32Size + ui32Offset); if(pBuf->pMapping->uSize == ui32MappingSize && (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr)) { PVR_DPF((PVR_DBG_MESSAGE, "BM_Wrap (Matched previous Wrap! uSize=0x%x, uOffset=0x%x, SysAddr=%08X)", ui32Size, ui32Offset, sHashAddress.uiAddr)); pBuf->ui32RefCount++; *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) *pui32Flags = uFlags; return IMG_TRUE; } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), (IMG_PVOID *)&pBuf, IMG_NULL, "Buffer Manager buffer") != PVRSRV_OK) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: BM_Buf alloc FAILED")); return IMG_FALSE; } OSMemSet(pBuf, 0, sizeof (BM_BUF)); if (WrapMemory (psBMHeap, ui32Size, ui32Offset, bPhysContig, psSysAddr, pvCPUVAddr, uFlags, pBuf) != IMG_TRUE) { PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: WrapMemory FAILED")); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof (BM_BUF), pBuf, IMG_NULL); return IMG_FALSE; } if(pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { PVR_ASSERT(SysSysPAddrToCpuPAddr(sHashAddress).uiAddr == pBuf->CpuPAddr.uiAddr); if (!HASH_Insert (psBMContext->pBufferHash, sHashAddress.uiAddr, (IMG_UINTPTR_T)pBuf)) { FreeBuf (pBuf, uFlags, IMG_TRUE); PVR_DPF((PVR_DBG_ERROR, "BM_Wrap: HASH_Insert FAILED")); return IMG_FALSE; } } PVR_DPF ((PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uFlags=0x%x, devVAddr=%08X)", ui32Size, uFlags, pBuf->DevVAddr.uiAddr)); pBuf->ui32RefCount = 1; *phBuf = (BM_HANDLE)pBuf; if(pui32Flags) { *pui32Flags = (uFlags & ~PVRSRV_HAP_MAPTYPE_MASK) | PVRSRV_HAP_MULTI_PROCESS; } return IMG_TRUE; }
IMG_BOOL BM_Wrap(void *hDevMemHeap, u32 ui32Size, u32 ui32Offset, IMG_BOOL bPhysContig, struct IMG_SYS_PHYADDR *psSysAddr, void *pvCPUVAddr, u32 *pui32Flags, void **phBuf) { struct BM_BUF *pBuf; struct BM_CONTEXT *psBMContext; struct BM_HEAP *psBMHeap; struct SYS_DATA *psSysData; struct IMG_SYS_PHYADDR sHashAddress; u32 uFlags; psBMHeap = (struct BM_HEAP *)hDevMemHeap; psBMContext = psBMHeap->pBMContext; uFlags = psBMHeap->ui32Attribs & (PVRSRV_HAP_CACHETYPE_MASK | PVRSRV_HAP_MAPTYPE_MASK); if (pui32Flags) uFlags |= *pui32Flags; PVR_DPF(PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uOffset=0x%x, " "bPhysContig=0x%x, pvCPUVAddr=0x%x, uFlags=0x%x)", ui32Size, ui32Offset, bPhysContig, pvCPUVAddr, uFlags); if (SysAcquireData(&psSysData) != PVRSRV_OK) return IMG_FALSE; sHashAddress = psSysAddr[0]; sHashAddress.uiAddr += ui32Offset; pBuf = (struct BM_BUF *)HASH_Retrieve(psBMContext->pBufferHash, (u32) sHashAddress.uiAddr); if (pBuf) { u32 ui32MappingSize = HOST_PAGEALIGN(ui32Size + ui32Offset); if (pBuf->pMapping->uSize == ui32MappingSize && (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr)) { PVR_DPF(PVR_DBG_MESSAGE, "BM_Wrap " "(Matched previous Wrap! uSize=0x%x, " "uOffset=0x%x, SysAddr=%08X)", ui32Size, ui32Offset, sHashAddress.uiAddr); pBuf->ui32RefCount++; *phBuf = (void *)pBuf; if (pui32Flags) *pui32Flags = uFlags; return IMG_TRUE; } } if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), (void **)&pBuf, NULL) != PVRSRV_OK) { PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: BM_Buf alloc FAILED"); return IMG_FALSE; } OSMemSet(pBuf, 0, sizeof(struct BM_BUF)); if (WrapMemory(psBMHeap, ui32Size, ui32Offset, bPhysContig, psSysAddr, pvCPUVAddr, uFlags, pBuf) != IMG_TRUE) { PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: WrapMemory FAILED"); OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct BM_BUF), pBuf, NULL); return IMG_FALSE; } if (pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped || pBuf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr) { PVR_ASSERT(SysSysPAddrToCpuPAddr(sHashAddress).uiAddr == pBuf->CpuPAddr.uiAddr); if (!HASH_Insert(psBMContext->pBufferHash, (u32)sHashAddress.uiAddr, (u32) pBuf)) { FreeBuf(pBuf, uFlags); PVR_DPF(PVR_DBG_ERROR, "BM_Wrap: HASH_Insert FAILED"); return IMG_FALSE; } } PVR_DPF(PVR_DBG_MESSAGE, "BM_Wrap (uSize=0x%x, uFlags=0x%x)=%08X(devVAddr=%08X)", ui32Size, uFlags, pBuf, pBuf->DevVAddr.uiAddr); pBuf->ui32RefCount = 1; pvr_get_ctx(psBMContext); *phBuf = (void *) pBuf; if (pui32Flags) *pui32Flags = (uFlags & ~PVRSRV_HAP_MAPTYPE_MASK) | PVRSRV_HAP_MULTI_PROCESS; return IMG_TRUE; }
static IMG_BOOL _AttemptAllocAligned (RA_ARENA *pArena, IMG_SIZE_T uSize, BM_MAPPING **ppsMapping, IMG_UINT32 uFlags, IMG_UINT32 uAlignment, IMG_UINT32 uAlignmentOffset, IMG_UINTPTR_T *base) { IMG_UINT32 uIndex; PVR_ASSERT (pArena!=IMG_NULL); if (pArena == IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: invalid parameter - pArena")); return IMG_FALSE; } if (uAlignment>1) uAlignmentOffset %= uAlignment; uIndex = pvr_log2 (uSize); #if 0 if (1u<<uIndex < uSize) uIndex++; #endif while (uIndex < FREE_TABLE_LIMIT && pArena->aHeadFree[uIndex]==IMG_NULL) uIndex++; while (uIndex < FREE_TABLE_LIMIT) { if (pArena->aHeadFree[uIndex]!=IMG_NULL) { BT *pBT; pBT = pArena->aHeadFree [uIndex]; while (pBT!=IMG_NULL) { IMG_UINTPTR_T aligned_base; if (uAlignment>1) aligned_base = (pBT->base + uAlignmentOffset + uAlignment - 1) / uAlignment * uAlignment - uAlignmentOffset; else aligned_base = pBT->base; PVR_DPF ((PVR_DBG_MESSAGE, "RA_AttemptAllocAligned: pBT-base=0x%x " "pBT-size=0x%x alignedbase=0x%x size=0x%x", pBT->base, pBT->uSize, aligned_base, uSize)); if (pBT->base + pBT->uSize >= aligned_base + uSize) { if(!pBT->psMapping || pBT->psMapping->ui32Flags == uFlags) { _FreeListRemove (pArena, pBT); PVR_ASSERT (pBT->type == btt_free); #ifdef RA_STATS pArena->sStatistics.uLiveSegmentCount++; pArena->sStatistics.uFreeSegmentCount--; pArena->sStatistics.uFreeResourceCount-=pBT->uSize; #endif if (aligned_base > pBT->base) { BT *pNeighbour; pNeighbour = _SegmentSplit (pArena, pBT, (IMG_SIZE_T)(aligned_base - pBT->base)); if (pNeighbour==IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Front split failed")); _FreeListInsert (pArena, pBT); return IMG_FALSE; } _FreeListInsert (pArena, pBT); #ifdef RA_STATS pArena->sStatistics.uFreeSegmentCount++; pArena->sStatistics.uFreeResourceCount+=pBT->uSize; #endif pBT = pNeighbour; } if (pBT->uSize > uSize) { BT *pNeighbour; pNeighbour = _SegmentSplit (pArena, pBT, uSize); if (pNeighbour==IMG_NULL) { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned: Back split failed")); _FreeListInsert (pArena, pBT); return IMG_FALSE; } _FreeListInsert (pArena, pNeighbour); #ifdef RA_STATS pArena->sStatistics.uFreeSegmentCount++; pArena->sStatistics.uFreeResourceCount+=pNeighbour->uSize; #endif } pBT->type = btt_live; #if defined(VALIDATE_ARENA_TEST) if (pBT->eResourceType == IMPORTED_RESOURCE_TYPE) { pBT->eResourceSpan = IMPORTED_RESOURCE_SPAN_LIVE; } else if (pBT->eResourceType == NON_IMPORTED_RESOURCE_TYPE) { pBT->eResourceSpan = RESOURCE_SPAN_LIVE; } else { PVR_DPF ((PVR_DBG_ERROR,"_AttemptAllocAligned ERROR: pBT->eResourceType unrecognized")); PVR_DBG_BREAK; } #endif if (!HASH_Insert (pArena->pSegmentHash, pBT->base, (IMG_UINTPTR_T) pBT)) { _FreeBT (pArena, pBT, IMG_FALSE); return IMG_FALSE; } if (ppsMapping!=IMG_NULL) *ppsMapping = pBT->psMapping; *base = pBT->base; return IMG_TRUE; } else { PVR_DPF ((PVR_DBG_MESSAGE, "AttemptAllocAligned: mismatch in flags. Import has %x, request was %x", pBT->psMapping->ui32Flags, uFlags)); } } pBT = pBT->pNextFree; } } uIndex++; } return IMG_FALSE; }