/drivers/gpu/mali/mali/linux/mali_kernel_linux.c
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);