gpu: pvr: get rid of unnecessary hash lookups for the proc object
[sgx.git] / pvr / perproc.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 "services_headers.h"
28 #include "resman.h"
29 #include "handle.h"
30 #include "perproc.h"
31 #include "osperproc.h"
32
33 #define HASH_TAB_INIT_SIZE 32
34
35 static struct HASH_TABLE *psHashTab;
36
37 static enum PVRSRV_ERROR FreePerProcessData(
38                                 struct PVRSRV_PER_PROCESS_DATA *psPerProc)
39 {
40         enum PVRSRV_ERROR eError;
41         u32 uiPerProc;
42
43         PVR_ASSERT(psPerProc != NULL);
44
45         if (psPerProc == NULL) {
46                 PVR_DPF(PVR_DBG_ERROR,
47                          "FreePerProcessData: invalid parameter");
48                 return PVRSRV_ERROR_INVALID_PARAMS;
49         }
50
51         uiPerProc = HASH_Remove(psHashTab, (u32)psPerProc->ui32PID);
52         if (uiPerProc == 0) {
53                 PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
54                         "Couldn't find process in per-process data hash table");
55
56                 PVR_ASSERT(psPerProc->ui32PID == 0);
57         } else {
58                 PVR_ASSERT((struct PVRSRV_PER_PROCESS_DATA *)
59                                 uiPerProc == psPerProc);
60                 PVR_ASSERT(((struct PVRSRV_PER_PROCESS_DATA *)uiPerProc)->
61                                 ui32PID == psPerProc->ui32PID);
62         }
63
64         if (psPerProc->psHandleBase != NULL) {
65                 eError = PVRSRVFreeHandleBase(psPerProc->psHandleBase);
66                 if (eError != PVRSRV_OK) {
67                         PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
68                                 "Couldn't free handle base for process (%d)",
69                                  eError);
70                         return eError;
71                 }
72         }
73
74         if (psPerProc->hPerProcData != NULL) {
75                 eError =
76                     PVRSRVReleaseHandle(KERNEL_HANDLE_BASE,
77                                         psPerProc->hPerProcData,
78                                         PVRSRV_HANDLE_TYPE_PERPROC_DATA);
79
80                 if (eError != PVRSRV_OK) {
81                         PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
82                                 "Couldn't release per-process data handle (%d)",
83                                  eError);
84                         return eError;
85                 }
86         }
87
88         eError = OSPerProcessPrivateDataDeInit(psPerProc->hOsPrivateData);
89         if (eError != PVRSRV_OK) {
90                 PVR_DPF(PVR_DBG_ERROR, "FreePerProcessData: "
91                                 "OSPerProcessPrivateDataDeInit failed (%d)",
92                          eError);
93                 return eError;
94         }
95
96         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP, sizeof(*psPerProc), psPerProc,
97                   psPerProc->hBlockAlloc);
98
99         return PVRSRV_OK;
100 }
101
102 struct PVRSRV_PER_PROCESS_DATA *PVRSRVPerProcessData(u32 ui32PID)
103 {
104         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
105
106         PVR_ASSERT(psHashTab != NULL);
107
108         psPerProc =
109             (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
110                                                       (u32) ui32PID);
111         return psPerProc;
112 }
113
114 enum PVRSRV_ERROR PVRSRVPerProcessDataConnect(u32 ui32PID)
115 {
116         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
117         void *hBlockAlloc;
118         enum PVRSRV_ERROR eError = PVRSRV_OK;
119
120         PVR_ASSERT(psHashTab != NULL);
121
122         psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
123                                                       (u32)ui32PID);
124         if (psPerProc == NULL) {
125                 eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
126                                     sizeof(*psPerProc), (void **)&psPerProc,
127                                     &hBlockAlloc);
128                 if (eError != PVRSRV_OK) {
129                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
130                                 "Couldn't allocate per-process data (%d)",
131                                  eError);
132                         return eError;
133                 }
134                 OSMemSet(psPerProc, 0, sizeof(*psPerProc));
135                 psPerProc->hBlockAlloc = hBlockAlloc;
136
137                 if (!HASH_Insert(psHashTab, (u32) ui32PID, (u32)psPerProc)) {
138                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
139                            "Couldn't insert per-process data into hash table");
140                         eError = PVRSRV_ERROR_GENERIC;
141                         goto failure;
142                 }
143
144                 psPerProc->ui32PID = ui32PID;
145                 psPerProc->ui32RefCount = 0;
146
147                 eError =
148                     OSPerProcessPrivateDataInit(&psPerProc->hOsPrivateData);
149                 if (eError != PVRSRV_OK) {
150                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
151                                 "OSPerProcessPrivateDataInit failed (%d)",
152                                  eError);
153                         goto failure;
154                 }
155
156                 eError = PVRSRVAllocHandle(KERNEL_HANDLE_BASE,
157                                            &psPerProc->hPerProcData,
158                                            psPerProc,
159                                            PVRSRV_HANDLE_TYPE_PERPROC_DATA,
160                                            PVRSRV_HANDLE_ALLOC_FLAG_NONE);
161                 if (eError != PVRSRV_OK) {
162                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
163                            "Couldn't allocate handle for per-process data (%d)",
164                            eError);
165                         goto failure;
166                 }
167
168                 eError = PVRSRVAllocHandleBase(&psPerProc->psHandleBase);
169                 if (eError != PVRSRV_OK) {
170                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
171                                "Couldn't allocate handle base for process (%d)",
172                                eError);
173                         goto failure;
174                 }
175
176                 eError = OSPerProcessSetHandleOptions(psPerProc->psHandleBase);
177                 if (eError != PVRSRV_OK) {
178                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
179                                         "Couldn't set handle options (%d)",
180                                  eError);
181                         goto failure;
182                 }
183
184                 eError =
185                     PVRSRVResManConnect(psPerProc, &psPerProc->hResManContext);
186                 if (eError != PVRSRV_OK) {
187                         PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataConnect: "
188                                 "Couldn't register with the resource manager");
189                         goto failure;
190                 }
191         }
192
193         psPerProc->ui32RefCount++;
194         PVR_DPF(PVR_DBG_MESSAGE,
195                  "PVRSRVPerProcessDataConnect: Process 0x%x has ref-count %d",
196                  ui32PID, psPerProc->ui32RefCount);
197
198         return eError;
199
200 failure:
201         (void)FreePerProcessData(psPerProc);
202         return eError;
203 }
204
205 void PVRSRVPerProcessDataDisconnect(u32 ui32PID)
206 {
207         enum PVRSRV_ERROR eError;
208         struct PVRSRV_PER_PROCESS_DATA *psPerProc;
209
210         PVR_ASSERT(psHashTab != NULL);
211
212         psPerProc = (struct PVRSRV_PER_PROCESS_DATA *)HASH_Retrieve(psHashTab,
213                                                               (u32)ui32PID);
214         if (psPerProc == NULL) {
215                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDealloc: "
216                                 "Couldn't locate per-process data for PID %u",
217                          ui32PID);
218         } else {
219                 psPerProc->ui32RefCount--;
220                 if (psPerProc->ui32RefCount == 0) {
221                         PVR_DPF(PVR_DBG_MESSAGE,
222                                  "PVRSRVPerProcessDataDisconnect: "
223                                  "Last close from process 0x%x received",
224                                  ui32PID);
225
226                         PVRSRVResManDisconnect(psPerProc->hResManContext,
227                                                IMG_FALSE);
228
229                         eError = FreePerProcessData(psPerProc);
230                         if (eError != PVRSRV_OK)
231                                 PVR_DPF(PVR_DBG_ERROR,
232                                         "PVRSRVPerProcessDataDisconnect: "
233                                         "Error freeing per-process data");
234                 }
235         }
236
237         eError = PVRSRVPurgeHandles(KERNEL_HANDLE_BASE);
238         if (eError != PVRSRV_OK)
239                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataDisconnect: "
240                                 "Purge of global handle pool failed (%d)",
241                          eError);
242 }
243
244 enum PVRSRV_ERROR PVRSRVPerProcessDataInit(void)
245 {
246         PVR_ASSERT(psHashTab == NULL);
247
248         psHashTab = HASH_Create(HASH_TAB_INIT_SIZE);
249         if (psHashTab == NULL) {
250                 PVR_DPF(PVR_DBG_ERROR, "PVRSRVPerProcessDataInit: "
251                                 "Couldn't create per-process data hash table");
252                 return PVRSRV_ERROR_GENERIC;
253         }
254
255         return PVRSRV_OK;
256 }
257
258 enum PVRSRV_ERROR PVRSRVPerProcessDataDeInit(void)
259 {
260         if (psHashTab != NULL) {
261                 HASH_Delete(psHashTab);
262                 psHashTab = NULL;
263         }
264
265         return PVRSRV_OK;
266 }