linux-old/drivers/char/drm/drm_lock.h
<<
>>
Prefs
   1/* lock.c -- IOCTLs for locking -*- linux-c -*-
   2 * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
   3 *
   4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
   5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   6 * All Rights Reserved.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a
   9 * copy of this software and associated documentation files (the "Software"),
  10 * to deal in the Software without restriction, including without limitation
  11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12 * and/or sell copies of the Software, and to permit persons to whom the
  13 * Software is furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice (including the next
  16 * paragraph) shall be included in all copies or substantial portions of the
  17 * Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25 * OTHER DEALINGS IN THE SOFTWARE.
  26 *
  27 * Authors:
  28 *    Rickard E. (Rik) Faith <faith@valinux.com>
  29 *    Gareth Hughes <gareth@valinux.com>
  30 */
  31
  32#include "drmP.h"
  33
  34int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd,
  35               unsigned long arg)
  36{
  37        DRM_DEBUG("\n");
  38        return 0;
  39}
  40
  41int DRM(unblock)(struct inode *inode, struct file *filp, unsigned int cmd,
  42                 unsigned long arg)
  43{
  44        DRM_DEBUG("\n");
  45        return 0;
  46}
  47
  48int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context)
  49{
  50        unsigned int old, new, prev;
  51
  52        do {
  53                old = *lock;
  54                if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
  55                else                      new = context | _DRM_LOCK_HELD;
  56                prev = cmpxchg(lock, old, new);
  57        } while (prev != old);
  58        if (_DRM_LOCKING_CONTEXT(old) == context) {
  59                if (old & _DRM_LOCK_HELD) {
  60                        if (context != DRM_KERNEL_CONTEXT) {
  61                                DRM_ERROR("%d holds heavyweight lock\n",
  62                                          context);
  63                        }
  64                        return 0;
  65                }
  66        }
  67        if (new == (context | _DRM_LOCK_HELD)) {
  68                                /* Have lock */
  69                return 1;
  70        }
  71        return 0;
  72}
  73
  74/* This takes a lock forcibly and hands it to context.  Should ONLY be used
  75   inside *_unlock to give lock to kernel before calling *_dma_schedule. */
  76int DRM(lock_transfer)(drm_device_t *dev,
  77                       __volatile__ unsigned int *lock, unsigned int context)
  78{
  79        unsigned int old, new, prev;
  80
  81        dev->lock.pid = 0;
  82        do {
  83                old  = *lock;
  84                new  = context | _DRM_LOCK_HELD;
  85                prev = cmpxchg(lock, old, new);
  86        } while (prev != old);
  87        return 1;
  88}
  89
  90int DRM(lock_free)(drm_device_t *dev,
  91                   __volatile__ unsigned int *lock, unsigned int context)
  92{
  93        unsigned int old, new, prev;
  94        pid_t        pid = dev->lock.pid;
  95
  96        dev->lock.pid = 0;
  97        do {
  98                old  = *lock;
  99                new  = 0;
 100                prev = cmpxchg(lock, old, new);
 101        } while (prev != old);
 102        if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
 103                DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
 104                          context,
 105                          _DRM_LOCKING_CONTEXT(old),
 106                          pid);
 107                return 1;
 108        }
 109        wake_up_interruptible(&dev->lock.lock_queue);
 110        return 0;
 111}
 112
 113static int DRM(flush_queue)(drm_device_t *dev, int context)
 114{
 115        DECLARE_WAITQUEUE(entry, current);
 116        int               ret   = 0;
 117        drm_queue_t       *q    = dev->queuelist[context];
 118
 119        DRM_DEBUG("\n");
 120
 121        atomic_inc(&q->use_count);
 122        if (atomic_read(&q->use_count) > 1) {
 123                atomic_inc(&q->block_write);
 124                add_wait_queue(&q->flush_queue, &entry);
 125                atomic_inc(&q->block_count);
 126                for (;;) {
 127                        current->state = TASK_INTERRUPTIBLE;
 128                        if (!DRM_BUFCOUNT(&q->waitlist)) break;
 129                        schedule();
 130                        if (signal_pending(current)) {
 131                                ret = -EINTR; /* Can't restart */
 132                                break;
 133                        }
 134                }
 135                atomic_dec(&q->block_count);
 136                current->state = TASK_RUNNING;
 137                remove_wait_queue(&q->flush_queue, &entry);
 138        }
 139        atomic_dec(&q->use_count);
 140
 141                                /* NOTE: block_write is still incremented!
 142                                   Use drm_flush_unlock_queue to decrement. */
 143        return ret;
 144}
 145
 146static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
 147{
 148        drm_queue_t       *q    = dev->queuelist[context];
 149
 150        DRM_DEBUG("\n");
 151
 152        atomic_inc(&q->use_count);
 153        if (atomic_read(&q->use_count) > 1) {
 154                if (atomic_read(&q->block_write)) {
 155                        atomic_dec(&q->block_write);
 156                        wake_up_interruptible(&q->write_queue);
 157                }
 158        }
 159        atomic_dec(&q->use_count);
 160        return 0;
 161}
 162
 163int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
 164                               drm_lock_flags_t flags)
 165{
 166        int ret = 0;
 167        int i;
 168
 169        DRM_DEBUG("\n");
 170
 171        if (flags & _DRM_LOCK_FLUSH) {
 172                ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
 173                if (!ret) ret = DRM(flush_queue)(dev, context);
 174        }
 175        if (flags & _DRM_LOCK_FLUSH_ALL) {
 176                for (i = 0; !ret && i < dev->queue_count; i++) {
 177                        ret = DRM(flush_queue)(dev, i);
 178                }
 179        }
 180        return ret;
 181}
 182
 183int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
 184{
 185        int ret = 0;
 186        int i;
 187
 188        DRM_DEBUG("\n");
 189
 190        if (flags & _DRM_LOCK_FLUSH) {
 191                ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
 192                if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
 193        }
 194        if (flags & _DRM_LOCK_FLUSH_ALL) {
 195                for (i = 0; !ret && i < dev->queue_count; i++) {
 196                        ret = DRM(flush_unblock_queue)(dev, i);
 197                }
 198        }
 199
 200        return ret;
 201}
 202
 203int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
 204                unsigned long arg)
 205{
 206        drm_file_t        *priv   = filp->private_data;
 207        drm_device_t      *dev    = priv->dev;
 208        int               ret     = 0;
 209        drm_lock_t        lock;
 210
 211        DRM_DEBUG("\n");
 212
 213        if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
 214                return -EFAULT;
 215        ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
 216        DRM(flush_unblock)(dev, lock.context, lock.flags);
 217        return ret;
 218}
 219
 220/* If we get here, it means that the process has called DRM_IOCTL_LOCK
 221   without calling DRM_IOCTL_UNLOCK.
 222
 223   If the lock is not held, then let the signal proceed as usual.
 224
 225   If the lock is held, then set the contended flag and keep the signal
 226   blocked.
 227
 228
 229   Return 1 if the signal should be delivered normally.
 230   Return 0 if the signal should be blocked.  */
 231
 232int DRM(notifier)(void *priv)
 233{
 234        drm_sigdata_t *s = (drm_sigdata_t *)priv;
 235        unsigned int  old, new, prev;
 236
 237
 238                                /* Allow signal delivery if lock isn't held */
 239        if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
 240            || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
 241
 242                                /* Otherwise, set flag to force call to
 243                                   drmUnlock */
 244        do {
 245                old  = s->lock->lock;
 246                new  = old | _DRM_LOCK_CONT;
 247                prev = cmpxchg(&s->lock->lock, old, new);
 248        } while (prev != old);
 249        return 0;
 250}
 251
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.