import PULS_20180308
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / ged / src / ged_main.c
1 /*
2 * (C) Copyright 2010
3 * MediaTek <www.MediaTek.com>
4 *
5 * MTK GPU Extension Device
6 *
7 */
8
9 #include <linux/cdev.h>
10 #include <linux/delay.h>
11 #include <linux/device.h>
12 #include <linux/fs.h>
13 #include <linux/hardirq.h>
14 #include <linux/init.h>
15 #include <linux/kallsyms.h>
16 #include <linux/miscdevice.h>
17 #include <linux/module.h>
18 #include <linux/poll.h>
19 #include <linux/proc_fs.h>
20 #include <linux/wait.h>
21 #include <linux/sched.h>
22 #include <linux/vmalloc.h>
23 #include <linux/disp_assert_layer.h>
24 #include <mach/system.h>
25 #include <linux/slab.h>
26 #include <linux/spinlock.h>
27 #include <linux/semaphore.h>
28 #include <linux/workqueue.h>
29 #include <linux/kthread.h>
30 #include <linux/aee.h>
31
32 #include "ged_debugFS.h"
33 #include "ged_log.h"
34 #include "ged_bridge.h"
35 #include "ged_profile_dvfs.h"
36 #include "ged_monitor_3D_fence.h"
37
38 #define GED_DRIVER_DEVICE_NAME "ged"
39
40 #define GED_IOCTL_PARAM_BUF_SIZE 0x3000 //12KB
41
42 #ifdef GED_DEBUG
43 #define GED_LOG_BUF_COMMON_GLES "GLES"
44 static GED_LOG_BUF_HANDLE ghLogBuf_GLES = 0;
45 GED_LOG_BUF_HANDLE ghLogBuf_GED = 0;
46 #endif
47
48 static void* gvIOCTLParamBuf = NULL;
49
50 /******************************************************************************
51 * GED File operations
52 *****************************************************************************/
53 static int ged_open(struct inode *inode, struct file *filp)
54 {
55 GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
56 return 0;
57 }
58
59 static int ged_release(struct inode *inode, struct file *filp)
60 {
61 GED_LOGE("%s:%d:%d\n", __func__, MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
62 return 0;
63 }
64
65 static unsigned int ged_poll(struct file *file, struct poll_table_struct *ptable)
66 {
67 return 0;
68 }
69
70 static ssize_t ged_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
71 {
72 return 0;
73 }
74
75 static ssize_t ged_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
76 {
77 return 0;
78 }
79
80 static long ged_dispatch(GED_BRIDGE_PACKAGE *psBridgePackageKM)
81 {
82 int ret = -EFAULT;
83 void *pvInt, *pvOut;
84 typedef int (ged_bridge_func_type)(void*, void*);
85 ged_bridge_func_type* pFunc = NULL;
86
87 /* We make sure the both size and the sum of them are GE 0 integer.
88 * The sum will not overflow to zero, because we will get zero from two GE 0 integers
89 * if and only if they are both zero in a 2's complement numeral system.
90 * That is: if overflow happen, the sum will be a negative number.
91 */
92 if (psBridgePackageKM->i32InBufferSize >= 0 && psBridgePackageKM->i32OutBufferSize >= 0
93 && psBridgePackageKM->i32InBufferSize + psBridgePackageKM->i32OutBufferSize >= 0
94 && psBridgePackageKM->i32InBufferSize + psBridgePackageKM->i32OutBufferSize
95 < GED_IOCTL_PARAM_BUF_SIZE)
96 {
97 pvInt = gvIOCTLParamBuf;
98 pvOut = (void*)((char*)pvInt + (uintptr_t)psBridgePackageKM->i32InBufferSize);
99 if (psBridgePackageKM->i32InBufferSize > 0)
100 {
101 if (0 != ged_copy_from_user(pvInt, psBridgePackageKM->pvParamIn, psBridgePackageKM->i32InBufferSize))
102 {
103 GED_LOGE("ged_copy_from_user fail\n");
104 return ret;
105 }
106 }
107
108 // we will change the below switch into a function pointer mapping table in the future
109 switch(GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID))
110 {
111 case GED_BRIDGE_COMMAND_LOG_BUF_GET:
112 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_get;
113 break;
114 case GED_BRIDGE_COMMAND_LOG_BUF_WRITE:
115 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_write;
116 break;
117 case GED_BRIDGE_COMMAND_LOG_BUF_RESET:
118 pFunc = (ged_bridge_func_type*)ged_bridge_log_buf_reset;
119 break;
120 case GED_BRIDGE_COMMAND_BOOST_GPU_FREQ:
121 pFunc = (ged_bridge_func_type*)ged_bridge_boost_gpu_freq;
122 break;
123 case GED_BRIDGE_COMMAND_MONITOR_3D_FENCE:
124 pFunc = (ged_bridge_func_type*)ged_bridge_monitor_3D_fence;
125 break;
126 default:
127 GED_LOGE("Unknown Bridge ID: %u\n", GED_GET_BRIDGE_ID(psBridgePackageKM->ui32FunctionID));
128 break;
129 }
130
131 if (pFunc)
132 {
133 ret = pFunc(pvInt, pvOut);
134 }
135
136 if (psBridgePackageKM->i32OutBufferSize > 0)
137 {
138 if (0 != ged_copy_to_user(psBridgePackageKM->pvParamOut, pvOut, psBridgePackageKM->i32OutBufferSize))
139 {
140 return ret;
141 }
142 }
143 }
144
145 return ret;
146 }
147
148 DEFINE_SEMAPHORE(ged_dal_sem);
149
150 static long ged_ioctl(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
151 {
152 int ret = -EFAULT;
153 GED_BRIDGE_PACKAGE *psBridgePackageKM, *psBridgePackageUM = (GED_BRIDGE_PACKAGE*)arg;
154 GED_BRIDGE_PACKAGE sBridgePackageKM;
155
156 if (down_interruptible(&ged_dal_sem) < 0)
157 {
158 GED_LOGE("Fail to down ged_dal_sem\n");
159 return -ERESTARTSYS;
160 }
161
162 psBridgePackageKM = &sBridgePackageKM;
163 if (0 != ged_copy_from_user(psBridgePackageKM, psBridgePackageUM, sizeof(GED_BRIDGE_PACKAGE)))
164 {
165 GED_LOGE("Fail to ged_copy_from_user\n");
166 goto unlock_and_return;
167 }
168
169 ret = ged_dispatch(psBridgePackageKM);
170
171 unlock_and_return:
172 up(&ged_dal_sem);
173
174 return ret;
175 }
176
177 #ifdef CONFIG_COMPAT
178 static long ged_ioctl_compat(struct file *pFile, unsigned int ioctlCmd, unsigned long arg)
179 {
180 typedef struct GED_BRIDGE_PACKAGE_32_TAG
181 {
182 unsigned int ui32FunctionID;
183 int i32Size;
184 unsigned int ui32ParamIn;
185 int i32InBufferSize;
186 unsigned int ui32ParamOut;
187 int i32OutBufferSize;
188 } GED_BRIDGE_PACKAGE_32;
189
190 int ret = -EFAULT;
191 GED_BRIDGE_PACKAGE sBridgePackageKM64;
192 GED_BRIDGE_PACKAGE_32 sBridgePackageKM32;
193 GED_BRIDGE_PACKAGE_32 *psBridgePackageKM32 = &sBridgePackageKM32;
194 GED_BRIDGE_PACKAGE_32 *psBridgePackageUM32 = (GED_BRIDGE_PACKAGE_32*)arg;
195
196 if (down_interruptible(&ged_dal_sem) < 0)
197 {
198 GED_LOGE("Fail to down ged_dal_sem\n");
199 return -ERESTARTSYS;
200 }
201
202 if (0 != ged_copy_from_user(psBridgePackageKM32, psBridgePackageUM32, sizeof(GED_BRIDGE_PACKAGE_32)))
203 {
204 GED_LOGE("Fail to ged_copy_from_user\n");
205 goto unlock_and_return;
206 }
207
208 sBridgePackageKM64.ui32FunctionID = psBridgePackageKM32->ui32FunctionID;
209 sBridgePackageKM64.i32Size = sizeof(GED_BRIDGE_PACKAGE);
210 sBridgePackageKM64.pvParamIn = (void*) ((size_t) psBridgePackageKM32->ui32ParamIn);
211 sBridgePackageKM64.pvParamOut = (void*) ((size_t) psBridgePackageKM32->ui32ParamOut);
212 sBridgePackageKM64.i32InBufferSize = psBridgePackageKM32->i32InBufferSize;
213 sBridgePackageKM64.i32OutBufferSize = psBridgePackageKM32->i32OutBufferSize;
214
215 ret = ged_dispatch(&sBridgePackageKM64);
216
217 unlock_and_return:
218 up(&ged_dal_sem);
219
220 return ret;
221 }
222 #endif
223
224 /******************************************************************************
225 * Module related
226 *****************************************************************************/
227
228 static struct file_operations ged_fops = {
229 .owner = THIS_MODULE,
230 .open = ged_open,
231 .release = ged_release,
232 .poll = ged_poll,
233 .read = ged_read,
234 .write = ged_write,
235 .unlocked_ioctl = ged_ioctl,
236 #ifdef CONFIG_COMPAT
237 .compat_ioctl = ged_ioctl_compat,
238 #endif
239 };
240
241 #if 0
242 static struct miscdevice ged_dev = {
243 .minor = MISC_DYNAMIC_MINOR,
244 .name = "ged",
245 .fops = &ged_fops,
246 };
247 #endif
248
249 static void ged_exit(void)
250 {
251 #ifdef GED_DEBUG
252 ged_log_buf_free(ghLogBuf_GED);
253 ghLogBuf_GED = 0;
254
255 ged_log_buf_free(ghLogBuf_GLES);
256 ghLogBuf_GLES = 0;
257 #endif
258
259 ged_profile_dvfs_exit();
260
261 ged_log_system_exit();
262
263 ged_debugFS_exit();
264
265 remove_proc_entry(GED_DRIVER_DEVICE_NAME, NULL);
266
267 if (gvIOCTLParamBuf)
268 {
269 vfree(gvIOCTLParamBuf);
270 gvIOCTLParamBuf = NULL;
271 }
272 }
273
274 static int ged_init(void)
275 {
276 GED_ERROR err = GED_ERROR_FAIL;
277
278 gvIOCTLParamBuf = vmalloc(GED_IOCTL_PARAM_BUF_SIZE);
279 if (NULL == gvIOCTLParamBuf)
280 {
281 err = GED_ERROR_OOM;
282 goto ERROR;
283 }
284
285 if (NULL == proc_create(GED_DRIVER_DEVICE_NAME, 0644, NULL, &ged_fops))
286 {
287 err = GED_ERROR_FAIL;
288 GED_LOGE("ged: failed to register ged proc entry!\n");
289 goto ERROR;
290 }
291
292 err = ged_debugFS_init();
293 if (unlikely(err != GED_OK))
294 {
295 GED_LOGE("ged: failed to init debug FS!\n");
296 goto ERROR;
297 }
298
299 err = ged_log_system_init();
300 if (unlikely(err != GED_OK))
301 {
302 GED_LOGE("ged: failed to create gedlog entry!\n");
303 goto ERROR;
304 }
305
306 err = ged_profile_dvfs_init();
307 if (unlikely(err != GED_OK))
308 {
309 GED_LOGE("ged: failed to init profile dvfs!\n");
310 goto ERROR;
311 }
312
313 #ifdef GED_DEBUG
314 ghLogBuf_GLES = ged_log_buf_alloc(160, 128, GED_LOG_BUF_TYPE_RINGBUFFER, GED_LOG_BUF_COMMON_GLES, NULL);
315 ghLogBuf_GED = ged_log_buf_alloc(32, 64, GED_LOG_BUF_TYPE_RINGBUFFER, "GED internal", NULL);
316 #endif
317
318 return 0;
319
320 ERROR:
321 ged_exit();
322
323 return -EFAULT;
324 }
325
326 module_init(ged_init);
327 module_exit(ged_exit);
328
329 MODULE_LICENSE("GPL");
330 MODULE_DESCRIPTION("MediaTek GED Driver");
331 MODULE_AUTHOR("MediaTek Inc.");