aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-02-20 14:18:07 +0000
committerDave Airlie <airlied@redhat.com>2012-03-15 13:35:33 +0000
commit2c07a21d6fb0be47fda696a618b726ea258ed1dd (patch)
tree8ab0b7541ee4f9f75397d3da190426041dc08c6e /drivers
parentcbc7e22151d99ed1dd7649d268ad3d81b9e6255a (diff)
drm: add core support for unplugging a device (v2)
Two parts to this, one is simple unplug from sysfs for the device node. The second adds an unplugged state, if we have device opens, we just set the unplugged state and return, if we have no device opens we drop the drm device. If after a lastclose we discover we are unplugged we then drop the drm device. v2: use an atomic for unplugged and wrap it for users, add checks on open + mmap + ioctl entry points. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/drm_fops.c8
-rw-r--r--drivers/gpu/drm/drm_gem.c3
-rw-r--r--drivers/gpu/drm/drm_stub.c23
-rw-r--r--drivers/gpu/drm/drm_vm.c3
5 files changed, 41 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index d166bd08040..0b65fbc8a63 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -390,6 +390,10 @@ long drm_ioctl(struct file *filp,
unsigned int usize, asize;
dev = file_priv->minor->dev;
+
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
++file_priv->ioctl_count;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6263b014759..7348a3dab25 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -133,6 +133,9 @@ int drm_open(struct inode *inode, struct file *filp)
if (!(dev = minor->dev))
return -ENODEV;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
retcode = drm_open_helper(inode, filp, dev);
if (!retcode) {
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
@@ -181,6 +184,9 @@ int drm_stub_open(struct inode *inode, struct file *filp)
if (!(dev = minor->dev))
goto out;
+ if (drm_device_is_unplugged(dev))
+ goto out;
+
old_fops = filp->f_op;
filp->f_op = fops_get(dev->driver->fops);
if (filp->f_op == NULL) {
@@ -579,6 +585,8 @@ int drm_release(struct inode *inode, struct file *filp)
retcode = -EBUSY;
} else
retcode = drm_lastclose(dev);
+ if (drm_device_is_unplugged(dev))
+ drm_put_dev(dev);
}
mutex_unlock(&drm_global_mutex);
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 3ebe3c8f58b..0ef358e5324 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -661,6 +661,9 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_hash_item *hash;
int ret = 0;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 6d7b083c5b7..bbd40eaf982 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -429,6 +429,11 @@ int drm_put_minor(struct drm_minor **minor_p)
return 0;
}
+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.
@@ -492,3 +497,21 @@ void drm_put_dev(struct drm_device *dev)
kfree(dev);
}
EXPORT_SYMBOL(drm_put_dev);
+
+void drm_unplug_dev(struct drm_device *dev)
+{
+ /* for a USB device */
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_unplug_minor(dev->control);
+ drm_unplug_minor(dev->primary);
+
+ mutex_lock(&drm_global_mutex);
+
+ drm_device_set_unplugged(dev);
+
+ if (dev->open_count == 0) {
+ drm_put_dev(dev);
+ }
+ mutex_unlock(&drm_global_mutex);
+}
+EXPORT_SYMBOL(drm_unplug_dev);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 55cd6156781..14956181834 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -680,6 +680,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
int ret;
+ if (drm_device_is_unplugged(dev))
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
ret = drm_mmap_locked(filp, vma);
mutex_unlock(&dev->struct_mutex);