1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
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.
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.
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.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #include <linux/sched.h>
31 #include "pvr_bridge.h"
32 #include "pvr_bridge_km.h"
34 #include "syscommon.h"
35 #include "pvr_debug.h"
37 #include "private_data.h"
39 #include "sgx_bridge.h"
41 #include "bridged_pvr_bridge.h"
43 /* Global driver lock protecting all HW and SW state tracking objects. */
44 DEFINE_MUTEX(gPVRSRVLock);
45 static int pvr_dev_locked;
46 static DECLARE_WAIT_QUEUE_HEAD(pvr_dev_wq);
50 * The pvr_dvfs_* interface is needed to suppress a lockdep warning in
51 * the following situation during a clock rate change:
52 * On the CLK_PRE_RATE_CHANGE:
53 * 1. lock A <- __blocking_notifier_call_chain:nh->rwsem
54 * 2. lock B <- vdd2_pre_post_func:gPVRSRVLock
57 * On the CLK_POST_RATE_CHANGE/CLK_ABORT_RATE_CHANGE:
62 * The above has an ABA lock pattern which triggers the warning. This can't
63 * lead to a dead lock though since at 3. we always release A, before it's
64 * again acquired at 4. To avoid the warning use a wait queue based approach
65 * so that we can unlock B before 3.
67 void pvr_dev_lock(void)
69 while (cmpxchg(&pvr_dev_locked, 0, 1)) {
70 DEFINE_WAIT(pvr_dev_wait);
71 prepare_to_wait(&pvr_dev_wq, &pvr_dev_wait,
72 TASK_UNINTERRUPTIBLE);
75 finish_wait(&pvr_dev_wq, &pvr_dev_wait);
79 void pvr_dev_unlock(void)
81 BUG_ON(!pvr_dev_locked);
86 #if defined(DEBUG_BRIDGE_KM)
87 static off_t printLinuxBridgeStats(char *buffer, size_t size, off_t off);
90 enum PVRSRV_ERROR LinuxBridgeInit(void)
92 #if defined(DEBUG_BRIDGE_KM)
96 CreateProcReadEntry("bridge_stats", printLinuxBridgeStats);
98 return PVRSRV_ERROR_OUT_OF_MEMORY;
101 return CommonBridgeInit();
104 void LinuxBridgeDeInit(void)
106 #if defined(DEBUG_BRIDGE_KM)
107 RemoveProcEntry("bridge_stats");
111 #if defined(DEBUG_BRIDGE_KM)
112 static off_t printLinuxBridgeStats(char *buffer, size_t count, off_t off)
114 struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry;
122 goto unlock_and_return;
124 Ret = printAppend(buffer, count, 0,
125 "Total ioctl call count = %u\n"
126 "Total number of bytes copied via copy_from_user = %u\n"
127 "Total number of bytes copied via copy_to_user = %u\n"
128 "Total number of bytes copied via copy_*_user = %u\n\n"
129 "%-45s | %-40s | %10s | %20s | %10s\n",
130 g_BridgeGlobalStats.ui32IOCTLCount,
131 g_BridgeGlobalStats.ui32TotalCopyFromUserBytes,
132 g_BridgeGlobalStats.ui32TotalCopyToUserBytes,
133 g_BridgeGlobalStats.ui32TotalCopyFromUserBytes +
134 g_BridgeGlobalStats.ui32TotalCopyToUserBytes,
135 "Bridge Name", "Wrapper Function",
136 "Call Count", "copy_from_user Bytes",
137 "copy_to_user Bytes");
139 goto unlock_and_return;
142 if (off > BRIDGE_DISPATCH_TABLE_ENTRY_COUNT) {
144 goto unlock_and_return;
149 goto unlock_and_return;
152 psEntry = &g_BridgeDispatchTable[off - 1];
153 Ret = printAppend(buffer, count, 0,
154 "%-45s %-40s %-10u %-20u %-10u\n",
156 psEntry->pszFunctionName,
157 psEntry->ui32CallCount,
158 psEntry->ui32CopyFromUserTotalBytes,
159 psEntry->ui32CopyToUserTotalBytes);
168 long PVRSRV_BridgeDispatchKM(struct file *filp, unsigned int cmd,
171 u32 ui32BridgeID = PVRSRV_GET_BRIDGE_ID(cmd);
172 struct PVRSRV_BRIDGE_PACKAGE __user *psBridgePackageUM =
173 (struct PVRSRV_BRIDGE_PACKAGE __user *)arg;
174 struct PVRSRV_BRIDGE_PACKAGE sBridgePackageKM;
175 u32 ui32PID = OSGetCurrentProcessIDKM();
176 struct PVRSRV_PER_PROCESS_DATA *psPerProc;
181 if (pvr_is_disabled()) {
186 if (!OSAccessOK(PVR_VERIFY_WRITE, psBridgePackageUM,
187 sizeof(struct PVRSRV_BRIDGE_PACKAGE))) {
188 PVR_DPF(PVR_DBG_ERROR,
189 "%s: Received invalid pointer to function arguments",
192 goto unlock_and_return;
195 if (OSCopyFromUser(NULL, &sBridgePackageKM, psBridgePackageUM,
196 sizeof(struct PVRSRV_BRIDGE_PACKAGE)) != PVRSRV_OK)
197 goto unlock_and_return;
200 PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_CONNECT_SERVICES)) {
201 enum PVRSRV_ERROR eError;
203 eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE,
205 sBridgePackageKM.hKernelServices,
206 PVRSRV_HANDLE_TYPE_PERPROC_DATA);
207 if (eError != PVRSRV_OK) {
208 PVR_DPF(PVR_DBG_ERROR,
209 "%s: Invalid kernel services handle (%d)",
211 goto unlock_and_return;
214 if (psPerProc->ui32PID != ui32PID) {
215 PVR_DPF(PVR_DBG_ERROR,
216 "%s: Process %d tried to access data "
217 "belonging to process %d", __func__,
218 ui32PID, psPerProc->ui32PID);
219 goto unlock_and_return;
222 psPerProc = PVRSRVPerProcessData(ui32PID);
223 if (psPerProc == NULL) {
224 PVR_DPF(PVR_DBG_ERROR, "PVRSRV_BridgeDispatchKM: "
225 "Couldn't create per-process data area");
226 goto unlock_and_return;
230 sBridgePackageKM.ui32BridgeID = PVRSRV_GET_BRIDGE_ID(
231 sBridgePackageKM.ui32BridgeID);
233 err = BridgedDispatchKM(filp, psPerProc, &sBridgePackageKM);
234 if (err != PVRSRV_OK)
235 goto unlock_and_return;