1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful but, except
10 * as otherwise stated in writing, without any warranty; without even the
11 * implied warranty of merchantability or fitness for a particular purpose.
12 * See the GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
29 #include "services_headers.h"
30 #include "buffer_manager.h"
31 #include "pvr_pdump.h"
32 #include "pvr_bridge_km.h"
34 #include <linux/pagemap.h>
36 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
37 u32 ui32Flags, u32 ui32Size, u32 ui32Alignment,
38 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo);
40 struct RESMAN_MAP_DEVICE_MEM_DATA {
41 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
42 struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo;
45 static inline void get_page_details(u32 vaddr, size_t byte_size,
46 u32 *page_offset_out, int *page_count_out)
48 size_t host_page_size;
52 host_page_size = PAGE_SIZE;
53 page_offset = vaddr & (host_page_size - 1);
54 page_count = PAGE_ALIGN(byte_size + page_offset) / host_page_size;
56 *page_offset_out = page_offset;
57 *page_count_out = page_count;
60 static inline int get_page_count(u32 vaddr, size_t byte_size)
65 get_page_details(vaddr, byte_size, &page_offset, &page_count);
70 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapsKM(void *hDevCookie,
71 struct PVRSRV_HEAP_INFO *psHeapInfo)
73 struct PVRSRV_DEVICE_NODE *psDeviceNode;
75 struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
78 if (hDevCookie == NULL) {
79 PVR_DPF(PVR_DBG_ERROR,
80 "PVRSRVGetDeviceMemHeapsKM: hDevCookie invalid");
82 return PVRSRV_ERROR_INVALID_PARAMS;
85 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
87 ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
88 psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
90 PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
92 for (i = 0; i < ui32HeapCount; i++) {
93 psHeapInfo[i].ui32HeapID = psDeviceMemoryHeap[i].ui32HeapID;
94 psHeapInfo[i].hDevMemHeap = psDeviceMemoryHeap[i].hDevMemHeap;
95 psHeapInfo[i].sDevVAddrBase =
96 psDeviceMemoryHeap[i].sDevVAddrBase;
97 psHeapInfo[i].ui32HeapByteSize =
98 psDeviceMemoryHeap[i].ui32HeapSize;
99 psHeapInfo[i].ui32Attribs = psDeviceMemoryHeap[i].ui32Attribs;
102 for (; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
103 OSMemSet(psHeapInfo + i, 0, sizeof(*psHeapInfo));
104 psHeapInfo[i].ui32HeapID = (u32) PVRSRV_UNDEFINED_HEAP_ID;
110 enum PVRSRV_ERROR PVRSRVCreateDeviceMemContextKM(void *hDevCookie,
111 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
112 void **phDevMemContext,
113 u32 *pui32ClientHeapCount,
114 struct PVRSRV_HEAP_INFO *psHeapInfo,
115 IMG_BOOL *pbCreated, IMG_BOOL *pbShared)
117 struct PVRSRV_DEVICE_NODE *psDeviceNode;
118 u32 ui32HeapCount, ui32ClientHeapCount = 0;
119 struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
120 void *hDevMemContext;
122 struct IMG_DEV_PHYADDR sPDDevPAddr;
125 if (hDevCookie == NULL) {
126 PVR_DPF(PVR_DBG_ERROR,
127 "PVRSRVCreateDeviceMemContextKM: hDevCookie invalid");
129 return PVRSRV_ERROR_INVALID_PARAMS;
132 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
134 ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
135 psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
137 PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
139 hDevMemContext = BM_CreateContext(psDeviceNode,
140 &sPDDevPAddr, psPerProc, pbCreated);
141 if (hDevMemContext == NULL) {
142 PVR_DPF(PVR_DBG_ERROR,
143 "PVRSRVCreateDeviceMemContextKM: Failed BM_CreateContext");
144 return PVRSRV_ERROR_OUT_OF_MEMORY;
147 for (i = 0; i < ui32HeapCount; i++) {
148 switch (psDeviceMemoryHeap[i].DevMemHeapType) {
149 case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
150 psHeapInfo[ui32ClientHeapCount].ui32HeapID =
151 psDeviceMemoryHeap[i].ui32HeapID;
152 psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
153 psDeviceMemoryHeap[i].hDevMemHeap;
154 psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
155 psDeviceMemoryHeap[i].sDevVAddrBase;
156 psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
157 psDeviceMemoryHeap[i].ui32HeapSize;
158 psHeapInfo[ui32ClientHeapCount].ui32Attribs =
159 psDeviceMemoryHeap[i].ui32Attribs;
160 pbShared[ui32ClientHeapCount] = IMG_TRUE;
161 ui32ClientHeapCount++;
163 case DEVICE_MEMORY_HEAP_PERCONTEXT:
164 hDevMemHeap = BM_CreateHeap(hDevMemContext,
165 &psDeviceMemoryHeap[i]);
167 psHeapInfo[ui32ClientHeapCount].ui32HeapID =
168 psDeviceMemoryHeap[i].ui32HeapID;
169 psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
171 psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
172 psDeviceMemoryHeap[i].sDevVAddrBase;
173 psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
174 psDeviceMemoryHeap[i].ui32HeapSize;
175 psHeapInfo[ui32ClientHeapCount].ui32Attribs =
176 psDeviceMemoryHeap[i].ui32Attribs;
177 pbShared[ui32ClientHeapCount] = IMG_FALSE;
179 ui32ClientHeapCount++;
184 *pui32ClientHeapCount = ui32ClientHeapCount;
185 *phDevMemContext = hDevMemContext;
190 enum PVRSRV_ERROR PVRSRVDestroyDeviceMemContextKM(void *hDevCookie,
191 void *hDevMemContext)
193 PVR_UNREFERENCED_PARAMETER(hDevCookie);
195 pvr_put_ctx(hDevMemContext);
200 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapInfoKM(void *hDevCookie,
201 void *hDevMemContext,
202 u32 *pui32ClientHeapCount,
203 struct PVRSRV_HEAP_INFO *psHeapInfo,
206 struct PVRSRV_DEVICE_NODE *psDeviceNode;
207 u32 ui32HeapCount, ui32ClientHeapCount = 0;
208 struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
212 if (hDevCookie == NULL) {
213 PVR_DPF(PVR_DBG_ERROR,
214 "PVRSRVGetDeviceMemHeapInfoKM: hDevCookie invalid");
216 return PVRSRV_ERROR_INVALID_PARAMS;
219 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
221 ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
222 psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
224 PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
226 for (i = 0; i < ui32HeapCount; i++) {
227 switch (psDeviceMemoryHeap[i].DevMemHeapType) {
228 case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
229 psHeapInfo[ui32ClientHeapCount].ui32HeapID =
230 psDeviceMemoryHeap[i].ui32HeapID;
231 psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
232 psDeviceMemoryHeap[i].hDevMemHeap;
233 psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
234 psDeviceMemoryHeap[i].sDevVAddrBase;
235 psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
236 psDeviceMemoryHeap[i].ui32HeapSize;
237 psHeapInfo[ui32ClientHeapCount].ui32Attribs =
238 psDeviceMemoryHeap[i].ui32Attribs;
239 pbShared[ui32ClientHeapCount] = IMG_TRUE;
240 ui32ClientHeapCount++;
242 case DEVICE_MEMORY_HEAP_PERCONTEXT:
243 hDevMemHeap = BM_CreateHeap(hDevMemContext,
244 &psDeviceMemoryHeap[i]);
245 psHeapInfo[ui32ClientHeapCount].ui32HeapID =
246 psDeviceMemoryHeap[i].ui32HeapID;
247 psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
249 psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
250 psDeviceMemoryHeap[i].sDevVAddrBase;
251 psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
252 psDeviceMemoryHeap[i].ui32HeapSize;
253 psHeapInfo[ui32ClientHeapCount].ui32Attribs =
254 psDeviceMemoryHeap[i].ui32Attribs;
255 pbShared[ui32ClientHeapCount] = IMG_FALSE;
257 ui32ClientHeapCount++;
261 *pui32ClientHeapCount = ui32ClientHeapCount;
266 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
267 u32 ui32Flags, u32 ui32Size,
269 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
271 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
274 struct PVRSRV_MEMBLK *psMemBlock;
277 PVR_UNREFERENCED_PARAMETER(hDevCookie);
281 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
282 sizeof(struct PVRSRV_KERNEL_MEM_INFO),
283 (void **) &psMemInfo, NULL) != PVRSRV_OK) {
284 PVR_DPF(PVR_DBG_ERROR,
285 "AllocDeviceMem: Failed to alloc memory for block");
286 return PVRSRV_ERROR_OUT_OF_MEMORY;
289 OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
291 psMemBlock = &(psMemInfo->sMemBlk);
293 psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION;
295 bBMError = BM_Alloc(hDevMemHeap, NULL, ui32Size,
296 &psMemInfo->ui32Flags, ui32Alignment, &hBuffer);
299 PVR_DPF(PVR_DBG_ERROR, "AllocDeviceMem: BM_Alloc Failed");
300 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
301 sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
303 return PVRSRV_ERROR_OUT_OF_MEMORY;
306 psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
307 psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
309 psMemBlock->hBuffer = (void *)hBuffer;
310 psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
311 psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
312 psMemInfo->ui32AllocSize = ui32Size;
314 psMemInfo->pvSysBackupBuffer = NULL;
316 *ppsMemInfo = psMemInfo;
321 static enum PVRSRV_ERROR FreeDeviceMem(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
326 return PVRSRV_ERROR_INVALID_PARAMS;
328 hBuffer = psMemInfo->sMemBlk.hBuffer;
329 BM_Free(hBuffer, psMemInfo->ui32Flags);
331 if (psMemInfo->pvSysBackupBuffer)
332 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->ui32AllocSize,
333 psMemInfo->pvSysBackupBuffer, NULL);
335 OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct PVRSRV_KERNEL_MEM_INFO),
341 enum PVRSRV_ERROR PVRSRVAllocSyncInfoKM(void *hDevCookie, void *hDevMemContext,
342 struct PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo)
344 void *hSyncDevMemHeap;
345 struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
346 struct BM_CONTEXT *pBMContext;
347 enum PVRSRV_ERROR eError;
348 struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo;
349 struct PVRSRV_SYNC_DATA *psSyncData;
351 eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT,
352 sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
353 (void **) &psKernelSyncInfo, NULL);
354 if (eError != PVRSRV_OK) {
355 PVR_DPF(PVR_DBG_ERROR,
356 "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
357 return PVRSRV_ERROR_OUT_OF_MEMORY;
360 pBMContext = (struct BM_CONTEXT *)hDevMemContext;
361 psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo;
363 hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo->
364 ui32SyncHeapID].hDevMemHeap;
366 eError = AllocDeviceMem(hDevCookie, hSyncDevMemHeap,
367 PVRSRV_MEM_CACHE_CONSISTENT,
368 sizeof(struct PVRSRV_SYNC_DATA), sizeof(u32),
369 &psKernelSyncInfo->psSyncDataMemInfoKM);
371 if (eError != PVRSRV_OK) {
372 PVR_DPF(PVR_DBG_ERROR,
373 "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
374 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
375 sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
376 psKernelSyncInfo, NULL);
377 return PVRSRV_ERROR_OUT_OF_MEMORY;
380 psKernelSyncInfo->psSyncData =
381 psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM;
382 psSyncData = psKernelSyncInfo->psSyncData;
384 psSyncData->ui32WriteOpsPending = 0;
385 psSyncData->ui32WriteOpsComplete = 0;
386 psSyncData->ui32ReadOpsPending = 0;
387 psSyncData->ui32ReadOpsComplete = 0;
388 psSyncData->ui32LastOpDumpVal = 0;
389 psSyncData->ui32LastReadOpDumpVal = 0;
392 PDUMPMEM(psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM,
393 psKernelSyncInfo->psSyncDataMemInfoKM, 0,
394 psKernelSyncInfo->psSyncDataMemInfoKM->ui32AllocSize,
395 0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM));
398 psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr =
399 psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
400 offsetof(struct PVRSRV_SYNC_DATA, ui32WriteOpsComplete);
401 psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr =
402 psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
403 offsetof(struct PVRSRV_SYNC_DATA, ui32ReadOpsComplete);
405 psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = NULL;
407 *ppsKernelSyncInfo = psKernelSyncInfo;
412 enum PVRSRV_ERROR PVRSRVFreeSyncInfoKM(
413 struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo)
415 FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM);
416 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
417 sizeof(struct PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo,
424 void get_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
426 syncinfo->refcount++;
430 void put_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
432 struct PVRSRV_DEVICE_NODE *dev = syncinfo->dev_cookie;
434 syncinfo->refcount--;
436 if (!syncinfo->refcount) {
437 HASH_Remove(dev->sync_table,
438 syncinfo->phys_addr.uiAddr);
439 PVRSRVFreeSyncInfoKM(syncinfo);
444 enum PVRSRV_ERROR alloc_or_reuse_syncinfo(void *dev_cookie,
445 void *mem_context_handle,
446 struct PVRSRV_KERNEL_SYNC_INFO **syncinfo,
447 struct IMG_SYS_PHYADDR *phys_addr)
449 enum PVRSRV_ERROR error;
450 struct PVRSRV_DEVICE_NODE *dev;
452 dev = (struct PVRSRV_DEVICE_NODE *) dev_cookie;
454 *syncinfo = (struct PVRSRV_KERNEL_SYNC_INFO *)
455 HASH_Retrieve(dev->sync_table,
459 /* Dont' have one so create one */
460 error = PVRSRVAllocSyncInfoKM(dev_cookie, mem_context_handle,
463 if (error != PVRSRV_OK)
466 /* Setup our extra data */
467 (*syncinfo)->phys_addr.uiAddr = phys_addr->uiAddr;
468 (*syncinfo)->dev_cookie = dev_cookie;
469 (*syncinfo)->refcount = 1;
471 if (!HASH_Insert(dev->sync_table, phys_addr->uiAddr,
473 PVR_DPF(PVR_DBG_ERROR, "alloc_or_reuse_syncinfo: "
474 "Failed to add syncobject to hash table");
475 return PVRSRV_ERROR_GENERIC;
478 get_syncinfo(*syncinfo);
483 static enum PVRSRV_ERROR FreeDeviceMemCallBack(void *pvParam, u32 ui32Param)
485 enum PVRSRV_ERROR eError = PVRSRV_OK;
486 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
488 PVR_UNREFERENCED_PARAMETER(ui32Param);
490 psMemInfo->ui32RefCount--;
492 if (psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) {
493 void *hMemInfo = NULL;
495 if (psMemInfo->ui32RefCount != 0) {
496 PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
497 "mappings are open in other processes");
498 return PVRSRV_ERROR_GENERIC;
501 eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE,
504 PVRSRV_HANDLE_TYPE_MEM_INFO);
505 if (eError != PVRSRV_OK) {
506 PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
507 "can't find exported meminfo in the "
508 "global handle list");
512 eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
514 PVRSRV_HANDLE_TYPE_MEM_INFO);
515 if (eError != PVRSRV_OK) {
516 PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
517 "PVRSRVReleaseHandle failed for exported meminfo");
522 PVR_ASSERT(psMemInfo->ui32RefCount == 0);
524 if (psMemInfo->psKernelSyncInfo)
525 eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo);
527 if (eError == PVRSRV_OK)
528 eError = FreeDeviceMem(psMemInfo);
533 enum PVRSRV_ERROR PVRSRVFreeDeviceMemKM(void *hDevCookie,
534 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
536 PVR_UNREFERENCED_PARAMETER(hDevCookie);
539 return PVRSRV_ERROR_INVALID_PARAMS;
541 if (psMemInfo->sMemBlk.hResItem != NULL)
542 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
544 FreeDeviceMemCallBack(psMemInfo, 0);
549 enum PVRSRV_ERROR PVRSRVAllocDeviceMemKM(void *hDevCookie,
550 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
551 void *hDevMemHeap, u32 ui32Flags,
552 u32 ui32Size, u32 ui32Alignment,
553 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
555 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
556 enum PVRSRV_ERROR eError;
557 struct BM_HEAP *psBMHeap;
558 void *hDevMemContext;
560 if (!hDevMemHeap || (ui32Size == 0))
561 return PVRSRV_ERROR_INVALID_PARAMS;
563 eError = AllocDeviceMem(hDevCookie, hDevMemHeap, ui32Flags, ui32Size,
564 ui32Alignment, &psMemInfo);
566 if (eError != PVRSRV_OK)
569 if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) {
570 psMemInfo->psKernelSyncInfo = NULL;
572 psBMHeap = (struct BM_HEAP *)hDevMemHeap;
573 hDevMemContext = (void *) psBMHeap->pBMContext;
574 eError = PVRSRVAllocSyncInfoKM(hDevCookie,
576 &psMemInfo->psKernelSyncInfo);
577 if (eError != PVRSRV_OK)
581 *ppsMemInfo = psMemInfo;
583 if (ui32Flags & PVRSRV_MEM_NO_RESMAN) {
584 psMemInfo->sMemBlk.hResItem = NULL;
586 psMemInfo->sMemBlk.hResItem =
587 ResManRegisterRes(psPerProc->hResManContext,
588 RESMAN_TYPE_DEVICEMEM_ALLOCATION,
589 psMemInfo, 0, FreeDeviceMemCallBack);
590 if (psMemInfo->sMemBlk.hResItem == NULL) {
591 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
596 psMemInfo->ui32RefCount++;
601 FreeDeviceMem(psMemInfo);
606 enum PVRSRV_ERROR PVRSRVDissociateDeviceMemKM(void *hDevCookie,
607 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
609 enum PVRSRV_ERROR eError;
610 struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevCookie;
612 PVR_UNREFERENCED_PARAMETER(hDevCookie);
615 return PVRSRV_ERROR_INVALID_PARAMS;
617 eError = ResManDissociateRes(psMemInfo->sMemBlk.hResItem,
618 psDeviceNode->hResManContext);
620 PVR_ASSERT(eError == PVRSRV_OK);
625 enum PVRSRV_ERROR PVRSRVGetFreeDeviceMemKM(u32 ui32Flags, u32 *pui32Total,
626 u32 *pui32Free, u32 *pui32LargestBlock)
629 PVR_UNREFERENCED_PARAMETER(ui32Flags);
630 PVR_UNREFERENCED_PARAMETER(pui32Total);
631 PVR_UNREFERENCED_PARAMETER(pui32Free);
632 PVR_UNREFERENCED_PARAMETER(pui32LargestBlock);
637 enum PVRSRV_ERROR PVRSRVUnwrapExtMemoryKM(
638 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
641 return PVRSRV_ERROR_INVALID_PARAMS;
643 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
648 static enum PVRSRV_ERROR UnwrapExtMemoryCallBack(void *pvParam, u32 ui32Param)
650 enum PVRSRV_ERROR eError = PVRSRV_OK;
651 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
654 PVR_UNREFERENCED_PARAMETER(ui32Param);
656 hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem;
658 if (psMemInfo->psKernelSyncInfo)
659 put_syncinfo(psMemInfo->psKernelSyncInfo);
661 if (psMemInfo->sMemBlk.psIntSysPAddr) {
664 page_count = get_page_count((u32)psMemInfo->pvLinAddrKM,
665 psMemInfo->ui32AllocSize);
667 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
668 page_count * sizeof(struct IMG_SYS_PHYADDR),
669 psMemInfo->sMemBlk.psIntSysPAddr, NULL);
672 if (eError == PVRSRV_OK) {
673 psMemInfo->ui32RefCount--;
674 eError = FreeDeviceMem(psMemInfo);
678 OSReleasePhysPageAddr(hOSWrapMem);
683 enum PVRSRV_ERROR PVRSRVWrapExtMemoryKM(void *hDevCookie,
684 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
685 void *hDevMemContext, u32 ui32ByteSize,
686 u32 ui32PageOffset, IMG_BOOL bPhysContig,
687 struct IMG_SYS_PHYADDR *psExtSysPAddr,
689 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
691 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
692 struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
693 u32 ui32HostPageSize = HOST_PAGESIZE();
694 void *hDevMemHeap = NULL;
695 struct PVRSRV_DEVICE_NODE *psDeviceNode;
697 struct PVRSRV_MEMBLK *psMemBlock;
699 struct BM_HEAP *psBMHeap;
700 enum PVRSRV_ERROR eError;
701 void *pvPageAlignedCPUVAddr;
702 struct IMG_SYS_PHYADDR *psIntSysPAddr = NULL;
703 void *hOSWrapMem = NULL;
704 struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
708 psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
709 PVR_ASSERT(psDeviceNode != NULL);
711 if (!psDeviceNode || (!pvLinAddr && !psExtSysPAddr)) {
712 PVR_DPF(PVR_DBG_ERROR,
713 "PVRSRVWrapExtMemoryKM: invalid parameter");
714 return PVRSRV_ERROR_INVALID_PARAMS;
718 get_page_details((u32)pvLinAddr, ui32ByteSize,
719 &ui32PageOffset, &page_count);
720 pvPageAlignedCPUVAddr = (void *)((u8 *) pvLinAddr -
723 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
724 page_count * sizeof(struct IMG_SYS_PHYADDR),
725 (void **)&psIntSysPAddr, NULL) != PVRSRV_OK) {
726 PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
727 "Failed to alloc memory for block");
728 return PVRSRV_ERROR_OUT_OF_MEMORY;
731 eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
732 page_count * ui32HostPageSize,
733 psIntSysPAddr, &hOSWrapMem);
734 if (eError != PVRSRV_OK) {
735 PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM:"
736 " Failed to alloc memory for block");
737 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
738 goto ErrorExitPhase1;
740 psExtSysPAddr = psIntSysPAddr;
741 bPhysContig = IMG_FALSE;
745 &((struct BM_CONTEXT *)hDevMemContext)->psDeviceNode->
747 psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
748 for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
749 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
750 psDevMemoryInfo->ui32MappingHeapID) {
751 if (psDeviceMemoryHeap[i].DevMemHeapType ==
752 DEVICE_MEMORY_HEAP_PERCONTEXT) {
754 BM_CreateHeap(hDevMemContext,
755 &psDeviceMemoryHeap[i]);
758 psDevMemoryInfo->psDeviceMemoryHeap[i].
765 if (hDevMemHeap == NULL) {
766 PVR_DPF(PVR_DBG_ERROR,
767 "PVRSRVWrapExtMemoryKM: unable to find mapping heap");
768 eError = PVRSRV_ERROR_GENERIC;
769 goto ErrorExitPhase2;
772 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
773 sizeof(struct PVRSRV_KERNEL_MEM_INFO),
774 (void **) &psMemInfo, NULL) != PVRSRV_OK) {
775 PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
776 "Failed to alloc memory for block");
777 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
778 goto ErrorExitPhase2;
781 OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
782 psMemBlock = &(psMemInfo->sMemBlk);
784 bBMError = BM_Wrap(hDevMemHeap,
789 NULL, &psMemInfo->ui32Flags, &hBuffer);
791 PVR_DPF(PVR_DBG_ERROR,
792 "PVRSRVWrapExtMemoryKM: BM_Wrap Failed");
793 eError = PVRSRV_ERROR_BAD_MAPPING;
794 goto ErrorExitPhase3;
797 psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
798 psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
799 psMemBlock->hOSWrapMem = hOSWrapMem;
800 psMemBlock->psIntSysPAddr = psIntSysPAddr;
802 psMemBlock->hBuffer = (void *) hBuffer;
804 psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
805 psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
806 psMemInfo->ui32AllocSize = ui32ByteSize;
808 psMemInfo->pvSysBackupBuffer = NULL;
810 psBMHeap = (struct BM_HEAP *)hDevMemHeap;
811 hDevMemContext = (void *) psBMHeap->pBMContext;
812 eError = alloc_or_reuse_syncinfo(hDevCookie,
814 &psMemInfo->psKernelSyncInfo,
816 if (eError != PVRSRV_OK)
817 goto ErrorExitPhase4;
819 psMemInfo->ui32RefCount++;
821 psMemInfo->sMemBlk.hResItem =
822 ResManRegisterRes(psPerProc->hResManContext,
823 RESMAN_TYPE_DEVICEMEM_WRAP, psMemInfo, 0,
824 UnwrapExtMemoryCallBack);
826 *ppsMemInfo = psMemInfo;
831 FreeDeviceMem(psMemInfo);
836 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
837 sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
843 OSReleasePhysPageAddr(hOSWrapMem);
847 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
848 page_count * sizeof(struct IMG_SYS_PHYADDR),
849 psIntSysPAddr, NULL);
855 enum PVRSRV_ERROR PVRSRVUnmapDeviceMemoryKM(
856 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
859 return PVRSRV_ERROR_INVALID_PARAMS;
861 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
866 static enum PVRSRV_ERROR UnmapDeviceMemoryCallBack(void *pvParam, u32 ui32Param)
868 enum PVRSRV_ERROR eError;
869 struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = pvParam;
872 PVR_UNREFERENCED_PARAMETER(ui32Param);
874 page_count = get_page_count((u32)psMapData->psMemInfo->pvLinAddrKM,
875 psMapData->psMemInfo->ui32AllocSize);
877 if (psMapData->psMemInfo->sMemBlk.psIntSysPAddr)
878 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
879 page_count * sizeof(struct IMG_SYS_PHYADDR),
880 psMapData->psMemInfo->sMemBlk.psIntSysPAddr, NULL);
882 eError = FreeDeviceMem(psMapData->psMemInfo);
883 if (eError != PVRSRV_OK) {
884 PVR_DPF(PVR_DBG_ERROR, "UnmapDeviceMemoryCallBack: "
885 "Failed to free DST meminfo");
889 psMapData->psSrcMemInfo->ui32RefCount--;
891 PVR_ASSERT(psMapData->psSrcMemInfo->ui32RefCount != (u32) (-1));
893 * Don't free the source MemInfo as we didn't allocate it
894 * and it's not our job as the process the allocated
895 * should also free it when it's finished
897 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
898 sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, NULL);
903 static inline int bm_is_continuous(const struct BM_BUF *buf)
905 return buf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr;
908 enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM(
909 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
910 struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo,
911 void *hDstDevMemHeap,
912 struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo)
914 enum PVRSRV_ERROR eError;
916 u32 ui32HostPageSize = HOST_PAGESIZE();
919 struct IMG_SYS_PHYADDR *psSysPAddr = NULL;
920 struct IMG_DEV_PHYADDR sDevPAddr;
921 struct BM_BUF *psBuf;
922 struct IMG_DEV_VIRTADDR sDevVAddr;
923 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
925 struct PVRSRV_MEMBLK *psMemBlock;
927 struct PVRSRV_DEVICE_NODE *psDeviceNode;
928 void *pvPageAlignedCPUVAddr;
929 struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = NULL;
931 if (!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) {
932 PVR_DPF(PVR_DBG_ERROR,
933 "PVRSRVMapDeviceMemoryKM: invalid parameters");
934 return PVRSRV_ERROR_INVALID_PARAMS;
937 *ppsDstMemInfo = NULL;
939 get_page_details((u32)psSrcMemInfo->pvLinAddrKM,
940 psSrcMemInfo->ui32AllocSize,
941 &ui32PageOffset, &page_count);
942 pvPageAlignedCPUVAddr =
943 (void *) ((u8 *) psSrcMemInfo->pvLinAddrKM -
946 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
947 page_count * sizeof(struct IMG_SYS_PHYADDR),
948 (void **) &psSysPAddr, NULL) != PVRSRV_OK) {
949 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
950 "Failed to alloc memory for block");
951 return PVRSRV_ERROR_OUT_OF_MEMORY;
954 psBuf = psSrcMemInfo->sMemBlk.hBuffer;
956 psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode;
958 sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - ui32PageOffset;
959 for (i = 0; i < page_count; i++) {
961 BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr);
962 if (eError != PVRSRV_OK) {
963 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
964 "Failed to retrieve page list from device");
969 SysDevPAddrToSysPAddr(psDeviceNode->sDevId.eDeviceType,
972 sDevVAddr.uiAddr += ui32HostPageSize;
975 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
976 sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA),
977 (void **)&psMapData, NULL) != PVRSRV_OK) {
978 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
979 "Failed to alloc resman map data");
980 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
984 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
985 sizeof(struct PVRSRV_KERNEL_MEM_INFO),
986 (void **)&psMemInfo, NULL) != PVRSRV_OK) {
987 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
988 "Failed to alloc memory for block");
989 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
993 OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
995 psMemBlock = &(psMemInfo->sMemBlk);
997 bBMError = BM_Wrap(hDstDevMemHeap, psSrcMemInfo->ui32AllocSize,
998 ui32PageOffset, bm_is_continuous(psBuf), psSysPAddr,
999 pvPageAlignedCPUVAddr, &psMemInfo->ui32Flags,
1003 PVR_DPF(PVR_DBG_ERROR,
1004 "PVRSRVMapDeviceMemoryKM: BM_Wrap Failed");
1005 eError = PVRSRV_ERROR_BAD_MAPPING;
1009 psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1010 psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1012 psMemBlock->hBuffer = (void *) hBuffer;
1014 psMemBlock->psIntSysPAddr = psSysPAddr;
1016 psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM;
1018 psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1019 psMemInfo->ui32AllocSize = psSrcMemInfo->ui32AllocSize;
1020 psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo;
1022 psMemInfo->pvSysBackupBuffer = NULL;
1024 psSrcMemInfo->ui32RefCount++;
1026 psMapData->psMemInfo = psMemInfo;
1027 psMapData->psSrcMemInfo = psSrcMemInfo;
1029 psMemInfo->sMemBlk.hResItem =
1030 ResManRegisterRes(psPerProc->hResManContext,
1031 RESMAN_TYPE_DEVICEMEM_MAPPING, psMapData, 0,
1032 UnmapDeviceMemoryCallBack);
1034 *ppsDstMemInfo = psMemInfo;
1041 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1042 sizeof(struct IMG_SYS_PHYADDR), psSysPAddr, NULL);
1046 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1047 sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1052 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1053 sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData,
1060 enum PVRSRV_ERROR PVRSRVUnmapDeviceClassMemoryKM(
1061 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
1064 return PVRSRV_ERROR_INVALID_PARAMS;
1066 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
1071 static enum PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(void *pvParam,
1074 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
1076 PVR_UNREFERENCED_PARAMETER(ui32Param);
1078 return FreeDeviceMem(psMemInfo);
1081 enum PVRSRV_ERROR PVRSRVMapDeviceClassMemoryKM(
1082 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
1083 void *hDevMemContext, void *hDeviceClassBuffer,
1084 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo,
1087 enum PVRSRV_ERROR eError;
1088 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
1089 struct PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer;
1090 struct IMG_SYS_PHYADDR *psSysPAddr;
1091 void *pvCPUVAddr, *pvPageAlignedCPUVAddr;
1092 IMG_BOOL bPhysContig;
1093 struct BM_CONTEXT *psBMContext;
1094 struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
1095 struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
1096 void *hDevMemHeap = NULL;
1099 u32 ui32PageSize = HOST_PAGESIZE();
1101 struct PVRSRV_MEMBLK *psMemBlock;
1105 if (!hDeviceClassBuffer || !ppsMemInfo || !phOSMapInfo ||
1107 PVR_DPF(PVR_DBG_ERROR,
1108 "PVRSRVMapDeviceClassMemoryKM: invalid parameters");
1109 return PVRSRV_ERROR_INVALID_PARAMS;
1112 psDeviceClassBuffer = (struct PVRSRV_DEVICECLASS_BUFFER *)
1116 psDeviceClassBuffer->pfnGetBufferAddr(psDeviceClassBuffer->
1118 psDeviceClassBuffer->
1119 hExtBuffer, &psSysPAddr,
1121 (void __iomem **)&pvCPUVAddr,
1122 phOSMapInfo, &bPhysContig);
1123 if (eError != PVRSRV_OK) {
1124 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1125 "unable to get buffer address");
1126 return PVRSRV_ERROR_GENERIC;
1129 psBMContext = (struct BM_CONTEXT *)psDeviceClassBuffer->hDevMemContext;
1130 psDevMemoryInfo = &psBMContext->psDeviceNode->sDevMemoryInfo;
1131 psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
1132 for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
1133 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
1134 psDevMemoryInfo->ui32MappingHeapID) {
1135 if (psDeviceMemoryHeap[i].DevMemHeapType ==
1136 DEVICE_MEMORY_HEAP_PERCONTEXT)
1138 BM_CreateHeap(hDevMemContext,
1139 &psDeviceMemoryHeap[i]);
1142 psDevMemoryInfo->psDeviceMemoryHeap[i].
1148 if (hDevMemHeap == NULL) {
1149 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1150 "unable to find mapping heap");
1151 return PVRSRV_ERROR_GENERIC;
1154 ui32Offset = ((u32)pvCPUVAddr) & (ui32PageSize - 1);
1155 pvPageAlignedCPUVAddr = (void *)((u8 *)pvCPUVAddr - ui32Offset);
1157 if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
1158 sizeof(struct PVRSRV_KERNEL_MEM_INFO),
1159 (void **)&psMemInfo, NULL) != PVRSRV_OK) {
1160 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1161 "Failed to alloc memory for block");
1162 return PVRSRV_ERROR_OUT_OF_MEMORY;
1165 OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
1167 psMemBlock = &(psMemInfo->sMemBlk);
1169 bBMError = BM_Wrap(hDevMemHeap, ui32ByteSize, ui32Offset, bPhysContig,
1170 psSysPAddr, pvPageAlignedCPUVAddr,
1171 &psMemInfo->ui32Flags, &hBuffer);
1174 PVR_DPF(PVR_DBG_ERROR,
1175 "PVRSRVMapDeviceClassMemoryKM: BM_Wrap Failed");
1176 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1177 sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1179 return PVRSRV_ERROR_BAD_MAPPING;
1182 psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1183 psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1185 psMemBlock->hBuffer = (void *) hBuffer;
1187 psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
1189 psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1190 psMemInfo->ui32AllocSize = ui32ByteSize;
1191 psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo;
1193 psMemInfo->pvSysBackupBuffer = NULL;
1195 psMemInfo->sMemBlk.hResItem =
1196 ResManRegisterRes(psPerProc->hResManContext,
1197 RESMAN_TYPE_DEVICECLASSMEM_MAPPING, psMemInfo, 0,
1198 UnmapDeviceClassMemoryCallBack);
1200 *ppsMemInfo = psMemInfo;