From 1bb72532ac260a2d3982b40bdd4c936d779d0d16 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 2 Oct 2013 11:23:34 +0200 Subject: drm: add drm_dev_alloc() helper Instead of managing device allocation+initialization in each bus-driver, we should do that in a central place. drm_fill_in_dev() already does most of it, but also requires the global drm lock for partial AGP device registration. Split both apart so we have a clean device initialization/allocation phase, and a registration phase. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 121 +++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 47 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 39d864576be4..64bd52f13199 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -260,60 +260,15 @@ int drm_fill_in_dev(struct drm_device *dev, { int retcode; - INIT_LIST_HEAD(&dev->filelist); - INIT_LIST_HEAD(&dev->ctxlist); - INIT_LIST_HEAD(&dev->vmalist); - INIT_LIST_HEAD(&dev->maplist); - INIT_LIST_HEAD(&dev->vblank_event_list); - - spin_lock_init(&dev->count_lock); - spin_lock_init(&dev->event_lock); - mutex_init(&dev->struct_mutex); - mutex_init(&dev->ctxlist_mutex); - - if (drm_ht_create(&dev->map_hash, 12)) { - return -ENOMEM; - } - - /* the DRM has 6 basic counters */ - dev->counters = 6; - dev->types[0] = _DRM_STAT_LOCK; - dev->types[1] = _DRM_STAT_OPENS; - dev->types[2] = _DRM_STAT_CLOSES; - dev->types[3] = _DRM_STAT_IOCTLS; - dev->types[4] = _DRM_STAT_LOCKS; - dev->types[5] = _DRM_STAT_UNLOCKS; - - dev->driver = driver; - if (dev->driver->bus->agp_init) { retcode = dev->driver->bus->agp_init(dev); - if (retcode) - goto error_out_unreg; - } - - - - retcode = drm_ctxbitmap_init(dev); - if (retcode) { - DRM_ERROR("Cannot allocate memory for context bitmap.\n"); - goto error_out_unreg; - } - - if (driver->driver_features & DRIVER_GEM) { - retcode = drm_gem_init(dev); if (retcode) { - DRM_ERROR("Cannot initialize graphics execution " - "manager (GEM)\n"); - goto error_out_unreg; + drm_lastclose(dev); + return retcode; } } return 0; - - error_out_unreg: - drm_lastclose(dev); - return retcode; } EXPORT_SYMBOL(drm_fill_in_dev); @@ -490,3 +445,75 @@ void drm_unplug_dev(struct drm_device *dev) mutex_unlock(&drm_global_mutex); } EXPORT_SYMBOL(drm_unplug_dev); + +/** + * drm_dev_alloc - Allocate new drm device + * @driver: DRM driver to allocate device for + * @parent: Parent device object + * + * Allocate and initialize a new DRM device. No device registration is done. + * + * RETURNS: + * Pointer to new DRM device, or NULL if out of memory. + */ +struct drm_device *drm_dev_alloc(struct drm_driver *driver, + struct device *parent) +{ + struct drm_device *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; + + dev->dev = parent; + dev->driver = driver; + + INIT_LIST_HEAD(&dev->filelist); + INIT_LIST_HEAD(&dev->ctxlist); + INIT_LIST_HEAD(&dev->vmalist); + INIT_LIST_HEAD(&dev->maplist); + INIT_LIST_HEAD(&dev->vblank_event_list); + + spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->event_lock); + mutex_init(&dev->struct_mutex); + mutex_init(&dev->ctxlist_mutex); + + /* the DRM has 6 basic counters */ + dev->counters = 6; + dev->types[0] = _DRM_STAT_LOCK; + dev->types[1] = _DRM_STAT_OPENS; + dev->types[2] = _DRM_STAT_CLOSES; + dev->types[3] = _DRM_STAT_IOCTLS; + dev->types[4] = _DRM_STAT_LOCKS; + dev->types[5] = _DRM_STAT_UNLOCKS; + + if (drm_ht_create(&dev->map_hash, 12)) + goto err_free; + + ret = drm_ctxbitmap_init(dev); + if (ret) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + goto err_ht; + } + + if (driver->driver_features & DRIVER_GEM) { + ret = drm_gem_init(dev); + if (ret) { + DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n"); + goto err_ctxbitmap; + } + } + + return dev; + +err_ctxbitmap: + drm_ctxbitmap_cleanup(dev); +err_ht: + drm_ht_remove(&dev->map_hash); +err_free: + kfree(dev); + return NULL; +} +EXPORT_SYMBOL(drm_dev_alloc); -- cgit v1.2.2 From c22f0ace1926da399d9a16dfaf09174c1b03594c Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 2 Oct 2013 11:23:35 +0200 Subject: drm: merge device setup into drm_dev_register() All bus drivers do device setup themselves. This requires us to adjust all of them if we introduce new core features. Thus, merge all these into a uniform drm_dev_register() helper. Note that this removes the drm_lastclose() error path for AGP as it is horribly broken. Moreover, no bus driver called this in any other error path either. Instead, we use the recently introduced AGP cleanup helpers. We also keep a DRIVER_MODESET condition around pci_set_drvdata() to keep semantics. [airlied: keep passing flags through so drivers don't oops on load] Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 101 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 82 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 64bd52f13199..432994aafc3b 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -254,25 +254,6 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } -int drm_fill_in_dev(struct drm_device *dev, - const struct pci_device_id *ent, - struct drm_driver *driver) -{ - int retcode; - - if (dev->driver->bus->agp_init) { - retcode = dev->driver->bus->agp_init(dev); - if (retcode) { - drm_lastclose(dev); - return retcode; - } - } - - return 0; -} -EXPORT_SYMBOL(drm_fill_in_dev); - - /** * Get a secondary minor number. * @@ -452,6 +433,8 @@ EXPORT_SYMBOL(drm_unplug_dev); * @parent: Parent device object * * Allocate and initialize a new DRM device. No device registration is done. + * Call drm_dev_register() to advertice the device to user space and register it + * with other core subsystems. * * RETURNS: * Pointer to new DRM device, or NULL if out of memory. @@ -517,3 +500,83 @@ err_free: return NULL; } EXPORT_SYMBOL(drm_dev_alloc); + +/** + * drm_dev_register - Register DRM device + * @dev: Device to register + * + * Register the DRM device @dev with the system, advertise device to user-space + * and start normal device operation. @dev must be allocated via drm_dev_alloc() + * previously. + * + * Never call this twice on any device! + * + * RETURNS: + * 0 on success, negative error code on failure. + */ +int drm_dev_register(struct drm_device *dev, unsigned long flags) +{ + int ret; + + mutex_lock(&drm_global_mutex); + + if (dev->driver->bus->agp_init) { + ret = dev->driver->bus->agp_init(dev); + if (ret) + goto out_unlock; + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); + if (ret) + goto err_agp; + } + + if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) { + ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER); + if (ret) + goto err_control_node; + } + + ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); + if (ret) + goto err_render_node; + + if (dev->driver->load) { + ret = dev->driver->load(dev, flags); + if (ret) + goto err_primary_node; + } + + /* setup grouping for legacy outputs */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_mode_group_init_legacy_group(dev, + &dev->primary->mode_group); + if (ret) + goto err_unload; + } + + list_add_tail(&dev->driver_item, &dev->driver->device_list); + + ret = 0; + goto out_unlock; + +err_unload: + if (dev->driver->unload) + dev->driver->unload(dev); +err_primary_node: + drm_put_minor(&dev->primary); +err_render_node: + if (dev->render) + drm_put_minor(&dev->render); +err_control_node: + if (dev->control) + drm_put_minor(&dev->control); +err_agp: + if (dev->driver->bus->agp_destroy) + dev->driver->bus->agp_destroy(dev); +out_unlock: + mutex_unlock(&drm_global_mutex); + return ret; +} +EXPORT_SYMBOL(drm_dev_register); -- cgit v1.2.2 From 0dc8fe5985e01f238e7dc64ff1733cc0291811e8 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 2 Oct 2013 11:23:37 +0200 Subject: drm: introduce drm_dev_free() to fix error paths The error paths in DRM bus drivers currently leak memory as they don't correctly revert drm_dev_alloc(). Introduce drm_dev_free() to free DRM devices which haven't been registered, yet. We must be careful not to introduce any side-effects with cleanups done in drm_dev_free(). drm_ht_remove(), drm_ctxbitmap_cleanup() and drm_gem_destroy() are all fine in that regard. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 432994aafc3b..3b5b07482de8 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -363,7 +363,6 @@ static void drm_unplug_minor(struct drm_minor *minor) */ void drm_put_dev(struct drm_device *dev) { - struct drm_driver *driver; struct drm_map_list *r_list, *list_temp; DRM_DEBUG("\n"); @@ -372,7 +371,6 @@ void drm_put_dev(struct drm_device *dev) DRM_ERROR("cleanup called no dev\n"); return; } - driver = dev->driver; drm_lastclose(dev); @@ -386,9 +384,6 @@ void drm_put_dev(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); - drm_ht_remove(&dev->map_hash); - - drm_ctxbitmap_cleanup(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_put_minor(&dev->control); @@ -396,14 +391,11 @@ void drm_put_dev(struct drm_device *dev) if (dev->render) drm_put_minor(&dev->render); - if (driver->driver_features & DRIVER_GEM) - drm_gem_destroy(dev); - drm_put_minor(&dev->primary); list_del(&dev->driver_item); - kfree(dev->devname); - kfree(dev); + + drm_dev_free(dev); } EXPORT_SYMBOL(drm_put_dev); @@ -501,6 +493,29 @@ err_free: } EXPORT_SYMBOL(drm_dev_alloc); +/** + * drm_dev_free - Free DRM device + * @dev: DRM device to free + * + * Free a DRM device that has previously been allocated via drm_dev_alloc(). + * You must not use kfree() instead or you will leak memory. + * + * This must not be called once the device got registered. Use drm_put_dev() + * instead, which then calls drm_dev_free(). + */ +void drm_dev_free(struct drm_device *dev) +{ + if (dev->driver->driver_features & DRIVER_GEM) + drm_gem_destroy(dev); + + drm_ctxbitmap_cleanup(dev); + drm_ht_remove(&dev->map_hash); + + kfree(dev->devname); + kfree(dev); +} +EXPORT_SYMBOL(drm_dev_free); + /** * drm_dev_register - Register DRM device * @dev: Device to register -- cgit v1.2.2 From c3a49737ef7db0bdd4fcf6cf0b7140a883e32b2a Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Wed, 2 Oct 2013 11:23:38 +0200 Subject: drm: move device unregistration into drm_dev_unregister() Analog to drm_dev_register(), we now provide drm_dev_unregister() which does the reverse. drm_dev_put() is still in place and combines the calls to drm_dev_unregister() and drm_dev_free() so buses don't have to change. *_get() and *_put() are used for reference-counting in the kernel. However, drm_dev_put() definitely does not do any kind of ref-counting. Hence, use the more appropriate *_register(), *_unregister(), *_alloc() and *_free() names. Signed-off-by: David Herrmann Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 61 +++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 3b5b07482de8..2badef766d20 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -363,8 +363,6 @@ static void drm_unplug_minor(struct drm_minor *minor) */ void drm_put_dev(struct drm_device *dev) { - struct drm_map_list *r_list, *list_temp; - DRM_DEBUG("\n"); if (!dev) { @@ -372,29 +370,7 @@ void drm_put_dev(struct drm_device *dev) return; } - drm_lastclose(dev); - - if (dev->driver->unload) - dev->driver->unload(dev); - - if (dev->driver->bus->agp_destroy) - dev->driver->bus->agp_destroy(dev); - - drm_vblank_cleanup(dev); - - list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) - drm_rmmap(dev, r_list->map); - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_put_minor(&dev->control); - - if (dev->render) - drm_put_minor(&dev->render); - - drm_put_minor(&dev->primary); - - list_del(&dev->driver_item); - + drm_dev_unregister(dev); drm_dev_free(dev); } EXPORT_SYMBOL(drm_put_dev); @@ -595,3 +571,38 @@ out_unlock: return ret; } EXPORT_SYMBOL(drm_dev_register); + +/** + * drm_dev_unregister - Unregister DRM device + * @dev: Device to unregister + * + * Unregister the DRM device from the system. This does the reverse of + * drm_dev_register() but does not deallocate the device. The caller must call + * drm_dev_free() to free all resources. + */ +void drm_dev_unregister(struct drm_device *dev) +{ + struct drm_map_list *r_list, *list_temp; + + drm_lastclose(dev); + + if (dev->driver->unload) + dev->driver->unload(dev); + + if (dev->driver->bus->agp_destroy) + dev->driver->bus->agp_destroy(dev); + + drm_vblank_cleanup(dev); + + list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) + drm_rmmap(dev, r_list->map); + + if (dev->control) + drm_put_minor(&dev->control); + if (dev->render) + drm_put_minor(&dev->render); + drm_put_minor(&dev->primary); + + list_del(&dev->driver_item); +} +EXPORT_SYMBOL(drm_dev_unregister); -- cgit v1.2.2 From 0111be42186fc5461b9e9d579014c70869ab3152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 4 Oct 2013 14:53:41 +0300 Subject: drm: Kill drm perf counter leftovers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user of these counters was killed in commit d79cdc8312689b39c6d83718c1c196af4b3cd18c Author: Daniel Vetter Date: Thu Aug 8 15:41:32 2013 +0200 drm: no-op out GET_STATS ioctl so clean up the leftovers as well. Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 2badef766d20..26055abf94ee 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -431,15 +431,6 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); - /* the DRM has 6 basic counters */ - dev->counters = 6; - dev->types[0] = _DRM_STAT_LOCK; - dev->types[1] = _DRM_STAT_OPENS; - dev->types[2] = _DRM_STAT_CLOSES; - dev->types[3] = _DRM_STAT_IOCTLS; - dev->types[4] = _DRM_STAT_LOCKS; - dev->types[5] = _DRM_STAT_UNLOCKS; - if (drm_ht_create(&dev->map_hash, 12)) goto err_free; -- cgit v1.2.2 From f73aca50b7f6e0f3e04d887f852b9f8b0e108fa7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:40 +0200 Subject: drm: call drm_unplug_minor() from drm_put_minor() This protects drm_unplug_minor() against repeated calls so we can use it in drm_put_minor(). This allows us to further simplify it in follow-ups as we no longer do minor-destruction in both functions but only in drm_unplug_minor(). Also add kernel-doc comments about what these calls do. [airlied: fixup for changes to kdev stuff] Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 26055abf94ee..ae3f293229ae 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -324,10 +324,30 @@ err_idr: EXPORT_SYMBOL(drm_get_minor); /** - * Put a secondary minor number. + * drm_unplug_minor - Unplug DRM minor + * @minor: Minor to unplug * - * \param sec_minor - structure to be released - * \return always zero + * Unplugs the given DRM minor but keeps the object. So after this returns, + * minor->dev is still valid so existing open-files can still access it to get + * device information from their drm_file ojects. + * If the minor is already unplugged or if @minor is NULL, nothing is done. + * The global DRM mutex must be held by the caller. + */ +static void drm_unplug_minor(struct drm_minor *minor) +{ + if (!minor || !device_is_registered(minor->kdev)) + return; + + drm_sysfs_device_remove(minor); +} + +/** + * drm_put_minor - Destroy DRM minor + * @minor_p: Double pointer to DRM minor + * + * This calls drm_unplug_minor() on the given minor and then frees it. The minor + * pointer is reset to NULL before this returns. + * The global DRM mutex must be held by the caller. */ int drm_put_minor(struct drm_minor **minor_p) { @@ -339,7 +359,7 @@ int drm_put_minor(struct drm_minor **minor_p) drm_debugfs_cleanup(minor); #endif - drm_sysfs_device_remove(minor); + drm_unplug_minor(minor); idr_remove(&drm_minors_idr, minor->index); @@ -349,11 +369,6 @@ int drm_put_minor(struct drm_minor **minor_p) } EXPORT_SYMBOL(drm_put_minor); -static void drm_unplug_minor(struct drm_minor *minor) -{ - drm_sysfs_device_remove(minor); -} - /** * Called via drm_exit() at module unload time or when pci device is * unplugged. -- cgit v1.2.2 From 4ac387f516bd3e5356cdb25266e244fa8a062281 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:41 +0200 Subject: drm: simplify drm_put_minor() Allow passing NULL as minor to simplify DRM destruction paths. Also remove the double-pointer reset as it is no longer needed. drm_put_minor() is only called when the underlying object is destroyed. Hence, resetting minors to NULL is not necessary. As drm_put_minor() is no longer used by other DRM files, we can make it static, too. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index ae3f293229ae..dd0cb02830f4 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -343,15 +343,17 @@ static void drm_unplug_minor(struct drm_minor *minor) /** * drm_put_minor - Destroy DRM minor - * @minor_p: Double pointer to DRM minor + * @minor: Minor to destroy * - * This calls drm_unplug_minor() on the given minor and then frees it. The minor - * pointer is reset to NULL before this returns. + * This calls drm_unplug_minor() on the given minor and then frees it. Nothing + * is done if @minor is NULL. It is fine to call this on already unplugged + * minors. * The global DRM mutex must be held by the caller. */ -int drm_put_minor(struct drm_minor **minor_p) +static void drm_put_minor(struct drm_minor *minor) { - struct drm_minor *minor = *minor_p; + if (!minor) + return; DRM_DEBUG("release secondary minor %d\n", minor->index); @@ -364,10 +366,7 @@ int drm_put_minor(struct drm_minor **minor_p) idr_remove(&drm_minors_idr, minor->index); kfree(minor); - *minor_p = NULL; - return 0; } -EXPORT_SYMBOL(drm_put_minor); /** * Called via drm_exit() at module unload time or when pci device is @@ -562,13 +561,11 @@ err_unload: if (dev->driver->unload) dev->driver->unload(dev); err_primary_node: - drm_put_minor(&dev->primary); + drm_put_minor(dev->primary); err_render_node: - if (dev->render) - drm_put_minor(&dev->render); + drm_put_minor(dev->render); err_control_node: - if (dev->control) - drm_put_minor(&dev->control); + drm_put_minor(dev->control); err_agp: if (dev->driver->bus->agp_destroy) dev->driver->bus->agp_destroy(dev); @@ -603,11 +600,9 @@ void drm_dev_unregister(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); - if (dev->control) - drm_put_minor(&dev->control); - if (dev->render) - drm_put_minor(&dev->render); - drm_put_minor(&dev->primary); + drm_put_minor(dev->control); + drm_put_minor(dev->render); + drm_put_minor(dev->primary); list_del(&dev->driver_item); } -- cgit v1.2.2 From a99ee459fd0ae38c0ccc7f93af718ef476657d1b Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:42 +0200 Subject: drm: make drm_get_minor() static drm_get_minor() is only used in one file. Make it static and add a kernel-doc comment which documents the current semantics. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index dd0cb02830f4..76b4d718af60 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -255,16 +255,20 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, } /** - * Get a secondary minor number. + * drm_get_minor - Allocate and register new DRM minor + * @dev: DRM device + * @minor: Pointer to where new minor is stored + * @type: Type of minor * - * \param dev device data structure - * \param sec-minor structure to hold the assigned minor - * \return negative number on failure. + * Allocate a new minor of the given type and register it. A pointer to the new + * minor is returned in @minor. + * Caller must hold the global DRM mutex. * - * Search an empty entry and initialize it to the given parameters. This - * routines assigns minor numbers to secondary heads of multi-headed cards + * RETURNS: + * 0 on success, negative error code on failure. */ -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 *new_minor; int ret; @@ -321,7 +325,6 @@ err_idr: *minor = NULL; return ret; } -EXPORT_SYMBOL(drm_get_minor); /** * drm_unplug_minor - Unplug DRM minor -- cgit v1.2.2 From 865fb47f7f9aa1a1be2ce6a1d37af98f8d4a0d04 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:43 +0200 Subject: drm: cleanup debugfs in drm_unplug_minor() There is no reason to delay debugfs-cleanup to drm_put_minor(). We should forbid any access to debugfs files once the device is dead. Chances they oops once a card was unplugged are very high, anyway. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 76b4d718af60..b37b0d99f262 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -341,6 +341,10 @@ static void drm_unplug_minor(struct drm_minor *minor) if (!minor || !device_is_registered(minor->kdev)) return; +#if defined(CONFIG_DEBUG_FS) + drm_debugfs_cleanup(minor); +#endif + drm_sysfs_device_remove(minor); } @@ -360,10 +364,6 @@ static void drm_put_minor(struct drm_minor *minor) DRM_DEBUG("release secondary minor %d\n", minor->index); -#if defined(CONFIG_DEBUG_FS) - drm_debugfs_cleanup(minor); -#endif - drm_unplug_minor(minor); idr_remove(&drm_minors_idr, minor->index); -- cgit v1.2.2 From f67e946bf215f05be51f5579fcfc164c01b9c4f2 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:44 +0200 Subject: drm: remove minor-id during unplug Don't delay minor removal to drm_put_minor(). Otherwise, user-space can still open the minor and cause the kernel to oops. Instead, remove the minor during unplug so any new open() will fail to access this minor. Note that open() and drm_unplug_minor() are both protected by the global DRM mutex so we're fine. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index b37b0d99f262..e7c31e859b6b 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -346,6 +346,7 @@ static void drm_unplug_minor(struct drm_minor *minor) #endif drm_sysfs_device_remove(minor); + idr_remove(&drm_minors_idr, minor->index); } /** @@ -365,9 +366,6 @@ static void drm_put_minor(struct drm_minor *minor) DRM_DEBUG("release secondary minor %d\n", minor->index); drm_unplug_minor(minor); - - idr_remove(&drm_minors_idr, minor->index); - kfree(minor); } -- cgit v1.2.2 From 8f6599da8e772fa8de54cdf98e9e03cbaf3946da Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sun, 20 Oct 2013 18:55:45 +0200 Subject: drm: delay minor destruction to drm_dev_free() Instead of freeing minors in drm_dev_unregister(), we only unplug them and delay the free to drm_dev_free(). Note that if drm_dev_register() has never been called, minors are NULL and this has no effect. This change is needed to allow early device unregistration. If we want to call drm_dev_unregister() on live devices, we need to guarantee that minors are still valid (but unplugged). This way, any open file can still access file_priv->minor->dev to get the DRM device. However, the minor is unplugged so no new users can occur. Signed-off-by: David Herrmann Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_stub.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/drm_stub.c') diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index e7c31e859b6b..c200136a5d8e 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -487,6 +487,10 @@ EXPORT_SYMBOL(drm_dev_alloc); */ void drm_dev_free(struct drm_device *dev) { + drm_put_minor(dev->control); + drm_put_minor(dev->render); + drm_put_minor(dev->primary); + if (dev->driver->driver_features & DRIVER_GEM) drm_gem_destroy(dev); @@ -601,9 +605,9 @@ void drm_dev_unregister(struct drm_device *dev) list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) drm_rmmap(dev, r_list->map); - drm_put_minor(dev->control); - drm_put_minor(dev->render); - drm_put_minor(dev->primary); + drm_unplug_minor(dev->control); + drm_unplug_minor(dev->render); + drm_unplug_minor(dev->primary); list_del(&dev->driver_item); } -- cgit v1.2.2