diff options
| -rw-r--r-- | linux-core/drmP.h | 13 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 50 | ||||
| -rw-r--r-- | linux-core/drm_fops.c | 30 | ||||
| -rw-r--r-- | linux-core/drm_proc.c | 2 | ||||
| -rw-r--r-- | linux-core/drm_stub.c | 143 | ||||
| -rw-r--r-- | linux-core/drm_sysfs.c | 4 | 
6 files changed, 141 insertions, 101 deletions
| diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1c815c5f..afc16f5f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -733,11 +733,12 @@ struct drm_driver {  #define DRM_MINOR_UNASSIGNED 0  #define DRM_MINOR_CONTROL 1  #define DRM_MINOR_RENDER 2 +#define DRM_MINOR_GPGPU 3 /* this node is restricted to operations that don't require a master */  /**   * DRM minor structure. This structure represents a drm minor number.   */  struct drm_minor { -	int minor;			/**< Minor device number */ +	int index;			/**< Minor device number */  	int type;                       /**< Control or render */  	dev_t device;			/**< Device number for mknod */  	struct device kdev;		/**< Linux device */ @@ -882,8 +883,8 @@ struct drm_device {  	unsigned int agp_buffer_token;  	/* minor number for control node */ -	struct drm_minor control; -	struct drm_minor primary;		/**< primary screen head */ +	struct drm_minor *control; +	struct drm_minor *primary;		/**< primary screen head */  	struct drm_fence_manager fm;  	struct drm_buffer_manager bm; @@ -1214,13 +1215,15 @@ extern void drm_agp_chipset_flush(struct drm_device *dev);  extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,  		     struct drm_driver *driver);  extern int drm_put_dev(struct drm_device *dev); -extern int drm_put_minor(struct drm_minor *minor); +extern int drm_put_minor(struct drm_minor **minor);  extern unsigned int drm_debug; /* 1 to enable debug output */  extern unsigned int drm_minors_limit; -extern struct drm_minor **drm_minors; +  extern struct class *drm_class;  extern struct proc_dir_entry *drm_proc_root; +extern struct idr drm_minors_idr; +  extern drm_local_map_t *drm_getsarea(struct drm_device *dev);  				/* Proc support (drm_proc.h) */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7177f171..e9955239 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -435,30 +435,29 @@ static void drm_cleanup(struct drm_device * dev)  		DRM_ERROR("Cannot unload module\n");  } -void drm_exit(struct drm_driver *driver) +int drm_minors_cleanup(int id, void *ptr, void *data)  { -	int i; -	struct drm_device *dev = NULL; -	struct drm_minor *minor; +	struct drm_minor *minor = ptr; +	struct drm_device *dev; +	struct drm_driver *driver = data; +	if (id < 127 || id > 192) +		return 0; + +	dev = minor->dev; +	if (minor->dev->driver != driver) +		return 0; + +	if (dev) +		pci_dev_put(dev->pdev); +	drm_cleanup(dev); +	return 1; +} +void drm_exit(struct drm_driver *driver) +{  	DRM_DEBUG("\n");  	if (drm_fb_loaded) { -		for (i = 0; i < drm_minors_limit; i++) { -			minor = drm_minors[i]; -			if (!minor) -				continue; -			if (!minor->dev) -				continue; -			if (minor->dev->driver != driver) -				continue; -			dev = minor->dev; -			if (dev) { -				/* release the pci driver */ -				if (dev->pdev) -					pci_dev_put(dev->pdev); -				drm_cleanup(dev); -			} -		} +		idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver);  	} else  		pci_unregister_driver(&driver->pci_driver);  #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -481,6 +480,7 @@ static int __init drm_core_init(void)  	unsigned long avail_memctl_mem;  	unsigned long max_memctl_mem; +	idr_init(&drm_minors_idr);  	si_meminfo(&si);  	/* @@ -502,11 +502,6 @@ static int __init drm_core_init(void)  	drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit);  	ret = -ENOMEM; -	drm_minors_limit = -	    (drm_minors_limit < DRM_MAX_MINOR + 1 ? drm_minors_limit : DRM_MAX_MINOR + 1); -	drm_minors = drm_calloc(drm_minors_limit, sizeof(*drm_minors), DRM_MEM_STUB); -	if (!drm_minors) -		goto err_p1;  	if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))  		goto err_p1; @@ -535,7 +530,8 @@ err_p3:  	drm_sysfs_destroy();  err_p2:  	unregister_chrdev(DRM_MAJOR, "drm"); -	drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); + +	idr_destroy(&drm_minors_idr);  err_p1:  	return ret;  } @@ -547,7 +543,7 @@ static void __exit drm_core_exit(void)  	unregister_chrdev(DRM_MAJOR, "drm"); -	drm_free(drm_minors, sizeof(*drm_minors) * drm_minors_limit, DRM_MEM_STUB); +	idr_destroy(&drm_minors_idr);  }  module_init(drm_core_init); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 28aaeb1f..344d90e1 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -128,16 +128,15 @@ static int drm_setup(struct drm_device * dev)  int drm_open(struct inode *inode, struct file *filp)  {  	struct drm_device *dev = NULL; -	int minor = iminor(inode); +	int minor_id = iminor(inode); +	struct drm_minor *minor;  	int retcode = 0; -	if (!((minor >= 0) && (minor < drm_minors_limit))) +	minor = idr_find(&drm_minors_idr, minor_id); +	if (!minor)  		return -ENODEV; -	if (!drm_minors[minor]) -		return -ENODEV; - -	if (!(dev = drm_minors[minor]->dev)) +	if (!(dev = minor->dev))  		return -ENODEV;  	retcode = drm_open_helper(inode, filp, dev); @@ -176,19 +175,18 @@ EXPORT_SYMBOL(drm_open);  int drm_stub_open(struct inode *inode, struct file *filp)  {  	struct drm_device *dev = NULL; -	int minor = iminor(inode); +	struct drm_minor *minor; +	int minor_id = iminor(inode);  	int err = -ENODEV;  	const struct file_operations *old_fops;  	DRM_DEBUG("\n"); -	if (!((minor >= 0) && (minor < drm_minors_limit))) +	minor = idr_find(&drm_minors_idr, minor_id); +	if (!minor)  		return -ENODEV; - -	if (!drm_minors[minor]) -		return -ENODEV; - -	if (!(dev = drm_minors[minor]->dev)) +	 +	if (!(dev = minor->dev))  		return -ENODEV;  	old_fops = filp->f_op; @@ -233,7 +231,7 @@ static int drm_cpu_valid(void)  static int drm_open_helper(struct inode *inode, struct file *filp,  			   struct drm_device * dev)  { -	int minor = iminor(inode); +	int minor_id = iminor(inode);  	struct drm_file *priv;  	int ret;  	int i, j; @@ -243,7 +241,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  	if (!drm_cpu_valid())  		return -EINVAL; -	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); +	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id);  	priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);  	if (!priv) @@ -254,7 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,  	priv->filp = filp;  	priv->uid = current->euid;  	priv->pid = current->pid; -	priv->minor = drm_minors[minor]; +	priv->minor = idr_find(&drm_minors_idr, minor_id);  	priv->ioctl_count = 0;  	/* for compatibility root is always authenticated */  	priv->authenticated = capable(CAP_SYS_ADMIN); diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 8f26726c..b28d8238 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -535,7 +535,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,  	list_for_each_entry(priv, &dev->filelist, lhead) {  		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",  			       priv->authenticated ? 'y' : 'n', -			       priv->minor->minor, +			       priv->minor->index,  			       priv->pid,  			       priv->uid, priv->magic, priv->ioctl_count);  	} diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index cee00c5e..5a39afb3 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -50,10 +50,47 @@ MODULE_PARM_DESC(debug, "Enable debug output");  module_param_named(minors_limit, drm_minors_limit, int, 0444);  module_param_named(debug, drm_debug, int, 0600); -struct drm_minor **drm_minors; +struct idr drm_minors_idr; +  struct class *drm_class;  struct proc_dir_entry *drm_proc_root; +static int drm_minor_get_id(struct drm_device *dev, int type) +{ +	int new_id; +	int ret; +	int base = 0, limit = 127; + +	if (type == DRM_MINOR_CONTROL) { +		base += 128; +		limit = base + 64; +	} else if (type == DRM_MINOR_GPGPU) { +		base += 192; +		limit = base + 64; +	}	 + +again: +	if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { +		DRM_ERROR("Out of memory expanding drawable idr\n"); +		return -ENOMEM; +	} +	mutex_lock(&dev->struct_mutex); +	ret = idr_get_new_above(&drm_minors_idr, NULL, +				base, &new_id); +	mutex_unlock(&dev->struct_mutex); +	if (ret == -EAGAIN) { +		goto again; +	} else if (ret) { +		return ret; +	} + +	if (new_id >= limit) { +		idr_remove(&drm_minors_idr, new_id); +		return -EINVAL; +	} +	return new_id; +} +  static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,  			   const struct pci_device_id *ent,  			   struct drm_driver *driver) @@ -160,54 +197,61 @@ error_out_unreg:   * create the proc init entry via proc_init(). This routines assigns   * minor numbers to secondary heads of multi-headed cards   */ -static int drm_get_minor(struct drm_device *dev, struct drm_minor *minor, int type) +static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type)  { -	struct drm_minor **minors = drm_minors; +	struct drm_minor *new_minor;  	int ret; -	int index; +	int minor_id;  	DRM_DEBUG("\n"); -	for (index = 0; index < drm_minors_limit; index++, minors++) { -		if (!*minors) { - -			*minor = (struct drm_minor) { -				.type = type, -				.dev = dev, -				.device = MKDEV(DRM_MAJOR, index), -				.minor = index, -			}; - -			if (type == DRM_MINOR_RENDER) { -				ret = drm_proc_init(dev, index, drm_proc_root, -						    &minor->dev_root); -				if (ret) { -					DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); -					goto err_g1; -				} -			} else -				minor->dev_root = NULL; - -			ret = drm_sysfs_device_add(minor); -			if (ret) { -				printk(KERN_ERR -				       "DRM: Error sysfs_device_add.\n"); -				goto err_g2; -			} -			*minors = minor; - -			DRM_DEBUG("new minor assigned %d\n", index); -			return 0; +	minor_id = drm_minor_get_id(dev, type); +	if (minor_id < 0) +		return minor_id; + +	new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); +	if (!new_minor) { +		ret = -ENOMEM; +		goto err_idr; +	} + +	new_minor->type = type; +	new_minor->device = MKDEV(DRM_MAJOR, minor_id); +	new_minor->dev = dev; +	new_minor->index = minor_id; + +	idr_replace(&drm_minors_idr, new_minor, minor_id); +	 +	if (type == DRM_MINOR_RENDER) { +		ret = drm_proc_init(dev, minor_id, drm_proc_root, +				    &new_minor->dev_root); +		if (ret) { +			DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); +			goto err_mem;  		} +	} else +		new_minor->dev_root = NULL; + +	ret = drm_sysfs_device_add(new_minor); +	if (ret) { +		printk(KERN_ERR +		       "DRM: Error sysfs_device_add.\n"); +		goto err_g2;  	} -	DRM_ERROR("out of minors\n"); -	return -ENOMEM; +	*minor = new_minor; +	 +	DRM_DEBUG("new minor assigned %d\n", minor_id); +	return 0; + +  err_g2: -	if (minor->type == DRM_MINOR_RENDER) -		drm_proc_cleanup(index, drm_proc_root, minor->dev_root); -err_g1: -	*minor = (struct drm_minor) { -		.dev = NULL}; +	if (new_minor->type == DRM_MINOR_RENDER) +		drm_proc_cleanup(minor_id, drm_proc_root, new_minor->dev_root); +err_mem: +	kfree(new_minor); +err_idr: +	idr_remove(&drm_minors_idr, minor_id); +	*minor = NULL;  	return ret;  } @@ -259,7 +303,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,  	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",  		 driver->name, driver->major, driver->minor, driver->patchlevel, -		 driver->date, dev->primary.minor); +		 driver->date, dev->primary->index);  	return 0; @@ -320,19 +364,18 @@ int drm_put_dev(struct drm_device * dev)   * last minor released.   *   */ -int drm_put_minor(struct drm_minor *minor) +int drm_put_minor(struct drm_minor **minor_p)  { -	int index = minor->minor; - -	DRM_DEBUG("release secondary minor %d\n", index); +	struct drm_minor *minor = *minor_p; +	DRM_DEBUG("release secondary minor %d\n", minor->index);  	if (minor->type == DRM_MINOR_RENDER) -		drm_proc_cleanup(index, drm_proc_root, minor->dev_root); +		drm_proc_cleanup(minor->index, drm_proc_root, minor->dev_root);  	drm_sysfs_device_remove(minor); -	*minor = (struct drm_minor) {.type = DRM_MINOR_UNASSIGNED, -				     .dev = NULL}; +	idr_remove(&drm_minors_idr, minor->index); -	drm_minors[index] = NULL; +	kfree(minor); +	*minor_p = NULL;  	return 0;  } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 114e355e..cd03da8a 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -170,11 +170,11 @@ int drm_sysfs_device_add(struct drm_minor *minor)  	minor->kdev.release = drm_sysfs_device_release;  	minor->kdev.devt = minor->device;  	if (minor->type == DRM_MINOR_CONTROL) -	  minor_str = "controlD%d"; +		minor_str = "controlD%d";  	else  		minor_str = "card%d"; -	snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->minor); +	snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index);  	err = device_register(&minor->kdev);  	if (err) { | 
