gpu: pvr: Reuse the same syncobject across all wraps
[sgx.git] / pvr / devicemem.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
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.
8  *
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.
13  *
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.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include <stddef.h>
28
29 #include "services_headers.h"
30 #include "buffer_manager.h"
31 #include "pdump_km.h"
32 #include "pvr_bridge_km.h"
33
34 #include <linux/pagemap.h>
35
36 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
37                                 u32 ui32Flags, u32 ui32Size, u32 ui32Alignment,
38                                 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo);
39
40 struct RESMAN_MAP_DEVICE_MEM_DATA {
41         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
42         struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo;
43 };
44
45 static inline void get_page_details(u32 vaddr, size_t byte_size,
46                 u32 *page_offset_out, int *page_count_out)
47 {
48         size_t host_page_size;
49         u32 page_offset;
50         int page_count;
51
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;
55
56         *page_offset_out = page_offset;
57         *page_count_out = page_count;
58 }
59
60 static inline int get_page_count(u32 vaddr, size_t byte_size)
61 {
62         u32 page_offset;
63         int page_count;
64
65         get_page_details(vaddr, byte_size, &page_offset, &page_count);
66
67         return page_count;
68 }
69
70 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapsKM(void *hDevCookie,
71                                         struct PVRSRV_HEAP_INFO *psHeapInfo)
72 {
73         struct PVRSRV_DEVICE_NODE *psDeviceNode;
74         u32 ui32HeapCount;
75         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
76         u32 i;
77
78         if (hDevCookie == NULL) {
79                 PVR_DPF(PVR_DBG_ERROR,
80                          "PVRSRVGetDeviceMemHeapsKM: hDevCookie invalid");
81                 PVR_DBG_BREAK;
82                 return PVRSRV_ERROR_INVALID_PARAMS;
83         }
84
85         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
86
87         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
88         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
89
90         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
91
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;
100         }
101
102         for (; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
103                 OSMemSet(psHeapInfo + i, 0, sizeof(*psHeapInfo));
104                 psHeapInfo[i].ui32HeapID = (u32) PVRSRV_UNDEFINED_HEAP_ID;
105         }
106
107         return PVRSRV_OK;
108 }
109
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)
116 {
117         struct PVRSRV_DEVICE_NODE *psDeviceNode;
118         u32 ui32HeapCount, ui32ClientHeapCount = 0;
119         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
120         void *hDevMemContext;
121         void *hDevMemHeap;
122         struct IMG_DEV_PHYADDR sPDDevPAddr;
123         u32 i;
124
125         if (hDevCookie == NULL) {
126                 PVR_DPF(PVR_DBG_ERROR,
127                          "PVRSRVCreateDeviceMemContextKM: hDevCookie invalid");
128                 PVR_DBG_BREAK;
129                 return PVRSRV_ERROR_INVALID_PARAMS;
130         }
131
132         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
133
134         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
135         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
136
137         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
138
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;
145         }
146
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++;
162                         break;
163                 case DEVICE_MEMORY_HEAP_PERCONTEXT:
164                         hDevMemHeap = BM_CreateHeap(hDevMemContext,
165                                                     &psDeviceMemoryHeap[i]);
166
167                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
168                                     psDeviceMemoryHeap[i].ui32HeapID;
169                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
170                                     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;
178
179                         ui32ClientHeapCount++;
180                         break;
181                 }
182         }
183
184         *pui32ClientHeapCount = ui32ClientHeapCount;
185         *phDevMemContext = hDevMemContext;
186
187         return PVRSRV_OK;
188 }
189
190 enum PVRSRV_ERROR PVRSRVDestroyDeviceMemContextKM(void *hDevCookie,
191                                              void *hDevMemContext,
192                                              IMG_BOOL *pbDestroyed)
193 {
194         int destroyed;
195
196         PVR_UNREFERENCED_PARAMETER(hDevCookie);
197
198         destroyed = pvr_put_ctx(hDevMemContext);
199         if (pbDestroyed)
200                 *pbDestroyed = destroyed ? IMG_TRUE : IMG_FALSE;
201
202         return PVRSRV_OK;
203 }
204
205 enum PVRSRV_ERROR PVRSRVGetDeviceMemHeapInfoKM(void *hDevCookie,
206                                           void *hDevMemContext,
207                                           u32 *pui32ClientHeapCount,
208                                           struct PVRSRV_HEAP_INFO *psHeapInfo,
209                                           IMG_BOOL *pbShared)
210 {
211         struct PVRSRV_DEVICE_NODE *psDeviceNode;
212         u32 ui32HeapCount, ui32ClientHeapCount = 0;
213         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
214         void *hDevMemHeap;
215         u32 i;
216
217         if (hDevCookie == NULL) {
218                 PVR_DPF(PVR_DBG_ERROR,
219                          "PVRSRVGetDeviceMemHeapInfoKM: hDevCookie invalid");
220                 PVR_DBG_BREAK;
221                 return PVRSRV_ERROR_INVALID_PARAMS;
222         }
223
224         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
225
226         ui32HeapCount = psDeviceNode->sDevMemoryInfo.ui32HeapCount;
227         psDeviceMemoryHeap = psDeviceNode->sDevMemoryInfo.psDeviceMemoryHeap;
228
229         PVR_ASSERT(ui32HeapCount <= PVRSRV_MAX_CLIENT_HEAPS);
230
231         for (i = 0; i < ui32HeapCount; i++) {
232                 switch (psDeviceMemoryHeap[i].DevMemHeapType) {
233                 case DEVICE_MEMORY_HEAP_SHARED_EXPORTED:
234                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
235                                     psDeviceMemoryHeap[i].ui32HeapID;
236                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
237                                     psDeviceMemoryHeap[i].hDevMemHeap;
238                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
239                                     psDeviceMemoryHeap[i].sDevVAddrBase;
240                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
241                                     psDeviceMemoryHeap[i].ui32HeapSize;
242                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
243                                     psDeviceMemoryHeap[i].ui32Attribs;
244                         pbShared[ui32ClientHeapCount] = IMG_TRUE;
245                         ui32ClientHeapCount++;
246                         break;
247                 case DEVICE_MEMORY_HEAP_PERCONTEXT:
248                         hDevMemHeap = BM_CreateHeap(hDevMemContext,
249                                                     &psDeviceMemoryHeap[i]);
250                         psHeapInfo[ui32ClientHeapCount].ui32HeapID =
251                                     psDeviceMemoryHeap[i].ui32HeapID;
252                         psHeapInfo[ui32ClientHeapCount].hDevMemHeap =
253                                     hDevMemHeap;
254                         psHeapInfo[ui32ClientHeapCount].sDevVAddrBase =
255                                     psDeviceMemoryHeap[i].sDevVAddrBase;
256                         psHeapInfo[ui32ClientHeapCount].ui32HeapByteSize =
257                                     psDeviceMemoryHeap[i].ui32HeapSize;
258                         psHeapInfo[ui32ClientHeapCount].ui32Attribs =
259                                     psDeviceMemoryHeap[i].ui32Attribs;
260                         pbShared[ui32ClientHeapCount] = IMG_FALSE;
261
262                         ui32ClientHeapCount++;
263                         break;
264                 }
265         }
266         *pui32ClientHeapCount = ui32ClientHeapCount;
267
268         return PVRSRV_OK;
269 }
270
271 static enum PVRSRV_ERROR AllocDeviceMem(void *hDevCookie, void *hDevMemHeap,
272                                    u32 ui32Flags, u32 ui32Size,
273                                    u32 ui32Alignment,
274                                    struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
275 {
276         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
277         void *hBuffer;
278
279         struct PVRSRV_MEMBLK *psMemBlock;
280         IMG_BOOL bBMError;
281
282         PVR_UNREFERENCED_PARAMETER(hDevCookie);
283
284         *ppsMemInfo = NULL;
285
286         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
287                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
288                        (void **) &psMemInfo, NULL) != PVRSRV_OK) {
289                 PVR_DPF(PVR_DBG_ERROR,
290                          "AllocDeviceMem: Failed to alloc memory for block");
291                 return PVRSRV_ERROR_OUT_OF_MEMORY;
292         }
293
294         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
295
296         psMemBlock = &(psMemInfo->sMemBlk);
297
298         psMemInfo->ui32Flags = ui32Flags | PVRSRV_MEM_RAM_BACKED_ALLOCATION;
299
300         bBMError = BM_Alloc(hDevMemHeap, NULL, ui32Size,
301                             &psMemInfo->ui32Flags, ui32Alignment, &hBuffer);
302
303         if (!bBMError) {
304                 PVR_DPF(PVR_DBG_ERROR, "AllocDeviceMem: BM_Alloc Failed");
305                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
306                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
307                           NULL);
308                 return PVRSRV_ERROR_OUT_OF_MEMORY;
309         }
310
311         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
312         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
313
314         psMemBlock->hBuffer = (void *)hBuffer;
315         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
316         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
317         psMemInfo->ui32AllocSize = ui32Size;
318
319         psMemInfo->pvSysBackupBuffer = NULL;
320
321         *ppsMemInfo = psMemInfo;
322
323         return PVRSRV_OK;
324 }
325
326 static enum PVRSRV_ERROR FreeDeviceMem(struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
327 {
328         void *hBuffer;
329
330         if (!psMemInfo)
331                 return PVRSRV_ERROR_INVALID_PARAMS;
332
333         hBuffer = psMemInfo->sMemBlk.hBuffer;
334         BM_Free(hBuffer, psMemInfo->ui32Flags);
335
336         if (psMemInfo->pvSysBackupBuffer)
337                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, psMemInfo->ui32AllocSize,
338                           psMemInfo->pvSysBackupBuffer, NULL);
339
340         OSFreeMem(PVRSRV_PAGEABLE_SELECT, sizeof(struct PVRSRV_KERNEL_MEM_INFO),
341                   psMemInfo, NULL);
342
343         return PVRSRV_OK;
344 }
345
346 enum PVRSRV_ERROR PVRSRVAllocSyncInfoKM(void *hDevCookie, void *hDevMemContext,
347                     struct PVRSRV_KERNEL_SYNC_INFO **ppsKernelSyncInfo)
348 {
349         void *hSyncDevMemHeap;
350         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
351         struct BM_CONTEXT *pBMContext;
352         enum PVRSRV_ERROR eError;
353         struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo;
354         struct PVRSRV_SYNC_DATA *psSyncData;
355
356         eError = OSAllocMem(PVRSRV_PAGEABLE_SELECT,
357                             sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
358                             (void **) &psKernelSyncInfo, NULL);
359         if (eError != PVRSRV_OK) {
360                 PVR_DPF(PVR_DBG_ERROR,
361                          "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
362                 return PVRSRV_ERROR_OUT_OF_MEMORY;
363         }
364
365         pBMContext = (struct BM_CONTEXT *)hDevMemContext;
366         psDevMemoryInfo = &pBMContext->psDeviceNode->sDevMemoryInfo;
367
368         hSyncDevMemHeap = psDevMemoryInfo->psDeviceMemoryHeap[psDevMemoryInfo->
369                                                 ui32SyncHeapID].hDevMemHeap;
370
371         eError = AllocDeviceMem(hDevCookie, hSyncDevMemHeap,
372                                 PVRSRV_MEM_CACHE_CONSISTENT,
373                                 sizeof(struct PVRSRV_SYNC_DATA), sizeof(u32),
374                                 &psKernelSyncInfo->psSyncDataMemInfoKM);
375
376         if (eError != PVRSRV_OK) {
377                 PVR_DPF(PVR_DBG_ERROR,
378                          "PVRSRVAllocSyncInfoKM: Failed to alloc memory");
379                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
380                           sizeof(struct PVRSRV_KERNEL_SYNC_INFO),
381                           psKernelSyncInfo, NULL);
382                 return PVRSRV_ERROR_OUT_OF_MEMORY;
383         }
384
385         psKernelSyncInfo->psSyncData =
386             psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM;
387         psSyncData = psKernelSyncInfo->psSyncData;
388
389         psSyncData->ui32WriteOpsPending = 0;
390         psSyncData->ui32WriteOpsComplete = 0;
391         psSyncData->ui32ReadOpsPending = 0;
392         psSyncData->ui32ReadOpsComplete = 0;
393         psSyncData->ui32LastOpDumpVal = 0;
394         psSyncData->ui32LastReadOpDumpVal = 0;
395
396 #if defined(PDUMP)
397         PDUMPMEM(psKernelSyncInfo->psSyncDataMemInfoKM->pvLinAddrKM,
398                  psKernelSyncInfo->psSyncDataMemInfoKM, 0,
399                  psKernelSyncInfo->psSyncDataMemInfoKM->ui32AllocSize,
400                  0, MAKEUNIQUETAG(psKernelSyncInfo->psSyncDataMemInfoKM));
401 #endif
402
403         psKernelSyncInfo->sWriteOpsCompleteDevVAddr.uiAddr =
404             psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
405             offsetof(struct PVRSRV_SYNC_DATA, ui32WriteOpsComplete);
406         psKernelSyncInfo->sReadOpsCompleteDevVAddr.uiAddr =
407             psKernelSyncInfo->psSyncDataMemInfoKM->sDevVAddr.uiAddr +
408             offsetof(struct PVRSRV_SYNC_DATA, ui32ReadOpsComplete);
409
410         psKernelSyncInfo->psSyncDataMemInfoKM->psKernelSyncInfo = NULL;
411
412         *ppsKernelSyncInfo = psKernelSyncInfo;
413
414         return PVRSRV_OK;
415 }
416
417 enum PVRSRV_ERROR PVRSRVFreeSyncInfoKM(
418                         struct PVRSRV_KERNEL_SYNC_INFO *psKernelSyncInfo)
419 {
420         FreeDeviceMem(psKernelSyncInfo->psSyncDataMemInfoKM);
421         OSFreeMem(PVRSRV_PAGEABLE_SELECT,
422                   sizeof(struct PVRSRV_KERNEL_SYNC_INFO), psKernelSyncInfo,
423                   NULL);
424
425         return PVRSRV_OK;
426 }
427
428 static inline
429 void get_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
430 {
431         syncinfo->refcount++;
432 }
433
434 static inline
435 void put_syncinfo(struct PVRSRV_KERNEL_SYNC_INFO *syncinfo)
436 {
437         struct PVRSRV_DEVICE_NODE *dev = syncinfo->dev_cookie;
438
439         syncinfo->refcount--;
440
441         if (!syncinfo->refcount) {
442                 HASH_Remove(dev->sync_table,
443                             syncinfo->phys_addr.uiAddr);
444                 PVRSRVFreeSyncInfoKM(syncinfo);
445         }
446 }
447
448 static inline
449 enum PVRSRV_ERROR alloc_or_reuse_syncinfo(void *dev_cookie,
450                     void *mem_context_handle,
451                     struct PVRSRV_KERNEL_SYNC_INFO **syncinfo,
452                     struct IMG_SYS_PHYADDR *phys_addr)
453 {
454         enum PVRSRV_ERROR error;
455         struct PVRSRV_DEVICE_NODE *dev;
456
457         dev = (struct PVRSRV_DEVICE_NODE *) dev_cookie;
458
459         *syncinfo = (struct PVRSRV_KERNEL_SYNC_INFO *)
460                                         HASH_Retrieve(dev->sync_table,
461                                                       phys_addr->uiAddr);
462
463         if (!*syncinfo) {
464                 /* Dont' have one so create one */
465                 error = PVRSRVAllocSyncInfoKM(dev_cookie, mem_context_handle,
466                                                syncinfo);
467
468                 if (error != PVRSRV_OK)
469                         return error;
470
471                 /* Setup our extra data */
472                 (*syncinfo)->phys_addr.uiAddr = phys_addr->uiAddr;
473                 (*syncinfo)->dev_cookie = dev_cookie;
474                 (*syncinfo)->refcount = 1;
475
476                 if (!HASH_Insert(dev->sync_table, phys_addr->uiAddr,
477                             (u32) *syncinfo)) {
478                         PVR_DPF(PVR_DBG_ERROR, "alloc_or_reuse_syncinfo: "
479                                 "Failed to add syncobject to hash table");
480                         return PVRSRV_ERROR_GENERIC;
481                 }
482         } else
483                 get_syncinfo(*syncinfo);
484
485         return PVRSRV_OK;
486 }
487
488 static enum PVRSRV_ERROR FreeDeviceMemCallBack(void *pvParam, u32 ui32Param)
489 {
490         enum PVRSRV_ERROR eError = PVRSRV_OK;
491         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
492
493         PVR_UNREFERENCED_PARAMETER(ui32Param);
494
495         psMemInfo->ui32RefCount--;
496
497         if (psMemInfo->ui32Flags & PVRSRV_MEM_EXPORTED) {
498                 void *hMemInfo = NULL;
499
500                 if (psMemInfo->ui32RefCount != 0) {
501                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
502                                         "mappings are open in other processes");
503                         return PVRSRV_ERROR_GENERIC;
504                 }
505
506                 eError = PVRSRVFindHandle(KERNEL_HANDLE_BASE,
507                                           &hMemInfo,
508                                           psMemInfo,
509                                           PVRSRV_HANDLE_TYPE_MEM_INFO);
510                 if (eError != PVRSRV_OK) {
511                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
512                                 "can't find exported meminfo in the "
513                                 "global handle list");
514                         return eError;
515                 }
516
517                 eError = PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
518                                              hMemInfo,
519                                              PVRSRV_HANDLE_TYPE_MEM_INFO);
520                 if (eError != PVRSRV_OK) {
521                         PVR_DPF(PVR_DBG_ERROR, "FreeDeviceMemCallBack: "
522                         "PVRSRVReleaseHandle failed for exported meminfo");
523                         return eError;
524                 }
525         }
526
527         PVR_ASSERT(psMemInfo->ui32RefCount == 0);
528
529         if (psMemInfo->psKernelSyncInfo)
530                 eError = PVRSRVFreeSyncInfoKM(psMemInfo->psKernelSyncInfo);
531
532         if (eError == PVRSRV_OK)
533                 eError = FreeDeviceMem(psMemInfo);
534
535         return eError;
536 }
537
538 enum PVRSRV_ERROR PVRSRVFreeDeviceMemKM(void *hDevCookie,
539                                    struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
540 {
541         PVR_UNREFERENCED_PARAMETER(hDevCookie);
542
543         if (!psMemInfo)
544                 return PVRSRV_ERROR_INVALID_PARAMS;
545
546         if (psMemInfo->sMemBlk.hResItem != NULL)
547                 ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
548         else
549                 FreeDeviceMemCallBack(psMemInfo, 0);
550
551         return PVRSRV_OK;
552 }
553
554 enum PVRSRV_ERROR PVRSRVAllocDeviceMemKM(void *hDevCookie,
555                                      struct PVRSRV_PER_PROCESS_DATA *psPerProc,
556                                      void *hDevMemHeap, u32 ui32Flags,
557                                      u32 ui32Size, u32 ui32Alignment,
558                                      struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
559 {
560         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
561         enum PVRSRV_ERROR eError;
562         struct BM_HEAP *psBMHeap;
563         void *hDevMemContext;
564
565         if (!hDevMemHeap || (ui32Size == 0))
566                 return PVRSRV_ERROR_INVALID_PARAMS;
567
568         eError = AllocDeviceMem(hDevCookie, hDevMemHeap, ui32Flags, ui32Size,
569                                 ui32Alignment, &psMemInfo);
570
571         if (eError != PVRSRV_OK)
572                 return eError;
573
574         if (ui32Flags & PVRSRV_MEM_NO_SYNCOBJ) {
575                 psMemInfo->psKernelSyncInfo = NULL;
576         } else {
577                 psBMHeap = (struct BM_HEAP *)hDevMemHeap;
578                 hDevMemContext = (void *) psBMHeap->pBMContext;
579                 eError = PVRSRVAllocSyncInfoKM(hDevCookie,
580                                                hDevMemContext,
581                                                &psMemInfo->psKernelSyncInfo);
582                 if (eError != PVRSRV_OK)
583                         goto free_mainalloc;
584         }
585
586         *ppsMemInfo = psMemInfo;
587
588         if (ui32Flags & PVRSRV_MEM_NO_RESMAN) {
589                 psMemInfo->sMemBlk.hResItem = NULL;
590         } else {
591                 psMemInfo->sMemBlk.hResItem =
592                     ResManRegisterRes(psPerProc->hResManContext,
593                                       RESMAN_TYPE_DEVICEMEM_ALLOCATION,
594                                       psMemInfo, 0, FreeDeviceMemCallBack);
595                 if (psMemInfo->sMemBlk.hResItem == NULL) {
596                         eError = PVRSRV_ERROR_OUT_OF_MEMORY;
597                         goto free_mainalloc;
598                 }
599         }
600
601         psMemInfo->ui32RefCount++;
602
603         return PVRSRV_OK;
604
605 free_mainalloc:
606         FreeDeviceMem(psMemInfo);
607
608         return eError;
609 }
610
611 enum PVRSRV_ERROR PVRSRVDissociateDeviceMemKM(void *hDevCookie,
612                                   struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
613 {
614         enum PVRSRV_ERROR eError;
615         struct PVRSRV_DEVICE_NODE *psDeviceNode = hDevCookie;
616
617         PVR_UNREFERENCED_PARAMETER(hDevCookie);
618
619         if (!psMemInfo)
620                 return PVRSRV_ERROR_INVALID_PARAMS;
621
622         eError = ResManDissociateRes(psMemInfo->sMemBlk.hResItem,
623                                     psDeviceNode->hResManContext);
624
625         PVR_ASSERT(eError == PVRSRV_OK);
626
627         return eError;
628 }
629
630 enum PVRSRV_ERROR PVRSRVGetFreeDeviceMemKM(u32 ui32Flags, u32 *pui32Total,
631                                       u32 *pui32Free, u32 *pui32LargestBlock)
632 {
633
634         PVR_UNREFERENCED_PARAMETER(ui32Flags);
635         PVR_UNREFERENCED_PARAMETER(pui32Total);
636         PVR_UNREFERENCED_PARAMETER(pui32Free);
637         PVR_UNREFERENCED_PARAMETER(pui32LargestBlock);
638
639         return PVRSRV_OK;
640 }
641
642 enum PVRSRV_ERROR PVRSRVUnwrapExtMemoryKM(
643                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
644 {
645         if (!psMemInfo)
646                 return PVRSRV_ERROR_INVALID_PARAMS;
647
648         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
649
650         return PVRSRV_OK;
651 }
652
653 static enum PVRSRV_ERROR UnwrapExtMemoryCallBack(void *pvParam, u32 ui32Param)
654 {
655         enum PVRSRV_ERROR eError = PVRSRV_OK;
656         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
657         void *hOSWrapMem;
658
659         PVR_UNREFERENCED_PARAMETER(ui32Param);
660
661         hOSWrapMem = psMemInfo->sMemBlk.hOSWrapMem;
662
663         if (psMemInfo->psKernelSyncInfo)
664                 put_syncinfo(psMemInfo->psKernelSyncInfo);
665
666         if (psMemInfo->sMemBlk.psIntSysPAddr) {
667                 int page_count;
668
669                 page_count = get_page_count((u32)psMemInfo->pvLinAddrKM,
670                                 psMemInfo->ui32AllocSize);
671
672                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
673                           page_count * sizeof(struct IMG_SYS_PHYADDR),
674                           psMemInfo->sMemBlk.psIntSysPAddr, NULL);
675         }
676
677         if (eError == PVRSRV_OK) {
678                 psMemInfo->ui32RefCount--;
679                 eError = FreeDeviceMem(psMemInfo);
680         }
681
682         if (hOSWrapMem)
683                 OSReleasePhysPageAddr(hOSWrapMem);
684
685         return eError;
686 }
687
688 enum PVRSRV_ERROR PVRSRVWrapExtMemoryKM(void *hDevCookie,
689                             struct PVRSRV_PER_PROCESS_DATA *psPerProc,
690                             void *hDevMemContext, u32 ui32ByteSize,
691                             u32 ui32PageOffset, IMG_BOOL bPhysContig,
692                             struct IMG_SYS_PHYADDR *psExtSysPAddr,
693                             void *pvLinAddr,
694                             struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo)
695 {
696         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
697         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
698         u32 ui32HostPageSize = HOST_PAGESIZE();
699         void *hDevMemHeap = NULL;
700         struct PVRSRV_DEVICE_NODE *psDeviceNode;
701         void *hBuffer;
702         struct PVRSRV_MEMBLK *psMemBlock;
703         IMG_BOOL bBMError;
704         struct BM_HEAP *psBMHeap;
705         enum PVRSRV_ERROR eError;
706         void *pvPageAlignedCPUVAddr;
707         struct IMG_SYS_PHYADDR *psIntSysPAddr = NULL;
708         void *hOSWrapMem = NULL;
709         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
710         int page_count = 0;
711         u32 i;
712
713         psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie;
714         PVR_ASSERT(psDeviceNode != NULL);
715
716         if (psDeviceNode == NULL) {
717                 PVR_DPF(PVR_DBG_ERROR,
718                          "PVRSRVWrapExtMemoryKM: invalid parameter");
719                 return PVRSRV_ERROR_INVALID_PARAMS;
720         }
721
722         if (pvLinAddr) {
723                 get_page_details((u32)pvLinAddr, ui32ByteSize,
724                                 &ui32PageOffset, &page_count);
725                 pvPageAlignedCPUVAddr = (void *)((u8 *) pvLinAddr -
726                                         ui32PageOffset);
727
728                 if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
729                                page_count * sizeof(struct IMG_SYS_PHYADDR),
730                                (void **)&psIntSysPAddr, NULL) != PVRSRV_OK) {
731                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
732                                         "Failed to alloc memory for block");
733                         return PVRSRV_ERROR_OUT_OF_MEMORY;
734                 }
735
736                 eError = OSAcquirePhysPageAddr(pvPageAlignedCPUVAddr,
737                                        page_count * ui32HostPageSize,
738                                        psIntSysPAddr, &hOSWrapMem);
739                 if (eError != PVRSRV_OK) {
740                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM:"
741                                    " Failed to alloc memory for block");
742                                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
743                                 goto ErrorExitPhase1;
744                 }
745                 psExtSysPAddr = psIntSysPAddr;
746                 bPhysContig = IMG_FALSE;
747         }
748
749         psDevMemoryInfo =
750             &((struct BM_CONTEXT *)hDevMemContext)->psDeviceNode->
751                                                             sDevMemoryInfo;
752         psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
753         for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
754                 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
755                     psDevMemoryInfo->ui32MappingHeapID) {
756                         if (psDeviceMemoryHeap[i].DevMemHeapType ==
757                             DEVICE_MEMORY_HEAP_PERCONTEXT) {
758                                 hDevMemHeap =
759                                     BM_CreateHeap(hDevMemContext,
760                                                   &psDeviceMemoryHeap[i]);
761                         } else {
762                                 hDevMemHeap =
763                                     psDevMemoryInfo->psDeviceMemoryHeap[i].
764                                     hDevMemHeap;
765                         }
766                         break;
767                 }
768         }
769
770         if (hDevMemHeap == NULL) {
771                 PVR_DPF(PVR_DBG_ERROR,
772                          "PVRSRVWrapExtMemoryKM: unable to find mapping heap");
773                 eError = PVRSRV_ERROR_GENERIC;
774                 goto ErrorExitPhase2;
775         }
776
777         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
778                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
779                        (void **) &psMemInfo, NULL) != PVRSRV_OK) {
780                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVWrapExtMemoryKM: "
781                                         "Failed to alloc memory for block");
782                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
783                 goto ErrorExitPhase2;
784         }
785
786         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
787         psMemBlock = &(psMemInfo->sMemBlk);
788
789         bBMError = BM_Wrap(hDevMemHeap,
790                            ui32ByteSize,
791                            ui32PageOffset,
792                            bPhysContig,
793                            psExtSysPAddr,
794                            NULL, &psMemInfo->ui32Flags, &hBuffer);
795         if (!bBMError) {
796                 PVR_DPF(PVR_DBG_ERROR,
797                          "PVRSRVWrapExtMemoryKM: BM_Wrap Failed");
798                 eError = PVRSRV_ERROR_BAD_MAPPING;
799                 goto ErrorExitPhase3;
800         }
801
802         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
803         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
804         psMemBlock->hOSWrapMem = hOSWrapMem;
805         psMemBlock->psIntSysPAddr = psIntSysPAddr;
806
807         psMemBlock->hBuffer = (void *) hBuffer;
808
809         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
810         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
811         psMemInfo->ui32AllocSize = ui32ByteSize;
812
813         psMemInfo->pvSysBackupBuffer = NULL;
814
815         psBMHeap = (struct BM_HEAP *)hDevMemHeap;
816         hDevMemContext = (void *) psBMHeap->pBMContext;
817         eError = alloc_or_reuse_syncinfo(hDevCookie,
818                                          hDevMemContext,
819                                          &psMemInfo->psKernelSyncInfo,
820                                          psExtSysPAddr);
821         if (eError != PVRSRV_OK)
822                 goto ErrorExitPhase4;
823
824         psMemInfo->ui32RefCount++;
825
826         psMemInfo->sMemBlk.hResItem =
827             ResManRegisterRes(psPerProc->hResManContext,
828                               RESMAN_TYPE_DEVICEMEM_WRAP, psMemInfo, 0,
829                               UnwrapExtMemoryCallBack);
830
831         *ppsMemInfo = psMemInfo;
832
833         return PVRSRV_OK;
834
835 ErrorExitPhase4:
836         if (psMemInfo) {
837                 FreeDeviceMem(psMemInfo);
838
839                 psMemInfo = NULL;
840         }
841
842 ErrorExitPhase3:
843         if (psMemInfo) {
844                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
845                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
846                           NULL);
847         }
848
849 ErrorExitPhase2:
850         if (psIntSysPAddr)
851                 OSReleasePhysPageAddr(hOSWrapMem);
852
853 ErrorExitPhase1:
854         if (psIntSysPAddr) {
855                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
856                           page_count * sizeof(struct IMG_SYS_PHYADDR),
857                           psIntSysPAddr, NULL);
858         }
859
860         return eError;
861 }
862
863 enum PVRSRV_ERROR PVRSRVUnmapDeviceMemoryKM(
864                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
865 {
866         if (!psMemInfo)
867                 return PVRSRV_ERROR_INVALID_PARAMS;
868
869         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
870
871         return PVRSRV_OK;
872 }
873
874 static enum PVRSRV_ERROR UnmapDeviceMemoryCallBack(void *pvParam, u32 ui32Param)
875 {
876         enum PVRSRV_ERROR eError;
877         struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = pvParam;
878         int page_count;
879
880         PVR_UNREFERENCED_PARAMETER(ui32Param);
881
882         page_count = get_page_count((u32)psMapData->psMemInfo->pvLinAddrKM,
883                                 psMapData->psMemInfo->ui32AllocSize);
884
885         if (psMapData->psMemInfo->sMemBlk.psIntSysPAddr)
886                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
887                           page_count * sizeof(struct IMG_SYS_PHYADDR),
888                           psMapData->psMemInfo->sMemBlk.psIntSysPAddr, NULL);
889
890         eError = FreeDeviceMem(psMapData->psMemInfo);
891         if (eError != PVRSRV_OK) {
892                 PVR_DPF(PVR_DBG_ERROR, "UnmapDeviceMemoryCallBack: "
893                                 "Failed to free DST meminfo");
894                 return eError;
895         }
896
897         psMapData->psSrcMemInfo->ui32RefCount--;
898
899         PVR_ASSERT(psMapData->psSrcMemInfo->ui32RefCount != (u32) (-1));
900 /*
901  * Don't free the source MemInfo as we didn't allocate it
902  * and it's not our job as the process the allocated
903  * should also free it when it's finished
904  */
905         OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
906                   sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData, NULL);
907
908         return eError;
909 }
910
911 static inline int bm_is_continuous(const struct BM_BUF *buf)
912 {
913         return buf->pMapping->eCpuMemoryOrigin == hm_wrapped_virtaddr;
914 }
915
916 enum PVRSRV_ERROR PVRSRVMapDeviceMemoryKM(
917                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
918                               struct PVRSRV_KERNEL_MEM_INFO *psSrcMemInfo,
919                               void *hDstDevMemHeap,
920                               struct PVRSRV_KERNEL_MEM_INFO **ppsDstMemInfo)
921 {
922         enum PVRSRV_ERROR eError;
923         u32 ui32PageOffset;
924         u32 ui32HostPageSize = HOST_PAGESIZE();
925         int page_count;
926         int i;
927         struct IMG_SYS_PHYADDR *psSysPAddr = NULL;
928         struct IMG_DEV_PHYADDR sDevPAddr;
929         struct BM_BUF *psBuf;
930         struct IMG_DEV_VIRTADDR sDevVAddr;
931         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = NULL;
932         void *hBuffer;
933         struct PVRSRV_MEMBLK *psMemBlock;
934         IMG_BOOL bBMError;
935         struct PVRSRV_DEVICE_NODE *psDeviceNode;
936         void *pvPageAlignedCPUVAddr;
937         struct RESMAN_MAP_DEVICE_MEM_DATA *psMapData = NULL;
938
939         if (!psSrcMemInfo || !hDstDevMemHeap || !ppsDstMemInfo) {
940                 PVR_DPF(PVR_DBG_ERROR,
941                          "PVRSRVMapDeviceMemoryKM: invalid parameters");
942                 return PVRSRV_ERROR_INVALID_PARAMS;
943         }
944
945         *ppsDstMemInfo = NULL;
946
947         get_page_details((u32)psSrcMemInfo->pvLinAddrKM,
948                         psSrcMemInfo->ui32AllocSize,
949                         &ui32PageOffset, &page_count);
950         pvPageAlignedCPUVAddr =
951             (void *) ((u8 *) psSrcMemInfo->pvLinAddrKM -
952                           ui32PageOffset);
953
954         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
955                        page_count * sizeof(struct IMG_SYS_PHYADDR),
956                        (void **) &psSysPAddr, NULL) != PVRSRV_OK) {
957                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
958                                         "Failed to alloc memory for block");
959                 return PVRSRV_ERROR_OUT_OF_MEMORY;
960         }
961
962         psBuf = psSrcMemInfo->sMemBlk.hBuffer;
963
964         psDeviceNode = psBuf->pMapping->pBMHeap->pBMContext->psDeviceNode;
965
966         sDevVAddr.uiAddr = psSrcMemInfo->sDevVAddr.uiAddr - ui32PageOffset;
967         for (i = 0; i < page_count; i++) {
968                 eError =
969                     BM_GetPhysPageAddr(psSrcMemInfo, sDevVAddr, &sDevPAddr);
970                 if (eError != PVRSRV_OK) {
971                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
972                                 "Failed to retrieve page list from device");
973                         goto ErrorExit;
974                 }
975
976                 psSysPAddr[i] =
977                     SysDevPAddrToSysPAddr(psDeviceNode->sDevId.eDeviceType,
978                                           sDevPAddr);
979
980                 sDevVAddr.uiAddr += ui32HostPageSize;
981         }
982
983         if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP,
984                        sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA),
985                        (void **)&psMapData, NULL) != PVRSRV_OK) {
986                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
987                                 "Failed to alloc resman map data");
988                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
989                 goto ErrorExit;
990         }
991
992         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
993                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
994                        (void **)&psMemInfo, NULL) != PVRSRV_OK) {
995                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceMemoryKM: "
996                                 "Failed to alloc memory for block");
997                 eError = PVRSRV_ERROR_OUT_OF_MEMORY;
998                 goto ErrorExit;
999         }
1000
1001         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
1002
1003         psMemBlock = &(psMemInfo->sMemBlk);
1004
1005         bBMError = BM_Wrap(hDstDevMemHeap, psSrcMemInfo->ui32AllocSize,
1006                            ui32PageOffset, bm_is_continuous(psBuf), psSysPAddr,
1007                            pvPageAlignedCPUVAddr, &psMemInfo->ui32Flags,
1008                            &hBuffer);
1009
1010         if (!bBMError) {
1011                 PVR_DPF(PVR_DBG_ERROR,
1012                          "PVRSRVMapDeviceMemoryKM: BM_Wrap Failed");
1013                 eError = PVRSRV_ERROR_BAD_MAPPING;
1014                 goto ErrorExit;
1015         }
1016
1017         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1018         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1019
1020         psMemBlock->hBuffer = (void *) hBuffer;
1021
1022         psMemBlock->psIntSysPAddr = psSysPAddr;
1023
1024         psMemInfo->pvLinAddrKM = psSrcMemInfo->pvLinAddrKM;
1025
1026         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1027         psMemInfo->ui32AllocSize = psSrcMemInfo->ui32AllocSize;
1028         psMemInfo->psKernelSyncInfo = psSrcMemInfo->psKernelSyncInfo;
1029
1030         psMemInfo->pvSysBackupBuffer = NULL;
1031
1032         psSrcMemInfo->ui32RefCount++;
1033
1034         psMapData->psMemInfo = psMemInfo;
1035         psMapData->psSrcMemInfo = psSrcMemInfo;
1036
1037         psMemInfo->sMemBlk.hResItem =
1038             ResManRegisterRes(psPerProc->hResManContext,
1039                               RESMAN_TYPE_DEVICEMEM_MAPPING, psMapData, 0,
1040                               UnmapDeviceMemoryCallBack);
1041
1042         *ppsDstMemInfo = psMemInfo;
1043
1044         return PVRSRV_OK;
1045
1046 ErrorExit:
1047
1048         if (psSysPAddr) {
1049                 OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP,
1050                           sizeof(struct IMG_SYS_PHYADDR), psSysPAddr, NULL);
1051         }
1052
1053         if (psMemInfo) {
1054                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1055                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1056                           NULL);
1057         }
1058
1059         if (psMapData) {
1060                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1061                           sizeof(struct RESMAN_MAP_DEVICE_MEM_DATA), psMapData,
1062                           NULL);
1063         }
1064
1065         return eError;
1066 }
1067
1068 enum PVRSRV_ERROR PVRSRVUnmapDeviceClassMemoryKM(
1069                                 struct PVRSRV_KERNEL_MEM_INFO *psMemInfo)
1070 {
1071         if (!psMemInfo)
1072                 return PVRSRV_ERROR_INVALID_PARAMS;
1073
1074         ResManFreeResByPtr(psMemInfo->sMemBlk.hResItem);
1075
1076         return PVRSRV_OK;
1077 }
1078
1079 static enum PVRSRV_ERROR UnmapDeviceClassMemoryCallBack(void *pvParam,
1080                                                         u32 ui32Param)
1081 {
1082         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo = pvParam;
1083
1084         PVR_UNREFERENCED_PARAMETER(ui32Param);
1085
1086         return FreeDeviceMem(psMemInfo);
1087 }
1088
1089 enum PVRSRV_ERROR PVRSRVMapDeviceClassMemoryKM(
1090                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc,
1091                                 void *hDevMemContext, void *hDeviceClassBuffer,
1092                                 struct PVRSRV_KERNEL_MEM_INFO **ppsMemInfo,
1093                                 void **phOSMapInfo)
1094 {
1095         enum PVRSRV_ERROR eError;
1096         struct PVRSRV_KERNEL_MEM_INFO *psMemInfo;
1097         struct PVRSRV_DEVICECLASS_BUFFER *psDeviceClassBuffer;
1098         struct IMG_SYS_PHYADDR *psSysPAddr;
1099         void *pvCPUVAddr, *pvPageAlignedCPUVAddr;
1100         IMG_BOOL bPhysContig;
1101         struct BM_CONTEXT *psBMContext;
1102         struct DEVICE_MEMORY_INFO *psDevMemoryInfo;
1103         struct DEVICE_MEMORY_HEAP_INFO *psDeviceMemoryHeap;
1104         void *hDevMemHeap = NULL;
1105         u32 ui32ByteSize;
1106         u32 ui32Offset;
1107         u32 ui32PageSize = HOST_PAGESIZE();
1108         void *hBuffer;
1109         struct PVRSRV_MEMBLK *psMemBlock;
1110         IMG_BOOL bBMError;
1111         u32 i;
1112
1113         if (!hDeviceClassBuffer || !ppsMemInfo || !phOSMapInfo ||
1114             !hDevMemContext) {
1115                 PVR_DPF(PVR_DBG_ERROR,
1116                          "PVRSRVMapDeviceClassMemoryKM: invalid parameters");
1117                 return PVRSRV_ERROR_INVALID_PARAMS;
1118         }
1119
1120         psDeviceClassBuffer = (struct PVRSRV_DEVICECLASS_BUFFER *)
1121                                                         hDeviceClassBuffer;
1122
1123         eError =
1124             psDeviceClassBuffer->pfnGetBufferAddr(psDeviceClassBuffer->
1125                                                   hExtDevice,
1126                                                   psDeviceClassBuffer->
1127                                                   hExtBuffer, &psSysPAddr,
1128                                                   &ui32ByteSize,
1129                                                   (void __iomem **)&pvCPUVAddr,
1130                                                   phOSMapInfo, &bPhysContig);
1131         if (eError != PVRSRV_OK) {
1132                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1133                                         "unable to get buffer address");
1134                 return PVRSRV_ERROR_GENERIC;
1135         }
1136
1137         psBMContext = (struct BM_CONTEXT *)psDeviceClassBuffer->hDevMemContext;
1138         psDevMemoryInfo = &psBMContext->psDeviceNode->sDevMemoryInfo;
1139         psDeviceMemoryHeap = psDevMemoryInfo->psDeviceMemoryHeap;
1140         for (i = 0; i < PVRSRV_MAX_CLIENT_HEAPS; i++) {
1141                 if (HEAP_IDX(psDeviceMemoryHeap[i].ui32HeapID) ==
1142                     psDevMemoryInfo->ui32MappingHeapID) {
1143                         if (psDeviceMemoryHeap[i].DevMemHeapType ==
1144                             DEVICE_MEMORY_HEAP_PERCONTEXT)
1145                                 hDevMemHeap =
1146                                     BM_CreateHeap(hDevMemContext,
1147                                                   &psDeviceMemoryHeap[i]);
1148                         else
1149                                 hDevMemHeap =
1150                                     psDevMemoryInfo->psDeviceMemoryHeap[i].
1151                                                                     hDevMemHeap;
1152                         break;
1153                 }
1154         }
1155
1156         if (hDevMemHeap == NULL) {
1157                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1158                                         "unable to find mapping heap");
1159                 return PVRSRV_ERROR_GENERIC;
1160         }
1161
1162         ui32Offset = ((u32)pvCPUVAddr) & (ui32PageSize - 1);
1163         pvPageAlignedCPUVAddr = (void *)((u8 *)pvCPUVAddr - ui32Offset);
1164
1165         if (OSAllocMem(PVRSRV_PAGEABLE_SELECT,
1166                        sizeof(struct PVRSRV_KERNEL_MEM_INFO),
1167                        (void **)&psMemInfo, NULL) != PVRSRV_OK) {
1168                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVMapDeviceClassMemoryKM: "
1169                                         "Failed to alloc memory for block");
1170                 return PVRSRV_ERROR_OUT_OF_MEMORY;
1171         }
1172
1173         OSMemSet(psMemInfo, 0, sizeof(*psMemInfo));
1174
1175         psMemBlock = &(psMemInfo->sMemBlk);
1176
1177         bBMError = BM_Wrap(hDevMemHeap, ui32ByteSize, ui32Offset, bPhysContig,
1178                            psSysPAddr, pvPageAlignedCPUVAddr,
1179                            &psMemInfo->ui32Flags, &hBuffer);
1180
1181         if (!bBMError) {
1182                 PVR_DPF(PVR_DBG_ERROR,
1183                          "PVRSRVMapDeviceClassMemoryKM: BM_Wrap Failed");
1184                 OSFreeMem(PVRSRV_PAGEABLE_SELECT,
1185                           sizeof(struct PVRSRV_KERNEL_MEM_INFO), psMemInfo,
1186                           NULL);
1187                 return PVRSRV_ERROR_BAD_MAPPING;
1188         }
1189
1190         psMemBlock->sDevVirtAddr = BM_HandleToDevVaddr(hBuffer);
1191         psMemBlock->hOSMemHandle = BM_HandleToOSMemHandle(hBuffer);
1192
1193         psMemBlock->hBuffer = (void *) hBuffer;
1194
1195         psMemInfo->pvLinAddrKM = BM_HandleToCpuVaddr(hBuffer);
1196
1197         psMemInfo->sDevVAddr = psMemBlock->sDevVirtAddr;
1198         psMemInfo->ui32AllocSize = ui32ByteSize;
1199         psMemInfo->psKernelSyncInfo = psDeviceClassBuffer->psKernelSyncInfo;
1200
1201         psMemInfo->pvSysBackupBuffer = NULL;
1202
1203         psMemInfo->sMemBlk.hResItem =
1204             ResManRegisterRes(psPerProc->hResManContext,
1205                               RESMAN_TYPE_DEVICECLASSMEM_MAPPING, psMemInfo, 0,
1206                               UnmapDeviceClassMemoryCallBack);
1207
1208         *ppsMemInfo = psMemInfo;
1209
1210         return PVRSRV_OK;
1211 }