summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/drm_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/gpu/drm/drm_drv.c')
-rw-r--r--kernel/drivers/gpu/drm/drm_drv.c113
1 files changed, 66 insertions, 47 deletions
diff --git a/kernel/drivers/gpu/drm/drm_drv.c b/kernel/drivers/gpu/drm/drm_drv.c
index 48f7359e2..7dd6728dd 100644
--- a/kernel/drivers/gpu/drm/drm_drv.c
+++ b/kernel/drivers/gpu/drm/drm_drv.c
@@ -37,27 +37,22 @@
#include "drm_legacy.h"
#include "drm_internal.h"
-unsigned int drm_debug = 0; /* 1 to enable debug output */
+unsigned int drm_debug = 0; /* bitmask of DRM_UT_x */
EXPORT_SYMBOL(drm_debug);
-bool drm_atomic = 0;
-
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
-MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API");
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
module_param_named(debug, drm_debug, int, 0600);
-module_param_named_unsafe(atomic, drm_atomic, bool, 0600);
static DEFINE_SPINLOCK(drm_minor_lock);
static struct idr drm_minors_idr;
-struct class *drm_class;
static struct dentry *drm_debugfs_root;
void drm_err(const char *format, ...)
@@ -92,8 +87,6 @@ void drm_ut_debug_printk(const char *function_name, const char *format, ...)
}
EXPORT_SYMBOL(drm_ut_debug_printk);
-#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */
-
struct drm_master *drm_master_create(struct drm_minor *minor)
{
struct drm_master *master;
@@ -105,11 +98,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor)
kref_init(&master->refcount);
spin_lock_init(&master->lock.spinlock);
init_waitqueue_head(&master->lock.lock_queue);
- if (drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER)) {
- kfree(master);
- return NULL;
- }
- INIT_LIST_HEAD(&master->magicfree);
+ idr_init(&master->magic_map);
master->minor = minor;
return master;
@@ -138,16 +127,10 @@ static void drm_master_destroy(struct kref *kref)
r_list = NULL;
}
}
-
- if (master->unique) {
- kfree(master->unique);
- master->unique = NULL;
- master->unique_len = 0;
- }
-
- drm_ht_remove(&master->magiclist);
-
mutex_unlock(&dev->struct_mutex);
+
+ idr_destroy(&master->magic_map);
+ kfree(master->unique);
kfree(master);
}
@@ -177,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
goto out_unlock;
}
+ if (!file_priv->allowed_master) {
+ ret = drm_new_set_master(dev, file_priv);
+ goto out_unlock;
+ }
+
file_priv->minor->master = drm_master_get(file_priv->master);
file_priv->is_master = 1;
if (dev->driver->master_set) {
@@ -299,7 +287,6 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type)
if (!minor)
return;
- drm_mode_group_destroy(&minor->mode_group);
put_device(minor->kdev);
spin_lock_irqsave(&drm_minor_lock, flags);
@@ -413,15 +400,51 @@ void drm_minor_release(struct drm_minor *minor)
}
/**
+ * DOC: driver instance overview
+ *
+ * A device instance for a drm driver is represented by struct &drm_device. This
+ * is allocated with drm_dev_alloc(), usually from bus-specific ->probe()
+ * callbacks implemented by the driver. The driver then needs to initialize all
+ * the various subsystems for the drm device like memory management, vblank
+ * handling, modesetting support and intial output configuration plus obviously
+ * initialize all the corresponding hardware bits. An important part of this is
+ * also calling drm_dev_set_unique() to set the userspace-visible unique name of
+ * this device instance. Finally when everything is up and running and ready for
+ * userspace the device instance can be published using drm_dev_register().
+ *
+ * There is also deprecated support for initalizing device instances using
+ * bus-specific helpers and the ->load() callback. But due to
+ * backwards-compatibility needs the device instance have to be published too
+ * early, which requires unpretty global locking to make safe and is therefore
+ * only support for existing drivers not yet converted to the new scheme.
+ *
+ * When cleaning up a device instance everything needs to be done in reverse:
+ * First unpublish the device instance with drm_dev_unregister(). Then clean up
+ * any other resources allocated at device initialization and drop the driver's
+ * reference to &drm_device using drm_dev_unref().
+ *
+ * Note that the lifetime rules for &drm_device instance has still a lot of
+ * historical baggage. Hence use the reference counting provided by
+ * drm_dev_ref() and drm_dev_unref() only carefully.
+ *
+ * Also note that embedding of &drm_device is currently not (yet) supported (but
+ * it would be easy to add). Drivers can store driver-private data in the
+ * dev_priv field of &drm_device.
+ */
+
+/**
* drm_put_dev - Unregister and release a DRM device
* @dev: DRM device
*
* Called at module unload time or when a PCI device is unplugged.
*
- * Use of this function is discouraged. It will eventually go away completely.
- * Please use drm_dev_unregister() and drm_dev_unref() explicitly instead.
- *
* Cleans up all DRM device, calling drm_lastclose().
+ *
+ * Note: Use of this function is deprecated. It will eventually go away
+ * completely. Please use drm_dev_unregister() and drm_dev_unref() explicitly
+ * instead to make sure that the device isn't userspace accessible any more
+ * while teardown is in progress, ensuring that userspace can't access an
+ * inconsistent state.
*/
void drm_put_dev(struct drm_device *dev)
{
@@ -534,7 +557,9 @@ static void drm_fs_inode_free(struct inode *inode)
*
* 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.
+ * with other core subsystems. This should be done last in the device
+ * initialization sequence to make sure userspace can't access an inconsistent
+ * state.
*
* The initial ref-count of the object is 1. Use drm_dev_ref() and
* drm_dev_unref() to take and drop further ref-counts.
@@ -581,6 +606,8 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL);
if (ret)
goto err_minors;
+
+ WARN_ON(driver->suspend || driver->resume);
}
if (drm_core_check_feature(dev, DRIVER_RENDER)) {
@@ -596,11 +623,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
if (drm_ht_create(&dev->map_hash, 12))
goto err_minors;
- ret = drm_legacy_ctxbitmap_init(dev);
- if (ret) {
- DRM_ERROR("Cannot allocate memory for context bitmap.\n");
- goto err_ht;
- }
+ drm_legacy_ctxbitmap_init(dev);
if (drm_core_check_feature(dev, DRIVER_GEM)) {
ret = drm_gem_init(dev);
@@ -614,7 +637,6 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
err_ctxbitmap:
drm_legacy_ctxbitmap_cleanup(dev);
-err_ht:
drm_ht_remove(&dev->map_hash);
err_minors:
drm_minor_free(dev, DRM_MINOR_LEGACY);
@@ -692,6 +714,12 @@ EXPORT_SYMBOL(drm_dev_unref);
*
* Never call this twice on any device!
*
+ * NOTE: To ensure backward compatibility with existing drivers method this
+ * function calls the ->load() method after registering the device nodes,
+ * creating race conditions. Usage of the ->load() methods is therefore
+ * deprecated, drivers must perform all initialization before calling
+ * drm_dev_register().
+ *
* RETURNS:
* 0 on success, negative error code on failure.
*/
@@ -719,20 +747,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
goto err_minors;
}
- /* 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;
- }
-
ret = 0;
goto out_unlock;
-err_unload:
- if (dev->driver->unload)
- dev->driver->unload(dev);
err_minors:
drm_minor_unregister(dev, DRM_MINOR_LEGACY);
drm_minor_unregister(dev, DRM_MINOR_RENDER);
@@ -750,6 +767,9 @@ EXPORT_SYMBOL(drm_dev_register);
* 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_unref() to drop their final reference.
+ *
+ * This should be called first in the device teardown code to make sure
+ * userspace can't access the device instance any more.
*/
void drm_dev_unregister(struct drm_device *dev)
{
@@ -870,10 +890,9 @@ static int __init drm_core_init(void)
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
goto err_p1;
- drm_class = drm_sysfs_create(THIS_MODULE, "drm");
- if (IS_ERR(drm_class)) {
+ ret = drm_sysfs_init();
+ if (ret < 0) {
printk(KERN_ERR "DRM: Error creating drm class.\n");
- ret = PTR_ERR(drm_class);
goto err_p2;
}