RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / handle_idr.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Resource Handle Manager - IDR Back-end
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description    Provide IDR based resource handle management back-end
6 @License        Dual MIT/GPLv2
7
8 The contents of this file are subject to the MIT license as set out below.
9
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 ("GPL") in which case the provisions
22 of GPL are applicable instead of those above.
23
24 If you wish to allow use of your version of this file only under the terms of
25 GPL, and not to allow others to use your version of this file under the terms
26 of the MIT license, indicate your decision by deleting the provisions above
27 and replace them with the notice and other provisions required by GPL as set
28 out in the file called "GPL-COPYING" included in this distribution. If you do
29 not delete the provisions above, a recipient may use your version of this file
30 under the terms of either the MIT license or GPL.
31
32 This License is also included in this distribution in the file called
33 "MIT-COPYING".
34
35 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
36 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
37 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
39 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */ /***************************************************************************/
43
44 #include <linux/version.h>
45 #include <linux/kernel.h>
46 #include <linux/err.h>
47 #include <linux/gfp.h>
48 #include <linux/idr.h>
49
50 #include "handle_impl.h"
51 #include "allocmem.h"
52 #include "osfunc.h"
53 #include "pvr_debug.h"
54
55 #define ID_VALUE_MIN    1
56 #define ID_VALUE_MAX    INT_MAX
57
58 #define ID_TO_HANDLE(i) ((IMG_HANDLE)(uintptr_t)(i))
59 #define HANDLE_TO_ID(h) ((IMG_INT)(uintptr_t)(h))
60
61 struct _HANDLE_IMPL_BASE_
62 {
63         struct idr sIdr;
64
65         IMG_UINT32 ui32MaxHandleValue;
66
67         IMG_UINT32 ui32TotalHandCount;
68 };
69
70 typedef struct _HANDLE_ITER_DATA_WRAPPER_
71 {
72         PFN_HANDLE_ITER pfnHandleIter;
73         void *pvHandleIterData;
74 } HANDLE_ITER_DATA_WRAPPER;
75
76
77 static int HandleIterFuncWrapper(int id, void *data, void *iter_data)
78 {
79         HANDLE_ITER_DATA_WRAPPER *psIterData = (HANDLE_ITER_DATA_WRAPPER *)iter_data;
80
81         PVR_UNREFERENCED_PARAMETER(data);
82
83         return (int)psIterData->pfnHandleIter(ID_TO_HANDLE(id), psIterData->pvHandleIterData);
84 }
85
86 /*!
87 ******************************************************************************
88
89  @Function      AcquireHandle
90
91  @Description   Acquire a new handle
92
93  @Input         psBase - Pointer to handle base structure
94                 phHandle - Points to a handle pointer
95                 pvData - Pointer to resource to be associated with the handle
96
97  @Output        phHandle - Points to a handle pointer
98
99  @Return        Error code or PVRSRV_OK
100
101 ******************************************************************************/
102 static PVRSRV_ERROR AcquireHandle(HANDLE_IMPL_BASE *psBase, 
103                                   IMG_HANDLE *phHandle, 
104                                   void *pvData)
105 {
106         int id;
107         int result;
108
109         PVR_ASSERT(psBase != NULL);
110         PVR_ASSERT(phHandle != NULL);
111         PVR_ASSERT(pvData != NULL);
112
113 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
114         idr_preload(GFP_KERNEL);
115         id = idr_alloc(&psBase->sIdr, pvData, ID_VALUE_MIN, psBase->ui32MaxHandleValue + 1, 0);
116         idr_preload_end();
117
118         result = id;
119 #else
120         do
121         {
122                 if (idr_pre_get(&psBase->sIdr, GFP_KERNEL) == 0)
123                 {
124                         return PVRSRV_ERROR_OUT_OF_MEMORY;
125                 }
126
127                 result = idr_get_new_above(&psBase->sIdr, pvData, ID_VALUE_MIN, &id);
128         } while (result == -EAGAIN);
129
130         if ((IMG_UINT32)id > psBase->ui32MaxHandleValue)
131         {
132                 idr_remove(&psBase->sIdr, id);
133                 result = -ENOSPC;
134         }
135 #endif
136
137         if (result < 0)
138         {
139                 if (result == -ENOSPC)
140                 {
141                         PVR_DPF((PVR_DBG_ERROR, "%s: Limit of %u handles reached", 
142                                  __FUNCTION__, psBase->ui32MaxHandleValue));
143
144                         return PVRSRV_ERROR_UNABLE_TO_ADD_HANDLE;
145                 }
146
147                 return PVRSRV_ERROR_OUT_OF_MEMORY;
148         }
149
150         psBase->ui32TotalHandCount++;
151
152         *phHandle = ID_TO_HANDLE(id);
153
154         return PVRSRV_OK;
155 }
156
157 /*!
158 ******************************************************************************
159
160  @Function      ReleaseHandle
161
162  @Description   Release a handle that is no longer needed.
163
164  @Input         psBase - Pointer to handle base structure
165                 hHandle - Handle to release
166                 ppvData - Points to a void data pointer
167
168  @Output        ppvData - Points to a void data pointer
169
170  @Return        PVRSRV_OK or PVRSRV_ERROR
171
172 ******************************************************************************/
173 static PVRSRV_ERROR ReleaseHandle(HANDLE_IMPL_BASE *psBase, 
174                                   IMG_HANDLE hHandle, 
175                                   void **ppvData)
176 {
177         int id = HANDLE_TO_ID(hHandle);
178         void *pvData;
179
180         PVR_ASSERT(psBase);
181
182         /* Get the data associated with the handle. If we get back NULL then 
183            it's an invalid handle */
184
185         pvData = idr_find(&psBase->sIdr, id);
186         if (pvData)
187         {
188                 idr_remove(&psBase->sIdr, id);
189                 psBase->ui32TotalHandCount--;
190         }
191
192         if (pvData == NULL)
193         {
194                 PVR_DPF((PVR_DBG_ERROR, "%s: Handle out of range (%u > %u)", 
195                          __FUNCTION__, id, psBase->ui32TotalHandCount));
196                 return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
197         }
198
199         if (ppvData)
200         {
201                 *ppvData = pvData;
202         }
203
204         return PVRSRV_OK;
205 }
206
207 /*!
208 ******************************************************************************
209
210  @Function      GetHandleData
211
212  @Description   Get the data associated with the given handle
213
214  @Input         psBase - Pointer to handle base structure
215                 hHandle - Handle from which data should be retrieved
216                 ppvData - Points to a void data pointer
217
218  @Output        ppvData - Points to a void data pointer
219
220  @Return        Error code or PVRSRV_OK
221
222 ******************************************************************************/
223 static PVRSRV_ERROR GetHandleData(HANDLE_IMPL_BASE *psBase, 
224                                   IMG_HANDLE hHandle, 
225                                   void **ppvData)
226 {
227         int id = HANDLE_TO_ID(hHandle);
228         void *pvData;
229
230         PVR_ASSERT(psBase);
231         PVR_ASSERT(ppvData);
232
233         pvData = idr_find(&psBase->sIdr, id);
234         if (pvData)
235         {
236                 *ppvData = pvData;
237
238                 return PVRSRV_OK;
239         }
240         else
241         {
242                 return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
243         }
244 }
245
246 /*!
247 ******************************************************************************
248
249  @Function      SetHandleData
250
251  @Description   Set the data associated with the given handle
252
253  @Input         psBase - Pointer to handle base structure
254                 hHandle - Handle for which data should be changed
255                 pvData - Pointer to new data to be associated with the handle
256
257  @Return        Error code or PVRSRV_OK
258
259 ******************************************************************************/
260 static PVRSRV_ERROR SetHandleData(HANDLE_IMPL_BASE *psBase, 
261                                   IMG_HANDLE hHandle, 
262                                   void *pvData)
263 {
264         int id = HANDLE_TO_ID(hHandle);
265         void *pvOldData;
266
267         PVR_ASSERT(psBase);
268
269         pvOldData = idr_replace(&psBase->sIdr, pvData, id);
270         if (IS_ERR(pvOldData))
271         {
272                 if (PTR_ERR(pvOldData) == -ENOENT)
273                 {
274                         return PVRSRV_ERROR_HANDLE_NOT_ALLOCATED;
275                 }
276                 else
277                 {
278                         return PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE;
279                 }
280         }
281
282         return PVRSRV_OK;
283 }
284
285 static PVRSRV_ERROR IterateOverHandles(HANDLE_IMPL_BASE *psBase, PFN_HANDLE_ITER pfnHandleIter, void *pvHandleIterData)
286 {
287         HANDLE_ITER_DATA_WRAPPER sIterData;
288
289         PVR_ASSERT(psBase);
290         PVR_ASSERT(pfnHandleIter);
291
292         sIterData.pfnHandleIter = pfnHandleIter;
293         sIterData.pvHandleIterData = pvHandleIterData;
294
295         return (PVRSRV_ERROR)idr_for_each(&psBase->sIdr, HandleIterFuncWrapper, &sIterData);
296 }
297
298 /*!
299 ******************************************************************************
300
301  @Function      EnableHandlePurging
302
303  @Description   Enable purging for a given handle base
304
305  @Input         psBase - pointer to handle base structure
306
307  @Return        Error code or PVRSRV_OK
308
309 ******************************************************************************/
310 static PVRSRV_ERROR EnableHandlePurging(HANDLE_IMPL_BASE *psBase)
311 {
312         PVR_UNREFERENCED_PARAMETER(psBase);
313         PVR_ASSERT(psBase);
314
315         return PVRSRV_OK;
316 }
317
318 /*!
319 ******************************************************************************
320
321  @Function      PurgeHandles
322
323  @Description   Purge handles for a given handle base
324
325  @Input         psBase - Pointer to handle base structure
326
327  @Return        Error code or PVRSRV_OK
328
329 ******************************************************************************/
330 static PVRSRV_ERROR PurgeHandles(HANDLE_IMPL_BASE *psBase)
331 {
332         PVR_UNREFERENCED_PARAMETER(psBase);
333         PVR_ASSERT(psBase);
334
335         return PVRSRV_OK;
336 }
337
338 /*!
339 ******************************************************************************
340
341  @Function      CreateHandleBase
342
343  @Description   Create a handle base structure
344
345  @Input         ppsBase - pointer to handle base structure pointer
346
347  @Output        ppsBase - points to handle base structure pointer
348
349  @Return        Error code or PVRSRV_OK
350
351 ******************************************************************************/
352 static PVRSRV_ERROR CreateHandleBase(HANDLE_IMPL_BASE **ppsBase)
353 {
354         HANDLE_IMPL_BASE *psBase;
355
356         PVR_ASSERT(ppsBase);
357
358         psBase = OSAllocZMem(sizeof(*psBase));
359         if (psBase == NULL)
360         {
361                 PVR_DPF((PVR_DBG_ERROR, "%s: Couldn't allocate generic handle base", __FUNCTION__));
362
363                 return PVRSRV_ERROR_OUT_OF_MEMORY;
364         }
365
366         idr_init(&psBase->sIdr);
367
368         psBase->ui32MaxHandleValue = ID_VALUE_MAX;
369         psBase->ui32TotalHandCount = 0;
370
371         *ppsBase = psBase;
372
373         return PVRSRV_OK;
374 }
375
376 /*!
377 ******************************************************************************
378
379  @Function      DestroyHandleBase
380
381  @Description   Destroy a handle base structure
382
383  @Input         psBase - pointer to handle base structure
384
385  @Return        Error code or PVRSRV_OK
386
387 ******************************************************************************/
388 static PVRSRV_ERROR DestroyHandleBase(HANDLE_IMPL_BASE *psBase)
389 {
390         PVR_ASSERT(psBase);
391
392 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0))
393         idr_remove_all(&psBase->sIdr);
394 #endif
395
396         /* Finally destroy the idr */
397         idr_destroy(&psBase->sIdr);
398
399         OSFreeMem(psBase);
400
401         return PVRSRV_OK;
402 }
403
404
405 static const HANDLE_IMPL_FUNCTAB g_sHandleFuncTab = 
406 {
407         .pfnAcquireHandle = AcquireHandle,
408         .pfnReleaseHandle = ReleaseHandle,
409         .pfnGetHandleData = GetHandleData,
410         .pfnSetHandleData = SetHandleData,
411         .pfnIterateOverHandles = IterateOverHandles,
412         .pfnEnableHandlePurging = EnableHandlePurging,
413         .pfnPurgeHandles = PurgeHandles,
414         .pfnCreateHandleBase = CreateHandleBase,
415         .pfnDestroyHandleBase = DestroyHandleBase
416 };
417
418 PVRSRV_ERROR PVRSRVHandleGetFuncTable(HANDLE_IMPL_FUNCTAB const **ppsFuncs)
419 {
420         static IMG_BOOL bAcquired = IMG_FALSE;
421
422         if (bAcquired)
423         {
424                 PVR_DPF((PVR_DBG_ERROR, "%s: Function table already acquired", 
425                          __FUNCTION__));
426                 return PVRSRV_ERROR_RESOURCE_UNAVAILABLE;
427         }
428
429         if (ppsFuncs == NULL)
430         {
431                 return PVRSRV_ERROR_INVALID_PARAMS;
432         }
433
434         *ppsFuncs = &g_sHandleFuncTab;
435
436         bAcquired = IMG_TRUE;
437
438         return PVRSRV_OK;
439 }