RK3368 GPU version Rogue M 1.28
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / rogue_m / services / server / env / linux / physmem_dmabuf.c
1 /*************************************************************************/ /*!
2 @File           physmem_dmabuf.c
3 @Title          dmabuf memory allocator
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description    Part of the memory management. This module is responsible for
6                 implementing the function callbacks for dmabuf memory.
7 @License        Dual MIT/GPLv2
8
9 The contents of this file are subject to the MIT license as set out below.
10
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:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
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.
24
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.
32
33 This License is also included in this distribution in the file called
34 "MIT-COPYING".
35
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 */ /**************************************************************************/
44
45 #if defined(SUPPORT_DRM)
46 #include "pvr_drm.h"
47 #endif
48
49 #if !defined(SUPPORT_DRM) || defined(PVR_DRM_USE_PRIME)
50
51 #include "img_types.h"
52 #include "pvr_debug.h"
53 #include "pvrsrv_error.h"
54 #include "pvrsrv_memallocflags.h"
55
56 #include "allocmem.h"
57 #include "osfunc.h"
58 #include "pvrsrv.h"
59 #include "pdump_physmem.h"
60 #include "pmr.h"
61 #include "pmr_impl.h"
62 #include "physmem_dmabuf.h"
63
64 #if defined(SUPPORT_ION)
65 #include "hash.h"
66 #include "ion_sys.h"
67 #endif
68
69 #if defined(PVR_RI_DEBUG)
70 #include "ri_server.h"
71 #endif
72
73 #include <linux/err.h>
74 #include <linux/slab.h>
75 #include <linux/dma-buf.h>
76 #include <linux/scatterlist.h>
77
78 #if defined(LDM_PCI)
79 #include <linux/pci.h>
80 #elif defined(LDM_PLATFORM)
81 #include <linux/platform_device.h>
82 #else
83 #error Either LDM_PCI or LDM_PLATFORM must be defined
84 #endif
85
86 typedef struct _PMR_DMA_BUF_DATA_
87 {
88         /* Filled in at PMR create time */
89         PHYS_HEAP *psPhysHeap;
90         struct dma_buf_attachment *psAttachment;
91         PFN_DESTROY_DMABUF_PMR pfnDestroy;
92         IMG_BOOL bPoisonOnFree;
93         IMG_HANDLE hPDumpAllocInfo;
94
95         /* Modified by PMR lock/unlock */
96         struct sg_table *psSgTable;
97         IMG_DEV_PHYADDR *pasDevPhysAddr;
98         IMG_UINT32 ui32PageCount;
99 } PMR_DMA_BUF_DATA;
100
101 /* Start size of the g_psDmaBufHash hash table */
102 #define DMA_BUF_HASH_SIZE 20
103
104 extern
105 #if defined(LDM_PCI)
106         struct pci_dev
107 #elif defined(LDM_PLATFORM)
108         struct platform_device
109 #endif
110         *gpsPVRLDMDev;
111
112 #if defined(SUPPORT_ION)
113 static HASH_TABLE *g_psDmaBufHash = IMG_NULL;
114 static IMG_UINT32 g_ui32HashRefCount = 0;
115 #endif
116
117 #if defined(PVR_ANDROID_ION_USE_SG_LENGTH)
118 #define pvr_sg_length(sg) ((sg)->length)
119 #else
120 #define pvr_sg_length(sg) sg_dma_len(sg)
121 #endif
122
123 static const IMG_CHAR _AllocPoison[] = "^PoIsOn";
124 static const IMG_UINT32 _AllocPoisonSize = 7;
125 static const IMG_CHAR _FreePoison[] = "<DEAD-BEEF>";
126 static const IMG_UINT32 _FreePoisonSize = 11;
127
128 static void _Poison(IMG_PVOID pvKernAddr,
129                     IMG_DEVMEM_SIZE_T uiBufferSize,
130                     const IMG_CHAR *pacPoisonData,
131                     IMG_SIZE_T uiPoisonSize)
132 {
133         IMG_DEVMEM_SIZE_T uiDestByteIndex;
134         IMG_CHAR *pcDest = pvKernAddr;
135         IMG_UINT32 uiSrcByteIndex = 0;
136
137         for (uiDestByteIndex = 0; uiDestByteIndex < uiBufferSize; uiDestByteIndex++)
138         {
139                 pcDest[uiDestByteIndex] = pacPoisonData[uiSrcByteIndex];
140                 uiSrcByteIndex++;
141                 if (uiSrcByteIndex == uiPoisonSize)
142                 {
143                         uiSrcByteIndex = 0;
144                 }
145         }
146 }
147
148
149 /*****************************************************************************
150  *                       PMR callback functions                              *
151  *****************************************************************************/
152
153 static PVRSRV_ERROR PMRFinalizeDmaBuf(PMR_IMPL_PRIVDATA pvPriv)
154 {
155         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
156         struct dma_buf *psDmaBuf = psPrivData->psAttachment->dmabuf;
157         PVRSRV_ERROR eError;
158
159         if (psPrivData->hPDumpAllocInfo)
160         {
161                 PDumpPMRFree(psPrivData->hPDumpAllocInfo);
162                 psPrivData->hPDumpAllocInfo = NULL;
163         }
164
165         if (psPrivData->bPoisonOnFree)
166         {
167                 IMG_PVOID pvKernAddr;
168                 int i, err;
169
170                 err = dma_buf_begin_cpu_access(psDmaBuf, 0, psDmaBuf->size, DMA_FROM_DEVICE);
171                 if (err)
172                 {
173                         PVR_DPF((PVR_DBG_ERROR, "%s: Failed to begin cpu access for free poisoning", __func__));
174                         PVR_ASSERT(IMG_FALSE);
175                         goto exit;
176                 }
177
178                 for (i = 0; i < psDmaBuf->size / PAGE_SIZE; i++)
179                 {
180                         pvKernAddr = dma_buf_kmap(psDmaBuf, i);
181                         if (IS_ERR_OR_NULL(pvKernAddr))
182                         {
183                                 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to poison allocation before free", __func__));
184                                 PVR_ASSERT(IMG_FALSE);
185                                 goto exit_end_access;
186                         }
187
188                         _Poison(pvKernAddr, PAGE_SIZE, _FreePoison, _FreePoisonSize);
189
190                         dma_buf_kunmap(psDmaBuf, i, pvKernAddr);
191                 }
192
193 exit_end_access:
194                 dma_buf_end_cpu_access(psDmaBuf, 0, psDmaBuf->size, DMA_TO_DEVICE);
195         }
196
197 exit:
198         if (psPrivData->pfnDestroy)
199         {
200                 eError = psPrivData->pfnDestroy(psPrivData->psPhysHeap, psPrivData->psAttachment);
201                 if (eError != PVRSRV_OK)
202                 {
203                         return eError;
204                 }
205         }
206
207         OSFreeMem(psPrivData);
208
209         return PVRSRV_OK;
210 }
211
212 static PVRSRV_ERROR PMRLockPhysAddressesDmaBuf(PMR_IMPL_PRIVDATA pvPriv,
213                                                IMG_UINT32 uiLog2DevPageSize)
214 {
215         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
216         struct dma_buf_attachment *psAttachment = psPrivData->psAttachment;
217         IMG_DEV_PHYADDR *pasDevPhysAddr = NULL;
218         IMG_CPU_PHYADDR sCpuPhysAddr;
219         IMG_UINT32 ui32PageCount = 0;
220         struct scatterlist *sg;
221         struct sg_table *table;
222         PVRSRV_ERROR eError;
223         IMG_UINT32 i;
224
225         table = dma_buf_map_attachment(psAttachment, DMA_BIDIRECTIONAL);
226         if (!table)
227         {
228                 eError = PVRSRV_ERROR_INVALID_PARAMS;
229                 goto fail_map;
230         }
231
232         /*
233          * We do a two pass process, 1st workout how many pages there
234          * are, 2nd fill in the data.
235          */
236         for_each_sg(table->sgl, sg, table->nents, i)
237         {
238                 ui32PageCount += PAGE_ALIGN(pvr_sg_length(sg)) / PAGE_SIZE;
239         }
240
241         if (WARN_ON(!ui32PageCount))
242         {
243                 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to lock dmabuf with no pages",
244                                  __func__));
245                 eError = PVRSRV_ERROR_INVALID_PARAMS;
246                 goto fail_page_count;
247         }
248
249         pasDevPhysAddr = OSAllocMem(sizeof(*pasDevPhysAddr) * ui32PageCount);
250         if (!pasDevPhysAddr)
251         {
252                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
253                 goto fail_alloc;
254         }
255
256         ui32PageCount = 0;
257
258         for_each_sg(table->sgl, sg, table->nents, i)
259         {
260                 IMG_UINT32 j;
261
262                 for (j = 0; j < pvr_sg_length(sg); j += PAGE_SIZE)
263                 {
264                         /* Pass 2: Get the page data */
265                         sCpuPhysAddr.uiAddr = sg_phys(sg) + j;
266
267                         PhysHeapCpuPAddrToDevPAddr(psPrivData->psPhysHeap, 
268                                                    1,
269                                                    &pasDevPhysAddr[ui32PageCount],
270                                                    &sCpuPhysAddr);
271                         ui32PageCount++;
272                 }
273         }
274
275         psPrivData->pasDevPhysAddr = pasDevPhysAddr;
276         psPrivData->ui32PageCount = ui32PageCount;
277         psPrivData->psSgTable = table;
278
279         return PVRSRV_OK;
280
281 fail_alloc:
282 fail_page_count:
283         dma_buf_unmap_attachment(psAttachment, table, DMA_BIDIRECTIONAL);
284
285 fail_map:
286         PVR_ASSERT(eError!= PVRSRV_OK);
287         return eError;
288 }
289
290 static PVRSRV_ERROR PMRUnlockPhysAddressesDmaBuf(PMR_IMPL_PRIVDATA pvPriv)
291 {
292         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
293         struct dma_buf_attachment *psAttachment = psPrivData->psAttachment;
294         struct sg_table *psSgTable = psPrivData->psSgTable;
295
296         OSFreeMem(psPrivData->pasDevPhysAddr);
297
298         psPrivData->pasDevPhysAddr = NULL;
299         psPrivData->ui32PageCount = 0;
300
301         dma_buf_unmap_attachment(psAttachment, psSgTable, DMA_BIDIRECTIONAL);
302
303         return PVRSRV_OK;
304 }
305
306 static PVRSRV_ERROR PMRDevPhysAddrDmaBuf(PMR_IMPL_PRIVDATA pvPriv,
307                                          IMG_UINT32 ui32NumOfPages,
308                                          IMG_DEVMEM_OFFSET_T *puiOffset,
309                                          IMG_BOOL *pbValid,
310                                          IMG_DEV_PHYADDR *psDevPAddr)
311 {
312         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
313         IMG_UINT32 ui32PageIndex;
314         IMG_UINT32 idx;
315
316         for (idx=0; idx < ui32NumOfPages; idx++)
317         {
318                 if (pbValid[idx])
319                 {
320                         IMG_UINT32 ui32InPageOffset;
321
322                         ui32PageIndex = puiOffset[idx] >> PAGE_SHIFT;
323                         ui32InPageOffset = puiOffset[idx] - ((IMG_DEVMEM_OFFSET_T)ui32PageIndex << PAGE_SHIFT);
324
325                         PVR_ASSERT(ui32PageIndex < psPrivData->ui32PageCount);
326                         PVR_ASSERT(ui32InPageOffset < PAGE_SIZE);
327
328                         psDevPAddr[idx].uiAddr = psPrivData->pasDevPhysAddr[ui32PageIndex].uiAddr + ui32InPageOffset;
329                 }
330         }
331
332         return PVRSRV_OK;
333 }
334
335 static PVRSRV_ERROR
336 PMRAcquireKernelMappingDataDmaBuf(PMR_IMPL_PRIVDATA pvPriv,
337                                   IMG_SIZE_T uiOffset,
338                                   IMG_SIZE_T uiSize,
339                                   void **ppvKernelAddressOut,
340                                   IMG_HANDLE *phHandleOut,
341                                   PMR_FLAGS_T ulFlags)
342 {
343         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
344         struct dma_buf *psDmaBuf = psPrivData->psAttachment->dmabuf;
345         IMG_PVOID pvKernAddr;
346         PVRSRV_ERROR eError;
347         int err;
348
349         err = dma_buf_begin_cpu_access(psDmaBuf, 0, psDmaBuf->size, DMA_BIDIRECTIONAL);
350         if (err)
351         {
352                 eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
353                 goto fail;
354         }
355
356         pvKernAddr = dma_buf_vmap(psDmaBuf);
357         if (IS_ERR_OR_NULL(pvKernAddr))
358         {
359                 eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
360                 goto fail_kmap;
361         }
362
363         *ppvKernelAddressOut = pvKernAddr + uiOffset;
364         *phHandleOut = pvKernAddr;
365
366         return PVRSRV_OK;
367
368 fail_kmap:
369         dma_buf_end_cpu_access(psDmaBuf, 0, psDmaBuf->size, DMA_BIDIRECTIONAL);
370
371 fail:
372         PVR_ASSERT(eError != PVRSRV_OK);
373         return eError;
374 }
375
376 static void PMRReleaseKernelMappingDataDmaBuf(PMR_IMPL_PRIVDATA pvPriv,
377                                               IMG_HANDLE hHandle)
378 {
379         PMR_DMA_BUF_DATA *psPrivData = pvPriv;
380         struct dma_buf *psDmaBuf = psPrivData->psAttachment->dmabuf;
381         IMG_PVOID pvKernAddr = hHandle;
382
383         dma_buf_vunmap(psDmaBuf, pvKernAddr);
384
385         dma_buf_end_cpu_access(psDmaBuf, 0, psDmaBuf->size, DMA_BIDIRECTIONAL);
386 }
387
388 static PMR_IMPL_FUNCTAB _sPMRDmaBufFuncTab =
389 {
390         .pfnLockPhysAddresses           = PMRLockPhysAddressesDmaBuf,
391         .pfnUnlockPhysAddresses         = PMRUnlockPhysAddressesDmaBuf,
392         .pfnDevPhysAddr                 = PMRDevPhysAddrDmaBuf,
393         .pfnAcquireKernelMappingData    = PMRAcquireKernelMappingDataDmaBuf,
394         .pfnReleaseKernelMappingData    = PMRReleaseKernelMappingDataDmaBuf,
395         .pfnFinalize                    = PMRFinalizeDmaBuf,
396 };
397
398 /*****************************************************************************
399  *                       Public facing interface                             *
400  *****************************************************************************/
401
402 PVRSRV_ERROR
403 PhysmemCreateNewDmaBufBackedPMR(PHYS_HEAP *psHeap,
404                                 struct dma_buf_attachment *psAttachment,
405                                 PFN_DESTROY_DMABUF_PMR pfnDestroy,
406                                 PVRSRV_MEMALLOCFLAGS_T uiFlags,
407                                 PMR **ppsPMRPtr)
408 {
409         struct dma_buf *psDmaBuf = psAttachment->dmabuf;
410         PMR_DMA_BUF_DATA *psPrivData;
411         IMG_BOOL bMappingTable = IMG_TRUE;
412         PMR_FLAGS_T uiPMRFlags;
413         IMG_BOOL bZeroOnAlloc;
414         IMG_BOOL bPoisonOnAlloc;
415         IMG_BOOL bPoisonOnFree;
416         PVRSRV_ERROR eError;
417
418         if (uiFlags & PVRSRV_MEMALLOCFLAG_ZERO_ON_ALLOC)
419         {
420                 bZeroOnAlloc = IMG_TRUE;
421         }
422         else
423         {
424                 bZeroOnAlloc = IMG_FALSE;
425         }
426
427         if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_ALLOC)
428         {
429                 bPoisonOnAlloc = IMG_TRUE;
430         }
431         else
432         {
433                 bPoisonOnAlloc = IMG_FALSE;
434         }
435
436         if (uiFlags & PVRSRV_MEMALLOCFLAG_POISON_ON_FREE)
437         {
438                 bPoisonOnFree = IMG_TRUE;
439         }
440         else
441         {
442                 bPoisonOnFree = IMG_FALSE;
443         }
444
445         if (bZeroOnAlloc && bPoisonOnFree)
446         {
447                 /* Zero on Alloc and Poison on Alloc are mutually exclusive */
448                 eError = PVRSRV_ERROR_INVALID_PARAMS;
449                 goto fail_params;
450         }
451
452         psPrivData = OSAllocZMem(sizeof(*psPrivData));
453         if (psPrivData == NULL)
454         {
455                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
456                 goto fail_priv_alloc;
457         }
458
459         psPrivData->psPhysHeap = psHeap;
460         psPrivData->psAttachment = psAttachment;
461         psPrivData->pfnDestroy = pfnDestroy;
462         psPrivData->bPoisonOnFree = bPoisonOnFree;
463
464         if (bZeroOnAlloc || bPoisonOnAlloc)
465         {
466                 IMG_PVOID pvKernAddr;
467                 int i, err;
468
469                 err = dma_buf_begin_cpu_access(psDmaBuf,
470                                                0,
471                                                psDmaBuf->size,
472                                                DMA_FROM_DEVICE);
473                 if (err)
474                 {
475                         eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
476                         goto fail_begin;
477                 }
478
479                 for (i = 0; i < psDmaBuf->size / PAGE_SIZE; i++)
480                 {
481                         pvKernAddr = dma_buf_kmap(psDmaBuf, i);
482                         if (IS_ERR_OR_NULL(pvKernAddr))
483                         {
484                                 PVR_DPF((PVR_DBG_ERROR,
485                                          "%s: Failed to map page for %s",
486                                          __func__,
487                                          bZeroOnAlloc ? "zeroing" : "poisoning"));
488                                 eError = PVRSRV_ERROR_PMR_NO_KERNEL_MAPPING;
489
490                                 dma_buf_end_cpu_access(psDmaBuf,
491                                                        0,
492                                                        psDmaBuf->size,
493                                                        DMA_TO_DEVICE);
494
495                                 goto fail_kmap;
496                         }
497
498                         if (bZeroOnAlloc)
499                         {
500                                 memset(pvKernAddr, 0, PAGE_SIZE);
501                         }
502                         else
503                         {
504                                 _Poison(pvKernAddr, PAGE_SIZE, _AllocPoison, _AllocPoisonSize);
505                         }
506
507                         dma_buf_kunmap(psDmaBuf, i, pvKernAddr);
508                 }
509
510                 dma_buf_end_cpu_access(psDmaBuf,
511                                        0,
512                                        psDmaBuf->size,
513                                        DMA_TO_DEVICE);
514         }
515
516         uiPMRFlags = (PMR_FLAGS_T)(uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK);
517
518         /*
519          * Check no significant bits were lost in cast due to different
520          * bit widths for flags
521          */
522         PVR_ASSERT(uiPMRFlags == (uiFlags & PVRSRV_MEMALLOCFLAGS_PMRFLAGSMASK));
523
524         eError = PMRCreatePMR(psHeap,
525                               psDmaBuf->size,
526                               psDmaBuf->size,
527                               1,
528                               1,
529                               &bMappingTable,
530                               PAGE_SHIFT,
531                               uiPMRFlags,
532                               "PMRDMABUF",
533                               &_sPMRDmaBufFuncTab,
534                               psPrivData,
535                               ppsPMRPtr,
536                               &psPrivData->hPDumpAllocInfo,
537                               IMG_FALSE);
538         if (eError != PVRSRV_OK)
539         {
540                 PVR_DPF((PVR_DBG_ERROR, "%s: Failed to create PMR", __func__));
541                 goto fail_create_pmr;
542         }
543
544 #if defined(PVR_RI_DEBUG)
545         eError = RIWritePMREntryKM(*ppsPMRPtr,
546                                    sizeof("DMABUF"),
547                                    "DMABUF",
548                                    psDmaBuf->size);
549         if (eError != PVRSRV_OK)
550         {
551                 PVR_DPF((PVR_DBG_WARNING,
552                          "%s: Failed to write PMR entry (%s)",
553                          __func__, PVRSRVGetErrorStringKM(eError)));
554         }
555 #endif
556
557         return PVRSRV_OK;
558
559 fail_create_pmr:
560 fail_kmap:
561 fail_begin:
562         OSFreeMem(psPrivData);
563
564 fail_priv_alloc:
565 fail_params:
566         PVR_ASSERT(eError != PVRSRV_OK);
567         return eError;
568 }
569
570 #if defined(SUPPORT_ION)
571 static PVRSRV_ERROR PhysmemDestroyDmaBuf(PHYS_HEAP *psHeap,
572                                          struct dma_buf_attachment *psAttachment)
573 {
574         struct dma_buf *psDmaBuf = psAttachment->dmabuf;
575
576         HASH_Remove(g_psDmaBufHash, (IMG_UINTPTR_T) psDmaBuf);
577         g_ui32HashRefCount--;
578
579         if (g_ui32HashRefCount == 0)
580         {
581                 HASH_Delete(g_psDmaBufHash);
582                 g_psDmaBufHash = IMG_NULL;
583         }
584
585         PhysHeapRelease(psHeap);
586
587         dma_buf_detach(psDmaBuf, psAttachment);
588         dma_buf_put(psDmaBuf);
589
590         return PVRSRV_OK;
591 }
592
593 PVRSRV_ERROR
594 PhysmemImportDmaBuf(CONNECTION_DATA *psConnection,
595                     IMG_INT fd,
596                     PVRSRV_MEMALLOCFLAGS_T uiFlags,
597                     PMR **ppsPMRPtr,
598                     IMG_DEVMEM_SIZE_T *puiSize,
599                     IMG_DEVMEM_ALIGN_T *puiAlign)
600 {
601         PMR *psPMR;
602         struct dma_buf_attachment *psAttachment;
603         struct dma_buf *psDmaBuf;
604         PHYS_HEAP *psHeap;
605         PVRSRV_ERROR eError;
606
607         if (!psConnection)
608         {
609                 eError = PVRSRV_ERROR_INVALID_PARAMS;
610                 goto fail_params;
611         }
612
613         /* Get the buffer handle */
614         psDmaBuf = dma_buf_get(fd);
615         if (IS_ERR_OR_NULL(psDmaBuf))
616         {
617                 PVR_DPF((PVR_DBG_ERROR, "%s: dma_buf_get failed", __func__));
618                 eError = PVRSRV_ERROR_BAD_MAPPING;
619                 goto fail_dma_buf_get;
620         }
621
622         if (g_psDmaBufHash)
623         {
624                 /* We have a hash table so check if we've seen this dmabuf before */
625                 psPMR = (PMR *) HASH_Retrieve(g_psDmaBufHash, (IMG_UINTPTR_T) psDmaBuf);
626                 if (psPMR)
627                 {
628                         /* Reuse the PMR we already created */
629                         PMRRefPMR(psPMR);
630
631                         *ppsPMRPtr = psPMR;
632                         *puiSize = psDmaBuf->size;
633                         *puiAlign = PAGE_SIZE;
634
635                         dma_buf_put(psDmaBuf);
636
637                         return PVRSRV_OK;
638                 }
639         }
640
641         /* Attach a fake device to to the dmabuf */
642         psAttachment = dma_buf_attach(psDmaBuf, &gpsPVRLDMDev->dev);
643         if (IS_ERR_OR_NULL(psAttachment))
644         {
645                 PVR_DPF((PVR_DBG_ERROR, "%s: dma_buf_get failed", __func__));
646                 eError = PVRSRV_ERROR_BAD_MAPPING;
647                 goto fail_dma_buf_attach;
648         }
649
650         /*
651          * Get the physical heap for this PMR
652          *      
653          * Note:
654          * While we have no way to determine the type of the buffer
655          * we just assume that all dmabufs are from the same
656          * physical heap.
657          */
658         eError = PhysHeapAcquire(IonPhysHeapID(), &psHeap);
659         if (eError != PVRSRV_OK)
660         {
661                 PVR_DPF((PVR_DBG_ERROR, "%s: Failed PhysHeapAcquire", __func__));
662                 goto fail_physheap;
663         }
664
665         eError = PhysmemCreateNewDmaBufBackedPMR(psHeap,
666                                                  psAttachment,
667                                                  PhysmemDestroyDmaBuf,
668                                                  uiFlags,
669                                                  &psPMR);
670         if (eError != PVRSRV_OK)
671         {
672                 goto fail_create_new_pmr;
673         }
674
675         if (!g_psDmaBufHash)
676         {
677                 /*
678                  * As different processes may import the same dmabuf we need to
679                  * create a hash table so we don't generate a duplicate PMR but
680                  * rather just take a reference on an existing one.
681                  */
682                 g_psDmaBufHash = HASH_Create(DMA_BUF_HASH_SIZE);
683                 if (!g_psDmaBufHash)
684                 {
685                         eError = PVRSRV_ERROR_OUT_OF_MEMORY;
686                         goto fail_hash_create;
687                 }
688         }
689
690         /* First time we've seen this dmabuf so store it in the hash table */
691         HASH_Insert(g_psDmaBufHash, (IMG_UINTPTR_T) psDmaBuf, (IMG_UINTPTR_T) psPMR);
692         g_ui32HashRefCount++;
693
694         *ppsPMRPtr = psPMR;
695         *puiSize = psDmaBuf->size;
696         *puiAlign = PAGE_SIZE;
697
698         return PVRSRV_OK;
699
700 fail_hash_create:
701         PMRUnrefPMR(psPMR);
702
703 fail_create_new_pmr:
704         PhysHeapRelease(psHeap);
705
706 fail_physheap:
707         dma_buf_detach(psDmaBuf, psAttachment);
708
709 fail_dma_buf_attach:
710         dma_buf_put(psDmaBuf);
711
712 fail_dma_buf_get:
713 fail_params:
714         PVR_ASSERT(eError != PVRSRV_OK);
715         return eError;
716 }
717 #endif /* defined(SUPPORT_ION) */
718 #endif /* !defined(SUPPORT_DRM) || defined(PVR_DRM_USE_PRIME) */