brintos

brintos / linux-shallow public Read only

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