From 42c2cfcf7d5730a2961d425228e042f533b312fa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 20:30:19 +0200 Subject: Generic DRM support base-class support for user-space objects, like fence objects and buffer objects: Refcounting, Inter-process sharing, Synchronization Destruction. --- linux-core/drm_lock.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index a268d8ee..c12e4897 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -308,3 +308,60 @@ static int drm_notifier(void *priv) } while (prev != old); return 0; } + +/* + * Can be used by drivers to take the hardware lock if necessary. + * (Waiting for idle before reclaiming buffers etc.) + */ + +int drm_i_have_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + return (priv->lock_count && dev->lock.hw_lock && + _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && + dev->lock.filp == filp); +} + +EXPORT_SYMBOL(drm_i_have_hw_lock); + +int drm_kernel_take_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + int ret = 0; + + if (!drm_i_have_hw_lock(filp)) { + + DECLARE_WAITQUEUE(entry, current); + + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.filp = filp; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); + break; /* Got lock */ + } + /* Contention */ + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + return ret; +} + +EXPORT_SYMBOL(drm_kernel_take_hw_lock); + -- cgit v1.2.3 From 191e284709ee792a32124e96e43d5876406b93dc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 12:01:00 +0200 Subject: More bugfixes. Disable the i915 IRQ turnoff for now since it seems to be causing problems. --- linux-core/drm_lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 91fad8bf..69ce2291 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -270,7 +270,7 @@ int drm_lock_free(drm_device_t * dev, prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", + DRM_DEBUG("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } -- cgit v1.2.3 From f613022ceef1814cb734bb3375f01962fd3bcf10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 16:47:09 +0200 Subject: Allow a "native type" to be associated with a fence sequence. In the intel case, we can associate a flush with a sequence. --- linux-core/drm_lock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 69ce2291..8619defb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -201,7 +201,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; else - new = context | _DRM_LOCK_HELD; + new = context | _DRM_LOCK_HELD | _DRM_LOCK_CONT; prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCKING_CONTEXT(old) == context) { @@ -213,7 +213,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + if (new == (context | _DRM_LOCK_HELD | _DRM_LOCK_CONT)) { /* Have lock */ return 1; } -- cgit v1.2.3 From 26528627a6cea7f92a949e89e5db6e17ef9560c2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 14:40:11 +0200 Subject: Remove the call to drm_lock_transfer, since it is not used anymore. Fix up drm_lock_free to retain the last locking context information. --- linux-core/drm_lock.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 8619defb..97417636 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -170,11 +170,8 @@ int drm_unlock(struct inode *inode, struct file *filp, if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { + lock.context)) { DRM_ERROR("\n"); } } @@ -263,12 +260,12 @@ int drm_lock_free(drm_device_t * dev, { unsigned int old, new, prev; - dev->lock.filp = NULL; do { old = *lock; - new = 0; + new = _DRM_LOCKING_CONTEXT(old); prev = cmpxchg(lock, old, new); } while (prev != old); + if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { DRM_DEBUG("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); -- cgit v1.2.3 From 1c6f0ea43c47603c2265248ce8a91698c8982f3c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:11:27 +0200 Subject: Activate error message that was never hit since it was masked by drm_lock_transfer. Ifdef out drm_lock_transfer. I see no use for it currently. Should be removed. --- linux-core/drm_lock.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 97417636..86ee25cb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -35,9 +35,12 @@ #include "drmP.h" +#if 0 static int drm_lock_transfer(drm_device_t * dev, __volatile__ unsigned int *lock, unsigned int context); +#endif + static int drm_notifier(void *priv); /** @@ -172,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp, else { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) { - DRM_ERROR("\n"); + /* FIXME: Should really bail out here. */ } } @@ -217,6 +220,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } +#if 0 /** * This takes a lock forcibly and hands it to context. Should ONLY be used * inside *_unlock to give lock to kernel before calling *_dma_schedule. @@ -243,6 +247,7 @@ static int drm_lock_transfer(drm_device_t * dev, } while (prev != old); return 1; } +#endif /** * Free lock. @@ -267,7 +272,7 @@ int drm_lock_free(drm_device_t * dev, } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_DEBUG("%d freed heavyweight lock held by %d\n", + DRM_ERROR("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } -- cgit v1.2.3 From a7b8c8d523d7f726b8fb74cb37f807d2316cf5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 16 Aug 2006 15:47:22 +0200 Subject: Add support for interrupt triggered driver callback with lock held to DRM core. (cherry picked from d817cc1f30060fcc4a85a05b2de8a2a1687421b5 commit) --- linux-core/drm_lock.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 86ee25cb..04c145a6 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; + unsigned int irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; @@ -165,6 +166,16 @@ int drm_unlock(struct inode *inode, struct file *filp, return -EINVAL; } + spin_lock_irqsave(&dev->tasklet_lock, irqflags); + + if (dev->locked_tasklet_func) { + dev->locked_tasklet_func(dev); + + dev->locked_tasklet_func = NULL; + } + + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); + atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); /* kernel_context_switch isn't used by any of the x86 drm -- cgit v1.2.3 From c6be27401fbc12ec72bac13d07e3cc93bd63732a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:34:30 +0200 Subject: Trap and be verbose about a deadlock that occurs with AIGLX and drivers that use drm_reclaim_buffers_locked(). --- linux-core/drm_lock.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 04c145a6..0cf183a7 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -343,6 +343,7 @@ int drm_kernel_take_hw_lock(struct file *filp) DRM_DEVICE; int ret = 0; + unsigned long _end = jiffies + 3*DRM_HZ; if (!drm_i_have_hw_lock(filp)) { @@ -364,7 +365,12 @@ int drm_kernel_take_hw_lock(struct file *filp) break; /* Got lock */ } /* Contention */ - schedule(); + if (time_after_eq(jiffies,_end)) { + ret = -EBUSY; + break; + } + + schedule_timeout(1); if (signal_pending(current)) { ret = -ERESTARTSYS; break; -- cgit v1.2.3 From 16be6ba63a41f03e98a741464d3b51eefb277373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 2 Oct 2006 15:33:19 +0200 Subject: Fix type of second argument to spin_lock_irqsave(). (cherry picked from f6238cf6244b32bd84e3d2819963d7f5473867c8 commit) --- linux-core/drm_lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_lock.c') diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 0cf183a7..d11c570e 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -155,7 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; - unsigned int irqflags; + unsigned long irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; -- cgit v1.2.3