aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_fops.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2007-03-22 22:28:33 -0400
committerDave Airlie <airlied@linux.ie>2007-03-22 22:28:33 -0400
commit040ac32048d5efabd557c1e0a6ab8aec2c710c56 (patch)
treeba714a33105695c7d57ff833dbd18875ddb82492 /drivers/char/drm/drm_fops.c
parent4b560fde06aeb342f3ff0bce924627ab722d251a (diff)
drm: fix driver deadlock with AIGLX and reclaim_buffers_locked
Bugzilla Bug #9457 Add refcounting of user waiters to the DRM hardware lock, so that we can use DRM_LOCK_CONT flag more conservatively. Also add a kernel waiter refcount that if nonzero transfers the lock for the kernel context when it is released. This is useful when waiting for idle and can be used for very simple fence object driver implementations for the new memory manager Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm/drm_fops.c')
-rw-r--r--drivers/char/drm/drm_fops.c90
1 files changed, 44 insertions, 46 deletions
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 314abd9d6510..3b159cab3bc8 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -356,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp)
356 current->pid, (long)old_encode_dev(priv->head->device), 356 current->pid, (long)old_encode_dev(priv->head->device),
357 dev->open_count); 357 dev->open_count);
358 358
359 if (priv->lock_count && dev->lock.hw_lock && 359 if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
360 _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && 360 if (drm_i_have_hw_lock(filp)) {
361 dev->lock.filp == filp) {
362 DRM_DEBUG("File %p released, freeing lock for context %d\n",
363 filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
364
365 if (dev->driver->reclaim_buffers_locked)
366 dev->driver->reclaim_buffers_locked(dev, filp); 361 dev->driver->reclaim_buffers_locked(dev, filp);
367 362 } else {
368 drm_lock_free(dev, &dev->lock.hw_lock->lock, 363 unsigned long _end=jiffies + 3*DRM_HZ;
369 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); 364 int locked = 0;
370 365
371 /* FIXME: may require heavy-handed reset of 366 drm_idlelock_take(&dev->lock);
372 hardware at this point, possibly 367
373 processed via a callback to the X 368 /*
374 server. */ 369 * Wait for a while.
375 } else if (dev->driver->reclaim_buffers_locked && priv->lock_count 370 */
376 && dev->lock.hw_lock) { 371
377 /* The lock is required to reclaim buffers */ 372 do{
378 DECLARE_WAITQUEUE(entry, current); 373 spin_lock(&dev->lock.spinlock);
379 374 locked = dev->lock.idle_has_lock;
380 add_wait_queue(&dev->lock.lock_queue, &entry); 375 spin_unlock(&dev->lock.spinlock);
381 for (;;) { 376 if (locked)
382 __set_current_state(TASK_INTERRUPTIBLE); 377 break;
383 if (!dev->lock.hw_lock) { 378 schedule();
384 /* Device has been unregistered */ 379 } while (!time_after_eq(jiffies, _end));
385 retcode = -EINTR; 380
386 break; 381 if (!locked) {
382 DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
383 "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
384 "\tI will go on reclaiming the buffers anyway.\n");
387 } 385 }
388 if (drm_lock_take(&dev->lock.hw_lock->lock, 386
389 DRM_KERNEL_CONTEXT)) {
390 dev->lock.filp = filp;
391 dev->lock.lock_time = jiffies;
392 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
393 break; /* Got lock */
394 }
395 /* Contention */
396 schedule();
397 if (signal_pending(current)) {
398 retcode = -ERESTARTSYS;
399 break;
400 }
401 }
402 __set_current_state(TASK_RUNNING);
403 remove_wait_queue(&dev->lock.lock_queue, &entry);
404 if (!retcode) {
405 dev->driver->reclaim_buffers_locked(dev, filp); 387 dev->driver->reclaim_buffers_locked(dev, filp);
406 drm_lock_free(dev, &dev->lock.hw_lock->lock, 388 drm_idlelock_release(&dev->lock);
407 DRM_KERNEL_CONTEXT);
408 } 389 }
409 } 390 }
410 391
392 if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
393
394 drm_idlelock_take(&dev->lock);
395 dev->driver->reclaim_buffers_idlelocked(dev, filp);
396 drm_idlelock_release(&dev->lock);
397
398 }
399
400 if (drm_i_have_hw_lock(filp)) {
401 DRM_DEBUG("File %p released, freeing lock for context %d\n",
402 filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
403
404 drm_lock_free(&dev->lock,
405 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
406 }
407
408
411 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && 409 if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
412 !dev->driver->reclaim_buffers_locked) { 410 !dev->driver->reclaim_buffers_locked) {
413 dev->driver->reclaim_buffers(dev, filp); 411 dev->driver->reclaim_buffers(dev, filp);