1 /*************************************************************************/ /*!
3 @Title Device Memory Management internal utility functions
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Utility functions used internally by device memory management
7 @License Dual MIT/GPLv2
9 The contents of this file are subject to the MIT license as set out below.
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
21 Alternatively, the contents of this file may be used under the terms of
22 the GNU General Public License Version 2 ("GPL") in which case the provisions
23 of GPL are applicable instead of those above.
25 If you wish to allow use of your version of this file only under the terms of
26 GPL, and not to allow others to use your version of this file under the terms
27 of the MIT license, indicate your decision by deleting the provisions above
28 and replace them with the notice and other provisions required by GPL as set
29 out in the file called "GPL-COPYING" included in this distribution. If you do
30 not delete the provisions above, a recipient may use your version of this file
31 under the terms of either the MIT license or GPL.
33 This License is also included in this distribution in the file called
36 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
37 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
39 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
40 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
41 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
42 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 */ /**************************************************************************/
46 #include "img_types.h"
47 #include "pvrsrv_error.h"
49 #include "devicemem_utils.h"
50 #include "client_mm_bridge.h"
52 #if !defined(__KERNEL__) && defined(SUPPORT_ION)
57 The Devmem import structure is the structure we use
58 to manage memory that is "imported" (which is page
59 granular) from the server into our process, this
62 This allows memory to be imported without requiring
63 any CPU or device mapping. Memory can then be mapped
64 into the device or CPU on demand, but neither is
69 IMG_VOID _DevmemImportStructAcquire(DEVMEM_IMPORT *psImport)
71 IMG_INT iRefCount = OSAtomicIncrement(&psImport->hRefCount);
72 PVR_UNREFERENCED_PARAMETER(iRefCount);
73 PVR_ASSERT(iRefCount != 1);
75 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
83 IMG_VOID _DevmemImportStructRelease(DEVMEM_IMPORT *psImport)
85 IMG_INT iRefCount = OSAtomicDecrement(&psImport->hRefCount);
86 PVR_ASSERT(iRefCount >= 0);
88 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
96 BridgePMRUnrefPMR(psImport->hBridge,
98 OSLockDestroy(psImport->sCPUImport.hLock);
99 OSLockDestroy(psImport->sDeviceImport.hLock);
100 OSLockDestroy(psImport->hLock);
106 IMG_VOID _DevmemImportDiscard(DEVMEM_IMPORT *psImport)
108 PVR_ASSERT(OSAtomicRead(&psImport->hRefCount) == 0);
109 OSLockDestroy(psImport->sCPUImport.hLock);
110 OSLockDestroy(psImport->sDeviceImport.hLock);
111 OSLockDestroy(psImport->hLock);
116 PVRSRV_ERROR _DevmemMemDescAlloc(DEVMEM_MEMDESC **ppsMemDesc)
118 DEVMEM_MEMDESC *psMemDesc;
121 psMemDesc = OSAllocMem(sizeof(DEVMEM_MEMDESC));
123 if (psMemDesc == IMG_NULL)
125 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
129 /* Structure must be zero'd incase it needs to be freed before it is initialised! */
130 OSCachedMemSet(psMemDesc, 0, sizeof(DEVMEM_MEMDESC));
132 eError = OSLockCreate(&psMemDesc->hLock, LOCK_TYPE_PASSIVE);
133 if (eError != PVRSRV_OK)
138 eError = OSLockCreate(&psMemDesc->sDeviceMemDesc.hLock, LOCK_TYPE_PASSIVE);
139 if (eError != PVRSRV_OK)
144 eError = OSLockCreate(&psMemDesc->sCPUMemDesc.hLock, LOCK_TYPE_PASSIVE);
145 if (eError != PVRSRV_OK)
150 *ppsMemDesc = psMemDesc;
155 OSLockDestroy(psMemDesc->sDeviceMemDesc.hLock);
157 OSLockDestroy(psMemDesc->hLock);
159 OSFreeMem(psMemDesc);
161 PVR_ASSERT(eError != PVRSRV_OK);
167 Init the MemDesc structure
170 IMG_VOID _DevmemMemDescInit(DEVMEM_MEMDESC *psMemDesc,
171 IMG_DEVMEM_OFFSET_T uiOffset,
172 DEVMEM_IMPORT *psImport)
174 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
180 psMemDesc->psImport = psImport;
181 psMemDesc->uiOffset = uiOffset;
183 psMemDesc->sDeviceMemDesc.ui32RefCount = 0;
184 psMemDesc->sCPUMemDesc.ui32RefCount = 0;
185 OSAtomicWrite(&psMemDesc->hRefCount, 1);
189 IMG_VOID _DevmemMemDescAcquire(DEVMEM_MEMDESC *psMemDesc)
192 PVR_UNREFERENCED_PARAMETER(iRefCount);
194 iRefCount = OSAtomicIncrement(&psMemDesc->hRefCount);
195 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
203 IMG_VOID _DevmemMemDescRelease(DEVMEM_MEMDESC *psMemDesc)
206 PVR_ASSERT(psMemDesc != NULL);
208 iRefCount = OSAtomicDecrement(&psMemDesc->hRefCount);
209 PVR_ASSERT(iRefCount >= 0);
211 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
219 if (!psMemDesc->psImport->bExportable)
221 RA_Free(psMemDesc->psImport->sDeviceImport.psHeap->psSubAllocRA,
222 psMemDesc->psImport->sDeviceImport.sDevVAddr.uiAddr +
223 psMemDesc->uiOffset);
227 _DevmemImportStructRelease(psMemDesc->psImport);
230 OSLockDestroy(psMemDesc->sCPUMemDesc.hLock);
231 OSLockDestroy(psMemDesc->sDeviceMemDesc.hLock);
232 OSLockDestroy(psMemDesc->hLock);
233 OSFreeMem(psMemDesc);
238 IMG_VOID _DevmemMemDescDiscard(DEVMEM_MEMDESC *psMemDesc)
240 PVR_ASSERT(OSAtomicRead(&psMemDesc->hRefCount) == 0);
242 OSLockDestroy(psMemDesc->sCPUMemDesc.hLock);
243 OSLockDestroy(psMemDesc->sDeviceMemDesc.hLock);
244 OSLockDestroy(psMemDesc->hLock);
245 OSFreeMem(psMemDesc);
250 PVRSRV_ERROR _DevmemValidateParams(IMG_DEVMEM_SIZE_T uiSize,
251 IMG_DEVMEM_ALIGN_T uiAlign,
252 DEVMEM_FLAGS_T uiFlags)
254 if (!(uiFlags & PVRSRV_MEMALLOCFLAG_GPU_READABLE))
256 /* Don't support memory not GPU readable currently */
257 return PVRSRV_ERROR_INVALID_PARAMS;
260 if ((uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC) &&
261 (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC))
263 /* Zero on Alloc and Poison on Alloc are mutually exclusive */
264 return PVRSRV_ERROR_INVALID_PARAMS;
267 if (uiAlign & (uiAlign-1))
269 return PVRSRV_ERROR_INVALID_PARAMS;
272 /* Verify that size is a positive integer multiple of alignment */
274 if (uiSize & (uiAlign-1))
276 /* Size not a multiple of alignment */
277 return PVRSRV_ERROR_INVALID_PARAMS;
282 return PVRSRV_ERROR_INVALID_PARAMS;
289 Allocate and init an import structure
292 PVRSRV_ERROR _DevmemImportStructAlloc(IMG_HANDLE hBridge,
293 IMG_BOOL bExportable,
294 DEVMEM_IMPORT **ppsImport)
296 DEVMEM_IMPORT *psImport;
299 psImport = OSAllocMem(sizeof *psImport);
300 if (psImport == IMG_NULL)
302 return PVRSRV_ERROR_OUT_OF_MEMORY;
305 /* Setup some known bad values for things we don't have yet */
306 psImport->sDeviceImport.hReservation = LACK_OF_RESERVATION_POISON;
307 psImport->sDeviceImport.hMapping = LACK_OF_MAPPING_POISON;
308 psImport->sDeviceImport.psHeap = IMG_NULL;
309 psImport->sDeviceImport.bMapped = IMG_FALSE;
311 eError = OSLockCreate(&psImport->sDeviceImport.hLock, LOCK_TYPE_PASSIVE);
312 if (eError != PVRSRV_OK)
314 goto failDIOSLockCreate;
317 psImport->sCPUImport.hOSMMapData = IMG_NULL;
318 psImport->sCPUImport.pvCPUVAddr = IMG_NULL;
320 eError = OSLockCreate(&psImport->sCPUImport.hLock, LOCK_TYPE_PASSIVE);
321 if (eError != PVRSRV_OK)
323 goto failCIOSLockCreate;
326 /* Set up common elements */
327 psImport->hBridge = hBridge;
328 psImport->bExportable = bExportable;
330 /* Setup refcounts */
331 psImport->sDeviceImport.ui32RefCount = 0;
332 psImport->sCPUImport.ui32RefCount = 0;
333 OSAtomicWrite(&psImport->hRefCount, 0);
335 /* Create the lock */
336 eError = OSLockCreate(&psImport->hLock, LOCK_TYPE_PASSIVE);
337 if (eError != PVRSRV_OK)
342 #if !defined(__KERNEL__) && defined(SUPPORT_ION)
343 psImport->sCPUImport.iDmaBufFd = -1;
346 *ppsImport = psImport;
351 OSLockDestroy(psImport->sCPUImport.hLock);
353 OSLockDestroy(psImport->sDeviceImport.hLock);
356 PVR_ASSERT(eError != PVRSRV_OK);
362 Initialise the import structure
365 IMG_VOID _DevmemImportStructInit(DEVMEM_IMPORT *psImport,
366 IMG_DEVMEM_SIZE_T uiSize,
367 IMG_DEVMEM_ALIGN_T uiAlign,
368 DEVMEM_FLAGS_T uiFlags,
371 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
377 psImport->uiSize = uiSize;
378 psImport->uiAlign = uiAlign;
379 psImport->uiFlags = uiFlags;
380 psImport->hPMR = hPMR;
381 OSAtomicWrite(&psImport->hRefCount, 1);
385 Map an import to the device
388 PVRSRV_ERROR _DevmemImportStructDevMap(DEVMEM_HEAP *psHeap,
390 DEVMEM_IMPORT *psImport)
392 DEVMEM_DEVICE_IMPORT *psDeviceImport;
394 RA_BASE_T uiAllocatedAddr;
395 RA_LENGTH_T uiAllocatedSize;
396 IMG_DEV_VIRTADDR sBase;
397 IMG_HANDLE hReservation;
401 /* Round the provided import alignment to the configured heap alignment */
402 uiAlign = 1ULL << psHeap->uiLog2ImportAlignment;
403 uiAlign = (psImport->uiAlign + uiAlign - 1) & ~(uiAlign-1);
405 psDeviceImport = &psImport->sDeviceImport;
407 OSLockAcquire(psDeviceImport->hLock);
408 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
411 psDeviceImport->ui32RefCount,
412 psDeviceImport->ui32RefCount+1);
414 if (psDeviceImport->ui32RefCount++ == 0)
416 _DevmemImportStructAcquire(psImport);
418 OSAtomicIncrement(&psHeap->hImportCount);
420 if (psHeap->psCtx->hBridge != psImport->hBridge)
423 The import was done with a different connection then the
424 memory context which means they are not compatible.
426 eError = PVRSRV_ERROR_INVALID_PARAMS;
430 /* Allocate space in the VM */
431 bStatus = RA_Alloc(psHeap->psQuantizedVMRA,
433 0, /* flags: this RA doesn't use flags*/
437 IMG_NULL /* don't care about per-import priv data */
441 eError = PVRSRV_ERROR_DEVICEMEM_OUT_OF_DEVICE_VM;
445 /* No reason for the allocated virtual size to be different from
447 PVR_ASSERT(uiAllocatedSize == psImport->uiSize);
449 sBase.uiAddr = uiAllocatedAddr;
451 /* Setup page tables for the allocated VM space */
452 eError = BridgeDevmemIntReserveRange(psHeap->psCtx->hBridge,
453 psHeap->hDevMemServerHeap,
457 if (eError != PVRSRV_OK)
464 DEVMEM_FLAGS_T uiMapFlags;
466 uiMapFlags = psImport->uiFlags & PVRSRV_MEMALLOCFLAGS_PERMAPPINGFLAGSMASK;
468 /* Actually map the PMR to allocated VM space */
469 eError = BridgeDevmemIntMapPMR(psHeap->psCtx->hBridge,
470 psHeap->hDevMemServerHeap,
474 &psDeviceImport->hMapping);
475 if (eError != PVRSRV_OK)
479 psDeviceImport->bMapped = IMG_TRUE;
482 /* Setup device mapping specific parts of the mapping info */
483 psDeviceImport->hReservation = hReservation;
484 psDeviceImport->sDevVAddr.uiAddr = uiAllocatedAddr;
485 psDeviceImport->psHeap = psHeap;
490 Check that we've been asked to map it into the
491 same heap 2nd time around
493 if (psHeap != psDeviceImport->psHeap)
495 eError = PVRSRV_ERROR_INVALID_HEAP;
499 OSLockRelease(psDeviceImport->hLock);
504 BridgeDevmemIntUnreserveRange(psHeap->psCtx->hBridge,
507 RA_Free(psHeap->psQuantizedVMRA,
511 _DevmemImportStructRelease(psImport);
512 OSAtomicDecrement(&psHeap->hImportCount);
514 OSLockRelease(psDeviceImport->hLock);
515 PVR_ASSERT(eError != PVRSRV_OK);
520 Unmap an import from the Device
523 IMG_VOID _DevmemImportStructDevUnmap(DEVMEM_IMPORT *psImport)
526 DEVMEM_DEVICE_IMPORT *psDeviceImport;
528 psDeviceImport = &psImport->sDeviceImport;
530 OSLockAcquire(psDeviceImport->hLock);
531 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
534 psDeviceImport->ui32RefCount,
535 psDeviceImport->ui32RefCount-1);
537 if (--psDeviceImport->ui32RefCount == 0)
539 DEVMEM_HEAP *psHeap = psDeviceImport->psHeap;
541 if (psDeviceImport->bMapped)
543 eError = BridgeDevmemIntUnmapPMR(psImport->hBridge,
544 psDeviceImport->hMapping);
545 PVR_ASSERT(eError == PVRSRV_OK);
548 eError = BridgeDevmemIntUnreserveRange(psImport->hBridge,
549 psDeviceImport->hReservation);
550 PVR_ASSERT(eError == PVRSRV_OK);
552 RA_Free(psHeap->psQuantizedVMRA,
553 psDeviceImport->sDevVAddr.uiAddr);
555 OSLockRelease(psDeviceImport->hLock);
557 _DevmemImportStructRelease(psImport);
559 OSAtomicDecrement(&psHeap->hImportCount);
563 OSLockRelease(psDeviceImport->hLock);
568 Map an import into the CPU
571 PVRSRV_ERROR _DevmemImportStructCPUMap(DEVMEM_IMPORT *psImport)
574 DEVMEM_CPU_IMPORT *psCPUImport;
575 IMG_SIZE_T uiMappingLength;
577 psCPUImport = &psImport->sCPUImport;
579 OSLockAcquire(psCPUImport->hLock);
580 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
583 psCPUImport->ui32RefCount,
584 psCPUImport->ui32RefCount+1);
586 if (psCPUImport->ui32RefCount++ == 0)
588 _DevmemImportStructAcquire(psImport);
590 #if !defined(__KERNEL__) && defined(SUPPORT_ION)
591 if (psImport->sCPUImport.iDmaBufFd >= 0)
594 int iProt = PROT_READ;
596 iProt |= (psImport->uiFlags & PVRSRV_MEMALLOCFLAG_CPU_WRITEABLE) ? PROT_WRITE : 0;
597 /* For ion imports, use the ion fd and mmap facility to map the
598 * buffer to user space. We can bypass the services bridge in
599 * this case and possibly save some time.
601 pvCPUVAddr = mmap(NULL, psImport->uiSize, iProt,
602 MAP_SHARED, psImport->sCPUImport.iDmaBufFd, 0);
604 if (pvCPUVAddr == MAP_FAILED)
606 eError = PVRSRV_ERROR_DEVICEMEM_MAP_FAILED;
610 psCPUImport->hOSMMapData = pvCPUVAddr;
611 psCPUImport->pvCPUVAddr = pvCPUVAddr;
612 uiMappingLength = psImport->uiSize;
617 eError = OSMMapPMR(psImport->hBridge,
621 &psCPUImport->hOSMMapData,
622 &psCPUImport->pvCPUVAddr,
624 if (eError != PVRSRV_OK)
630 /* There is no reason the mapping length is different to the size */
631 PVR_ASSERT(uiMappingLength == psImport->uiSize);
633 OSLockRelease(psCPUImport->hLock);
638 psCPUImport->ui32RefCount--;
639 _DevmemImportStructRelease(psImport);
640 OSLockRelease(psCPUImport->hLock);
641 PVR_ASSERT(eError != PVRSRV_OK);
646 Unmap an import from the CPU
649 IMG_VOID _DevmemImportStructCPUUnmap(DEVMEM_IMPORT *psImport)
651 DEVMEM_CPU_IMPORT *psCPUImport;
653 psCPUImport = &psImport->sCPUImport;
655 OSLockAcquire(psCPUImport->hLock);
656 DEVMEM_REFCOUNT_PRINT("%s (%p) %d->%d",
659 psCPUImport->ui32RefCount,
660 psCPUImport->ui32RefCount-1);
662 if (--psCPUImport->ui32RefCount == 0)
664 /* FIXME: psImport->uiSize is a 64-bit quantity where as the 5th
665 * argument to OSUnmapPMR is a 32-bit quantity on 32-bit systems
666 * hence a compiler warning of implicit cast and loss of data.
667 * Added explicit cast and assert to remove warning.
669 #if (defined(_WIN32) && !defined(_WIN64)) || (defined(LINUX) && defined(__i386__))
670 PVR_ASSERT(psImport->uiSize<IMG_UINT32_MAX);
673 #if !defined(__KERNEL__) && defined(SUPPORT_ION)
674 if (psImport->sCPUImport.iDmaBufFd >= 0)
676 munmap(psCPUImport->hOSMMapData, psImport->uiSize);
681 OSMUnmapPMR(psImport->hBridge,
683 psCPUImport->hOSMMapData,
684 psCPUImport->pvCPUVAddr,
685 (IMG_SIZE_T)psImport->uiSize);
688 OSLockRelease(psCPUImport->hLock);
690 _DevmemImportStructRelease(psImport);
694 OSLockRelease(psCPUImport->hLock);