PageRenderTime 47ms CodeModel.GetById 28ms app.highlight 16ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/gpu/mali/mali/linux/mali_kernel_linux.c

https://bitbucket.org/ndreys/linux-sunxi
C | 515 lines | 363 code | 111 blank | 41 comment | 30 complexity | 3e32d362deb71db74684c28fa11d6758 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/**
  2 * Copyright (C) 2010-2012 ARM Limited. All rights reserved.
  3 * 
  4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
  5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
  6 * 
  7 * A copy of the licence is included with the program, and can also be obtained from Free Software
  8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  9 */
 10
 11/**
 12 * @file mali_kernel_linux.c
 13 * Implementation of the Linux device driver entrypoints
 14 */
 15#include <linux/module.h>   /* kernel module definitions */
 16#include <linux/fs.h>       /* file system operations */
 17#include <linux/cdev.h>     /* character device definitions */
 18#include <linux/mm.h>       /* memory manager definitions */
 19#include <linux/mali/mali_utgard_ioctl.h>
 20#include "mali_kernel_common.h"
 21#include "mali_session.h"
 22#include "mali_kernel_core.h"
 23#include "mali_osk.h"
 24#include "mali_kernel_linux.h"
 25#include "mali_ukk.h"
 26#include "mali_ukk_wrappers.h"
 27#include "mali_kernel_pm.h"
 28#include "mali_kernel_sysfs.h"
 29#include "mali_platform.h"
 30#include "mali_kernel_license.h"
 31
 32/* Streamline support for the Mali driver */
 33#if defined(CONFIG_TRACEPOINTS) && MALI_TIMELINE_PROFILING_ENABLED
 34/* Ask Linux to create the tracepoints */
 35#define CREATE_TRACE_POINTS
 36#include "mali_linux_trace.h"
 37#endif /* CONFIG_TRACEPOINTS */
 38
 39static _mali_osk_errcode_t initialize_kernel_device(void);
 40static int initialize_sysfs(void);
 41static void terminate_kernel_device(void);
 42
 43
 44/* from the __malidrv_build_info.c file that is generated during build */
 45extern const char *__malidrv_build_info(void);
 46
 47/* Module parameter to control log level */
 48int mali_debug_level = 2;
 49module_param(mali_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */
 50MODULE_PARM_DESC(mali_debug_level, "Higher number, more dmesg output");
 51
 52/* By default the module uses any available major, but it's possible to set it at load time to a specific number */
 53int mali_major = 0;
 54module_param(mali_major, int, S_IRUGO); /* r--r--r-- */
 55MODULE_PARM_DESC(mali_major, "Device major number");
 56
 57module_param(mali_max_job_runtime, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
 58MODULE_PARM_DESC(mali_max_job_runtime, "Maximum allowed job runtime in msecs.\nJobs will be killed after this no matter what");
 59
 60extern int mali_l2_max_reads;
 61module_param(mali_l2_max_reads, int, S_IRUSR | S_IRGRP | S_IROTH);
 62MODULE_PARM_DESC(mali_l2_max_reads, "Maximum reads for Mali L2 cache");
 63
 64#if MALI_TIMELINE_PROFILING_ENABLED
 65extern int mali_boot_profiling;
 66module_param(mali_boot_profiling, int, S_IRUSR | S_IRGRP | S_IROTH);
 67MODULE_PARM_DESC(mali_boot_profiling, "Start profiling as a part of Mali driver initialization");
 68#endif
 69
 70/* Export symbols from common code: mali_user_settings.c */
 71#include "mali_user_settings_db.h"
 72EXPORT_SYMBOL(mali_set_user_setting);
 73EXPORT_SYMBOL(mali_get_user_setting);
 74
 75static char mali_dev_name[] = "mali"; /* should be const, but the functions we call requires non-cost */
 76
 77/* the mali device */
 78static struct mali_dev device;
 79
 80
 81static int mali_open(struct inode *inode, struct file *filp);
 82static int mali_release(struct inode *inode, struct file *filp);
 83#ifdef HAVE_UNLOCKED_IOCTL
 84static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 85#else
 86static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
 87#endif
 88
 89static int mali_mmap(struct file * filp, struct vm_area_struct * vma);
 90
 91/* Linux char file operations provided by the Mali module */
 92struct file_operations mali_fops =
 93{
 94	.owner = THIS_MODULE,
 95	.open = mali_open,
 96	.release = mali_release,
 97#ifdef HAVE_UNLOCKED_IOCTL
 98	.unlocked_ioctl = mali_ioctl,
 99#else
100	.ioctl = mali_ioctl,
101#endif
102	.mmap = mali_mmap
103};
104
105
106int mali_driver_init(void)
107{
108	int ret = 0;
109
110	MALI_DEBUG_PRINT(2, ("\n"));
111	MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION));
112	MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__));
113	MALI_DEBUG_PRINT(2, ("Driver revision: %s\n", SVN_REV_STRING));
114
115	ret = _mali_dev_platform_register();
116	if (0 != ret) goto platform_register_failed;
117	ret = map_errcode(initialize_kernel_device());
118	if (0 != ret) goto initialize_kernel_device_failed;
119
120	ret = map_errcode(mali_platform_init());
121	if (0 != ret) goto platform_init_failed;
122
123	mali_osk_low_level_mem_init();
124
125	ret = map_errcode(mali_initialize_subsystems());
126	if (0 != ret) goto initialize_subsystems_failed;
127
128	ret = initialize_sysfs();
129	if (0 != ret) goto initialize_sysfs_failed;
130
131	MALI_PRINT(("Mali device driver loaded\n"));
132
133	return 0; /* Success */
134
135	/* Error handling */
136initialize_sysfs_failed:
137	mali_terminate_subsystems();
138initialize_subsystems_failed:
139	mali_osk_low_level_mem_term();
140	mali_platform_deinit();
141platform_init_failed:
142	terminate_kernel_device();
143initialize_kernel_device_failed:
144	_mali_dev_platform_unregister();
145platform_register_failed:
146	return ret;
147}
148
149void mali_driver_exit(void)
150{
151	MALI_DEBUG_PRINT(2, ("\n"));
152	MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION));
153
154	/* No need to terminate sysfs, this will be done automatically along with device termination */
155
156	mali_terminate_subsystems();
157
158	mali_osk_low_level_mem_term();
159
160	mali_platform_deinit();
161
162	terminate_kernel_device();
163	_mali_dev_platform_unregister();
164
165#if MALI_LICENSE_IS_GPL
166	/* @@@@ clean up the work queues! This should not be terminated here, since it isn't inited in the function above! */
167	flush_workqueue(mali_wq);
168	destroy_workqueue(mali_wq);
169	mali_wq = NULL;
170#endif
171
172	MALI_PRINT(("Mali device driver unloaded\n"));
173}
174
175static int initialize_kernel_device(void)
176{
177	int err;
178	dev_t dev = 0;
179	if (0 == mali_major)
180	{
181		/* auto select a major */
182		err = alloc_chrdev_region(&dev, 0/*first minor*/, 1/*count*/, mali_dev_name);
183		mali_major = MAJOR(dev);
184	}
185	else
186	{
187		/* use load time defined major number */
188		dev = MKDEV(mali_major, 0);
189		err = register_chrdev_region(dev, 1/*count*/, mali_dev_name);
190	}
191
192	if (err)
193	{
194			goto init_chrdev_err;
195	}
196
197	memset(&device, 0, sizeof(device));
198
199	/* initialize our char dev data */
200	cdev_init(&device.cdev, &mali_fops);
201	device.cdev.owner = THIS_MODULE;
202	device.cdev.ops = &mali_fops;
203
204	/* register char dev with the kernel */
205	err = cdev_add(&device.cdev, dev, 1/*count*/);
206	if (err)
207	{
208			goto init_cdev_err;
209	}
210
211	/* Success! */
212	return 0;
213
214init_cdev_err:
215	unregister_chrdev_region(dev, 1/*count*/);
216init_chrdev_err:
217	return err;
218}
219
220static int initialize_sysfs(void)
221{
222	dev_t dev = MKDEV(mali_major, 0);
223	return mali_sysfs_register(&device, dev, mali_dev_name);
224}
225
226static void terminate_kernel_device(void)
227{
228	dev_t dev = MKDEV(mali_major, 0);
229
230	mali_sysfs_unregister(&device, dev, mali_dev_name);
231
232	/* unregister char device */
233	cdev_del(&device.cdev);
234	/* free major */
235	unregister_chrdev_region(dev, 1/*count*/);
236	return;
237}
238
239/** @note munmap handler is done by vma close handler */
240static int mali_mmap(struct file * filp, struct vm_area_struct * vma)
241{
242	struct mali_session_data * session_data;
243	_mali_uk_mem_mmap_s args = {0, };
244
245    session_data = (struct mali_session_data *)filp->private_data;
246	if (NULL == session_data)
247	{
248		MALI_PRINT_ERROR(("mmap called without any session data available\n"));
249		return -EFAULT;
250	}
251
252	MALI_DEBUG_PRINT(4, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X\n", (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT), (unsigned int)(vma->vm_end - vma->vm_start)) );
253
254	/* Re-pack the arguments that mmap() packed for us */
255	args.ctx = session_data;
256	args.phys_addr = vma->vm_pgoff << PAGE_SHIFT;
257	args.size = vma->vm_end - vma->vm_start;
258	args.ukk_private = vma;
259
260	/* Call the common mmap handler */
261	MALI_CHECK(_MALI_OSK_ERR_OK ==_mali_ukk_mem_mmap( &args ), -EFAULT);
262
263    return 0;
264}
265
266static int mali_open(struct inode *inode, struct file *filp)
267{
268	struct mali_session_data * session_data;
269    _mali_osk_errcode_t err;
270
271	/* input validation */
272	if (0 != MINOR(inode->i_rdev)) return -ENODEV;
273
274	/* allocated struct to track this session */
275    err = _mali_ukk_open((void **)&session_data);
276    if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
277
278	/* initialize file pointer */
279	filp->f_pos = 0;
280
281	/* link in our session data */
282	filp->private_data = (void*)session_data;
283
284	return 0;
285}
286
287static int mali_release(struct inode *inode, struct file *filp)
288{
289    _mali_osk_errcode_t err;
290
291    /* input validation */
292	if (0 != MINOR(inode->i_rdev)) return -ENODEV;
293
294    err = _mali_ukk_close((void **)&filp->private_data);
295    if (_MALI_OSK_ERR_OK != err) return map_errcode(err);
296
297	return 0;
298}
299
300int map_errcode( _mali_osk_errcode_t err )
301{
302    switch(err)
303    {
304        case _MALI_OSK_ERR_OK : return 0;
305        case _MALI_OSK_ERR_FAULT: return -EFAULT;
306        case _MALI_OSK_ERR_INVALID_FUNC: return -ENOTTY;
307        case _MALI_OSK_ERR_INVALID_ARGS: return -EINVAL;
308        case _MALI_OSK_ERR_NOMEM: return -ENOMEM;
309        case _MALI_OSK_ERR_TIMEOUT: return -ETIMEDOUT;
310        case _MALI_OSK_ERR_RESTARTSYSCALL: return -ERESTARTSYS;
311        case _MALI_OSK_ERR_ITEM_NOT_FOUND: return -ENOENT;
312        default: return -EFAULT;
313    }
314}
315
316#ifdef HAVE_UNLOCKED_IOCTL
317static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
318#else
319static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
320#endif
321{
322	int err;
323	struct mali_session_data *session_data;
324
325#ifndef HAVE_UNLOCKED_IOCTL
326	/* inode not used */
327	(void)inode;
328#endif
329
330	MALI_DEBUG_PRINT(7, ("Ioctl received 0x%08X 0x%08lX\n", cmd, arg));
331
332	session_data = (struct mali_session_data *)filp->private_data;
333	if (NULL == session_data)
334	{
335		MALI_DEBUG_PRINT(7, ("filp->private_data was NULL\n"));
336		return -ENOTTY;
337	}
338
339	if (NULL == (void *)arg)
340	{
341		MALI_DEBUG_PRINT(7, ("arg was NULL\n"));
342		return -ENOTTY;
343	}
344
345	switch(cmd)
346	{
347		case MALI_IOC_GET_SYSTEM_INFO_SIZE:
348			err = get_system_info_size_wrapper(session_data, (_mali_uk_get_system_info_size_s __user *)arg);
349			break;
350
351		case MALI_IOC_GET_SYSTEM_INFO:
352			err = get_system_info_wrapper(session_data, (_mali_uk_get_system_info_s __user *)arg);
353			break;
354
355		case MALI_IOC_WAIT_FOR_NOTIFICATION:
356			err = wait_for_notification_wrapper(session_data, (_mali_uk_wait_for_notification_s __user *)arg);
357			break;
358
359		case MALI_IOC_GET_API_VERSION:
360			err = get_api_version_wrapper(session_data, (_mali_uk_get_api_version_s __user *)arg);
361			break;
362
363		case MALI_IOC_POST_NOTIFICATION:
364			err = post_notification_wrapper(session_data, (_mali_uk_post_notification_s __user *)arg);
365			break;
366
367		case MALI_IOC_GET_USER_SETTINGS:
368			err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg);
369			break;
370
371#if MALI_TIMELINE_PROFILING_ENABLED
372		case MALI_IOC_PROFILING_START:
373			err = profiling_start_wrapper(session_data, (_mali_uk_profiling_start_s __user *)arg);
374			break;
375
376		case MALI_IOC_PROFILING_ADD_EVENT:
377			err = profiling_add_event_wrapper(session_data, (_mali_uk_profiling_add_event_s __user *)arg);
378			break;
379
380		case MALI_IOC_PROFILING_STOP:
381			err = profiling_stop_wrapper(session_data, (_mali_uk_profiling_stop_s __user *)arg);
382			break;
383
384		case MALI_IOC_PROFILING_GET_EVENT:
385			err = profiling_get_event_wrapper(session_data, (_mali_uk_profiling_get_event_s __user *)arg);
386			break;
387
388		case MALI_IOC_PROFILING_CLEAR:
389			err = profiling_clear_wrapper(session_data, (_mali_uk_profiling_clear_s __user *)arg);
390			break;
391
392		case MALI_IOC_PROFILING_GET_CONFIG:
393			/* Deprecated: still compatible with get_user_settings */
394			err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg);
395			break;
396
397		case MALI_IOC_PROFILING_REPORT_SW_COUNTERS:
398			err = profiling_report_sw_counters_wrapper(session_data, (_mali_uk_sw_counters_report_s __user *)arg);
399			break;
400
401#else
402
403		case MALI_IOC_PROFILING_START:              /* FALL-THROUGH */
404		case MALI_IOC_PROFILING_ADD_EVENT:          /* FALL-THROUGH */
405		case MALI_IOC_PROFILING_STOP:               /* FALL-THROUGH */
406		case MALI_IOC_PROFILING_GET_EVENT:          /* FALL-THROUGH */
407		case MALI_IOC_PROFILING_CLEAR:              /* FALL-THROUGH */
408		case MALI_IOC_PROFILING_GET_CONFIG:         /* FALL-THROUGH */
409		case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: /* FALL-THROUGH */
410			MALI_DEBUG_PRINT(2, ("Profiling not supported\n"));
411			err = -ENOTTY;
412			break;
413
414#endif
415
416		case MALI_IOC_MEM_INIT:
417			err = mem_init_wrapper(session_data, (_mali_uk_init_mem_s __user *)arg);
418			break;
419
420		case MALI_IOC_MEM_TERM:
421			err = mem_term_wrapper(session_data, (_mali_uk_term_mem_s __user *)arg);
422			break;
423
424		case MALI_IOC_MEM_MAP_EXT:
425			err = mem_map_ext_wrapper(session_data, (_mali_uk_map_external_mem_s __user *)arg);
426			break;
427
428		case MALI_IOC_MEM_UNMAP_EXT:
429			err = mem_unmap_ext_wrapper(session_data, (_mali_uk_unmap_external_mem_s __user *)arg);
430			break;
431
432		case MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE:
433			err = mem_query_mmu_page_table_dump_size_wrapper(session_data, (_mali_uk_query_mmu_page_table_dump_size_s __user *)arg);
434			break;
435
436		case MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE:
437			err = mem_dump_mmu_page_table_wrapper(session_data, (_mali_uk_dump_mmu_page_table_s __user *)arg);
438			break;
439
440#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0
441
442		case MALI_IOC_MEM_ATTACH_UMP:
443			err = mem_attach_ump_wrapper(session_data, (_mali_uk_attach_ump_mem_s __user *)arg);
444			break;
445
446		case MALI_IOC_MEM_RELEASE_UMP:
447			err = mem_release_ump_wrapper(session_data, (_mali_uk_release_ump_mem_s __user *)arg);
448			break;
449
450#else
451
452		case MALI_IOC_MEM_ATTACH_UMP:
453		case MALI_IOC_MEM_RELEASE_UMP: /* FALL-THROUGH */
454			MALI_DEBUG_PRINT(2, ("UMP not supported\n"));
455			err = -ENOTTY;
456			break;
457#endif
458
459		case MALI_IOC_PP_START_JOB:
460			err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg);
461			break;
462
463		case MALI_IOC_PP_NUMBER_OF_CORES_GET:
464			err = pp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_pp_number_of_cores_s __user *)arg);
465			break;
466
467		case MALI_IOC_PP_CORE_VERSION_GET:
468			err = pp_get_core_version_wrapper(session_data, (_mali_uk_get_pp_core_version_s __user *)arg);
469			break;
470
471		case MALI_IOC_PP_DISABLE_WB:
472			err = pp_disable_wb_wrapper(session_data, (_mali_uk_pp_disable_wb_s __user *)arg);
473			break;
474
475		case MALI_IOC_GP2_START_JOB:
476			err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg);
477			break;
478
479		case MALI_IOC_GP2_NUMBER_OF_CORES_GET:
480			err = gp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_gp_number_of_cores_s __user *)arg);
481			break;
482
483		case MALI_IOC_GP2_CORE_VERSION_GET:
484			err = gp_get_core_version_wrapper(session_data, (_mali_uk_get_gp_core_version_s __user *)arg);
485			break;
486
487		case MALI_IOC_GP2_SUSPEND_RESPONSE:
488			err = gp_suspend_response_wrapper(session_data, (_mali_uk_gp_suspend_response_s __user *)arg);
489			break;
490
491		case MALI_IOC_VSYNC_EVENT_REPORT:
492			err = vsync_event_report_wrapper(session_data, (_mali_uk_vsync_event_report_s __user *)arg);
493			break;
494
495		case MALI_IOC_MEM_GET_BIG_BLOCK: /* Fallthrough */
496		case MALI_IOC_MEM_FREE_BIG_BLOCK:
497			MALI_PRINT_ERROR(("Non-MMU mode is no longer supported.\n"));
498			err = -ENOTTY;
499			break;
500
501		default:
502			MALI_DEBUG_PRINT(2, ("No handler for ioctl 0x%08X 0x%08lX\n", cmd, arg));
503			err = -ENOTTY;
504	};
505
506	return err;
507}
508
509
510module_init(mali_driver_init);
511module_exit(mali_driver_exit);
512
513MODULE_LICENSE(MALI_KERNEL_LINUX_LICENSE);
514MODULE_AUTHOR("ARM Ltd.");
515MODULE_VERSION(SVN_REV_STRING);