aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-02-20 09:18:07 -0500
committerDave Airlie <airlied@redhat.com>2012-03-15 09:35:33 -0400
commit2c07a21d6fb0be47fda696a618b726ea258ed1dd (patch)
tree8ab0b7541ee4f9f75397d3da190426041dc08c6e
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>
-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
-rw-r--r--include/drm/drmP.h16
6 files changed, 57 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index d166bd080400..0b65fbc8a630 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,
390 unsigned int usize, asize; 390 unsigned int usize, asize;
391 391
392 dev = file_priv->minor->dev; 392 dev = file_priv->minor->dev;
393
394 if (drm_device_is_unplugged(dev))
395 return -ENODEV;
396
393 atomic_inc(&dev->ioctl_count); 397 atomic_inc(&dev->ioctl_count);
394 atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]); 398 atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
395 ++file_priv->ioctl_count; 399 ++file_priv->ioctl_count;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 6263b0147598..7348a3dab250 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)
133 if (!(dev = minor->dev)) 133 if (!(dev = minor->dev))
134 return -ENODEV; 134 return -ENODEV;
135 135
136 if (drm_device_is_unplugged(dev))
137 return -ENODEV;
138
136 retcode = drm_open_helper(inode, filp, dev); 139 retcode = drm_open_helper(inode, filp, dev);
137 if (!retcode) { 140 if (!retcode) {
138 atomic_inc(&dev->counts[_DRM_STAT_OPENS]); 141 atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
@@ -181,6 +184,9 @@ int drm_stub_open(struct inode *inode, struct file *filp)
181 if (!(dev = minor->dev)) 184 if (!(dev = minor->dev))
182 goto out; 185 goto out;
183 186
187 if (drm_device_is_unplugged(dev))
188 goto out;
189
184 old_fops = filp->f_op; 190 old_fops = filp->f_op;
185 filp->f_op = fops_get(dev->driver->fops); 191 filp->f_op = fops_get(dev->driver->fops);
186 if (filp->f_op == NULL) { 192 if (filp->f_op == NULL) {
@@ -579,6 +585,8 @@ int drm_release(struct inode *inode, struct file *filp)
579 retcode = -EBUSY; 585 retcode = -EBUSY;
580 } else 586 } else
581 retcode = drm_lastclose(dev); 587 retcode = drm_lastclose(dev);
588 if (drm_device_is_unplugged(dev))
589 drm_put_dev(dev);
582 } 590 }
583 mutex_unlock(&drm_global_mutex); 591 mutex_unlock(&drm_global_mutex);
584 592
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 3ebe3c8f58b5..0ef358e53245 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)
661 struct drm_hash_item *hash; 661 struct drm_hash_item *hash;
662 int ret = 0; 662 int ret = 0;
663 663
664 if (drm_device_is_unplugged(dev))
665 return -ENODEV;
666
664 mutex_lock(&dev->struct_mutex); 667 mutex_lock(&dev->struct_mutex);
665 668
666 if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) { 669 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 6d7b083c5b77..bbd40eaf9821 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)
429 return 0; 429 return 0;
430} 430}
431 431
432static void drm_unplug_minor(struct drm_minor *minor)
433{
434 drm_sysfs_device_remove(minor);
435}
436
432/** 437/**
433 * Called via drm_exit() at module unload time or when pci device is 438 * Called via drm_exit() at module unload time or when pci device is
434 * unplugged. 439 * unplugged.
@@ -492,3 +497,21 @@ void drm_put_dev(struct drm_device *dev)
492 kfree(dev); 497 kfree(dev);
493} 498}
494EXPORT_SYMBOL(drm_put_dev); 499EXPORT_SYMBOL(drm_put_dev);
500
501void drm_unplug_dev(struct drm_device *dev)
502{
503 /* for a USB device */
504 if (drm_core_check_feature(dev, DRIVER_MODESET))
505 drm_unplug_minor(dev->control);
506 drm_unplug_minor(dev->primary);
507
508 mutex_lock(&drm_global_mutex);
509
510 drm_device_set_unplugged(dev);
511
512 if (dev->open_count == 0) {
513 drm_put_dev(dev);
514 }
515 mutex_unlock(&drm_global_mutex);
516}
517EXPORT_SYMBOL(drm_unplug_dev);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 55cd61567812..149561818349 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)
680 struct drm_device *dev = priv->minor->dev; 680 struct drm_device *dev = priv->minor->dev;
681 int ret; 681 int ret;
682 682
683 if (drm_device_is_unplugged(dev))
684 return -ENODEV;
685
683 mutex_lock(&dev->struct_mutex); 686 mutex_lock(&dev->struct_mutex);
684 ret = drm_mmap_locked(filp, vma); 687 ret = drm_mmap_locked(filp, vma);
685 mutex_unlock(&dev->struct_mutex); 688 mutex_unlock(&dev->struct_mutex);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index cfd921ff0cc4..574bd1c81ebd 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1170,6 +1170,8 @@ struct drm_device {
1170 struct idr object_name_idr; 1170 struct idr object_name_idr;
1171 /*@} */ 1171 /*@} */
1172 int switch_power_state; 1172 int switch_power_state;
1173
1174 atomic_t unplugged; /* device has been unplugged or gone away */
1173}; 1175};
1174 1176
1175#define DRM_SWITCH_POWER_ON 0 1177#define DRM_SWITCH_POWER_ON 0
@@ -1235,6 +1237,19 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
1235} 1237}
1236#endif 1238#endif
1237 1239
1240static inline void drm_device_set_unplugged(struct drm_device *dev)
1241{
1242 smp_wmb();
1243 atomic_set(&dev->unplugged, 1);
1244}
1245
1246static inline int drm_device_is_unplugged(struct drm_device *dev)
1247{
1248 int ret = atomic_read(&dev->unplugged);
1249 smp_rmb();
1250 return ret;
1251}
1252
1238/******************************************************************/ 1253/******************************************************************/
1239/** \name Internal function definitions */ 1254/** \name Internal function definitions */
1240/*@{*/ 1255/*@{*/
@@ -1455,6 +1470,7 @@ extern void drm_master_put(struct drm_master **master);
1455 1470
1456extern void drm_put_dev(struct drm_device *dev); 1471extern void drm_put_dev(struct drm_device *dev);
1457extern int drm_put_minor(struct drm_minor **minor); 1472extern int drm_put_minor(struct drm_minor **minor);
1473extern void drm_unplug_dev(struct drm_device *dev);
1458extern unsigned int drm_debug; 1474extern unsigned int drm_debug;
1459 1475
1460extern unsigned int drm_vblank_offdelay; 1476extern unsigned int drm_vblank_offdelay;