diff options
Diffstat (limited to 'drivers/gpu/drm/drm_drv.c')
| -rw-r--r-- | drivers/gpu/drm/drm_drv.c | 117 | 
1 files changed, 87 insertions, 30 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 60e5ac179c15..cdd591b11488 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -29,17 +29,20 @@  #include <linux/bitops.h>  #include <linux/cgroup_dmem.h>  #include <linux/debugfs.h> +#include <linux/export.h>  #include <linux/fs.h>  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/mount.h>  #include <linux/pseudo_fs.h> +#include <linux/sched.h>  #include <linux/slab.h>  #include <linux/sprintf.h>  #include <linux/srcu.h>  #include <linux/xarray.h>  #include <drm/drm_accel.h> +#include <drm/drm_bridge.h>  #include <drm/drm_cache.h>  #include <drm/drm_client_event.h>  #include <drm/drm_color_mgmt.h> @@ -69,8 +72,6 @@ DEFINE_XARRAY_ALLOC(drm_minors_xa);   */  static bool drm_core_init_complete; -static struct dentry *drm_debugfs_root; -  DEFINE_STATIC_SRCU(drm_unplug_srcu);  /* @@ -183,8 +184,7 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)  		return 0;  	if (minor->type != DRM_MINOR_ACCEL) { -		ret = drm_debugfs_register(minor, minor->index, -					   drm_debugfs_root); +		ret = drm_debugfs_register(minor, minor->index);  		if (ret) {  			DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");  			goto err_debugfs; @@ -500,6 +500,25 @@ void drm_dev_unplug(struct drm_device *dev)  }  EXPORT_SYMBOL(drm_dev_unplug); +/** + * drm_dev_set_dma_dev - set the DMA device for a DRM device + * @dev: DRM device + * @dma_dev: DMA device or NULL + * + * Sets the DMA device of the given DRM device. Only required if + * the DMA device is different from the DRM device's parent. After + * calling this function, the DRM device holds a reference on + * @dma_dev. Pass NULL to clear the DMA device. + */ +void drm_dev_set_dma_dev(struct drm_device *dev, struct device *dma_dev) +{ +	dma_dev = get_device(dma_dev); + +	put_device(dev->dma_dev); +	dev->dma_dev = dma_dev; +} +EXPORT_SYMBOL(drm_dev_set_dma_dev); +  /*   * Available recovery methods for wedged device. To be sent along with device   * wedged uevent. @@ -518,10 +537,15 @@ static const char *drm_get_wedge_recovery(unsigned int opt)  	}  } +#define WEDGE_STR_LEN	32 +#define PID_STR_LEN	15 +#define COMM_STR_LEN	(TASK_COMM_LEN + 5) +  /**   * drm_dev_wedged_event - generate a device wedged uevent   * @dev: DRM device   * @method: method(s) to be used for recovery + * @info: optional information about the guilty task   *   * This generates a device wedged uevent for the DRM device specified by @dev.   * Recovery @method\(s) of choice will be sent in the uevent environment as @@ -534,13 +558,13 @@ static const char *drm_get_wedge_recovery(unsigned int opt)   *   * Returns: 0 on success, negative error code otherwise.   */ -int drm_dev_wedged_event(struct drm_device *dev, unsigned long method) +int drm_dev_wedged_event(struct drm_device *dev, unsigned long method, +			 struct drm_wedge_task_info *info)  { +	char event_string[WEDGE_STR_LEN], pid_string[PID_STR_LEN], comm_string[COMM_STR_LEN]; +	char *envp[] = { event_string, NULL, NULL, NULL };  	const char *recovery = NULL;  	unsigned int len, opt; -	/* Event string length up to 28+ characters with available methods */ -	char event_string[32]; -	char *envp[] = { event_string, NULL };  	len = scnprintf(event_string, sizeof(event_string), "%s", "WEDGED="); @@ -562,6 +586,13 @@ int drm_dev_wedged_event(struct drm_device *dev, unsigned long method)  	drm_info(dev, "device wedged, %s\n", method == DRM_WEDGE_RECOVERY_NONE ?  		 "but recovered through reset" : "needs recovery"); +	if (info && (info->comm[0] != '\0') && (info->pid >= 0)) { +		snprintf(pid_string, sizeof(pid_string), "PID=%u", info->pid); +		snprintf(comm_string, sizeof(comm_string), "TASK=%s", info->comm); +		envp[1] = pid_string; +		envp[2] = comm_string; +	} +  	return kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp);  }  EXPORT_SYMBOL(drm_dev_wedged_event); @@ -654,6 +685,8 @@ static void drm_dev_init_release(struct drm_device *dev, void *res)  {  	drm_fs_inode_free(dev->anon_inode); +	put_device(dev->dma_dev); +	dev->dma_dev = NULL;  	put_device(dev->dev);  	/* Prevent use-after-free in drm_managed_release when debugging is  	 * enabled. Slightly awkward, but can't really be helped. */ @@ -751,10 +784,7 @@ static int drm_dev_init(struct drm_device *dev,  		goto err;  	} -	if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) -		accel_debugfs_init(dev); -	else -		drm_debugfs_dev_init(dev, drm_debugfs_root); +	drm_debugfs_dev_init(dev);  	return 0; @@ -808,36 +838,62 @@ void *__devm_drm_dev_alloc(struct device *parent,  EXPORT_SYMBOL(__devm_drm_dev_alloc);  /** - * drm_dev_alloc - Allocate new DRM device - * @driver: DRM driver to allocate device for + * __drm_dev_alloc - Allocation of a &drm_device instance   * @parent: Parent device object + * @driver: DRM driver + * @size: the size of the struct which contains struct drm_device + * @offset: the offset of the &drm_device within the container.   * - * This is the deprecated version of devm_drm_dev_alloc(), which does not support - * subclassing through embedding the struct &drm_device in a driver private - * structure, and which does not support automatic cleanup through devres. + * This should *NOT* be by any drivers, but is a dedicated interface for the + * corresponding Rust abstraction.   * - * RETURNS: - * Pointer to new DRM device, or ERR_PTR on failure. + * This is the same as devm_drm_dev_alloc(), but without the corresponding + * resource management through the parent device, but not the same as + * drm_dev_alloc(), since the latter is the deprecated version, which does not + * support subclassing. + * + * Returns: A pointer to new DRM device, or an ERR_PTR on failure.   */ -struct drm_device *drm_dev_alloc(const struct drm_driver *driver, -				 struct device *parent) +void *__drm_dev_alloc(struct device *parent, +		      const struct drm_driver *driver, +		      size_t size, size_t offset)  { -	struct drm_device *dev; +	void *container; +	struct drm_device *drm;  	int ret; -	dev = kzalloc(sizeof(*dev), GFP_KERNEL); -	if (!dev) +	container = kzalloc(size, GFP_KERNEL); +	if (!container)  		return ERR_PTR(-ENOMEM); -	ret = drm_dev_init(dev, driver, parent); +	drm = container + offset; +	ret = drm_dev_init(drm, driver, parent);  	if (ret) { -		kfree(dev); +		kfree(container);  		return ERR_PTR(ret);  	} +	drmm_add_final_kfree(drm, container); -	drmm_add_final_kfree(dev, dev); +	return container; +} +EXPORT_SYMBOL(__drm_dev_alloc); -	return dev; +/** + * drm_dev_alloc - Allocate new DRM device + * @driver: DRM driver to allocate device for + * @parent: Parent device object + * + * This is the deprecated version of devm_drm_dev_alloc(), which does not support + * subclassing through embedding the struct &drm_device in a driver private + * structure, and which does not support automatic cleanup through devres. + * + * RETURNS: + * Pointer to new DRM device, or ERR_PTR on failure. + */ +struct drm_device *drm_dev_alloc(const struct drm_driver *driver, +				 struct device *parent) +{ +	return __drm_dev_alloc(parent, driver, sizeof(struct drm_device), 0);  }  EXPORT_SYMBOL(drm_dev_alloc); @@ -1168,7 +1224,7 @@ static void drm_core_exit(void)  	drm_panic_exit();  	accel_core_exit();  	unregister_chrdev(DRM_MAJOR, "drm"); -	debugfs_remove(drm_debugfs_root); +	drm_debugfs_remove_root();  	drm_sysfs_destroy();  	WARN_ON(!xa_empty(&drm_minors_xa));  	drm_connector_ida_destroy(); @@ -1187,7 +1243,8 @@ static int __init drm_core_init(void)  		goto error;  	} -	drm_debugfs_root = debugfs_create_dir("dri", NULL); +	drm_debugfs_init_root(); +	drm_debugfs_bridge_params();  	ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);  	if (ret < 0)  | 
