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

https://bitbucket.org/ndreys/linux-sunxi · C · 515 lines · 363 code · 111 blank · 41 comment · 32 complexity · 3e32d362deb71db74684c28fa11d6758 MD5 · raw file

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