import PULS_20180308
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / gpu / ged / src / ged_main.c
CommitLineData
6fa3eb70
S
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"
44static GED_LOG_BUF_HANDLE ghLogBuf_GLES = 0;
45GED_LOG_BUF_HANDLE ghLogBuf_GED = 0;
46#endif
47
48static void* gvIOCTLParamBuf = NULL;
49
50/******************************************************************************
51 * GED File operations
52 *****************************************************************************/
53static 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
59static 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
65static unsigned int ged_poll(struct file *file, struct poll_table_struct *ptable)
66{
67 return 0;
68}
69
70static ssize_t ged_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
71{
72 return 0;
73}
74
75static ssize_t ged_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
76{
77 return 0;
78}
79
80static 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
4b9e9796
S
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)
6fa3eb70
S
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
148DEFINE_SEMAPHORE(ged_dal_sem);
149
150static 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
171unlock_and_return:
172 up(&ged_dal_sem);
173
174 return ret;
175}
176
177#ifdef CONFIG_COMPAT
178static 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
217unlock_and_return:
218 up(&ged_dal_sem);
219
220 return ret;
221}
222#endif
223
224/******************************************************************************
225 * Module related
226 *****************************************************************************/
227
228static 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
242static struct miscdevice ged_dev = {
243 .minor = MISC_DYNAMIC_MINOR,
244 .name = "ged",
245 .fops = &ged_fops,
246};
247#endif
248
249static 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
274static 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
320ERROR:
321 ged_exit();
322
323 return -EFAULT;
324}
325
326module_init(ged_init);
327module_exit(ged_exit);
328
329MODULE_LICENSE("GPL");
330MODULE_DESCRIPTION("MediaTek GED Driver");
331MODULE_AUTHOR("MediaTek Inc.");