1 /*************************************************************************/ /*!
3 @Title Debug driver main file
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
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:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
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.
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.
31 This License is also included in this distribution in the file called
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>
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>
53 #if defined(LDM_PLATFORM) && !defined(SUPPORT_DRM)
54 #include <linux/platform_device.h>
57 #if defined(LDM_PCI) && !defined(SUPPORT_DRM)
58 #include <linux/pci.h>
61 #include <asm/uaccess.h>
63 #if defined(SUPPORT_DRM)
67 #include "img_types.h"
69 #include "dbgdriv_ioctl.h"
70 #include "dbgdrvif_srv5.h"
73 #include "pvr_debug.h"
74 #include "pvrmodule.h"
75 #include "pvr_uaccess.h"
77 #if defined(SUPPORT_DRM)
79 #include "pvr_drm_shared.h"
82 #else /* defined(SUPPORT_DRM) */
84 #define DRVNAME "dbgdrv"
85 MODULE_SUPPORTED_DEVICE(DRVNAME);
87 static struct class *psDbgDrvClass;
89 static int AssignedMajorNumber = 0;
91 long dbgdrv_ioctl(struct file *, unsigned int, unsigned long);
92 long dbgdrv_ioctl_compat(struct file *, unsigned int, unsigned long);
94 static int dbgdrv_open(struct inode unref__ * pInode, struct file unref__ * pFile)
99 static int dbgdrv_release(struct inode unref__ * pInode, struct file unref__ * pFile)
104 static int dbgdrv_mmap(struct file* pFile, struct vm_area_struct* ps_vma)
109 static struct file_operations dbgdrv_fops =
111 .owner = THIS_MODULE,
112 .unlocked_ioctl = dbgdrv_ioctl,
113 .compat_ioctl = dbgdrv_ioctl_compat,
115 .release = dbgdrv_release,
119 #endif /* defined(SUPPORT_DRM) */
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
128 static IMG_CHAR* g_outTmpBuf = IMG_NULL;
129 static IMG_UINT32 g_outTmpBufSize = 64*PAGE_SIZE;
130 static void* g_pvOutTmpBufMutex = IMG_NULL;
132 IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table);
134 IMG_VOID DBGDrvGetServiceTable(IMG_VOID **fn_table)
136 extern DBGKM_SERVICE_TABLE g_sDBGKMServices;
138 *fn_table = &g_sDBGKMServices;
141 #if defined(SUPPORT_DRM)
142 void dbgdrv_cleanup(void)
144 void cleanup_module(void)
150 g_outTmpBuf = IMG_NULL;
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();
161 HostDestroyMutex(g_pvOutTmpBufMutex);
162 HostDestroyMutex(g_pvAPIMutex);
166 #if defined(SUPPORT_DRM)
167 IMG_INT dbgdrv_init(void)
169 int init_module(void)
172 #if !defined(SUPPORT_DRM)
173 struct device *psDev;
176 #if !defined(SUPPORT_DRM)
181 if ((g_pvAPIMutex=HostCreateMutex()) == IMG_NULL)
186 /* Init TmpBuf mutex */
187 if ((g_pvOutTmpBufMutex=HostCreateMutex()) == IMG_NULL)
192 #if defined(SUPPORT_DBGDRV_EVENT_OBJECTS)
194 * The current implementation of HostCreateEventObjects on Linux
195 * can never fail, so there is no need to check for error.
197 (void) HostCreateEventObjects();
200 #if !defined(SUPPORT_DRM)
201 AssignedMajorNumber =
202 register_chrdev(AssignedMajorNumber, DRVNAME, &dbgdrv_fops);
204 if (AssignedMajorNumber <= 0)
206 PVR_DPF((PVR_DBG_ERROR," unable to get major\n"));
207 goto ErrDestroyEventObjects;
211 * This code (using GPL symbols) facilitates automatic device
212 * node creation on platforms with udev (or similar).
214 psDbgDrvClass = class_create(THIS_MODULE, DRVNAME);
215 if (IS_ERR(psDbgDrvClass))
217 PVR_DPF((PVR_DBG_ERROR, "%s: unable to create class (%ld)",
218 __func__, PTR_ERR(psDbgDrvClass)));
219 goto ErrUnregisterCharDev;
222 psDev = device_create(psDbgDrvClass, NULL, MKDEV(AssignedMajorNumber, 0), NULL, DRVNAME);
225 PVR_DPF((PVR_DBG_ERROR, "%s: unable to create device (%ld)",
226 __func__, PTR_ERR(psDev)));
227 goto ErrDestroyClass;
229 #endif /* !defined(SUPPORT_DRM) */
233 #if !defined(SUPPORT_DRM)
234 ErrDestroyEventObjects:
235 #if defined(SUPPORT_DBGDRV_EVENT_OBJECTS)
236 HostDestroyEventObjects();
238 ErrUnregisterCharDev:
239 unregister_chrdev(AssignedMajorNumber, DRVNAME);
241 class_destroy(psDbgDrvClass);
243 #endif /* !defined(SUPPORT_DRM) */
246 static IMG_INT dbgdrv_ioctl_work(IMG_VOID *arg, IMG_BOOL bCompat)
248 IOCTL_PACKAGE *pIP = (IOCTL_PACKAGE *) arg;
249 char *buffer, *in, *out;
251 IMG_VOID *pBufferIn, *pBufferOut;
253 if ((pIP->ui32InBufferSize > (PAGE_SIZE >> 1) ) || (pIP->ui32OutBufferSize > (PAGE_SIZE >> 1)))
255 PVR_DPF((PVR_DBG_ERROR,"Sizes of the buffers are too large, cannot do ioctl\n"));
259 buffer = (char *) HostPageablePageAlloc(1);
262 PVR_DPF((PVR_DBG_ERROR,"Failed to allocate buffer, cannot do ioctl\n"));
267 out = buffer + (PAGE_SIZE >>1);
269 pBufferIn = WIDEPTR_GET_PTR(pIP->pInBuffer, bCompat);
270 pBufferOut = WIDEPTR_GET_PTR(pIP->pOutBuffer, bCompat);
272 if (pvr_copy_from_user(in, pBufferIn, pIP->ui32InBufferSize) != 0)
277 /* Extra -1 because ioctls start at DEBUG_SERVICE_IOCTL_BASE + 1 */
278 cmd = MAKEIOCTLINDEX(pIP->ui32Cmd) - DEBUG_SERVICE_IOCTL_BASE - 1;
280 if (pIP->ui32Cmd == DEBUG_SERVICE_READ)
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;
288 psStream = SID2PStream(psReadInParams->hStream);
294 /* Serialise IOCTL Read op access to the singular output buffer */
295 HostAquireMutex(g_pvOutTmpBufMutex);
297 if ((g_outTmpBuf == IMG_NULL) || (psReadInParams->ui32OutBufferSize > g_outTmpBufSize))
299 if (psReadInParams->ui32OutBufferSize > g_outTmpBufSize)
301 g_outTmpBufSize = psReadInParams->ui32OutBufferSize;
303 g_outTmpBuf = vmalloc(g_outTmpBufSize);
306 HostReleaseMutex(g_pvOutTmpBufMutex);
311 /* Ensure only one thread is allowed into the DBGDriv core at a time */
312 HostAquireMutex(g_pvAPIMutex);
314 psReadOutParams->ui32DataRead = DBGDrivRead(psStream,
315 psReadInParams->ui32BufID,
316 psReadInParams->ui32OutBufferSize,
318 psReadOutParams->ui32SplitMarker = DBGDrivGetMarker(psStream);
320 HostReleaseMutex(g_pvAPIMutex);
322 pvOutBuffer = WIDEPTR_GET_PTR(psReadInParams->pui8OutBuffer, bCompat);
324 if (pvr_copy_to_user(pvOutBuffer,
326 *pui32BytesCopied) != 0)
328 HostReleaseMutex(g_pvOutTmpBufMutex);
332 HostReleaseMutex(g_pvOutTmpBufMutex);
337 (g_DBGDrivProc[cmd])(in, out, bCompat);
340 if (copy_to_user(pBufferOut, out, pIP->ui32OutBufferSize) != 0)
345 HostPageablePageFree((IMG_VOID *)buffer);
349 HostPageablePageFree((IMG_VOID *)buffer);
353 #if defined(SUPPORT_DRM)
354 int dbgdrv_ioctl(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile)
356 long dbgdrv_ioctl(struct file *file, unsigned int ioctlCmd, unsigned long arg)
359 return dbgdrv_ioctl_work((IMG_VOID *) arg, IMG_FALSE);
362 #if defined(SUPPORT_DRM)
363 int dbgdrv_ioctl_compat(struct drm_device *dev, IMG_VOID *arg, struct drm_file *pFile)
365 long dbgdrv_ioctl_compat(struct file *file, unsigned int ioctlCmd, unsigned long arg)
368 return dbgdrv_ioctl_work((IMG_VOID *) arg, IMG_TRUE);
373 EXPORT_SYMBOL(DBGDrvGetServiceTable);