RK3368 GPU version Rogue M 1.28
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / rogue_m / tools / services / debug / dbgdriv / linux / main.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Debug driver main file
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License        Dual MIT/GPLv2
6
7 The contents of this file are subject to the MIT license as set out below.
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
22
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
30
31 This License is also included in this distribution in the file called
32 "MIT-COPYING".
33
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
42 #include <linux/errno.h>
43 #include <linux/module.h>
44 #include <linux/fs.h>
45 #include <linux/kernel.h>
46 #include <linux/kdev_t.h>
47 #include <linux/pci.h>
48 #include <linux/list.h>
49 #include <linux/init.h>
50 #include <linux/vmalloc.h>
51 #include <linux/version.h>
52
53 #if defined(LDM_PLATFORM) && !defined(SUPPORT_DRM)
54 #include <linux/platform_device.h>
55 #endif
56
57 #if defined(LDM_PCI) && !defined(SUPPORT_DRM)
58 #include <linux/pci.h>
59 #endif
60
61 #include <asm/uaccess.h>
62
63 #if defined(SUPPORT_DRM)
64 #include <drm/drmP.h>
65 #endif
66
67 #include "img_types.h"
68 #include "linuxsrv.h"
69 #include "dbgdriv_ioctl.h"
70 #include "dbgdrvif_srv5.h"
71 #include "dbgdriv.h"
72 #include "hostfunc.h"
73 #include "pvr_debug.h"
74 #include "pvrmodule.h"
75 #include "pvr_uaccess.h"
76
77 #if defined(SUPPORT_DRM)
78
79 #include "pvr_drm_shared.h"
80 #include "pvr_drm.h"
81
82 #else /* defined(SUPPORT_DRM) */
83
84 #define DRVNAME "dbgdrv"
85 MODULE_SUPPORTED_DEVICE(DRVNAME);
86
87 static struct class *psDbgDrvClass;
88
89 static int AssignedMajorNumber = 0;
90
91 long dbgdrv_ioctl(struct file *, unsigned int, unsigned long);
92 long dbgdrv_ioctl_compat(struct file *, unsigned int, unsigned long);
93
94 static int dbgdrv_open(struct inode unref__ * pInode, struct file unref__ * pFile)
95 {
96         return 0;
97 }
98
99 static int dbgdrv_release(struct inode unref__ * pInode, struct file unref__ * pFile)
100 {
101         return 0;
102 }
103
104 static int dbgdrv_mmap(struct file* pFile, struct vm_area_struct* ps_vma)
105 {
106         return 0;
107 }
108
109 static struct file_operations dbgdrv_fops =
110 {
111         .owner          = THIS_MODULE,
112         .unlocked_ioctl = dbgdrv_ioctl,
113         .compat_ioctl   = dbgdrv_ioctl_compat,
114         .open           = dbgdrv_open,
115         .release        = dbgdrv_release,
116         .mmap           = dbgdrv_mmap,
117 };
118
119 #endif  /* defined(SUPPORT_DRM) */
120
121 /* Outward temp buffer used by IOCTL handler allocated once and grows as needed.
122  * This optimisation means the debug driver performs less vmallocs/vfrees
123  * reducing the chance of kernel vmalloc space exhaustion.
124  * Singular out buffer for PDump UM reads is not multi-thread safe and so
125  * it now needs a mutex to protect it from multiple simultaneous reads in 
126  * the future.
127  */
128 static IMG_CHAR*  g_outTmpBuf = IMG_NULL;
129 static IMG_UINT32 g_outTmpBufSize = 64*PAGE_SIZE;
130 static void*      g_pvOutTmpBufMutex = IMG_NULL;
131
132 IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table);
133
134 IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table)
135 {
136         extern DBGKM_SERVICE_TABLE g_sDBGKMServices;
137
138         *fn_table = &g_sDBGKMServices;
139 }
140
141 #if defined(SUPPORT_DRM)
142 void dbgdrv_cleanup(void)
143 #else
144 void cleanup_module(void)
145 #endif
146 {
147         if (g_outTmpBuf)
148         {
149                 vfree(g_outTmpBuf);
150                 g_outTmpBuf = IMG_NULL;
151         }
152
153 #if !defined(SUPPORT_DRM)
154         device_destroy(psDbgDrvClass, MKDEV(AssignedMajorNumber, 0));
155         class_destroy(psDbgDrvClass);
156         unregister_chrdev(AssignedMajorNumber, DRVNAME);
157 #endif /* !defined(SUPPORT_DRM) */
158 #if defined(SUPPORT_DBGDRV_EVENT_OBJECTS)
159         HostDestroyEventObjects();
160 #endif
161         HostDestroyMutex(g_pvOutTmpBufMutex);
162         HostDestroyMutex(g_pvAPIMutex);
163         return;
164 }
165
166 #if defined(SUPPORT_DRM)
167 IMG_INT dbgdrv_init(void)
168 #else
169 int init_module(void)
170 #endif
171 {
172 #if !defined(SUPPORT_DRM)
173         struct device *psDev;
174 #endif
175
176 #if !defined(SUPPORT_DRM)
177         int err = -EBUSY;
178 #endif
179
180         /* Init API mutex */
181         if ((g_pvAPIMutex=HostCreateMutex()) == IMG_NULL)
182         {
183                 return -ENOMEM;
184         }
185
186         /* Init TmpBuf mutex */
187         if ((g_pvOutTmpBufMutex=HostCreateMutex()) == IMG_NULL)
188         {
189                 return -ENOMEM;
190         }
191
192 #if defined(SUPPORT_DBGDRV_EVENT_OBJECTS)
193         /*
194          * The current implementation of HostCreateEventObjects on Linux
195          * can never fail, so there is no need to check for error.
196          */
197         (void) HostCreateEventObjects();
198 #endif
199
200 #if !defined(SUPPORT_DRM)
201         AssignedMajorNumber =
202                 register_chrdev(AssignedMajorNumber, DRVNAME, &dbgdrv_fops);
203
204         if (AssignedMajorNumber <= 0)
205         {
206                 PVR_DPF((PVR_DBG_ERROR," unable to get major\n"));
207                 goto ErrDestroyEventObjects;
208         }
209
210         /*
211          * This code (using GPL symbols) facilitates automatic device
212          * node creation on platforms with udev (or similar).
213          */
214         psDbgDrvClass = class_create(THIS_MODULE, DRVNAME);
215         if (IS_ERR(psDbgDrvClass))
216         {
217                 PVR_DPF((PVR_DBG_ERROR, "%s: unable to create class (%ld)",
218                                  __func__, PTR_ERR(psDbgDrvClass)));
219                 goto ErrUnregisterCharDev;
220         }
221
222         psDev = device_create(psDbgDrvClass, NULL, MKDEV(AssignedMajorNumber, 0), NULL, DRVNAME);
223         if (IS_ERR(psDev))
224         {
225                 PVR_DPF((PVR_DBG_ERROR, "%s: unable to create device (%ld)",
226                                                                 __func__, PTR_ERR(psDev)));
227                 goto ErrDestroyClass;
228         }
229 #endif /* !defined(SUPPORT_DRM) */
230
231         return 0;
232
233 #if !defined(SUPPORT_DRM)
234 ErrDestroyEventObjects:
235 #if defined(SUPPORT_DBGDRV_EVENT_OBJECTS)
236         HostDestroyEventObjects();
237 #endif
238 ErrUnregisterCharDev:
239         unregister_chrdev(AssignedMajorNumber, DRVNAME);
240 ErrDestroyClass:
241         class_destroy(psDbgDrvClass);
242         return err;
243 #endif /* !defined(SUPPORT_DRM) */
244 }
245
246 static IMG_INT dbgdrv_ioctl_work(IMG_VOID *arg, IMG_BOOL bCompat)
247 {
248         IOCTL_PACKAGE *pIP = (IOCTL_PACKAGE *) arg;
249         char *buffer, *in, *out;
250         unsigned int cmd;
251         IMG_VOID *pBufferIn, *pBufferOut;
252
253         if ((pIP->ui32InBufferSize > (PAGE_SIZE >> 1) ) || (pIP->ui32OutBufferSize > (PAGE_SIZE >> 1)))
254         {
255                 PVR_DPF((PVR_DBG_ERROR,"Sizes of the buffers are too large, cannot do ioctl\n"));
256                 return -1;
257         }
258
259         buffer = (char *) HostPageablePageAlloc(1);
260         if (!buffer)
261         {
262                 PVR_DPF((PVR_DBG_ERROR,"Failed to allocate buffer, cannot do ioctl\n"));
263                 return -EFAULT;
264         }
265
266         in = buffer;
267         out = buffer + (PAGE_SIZE >>1);
268
269         pBufferIn = WIDEPTR_GET_PTR(pIP->pInBuffer, bCompat);
270         pBufferOut = WIDEPTR_GET_PTR(pIP->pOutBuffer, bCompat);
271
272         if (pvr_copy_from_user(in, pBufferIn, pIP->ui32InBufferSize) != 0)
273         {
274                 goto init_failed;
275         }
276
277         /* Extra -1 because ioctls start at DEBUG_SERVICE_IOCTL_BASE + 1 */
278         cmd = MAKEIOCTLINDEX(pIP->ui32Cmd) - DEBUG_SERVICE_IOCTL_BASE - 1;
279
280         if (pIP->ui32Cmd == DEBUG_SERVICE_READ)
281         {
282                 IMG_UINT32 *pui32BytesCopied = (IMG_UINT32 *)out;
283                 DBG_OUT_READ *psReadOutParams = (DBG_OUT_READ *)out;
284                 DBG_IN_READ *psReadInParams = (DBG_IN_READ *)in;
285                 IMG_VOID *pvOutBuffer;
286                 PDBG_STREAM psStream;
287
288                 psStream = SID2PStream(psReadInParams->hStream);
289                 if (!psStream)
290                 {
291                         goto init_failed;
292                 }
293
294                 /* Serialise IOCTL Read op access to the singular output buffer */
295                 HostAquireMutex(g_pvOutTmpBufMutex);
296
297                 if ((g_outTmpBuf == IMG_NULL) || (psReadInParams->ui32OutBufferSize > g_outTmpBufSize))
298                 {
299                         if (psReadInParams->ui32OutBufferSize > g_outTmpBufSize)
300                         {
301                                 g_outTmpBufSize = psReadInParams->ui32OutBufferSize;
302                         }
303                         g_outTmpBuf = vmalloc(g_outTmpBufSize);
304                         if (!g_outTmpBuf)
305                         {
306                                 HostReleaseMutex(g_pvOutTmpBufMutex);
307                                 goto init_failed;
308                         }
309                 }
310
311                 /* Ensure only one thread is allowed into the DBGDriv core at a time */
312                 HostAquireMutex(g_pvAPIMutex);
313
314                 psReadOutParams->ui32DataRead = DBGDrivRead(psStream,
315                                                                                    psReadInParams->ui32BufID,
316                                                                                    psReadInParams->ui32OutBufferSize,
317                                                                                    g_outTmpBuf);
318                 psReadOutParams->ui32SplitMarker = DBGDrivGetMarker(psStream);
319
320                 HostReleaseMutex(g_pvAPIMutex);
321
322                 pvOutBuffer = WIDEPTR_GET_PTR(psReadInParams->pui8OutBuffer, bCompat);
323
324                 if (pvr_copy_to_user(pvOutBuffer,
325                                                 g_outTmpBuf,
326                                                 *pui32BytesCopied) != 0)
327                 {
328                         HostReleaseMutex(g_pvOutTmpBufMutex);
329                         goto init_failed;
330                 }
331
332                 HostReleaseMutex(g_pvOutTmpBufMutex);
333
334         }
335         else
336         {
337                 (g_DBGDrivProc[cmd])(in, out, bCompat);
338         }
339
340         if (copy_to_user(pBufferOut, out, pIP->ui32OutBufferSize) != 0)
341         {
342                 goto init_failed;
343         }
344
345         HostPageablePageFree((IMG_VOID *)buffer);
346         return 0;
347
348 init_failed:
349         HostPageablePageFree((IMG_VOID *)buffer);
350         return -EFAULT;
351 }
352
353 #if defined(SUPPORT_DRM)
354 int dbgdrv_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile)
355 #else
356 long dbgdrv_ioctl(struct file *file, unsigned int ioctlCmd, unsigned long arg)
357 #endif
358 {
359         return dbgdrv_ioctl_work((IMG_VOID *) arg, IMG_FALSE);
360 }
361
362 #if defined(SUPPORT_DRM)
363 int dbgdrv_ioctl_compat(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile)
364 #else
365 long dbgdrv_ioctl_compat(struct file *file, unsigned int ioctlCmd, unsigned long arg)
366 #endif
367 {
368         return dbgdrv_ioctl_work((IMG_VOID *) arg, IMG_TRUE);
369 }
370
371
372
373 EXPORT_SYMBOL(DBGDrvGetServiceTable);