summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-02-13 12:12:52 +1000
committerDave Airlie <airlied@redhat.com>2008-02-13 12:12:52 +1000
commitf276c845bde4c712aa383540a2dd2055ecc00031 (patch)
treeb7b4847cd819cb356e4f13a74326655c7244e7f9 /linux-core
parent04257f1a5a28550dc430d8051bb58fd0ac34e77d (diff)
drm: re-write minor number allocation to use an idr.
Fixup the minor number allocation scheme to use an idr and move the control nodes up higher.
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/drmP.h13
-rw-r--r--linux-core/drm_drv.c50
-rw-r--r--linux-core/drm_fops.c30
-rw-r--r--linux-core/drm_proc.c2
-rw-r--r--linux-core/drm_stub.c143
-rw-r--r--linux-core/drm_sysfs.c4
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) {