summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorJeff Hartmann <jhartmann@valinux.com>2000-04-05 18:48:23 +0000
committerJeff Hartmann <jhartmann@valinux.com>2000-04-05 18:48:23 +0000
commit1dcfddf9154bcce3d6e004acee7dd503c27d0f0b (patch)
treeacc9712c1dd5a6dfa2660b3f88c406198345c362 /linux
parentba1b1ae3806490cce16a9c8957b52cd74967f463 (diff)
Fixed reclaim Oops
Diffstat (limited to 'linux')
-rw-r--r--linux/i810_dma.c12
-rw-r--r--linux/i810_drv.c4
-rw-r--r--linux/mga_dma.c9
-rw-r--r--linux/mga_drv.c89
-rw-r--r--linux/mga_drv.h1
5 files changed, 88 insertions, 27 deletions
diff --git a/linux/i810_dma.c b/linux/i810_dma.c
index 30fda5b8..6ac4d2ee 100644
--- a/linux/i810_dma.c
+++ b/linux/i810_dma.c
@@ -714,17 +714,17 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
if (!dma) return;
if(dev->dev_private == NULL) return;
-
+ if(dma->buflist == NULL) return;
i810_flush_queue(dev);
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-
- if (buf->pid == pid) {
- /* Only buffers that need to get reclaimed ever
- * get set to free */
- if(buf_priv == NULL) return;
+
+ /* Only buffers that need to get reclaimed ever
+ * get set to free
+ */
+ if (buf->pid == pid && buf_priv) {
cmpxchg(buf_priv->in_use,
I810_BUF_USED, I810_BUF_FREE);
}
diff --git a/linux/i810_drv.c b/linux/i810_drv.c
index d3b35c49..f1c83250 100644
--- a/linux/i810_drv.c
+++ b/linux/i810_drv.c
@@ -499,7 +499,7 @@ int i810_release(struct inode *inode, struct file *filp)
DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
current->pid, dev->device, dev->open_count);
- if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
&& dev->lock.pid == current->pid) {
i810_reclaim_buffers(dev, priv->pid);
DRM_ERROR("Process %d dead, freeing lock for context %d\n",
@@ -513,7 +513,7 @@ int i810_release(struct inode *inode, struct file *filp)
hardware at this point, possibly
processed via a callback to the X
server. */
- } else {
+ } else if (dev->lock.hw_lock) {
/* The lock is required to reclaim buffers */
DECLARE_WAITQUEUE(entry, current);
add_wait_queue(&dev->lock.lock_queue, &entry);
diff --git a/linux/mga_dma.c b/linux/mga_dma.c
index 59cbad6b..371706f4 100644
--- a/linux/mga_dma.c
+++ b/linux/mga_dma.c
@@ -1016,6 +1016,7 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid)
if (!dma) return;
if(dev->dev_private == NULL) return;
+ if(dma->buflist == NULL) return;
mga_flush_queue(dev);
@@ -1023,10 +1024,10 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid)
drm_buf_t *buf = dma->buflist[ i ];
drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->pid == pid) {
- if(buf_priv == NULL) return;
- /* Only buffers that need to get reclaimed ever
- * get set to free */
+ /* Only buffers that need to get reclaimed ever
+ * get set to free
+ */
+ if (buf->pid == pid && buf_priv) {
if(buf_priv->my_freelist->age == MGA_BUF_USED)
buf_priv->my_freelist->age = MGA_BUF_FREE;
}
diff --git a/linux/mga_drv.c b/linux/mga_drv.c
index 48041354..82dda64d 100644
--- a/linux/mga_drv.c
+++ b/linux/mga_drv.c
@@ -510,27 +510,86 @@ int mga_release(struct inode *inode, struct file *filp)
drm_device_t *dev = priv->dev;
int retcode = 0;
- DRM_DEBUG("open_count = %d\n", dev->open_count);
- if (!(retcode = drm_release(inode, filp))) {
- MOD_DEC_USE_COUNT;
- atomic_inc(&dev->total_close);
- spin_lock(&dev->count_lock);
- if (!--dev->open_count) {
- if (atomic_read(&dev->ioctl_count) || dev->blocked) {
- DRM_ERROR("Device busy: %d %d\n",
- atomic_read(&dev->ioctl_count),
- dev->blocked);
- spin_unlock(&dev->count_lock);
- return -EBUSY;
+ DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+ current->pid, dev->device, dev->open_count);
+
+ if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ && dev->lock.pid == current->pid) {
+ mga_reclaim_buffers(dev, priv->pid);
+ DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+ current->pid,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ drm_lock_free(dev,
+ &dev->lock.hw_lock->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+ /* FIXME: may require heavy-handed reset of
+ hardware at this point, possibly
+ processed via a callback to the X
+ server. */
+ } else if (dev->lock.hw_lock) {
+ /* The lock is required to reclaim buffers */
+ DECLARE_WAITQUEUE(entry, current);
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ retcode = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT)) {
+ dev->lock.pid = priv->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ break; /* Got lock */
+ }
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (signal_pending(current)) {
+ retcode = -ERESTARTSYS;
+ break;
}
- spin_unlock(&dev->count_lock);
- return mga_takedown(dev);
}
- spin_unlock(&dev->count_lock);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+ if(!retcode) {
+ mga_reclaim_buffers(dev, priv->pid);
+ drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ DRM_KERNEL_CONTEXT);
+ }
+ }
+ drm_fasync(-1, filp, 0);
+
+ down(&dev->struct_sem);
+ if (priv->prev) priv->prev->next = priv->next;
+ else dev->file_first = priv->next;
+ if (priv->next) priv->next->prev = priv->prev;
+ else dev->file_last = priv->prev;
+ up(&dev->struct_sem);
+
+ drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+ MOD_DEC_USE_COUNT;
+ atomic_inc(&dev->total_close);
+ spin_lock(&dev->count_lock);
+ if (!--dev->open_count) {
+ if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+ DRM_ERROR("Device busy: %d %d\n",
+ atomic_read(&dev->ioctl_count),
+ dev->blocked);
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&dev->count_lock);
+ return mga_takedown(dev);
}
+ spin_unlock(&dev->count_lock);
return retcode;
}
+
/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
diff --git a/linux/mga_drv.h b/linux/mga_drv.h
index 43deb613..801e707d 100644
--- a/linux/mga_drv.h
+++ b/linux/mga_drv.h
@@ -131,6 +131,7 @@ extern unsigned int mga_create_sync_tag(drm_device_t *dev);
extern drm_buf_t *mga_freelist_get(drm_device_t *dev);
extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf);
extern int mga_advance_primary(drm_device_t *dev);
+extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid);
/* mga_bufs.c */