drm_accel.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2022 HabanaLabs, Ltd.
  4. * All Rights Reserved.
  5. *
  6. */
  7. #include <linux/debugfs.h>
  8. #include <linux/device.h>
  9. #include <linux/xarray.h>
  10. #include <drm/drm_accel.h>
  11. #include <drm/drm_auth.h>
  12. #include <drm/drm_debugfs.h>
  13. #include <drm/drm_drv.h>
  14. #include <drm/drm_file.h>
  15. #include <drm/drm_ioctl.h>
  16. #include <drm/drm_print.h>
  17. DEFINE_XARRAY_ALLOC(accel_minors_xa);
  18. static struct dentry *accel_debugfs_root;
  19. static const struct device_type accel_sysfs_device_minor = {
  20. .name = "accel_minor"
  21. };
  22. static char *accel_devnode(const struct device *dev, umode_t *mode)
  23. {
  24. return kasprintf(GFP_KERNEL, "accel/%s", dev_name(dev));
  25. }
  26. static const struct class accel_class = {
  27. .name = "accel",
  28. .devnode = accel_devnode,
  29. };
  30. static int accel_sysfs_init(void)
  31. {
  32. return class_register(&accel_class);
  33. }
  34. static void accel_sysfs_destroy(void)
  35. {
  36. class_unregister(&accel_class);
  37. }
  38. static int accel_name_info(struct seq_file *m, void *data)
  39. {
  40. struct drm_info_node *node = (struct drm_info_node *) m->private;
  41. struct drm_minor *minor = node->minor;
  42. struct drm_device *dev = minor->dev;
  43. struct drm_master *master;
  44. mutex_lock(&dev->master_mutex);
  45. master = dev->master;
  46. seq_printf(m, "%s", dev->driver->name);
  47. if (dev->dev)
  48. seq_printf(m, " dev=%s", dev_name(dev->dev));
  49. if (master && master->unique)
  50. seq_printf(m, " master=%s", master->unique);
  51. if (dev->unique)
  52. seq_printf(m, " unique=%s", dev->unique);
  53. seq_puts(m, "\n");
  54. mutex_unlock(&dev->master_mutex);
  55. return 0;
  56. }
  57. static const struct drm_info_list accel_debugfs_list[] = {
  58. {"name", accel_name_info, 0}
  59. };
  60. #define ACCEL_DEBUGFS_ENTRIES ARRAY_SIZE(accel_debugfs_list)
  61. /**
  62. * accel_debugfs_init() - Initialize debugfs for device
  63. * @dev: Pointer to the device instance.
  64. *
  65. * This function creates a root directory for the device in debugfs.
  66. */
  67. void accel_debugfs_init(struct drm_device *dev)
  68. {
  69. drm_debugfs_dev_init(dev, accel_debugfs_root);
  70. }
  71. /**
  72. * accel_debugfs_register() - Register debugfs for device
  73. * @dev: Pointer to the device instance.
  74. *
  75. * Creates common files for accelerators.
  76. */
  77. void accel_debugfs_register(struct drm_device *dev)
  78. {
  79. struct drm_minor *minor = dev->accel;
  80. minor->debugfs_root = dev->debugfs_root;
  81. drm_debugfs_create_files(accel_debugfs_list, ACCEL_DEBUGFS_ENTRIES,
  82. dev->debugfs_root, minor);
  83. }
  84. /**
  85. * accel_set_device_instance_params() - Set some device parameters for accel device
  86. * @kdev: Pointer to the device instance.
  87. * @index: The minor's index
  88. *
  89. * This function creates the dev_t of the device using the accel major and
  90. * the device's minor number. In addition, it sets the class and type of the
  91. * device instance to the accel sysfs class and device type, respectively.
  92. */
  93. void accel_set_device_instance_params(struct device *kdev, int index)
  94. {
  95. kdev->devt = MKDEV(ACCEL_MAJOR, index);
  96. kdev->class = &accel_class;
  97. kdev->type = &accel_sysfs_device_minor;
  98. }
  99. /**
  100. * accel_open - open method for ACCEL file
  101. * @inode: device inode
  102. * @filp: file pointer.
  103. *
  104. * This function must be used by drivers as their &file_operations.open method.
  105. * It looks up the correct ACCEL device and instantiates all the per-file
  106. * resources for it. It also calls the &drm_driver.open driver callback.
  107. *
  108. * Return: 0 on success or negative errno value on failure.
  109. */
  110. int accel_open(struct inode *inode, struct file *filp)
  111. {
  112. struct drm_device *dev;
  113. struct drm_minor *minor;
  114. int retcode;
  115. minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
  116. if (IS_ERR(minor))
  117. return PTR_ERR(minor);
  118. dev = minor->dev;
  119. atomic_fetch_inc(&dev->open_count);
  120. /* share address_space across all char-devs of a single device */
  121. filp->f_mapping = dev->anon_inode->i_mapping;
  122. retcode = drm_open_helper(filp, minor);
  123. if (retcode)
  124. goto err_undo;
  125. return 0;
  126. err_undo:
  127. atomic_dec(&dev->open_count);
  128. drm_minor_release(minor);
  129. return retcode;
  130. }
  131. EXPORT_SYMBOL_GPL(accel_open);
  132. static int accel_stub_open(struct inode *inode, struct file *filp)
  133. {
  134. const struct file_operations *new_fops;
  135. struct drm_minor *minor;
  136. int err;
  137. minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
  138. if (IS_ERR(minor))
  139. return PTR_ERR(minor);
  140. new_fops = fops_get(minor->dev->driver->fops);
  141. if (!new_fops) {
  142. err = -ENODEV;
  143. goto out;
  144. }
  145. replace_fops(filp, new_fops);
  146. if (filp->f_op->open)
  147. err = filp->f_op->open(inode, filp);
  148. else
  149. err = 0;
  150. out:
  151. drm_minor_release(minor);
  152. return err;
  153. }
  154. static const struct file_operations accel_stub_fops = {
  155. .owner = THIS_MODULE,
  156. .open = accel_stub_open,
  157. .llseek = noop_llseek,
  158. };
  159. void accel_core_exit(void)
  160. {
  161. unregister_chrdev(ACCEL_MAJOR, "accel");
  162. debugfs_remove(accel_debugfs_root);
  163. accel_sysfs_destroy();
  164. WARN_ON(!xa_empty(&accel_minors_xa));
  165. }
  166. int __init accel_core_init(void)
  167. {
  168. int ret;
  169. ret = accel_sysfs_init();
  170. if (ret < 0) {
  171. DRM_ERROR("Cannot create ACCEL class: %d\n", ret);
  172. goto error;
  173. }
  174. accel_debugfs_root = debugfs_create_dir("accel", NULL);
  175. ret = register_chrdev(ACCEL_MAJOR, "accel", &accel_stub_fops);
  176. if (ret < 0)
  177. DRM_ERROR("Cannot register ACCEL major: %d\n", ret);
  178. error:
  179. /*
  180. * Any cleanup due to errors will be done in drm_core_exit() that
  181. * will call accel_core_exit()
  182. */
  183. return ret;
  184. }