gpu: pvr: pdumpfs: add Kconfig and debugfs pdump mode handling
[sgx.git] / pvr / pvr_bridge_k.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 <linux/sched.h>
28
29 #include "img_defs.h"
30 #include "services.h"
31 #include "pvr_bridge.h"
32 #include "pvr_bridge_km.h"
33 #include "perproc.h"
34 #include "syscommon.h"
35 #include "pvr_debug.h"
36 #include "proc.h"
37 #include "private_data.h"
38
39 #include "sgx_bridge.h"
40
41 #include "bridged_pvr_bridge.h"
42
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);
47 int pvr_disabled;
48
49 /*
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
55  * 3. unlock A
56  *
57  * On the CLK_POST_RATE_CHANGE/CLK_ABORT_RATE_CHANGE:
58  * 4. lock A
59  * 5. unlock B
60  * 6. unlock A
61  *
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.
66  */
67 void pvr_dev_lock(void)
68 {
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);
73                 if (pvr_dev_locked)
74                         schedule();
75                 finish_wait(&pvr_dev_wq, &pvr_dev_wait);
76         }
77 }
78
79 void pvr_dev_unlock(void)
80 {
81         BUG_ON(!pvr_dev_locked);
82         pvr_dev_locked = 0;
83         wake_up(&pvr_dev_wq);
84 }
85
86 #if defined(DEBUG_BRIDGE_KM)
87 static off_t printLinuxBridgeStats(char *buffer, size_t size, off_t off);
88 #endif
89
90 enum PVRSRV_ERROR LinuxBridgeInit(void)
91 {
92 #if defined(DEBUG_BRIDGE_KM)
93         {
94                 int iStatus;
95                 iStatus =
96                     CreateProcReadEntry("bridge_stats", printLinuxBridgeStats);
97                 if (iStatus != 0)
98                         return PVRSRV_ERROR_OUT_OF_MEMORY;
99         }
100 #endif
101         return CommonBridgeInit();
102 }
103
104 void LinuxBridgeDeInit(void)
105 {
106 #if defined(DEBUG_BRIDGE_KM)
107         RemoveProcEntry("bridge_stats");
108 #endif
109 }
110
111 #if defined(DEBUG_BRIDGE_KM)
112 static off_t printLinuxBridgeStats(char *buffer, size_t count, off_t off)
113 {
114         struct PVRSRV_BRIDGE_DISPATCH_TABLE_ENTRY *psEntry;
115         off_t Ret;
116
117         pvr_lock();
118
119         if (!off) {
120                 if (count < 500) {
121                         Ret = 0;
122                         goto unlock_and_return;
123                 }
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");
138
139                 goto unlock_and_return;
140         }
141
142         if (off > BRIDGE_DISPATCH_TABLE_ENTRY_COUNT) {
143                 Ret = END_OF_FILE;
144                 goto unlock_and_return;
145         }
146
147         if (count < 300) {
148                 Ret = 0;
149                 goto unlock_and_return;
150         }
151
152         psEntry = &g_BridgeDispatchTable[off - 1];
153         Ret = printAppend(buffer, count, 0,
154                           "%-45s   %-40s   %-10u   %-20u   %-10u\n",
155                           psEntry->pszIOCName,
156                           psEntry->pszFunctionName,
157                           psEntry->ui32CallCount,
158                           psEntry->ui32CopyFromUserTotalBytes,
159                           psEntry->ui32CopyToUserTotalBytes);
160
161 unlock_and_return:
162         pvr_unlock();
163
164         return Ret;
165 }
166 #endif
167
168 long PVRSRV_BridgeDispatchKM(struct file *filp, unsigned int cmd,
169                              unsigned long arg)
170 {
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;
177         int err = -EFAULT;
178
179         pvr_lock();
180
181         if (pvr_is_disabled()) {
182                 pvr_unlock();
183                 return -ENODEV;
184         }
185
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",
190                          __func__);
191
192                 goto unlock_and_return;
193         }
194
195         if (OSCopyFromUser(NULL, &sBridgePackageKM, psBridgePackageUM,
196                            sizeof(struct PVRSRV_BRIDGE_PACKAGE)) != PVRSRV_OK)
197                 goto unlock_and_return;
198
199         if (ui32BridgeID !=
200             PVRSRV_GET_BRIDGE_ID(PVRSRV_BRIDGE_CONNECT_SERVICES)) {
201                 enum PVRSRV_ERROR eError;
202
203                 eError = PVRSRVLookupHandle(KERNEL_HANDLE_BASE,
204                                             (void **)&psPerProc,
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)",
210                                  __func__, eError);
211                         goto unlock_and_return;
212                 }
213
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;
220                 }
221         } else {
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;
227                 }
228         }
229
230         sBridgePackageKM.ui32BridgeID = PVRSRV_GET_BRIDGE_ID(
231                                                 sBridgePackageKM.ui32BridgeID);
232
233         err = BridgedDispatchKM(filp, psPerProc, &sBridgePackageKM);
234         if (err != PVRSRV_OK)
235                 goto unlock_and_return;
236
237 unlock_and_return:
238         pvr_unlock();
239
240         return err;
241 }