aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/services4/srvkm/env/linux/ion.c')
-rw-r--r--drivers/gpu/pvr/services4/srvkm/env/linux/ion.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/ion.c b/drivers/gpu/pvr/services4/srvkm/env/linux/ion.c
new file mode 100644
index 000000000000..09d8f1055b48
--- /dev/null
+++ b/drivers/gpu/pvr/services4/srvkm/env/linux/ion.c
@@ -0,0 +1,580 @@
1/*************************************************************************/ /*!
2@Title Ion driver inter-operability code.
3@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4@License Dual MIT/GPLv2
5
6The contents of this file are subject to the MIT license as set out below.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy
9of this software and associated documentation files (the "Software"), to deal
10in the Software without restriction, including without limitation the rights
11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12copies of the Software, and to permit persons to whom the Software is
13furnished to do so, subject to the following conditions:
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18Alternatively, the contents of this file may be used under the terms of
19the GNU General Public License Version 2 ("GPL") in which case the provisions
20of GPL are applicable instead of those above.
21
22If you wish to allow use of your version of this file only under the terms of
23GPL, and not to allow others to use your version of this file under the terms
24of the MIT license, indicate your decision by deleting the provisions above
25and replace them with the notice and other provisions required by GPL as set
26out in the file called "GPL-COPYING" included in this distribution. If you do
27not delete the provisions above, a recipient may use your version of this file
28under the terms of either the MIT license or GPL.
29
30This License is also included in this distribution in the file called
31"MIT-COPYING".
32
33EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
34PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
35BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
37COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
38IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40*/ /**************************************************************************/
41
42#include <linux/version.h>
43#include "ion.h"
44
45/* Three possible configurations:
46 *
47 * - SUPPORT_ION && CONFIG_ION_OMAP
48 * Real ion support, but sharing with an SOC ion device. We need
49 * to co-share the heaps too.
50 *
51 * - SUPPORT_ION && !CONFIG_ION_OMAP
52 * "Reference" ion implementation. Creates its own ion device
53 * and heaps for the driver to use.
54 */
55
56#if defined(SUPPORT_ION) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
57#include <linux/scatterlist.h>
58#include <linux/kernel.h>
59#include <linux/slab.h>
60#include <linux/err.h>
61
62#if defined(CONFIG_ION_OMAP)
63
64/* Real ion with sharing */
65
66extern struct ion_device *omap_ion_device;
67struct ion_device *gpsIonDev;
68
69PVRSRV_ERROR IonInit(IMG_VOID)
70{
71 gpsIonDev = omap_ion_device;
72 return PVRSRV_OK;
73}
74
75IMG_VOID IonDeinit(IMG_VOID)
76{
77 gpsIonDev = IMG_NULL;
78}
79
80#else /* defined(CONFIG_ION_OMAP) */
81
82#if defined(CONFIG_ION_S5P)
83
84/* Real ion with sharing (s5pv210) */
85
86extern struct ion_device *s5p_ion_device;
87struct ion_device *gpsIonDev;
88
89PVRSRV_ERROR IonInit(IMG_VOID)
90{
91 gpsIonDev = s5p_ion_device;
92 return PVRSRV_OK;
93}
94
95IMG_VOID IonDeinit(IMG_VOID)
96{
97 gpsIonDev = IMG_NULL;
98}
99
100#else /* defined(CONFIG_ION_S5P) */
101
102#if defined(CONFIG_ION_SUNXI)
103
104/* Real ion with sharing (sunxi) */
105
106extern struct ion_device *sunxi_ion_device;
107struct ion_device *gpsIonDev;
108
109PVRSRV_ERROR IonInit(IMG_VOID)
110{
111 gpsIonDev = sunxi_ion_device;
112 return PVRSRV_OK;
113}
114
115IMG_VOID IonDeinit(IMG_VOID)
116{
117 gpsIonDev = IMG_NULL;
118}
119
120#else /* defined(CONFIG_ION_SUNXI) */
121
122#if defined(CONFIG_ION_INCDHAD1)
123
124/* Real ion with sharing (incdhad1) */
125
126extern struct ion_device *incdhad1_ion_device;
127struct ion_device *gpsIonDev;
128
129PVRSRV_ERROR IonInit(IMG_VOID)
130{
131 gpsIonDev = incdhad1_ion_device;
132 return PVRSRV_OK;
133}
134
135
136IMG_VOID IonDeinit(IMG_VOID)
137{
138 gpsIonDev = IMG_NULL;
139}
140
141#else /* defined(CONFIG_ION_INCDHAD1) */
142
143/* "Reference" ion implementation */
144
145#include SUPPORT_ION_PRIV_HEADER
146#include <linux/version.h>
147#include "ion_sys_private.h"
148#include "lma_heap_ion.h"
149
150static struct ion_heap **gapsIonHeaps;
151struct ion_device *gpsIonDev;
152
153#if defined(LMA)
154struct ion_platform_data gsTCIonConfig = {
155 .nr = 1,
156 .heaps =
157#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,39))
158#else
159 (struct ion_platform_heap [])
160#endif
161 {
162 {
163 /* This heap must be first. The base address and size are filled
164 in from data passed down by sysconfig.c. */
165 .type = ION_HEAP_TYPE_CUSTOM,
166 .name = "tc_local_mem",
167 .id = ION_HEAP_TYPE_CUSTOM,
168 .base = 0, /* filled in later */
169 .size = 0, /* filled in later */
170 }
171 }
172};
173
174PVRSRV_ERROR IonInit(void *pvPrivateData)
175{
176 PVRSRV_ERROR eError = PVRSRV_OK;
177 int i;
178
179 ION_TC_PRIVATE_DATA sPrivateData = *(ION_TC_PRIVATE_DATA *)pvPrivateData;
180
181 /* Fill in the heap base and size according to the private data. */
182 gsTCIonConfig.heaps[0].base = sPrivateData.uiHeapBase;
183 gsTCIonConfig.heaps[0].size = sPrivateData.uiHeapSize;
184
185 gapsIonHeaps = kzalloc(sizeof(struct ion_heap *) * gsTCIonConfig.nr,
186 GFP_KERNEL);
187 gpsIonDev = ion_device_create(NULL);
188 if (IS_ERR_OR_NULL(gpsIonDev))
189 {
190 kfree(gapsIonHeaps);
191 return PVRSRV_ERROR_OUT_OF_MEMORY;
192 }
193
194 for (i = 0; i < gsTCIonConfig.nr; i++)
195 {
196 struct ion_platform_heap *psPlatHeapData = &gsTCIonConfig.heaps[i];
197
198 switch (psPlatHeapData->type)
199 {
200 case ION_HEAP_TYPE_CUSTOM:
201 /* Custom heap: this is used to mean a TC-specific heap,
202 which allocates from local memory. */
203 gapsIonHeaps[i] = lma_heap_create(psPlatHeapData);
204 break;
205 default:
206 /* For any other type of heap, hand this to ion to create as
207 appropriate. We don't necessarily need any of these -
208 this just gives us the flexibility to have another kind
209 of heap if necessary. */
210 gapsIonHeaps[i] = ion_heap_create(psPlatHeapData);
211 break;
212 }
213
214 if (IS_ERR_OR_NULL(gapsIonHeaps[i]))
215 {
216 printk("%s: Failed to create ion heap '%s'", __func__, psPlatHeapData->name);
217 IonDeinit();
218 return PVRSRV_ERROR_OUT_OF_MEMORY;
219 }
220
221 ion_device_add_heap(gpsIonDev, gapsIonHeaps[i]);
222 }
223
224 return eError;
225}
226
227void IonDeinit(void)
228{
229 int i;
230 for (i = 0; i < gsTCIonConfig.nr; i++)
231 if (gapsIonHeaps[i])
232 ion_heap_destroy(gapsIonHeaps[i]);
233 kfree(gapsIonHeaps);
234 ion_device_destroy(gpsIonDev);
235}
236
237#else
238
239#if defined(ION_CARVEOUT_MEM_BASE) && defined(ION_CARVEOUT_MEM_SIZE)
240/* Only define the carveout heap on boards with BASE and SIZE defined,
241 * otherwise crashes may be seen when empty cache flushes are issued
242 * (seen on the MIPS architecture).
243 */
244#define ION_HAS_CARVEOUT_HEAP
245#endif
246
247static struct ion_platform_data gsGenericConfig =
248{
249#if defined(ION_HAS_CARVEOUT_HEAP)
250 .nr = 3,
251#else
252 .nr = 2,
253#endif
254 .heaps =
255#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,39))
256 (struct ion_platform_heap [])
257#endif
258 {
259 {
260 .type = ION_HEAP_TYPE_SYSTEM,
261 .name = "system",
262 .id = ION_HEAP_TYPE_SYSTEM,
263 },
264 {
265 .type = ION_HEAP_TYPE_DMA,
266 .name = "dma",
267 .id = ION_HEAP_TYPE_DMA,
268 },
269#if defined(ION_HAS_CARVEOUT_HEAP)
270 {
271 .type = ION_HEAP_TYPE_CARVEOUT,
272 .name = "carveout",
273 .id = ION_HEAP_TYPE_CARVEOUT,
274 .base = ION_CARVEOUT_MEM_BASE,
275 .size = ION_CARVEOUT_MEM_SIZE,
276 },
277#endif /* defined(ION_HAS_CARVEOUT_HEAP) */
278 }
279};
280
281PVRSRV_ERROR IonInit(IMG_VOID)
282{
283 int uiHeapCount = gsGenericConfig.nr;
284 int uiError;
285 int i;
286
287 gapsIonHeaps = kzalloc(sizeof(struct ion_heap *) * uiHeapCount, GFP_KERNEL);
288 /* Create the ion devicenode */
289 gpsIonDev = ion_device_create(NULL);
290 if (IS_ERR_OR_NULL(gpsIonDev)) {
291 kfree(gapsIonHeaps);
292 return PVRSRV_ERROR_OUT_OF_MEMORY;
293 }
294
295 /* Register all the heaps */
296 for (i = 0; i < gsGenericConfig.nr; i++)
297 {
298 struct ion_platform_heap *psPlatHeapData = &gsGenericConfig.heaps[i];
299
300 gapsIonHeaps[i] = ion_heap_create(psPlatHeapData);
301 if (IS_ERR_OR_NULL(gapsIonHeaps[i]))
302 {
303 uiError = PTR_ERR(gapsIonHeaps[i]);
304 goto failHeapCreate;
305 }
306 ion_device_add_heap(gpsIonDev, gapsIonHeaps[i]);
307 }
308
309 return PVRSRV_OK;
310failHeapCreate:
311 for (i = 0; i < uiHeapCount; i++)
312 {
313 if (gapsIonHeaps[i])
314 {
315 ion_heap_destroy(gapsIonHeaps[i]);
316 }
317 }
318 kfree(gapsIonHeaps);
319 return PVRSRV_ERROR_OUT_OF_MEMORY;
320}
321
322IMG_VOID IonDeinit(IMG_VOID)
323{
324 int uiHeapCount = gsGenericConfig.nr;
325 int i;
326
327 for (i = 0; i < uiHeapCount; i++)
328 {
329 if (gapsIonHeaps[i])
330 {
331 ion_heap_destroy(gapsIonHeaps[i]);
332 }
333 }
334 kfree(gapsIonHeaps);
335 ion_device_destroy(gpsIonDev);
336}
337
338#endif /* defined(LMA) */
339
340#endif /* defined(CONFIG_ION_INCDHAD1) */
341
342#endif /* defined(CONFIG_ION_SUNXI) */
343
344#endif /* defined(CONFIG_ION_S5P) */
345
346#endif /* defined(CONFIG_ION_OMAP) */
347
348#define MAX_IMPORT_ION_FDS 3
349
350typedef struct _ION_IMPORT_DATA_
351{
352 /* ion client handles are imported into */
353 struct ion_client *psIonClient;
354
355 /* Number of ion handles represented by this import */
356 IMG_UINT32 ui32NumIonHandles;
357
358 /* Array of ion handles in use by services */
359 struct ion_handle *apsIonHandle[MAX_IMPORT_ION_FDS];
360
361 /* Array of physical addresses represented by these buffers */
362 IMG_SYS_PHYADDR *psSysPhysAddr;
363
364#if defined(PDUMP)
365 /* If ui32NumBuffers is 1 and ion_map_kernel() is implemented by the
366 * allocator, this may be non-NULL. Otherwise it will be NULL.
367 */
368 IMG_PVOID pvKernAddr0;
369#endif /* defined(PDUMP) */
370}
371ION_IMPORT_DATA;
372
373PVRSRV_ERROR IonImportBufferAndAcquirePhysAddr(IMG_HANDLE hIonDev,
374 IMG_UINT32 ui32NumFDs,
375 IMG_INT32 *pai32BufferFDs,
376 IMG_UINT32 *pui32PageCount,
377 IMG_SYS_PHYADDR **ppsSysPhysAddr,
378 IMG_PVOID *ppvKernAddr0,
379 IMG_HANDLE *phPriv,
380 IMG_HANDLE *phUnique)
381{
382 struct scatterlist *psTemp, *psScatterList[MAX_IMPORT_ION_FDS] = {};
383 PVRSRV_ERROR eError = PVRSRV_ERROR_OUT_OF_MEMORY;
384 struct ion_client *psIonClient = hIonDev;
385 IMG_UINT32 i, k, ui32PageCount = 0;
386 ION_IMPORT_DATA *psImportData;
387
388 if(ui32NumFDs > MAX_IMPORT_ION_FDS)
389 {
390 printk(KERN_ERR "%s: More ion export fds passed in than supported "
391 "(%d provided, %d max)", __func__, ui32NumFDs,
392 MAX_IMPORT_ION_FDS);
393 return PVRSRV_ERROR_INVALID_PARAMS;
394 }
395
396 psImportData = kzalloc(sizeof(ION_IMPORT_DATA), GFP_KERNEL);
397 if (psImportData == NULL)
398 {
399 goto exitFailKMallocImportData;
400 }
401
402 /* Set up import data for free call */
403 psImportData->psIonClient = psIonClient;
404 psImportData->ui32NumIonHandles = ui32NumFDs;
405
406 for(i = 0; i < ui32NumFDs; i++)
407 {
408 int fd = (int)pai32BufferFDs[i];
409 struct sg_table *psSgTable;
410
411 psImportData->apsIonHandle[i] = ion_import_dma_buf(psIonClient, fd);
412 if (psImportData->apsIonHandle[i] == IMG_NULL)
413 {
414 eError = PVRSRV_ERROR_BAD_MAPPING;
415 goto exitFailImport;
416 }
417
418 psSgTable = ion_sg_table(psIonClient, psImportData->apsIonHandle[i]);
419 psScatterList[i] = psSgTable->sgl;
420 if (psScatterList[i] == NULL)
421 {
422 eError = PVRSRV_ERROR_INVALID_PARAMS;
423 goto exitFailImport;
424 }
425
426 /* Although all heaps will provide an sg_table, the tables cannot
427 * always be trusted because sg_lists are just pointers to "struct
428 * page" values, and some memory e.g. carveout may not have valid
429 * "struct page" values. In particular, on ARM, carveout is
430 * generally reserved with memblock_remove(), which leaves the
431 * "struct page" entries uninitialized when SPARSEMEM is enabled.
432 * The effect of this is that page_to_pfn(pfn_to_page(pfn)) != pfn.
433 *
434 * There's more discussion on this mailing list thread:
435 * http://lists.linaro.org/pipermail/linaro-mm-sig/2012-August/002440.html
436 *
437 * If the heap this buffer comes from implements ->phys(), it's
438 * probably a contiguous allocator. If the phys() function is
439 * implemented, we'll use it to check sg_table->sgl[0]. If we find
440 * they don't agree, we'll assume phys() is more reliable and use
441 * that.
442 *
443 * Some heaps out there will implement phys() even though they are
444 * not for physically contiguous allocations (so the sg_table must
445 * be used). Therefore use the sg_table if the phys() and first
446 * sg_table entry match. This should be reliable because for most
447 * contiguous allocators, the sg_table should be a single span
448 * from 'start' to 'start+size'.
449 *
450 * Also, ion prints out an error message if the heap doesn't implement
451 * ->phys(), which we want to avoid, so only use ->phys() if the
452 * sg_table contains a single span and therefore could plausibly
453 * be a contiguous allocator.
454 */
455 if(!sg_next(psScatterList[i]))
456 {
457 ion_phys_addr_t sPhyAddr;
458 size_t sLength;
459
460 if(!ion_phys(psIonClient, psImportData->apsIonHandle[i],
461 &sPhyAddr, &sLength))
462 {
463 BUG_ON(sLength & ~PAGE_MASK);
464
465 if(sg_phys(psScatterList[i]) != sPhyAddr)
466 {
467 psScatterList[i] = IMG_NULL;
468 ui32PageCount += sLength / PAGE_SIZE;
469 }
470 }
471 }
472
473 for(psTemp = psScatterList[i]; psTemp; psTemp = sg_next(psTemp))
474 {
475 IMG_UINT32 j;
476 for (j = 0; j < psTemp->length; j += PAGE_SIZE)
477 {
478 ui32PageCount++;
479 }
480 }
481 }
482
483 BUG_ON(ui32PageCount == 0);
484
485 psImportData->psSysPhysAddr = kmalloc(sizeof(IMG_SYS_PHYADDR) * ui32PageCount, GFP_KERNEL);
486 if (psImportData->psSysPhysAddr == NULL)
487 {
488 goto exitFailImport;
489 }
490
491 for(i = 0, k = 0; i < ui32NumFDs; i++)
492 {
493 if(psScatterList[i])
494 {
495 for(psTemp = psScatterList[i]; psTemp; psTemp = sg_next(psTemp))
496 {
497 IMG_UINT32 j;
498 for (j = 0; j < psTemp->length; j += PAGE_SIZE)
499 {
500 psImportData->psSysPhysAddr[k].uiAddr = sg_phys(psTemp) + j;
501 k++;
502 }
503 }
504 }
505 else
506 {
507 ion_phys_addr_t sPhyAddr;
508 size_t sLength, j;
509
510 ion_phys(psIonClient, psImportData->apsIonHandle[i],
511 &sPhyAddr, &sLength);
512
513 for(j = 0; j < sLength; j += PAGE_SIZE)
514 {
515 psImportData->psSysPhysAddr[k].uiAddr = sPhyAddr + j;
516 k++;
517 }
518 }
519 }
520
521 *pui32PageCount = ui32PageCount;
522 *ppsSysPhysAddr = psImportData->psSysPhysAddr;
523
524#if defined(PDUMP)
525 if(ui32NumFDs == 1)
526 {
527 IMG_PVOID pvKernAddr0;
528
529 pvKernAddr0 = ion_map_kernel(psIonClient, psImportData->apsIonHandle[0]);
530 if (IS_ERR(pvKernAddr0))
531 {
532 pvKernAddr0 = IMG_NULL;
533 }
534
535 psImportData->pvKernAddr0 = pvKernAddr0;
536 *ppvKernAddr0 = pvKernAddr0;
537 }
538 else
539#endif /* defined(PDUMP) */
540 {
541 *ppvKernAddr0 = NULL;
542 }
543
544 *phPriv = psImportData;
545 *phUnique = (IMG_HANDLE)psImportData->psSysPhysAddr[0].uiAddr;
546
547 return PVRSRV_OK;
548
549exitFailImport:
550 for(i = 0; psImportData->apsIonHandle[i] != NULL; i++)
551 {
552 ion_free(psIonClient, psImportData->apsIonHandle[i]);
553 }
554 kfree(psImportData);
555exitFailKMallocImportData:
556 return eError;
557}
558
559IMG_VOID IonUnimportBufferAndReleasePhysAddr(IMG_HANDLE hPriv)
560{
561 ION_IMPORT_DATA *psImportData = hPriv;
562 IMG_UINT32 i;
563
564#if defined(PDUMP)
565 if (psImportData->pvKernAddr0)
566 {
567 ion_unmap_kernel(psImportData->psIonClient, psImportData->apsIonHandle[0]);
568 }
569#endif /* defined(PDUMP) */
570
571 for(i = 0; i < psImportData->ui32NumIonHandles; i++)
572 {
573 ion_free(psImportData->psIonClient, psImportData->apsIonHandle[i]);
574 }
575
576 kfree(psImportData->psSysPhysAddr);
577 kfree(psImportData);
578}
579
580#endif /* defined(SUPPORT_ION) */