The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm/drm_lock.h

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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  * $FreeBSD: releng/5.0/sys/dev/drm/drm_lock.h 95584 2002-04-27 20:47:57Z anholt $
   32  */
   33 
   34 #define __NO_VERSION__
   35 #include "dev/drm/drmP.h"
   36 
   37 int DRM(block)( DRM_OS_IOCTL )
   38 {
   39         DRM_DEBUG("\n");
   40         return 0;
   41 }
   42 
   43 int DRM(unblock)( DRM_OS_IOCTL )
   44 {
   45         DRM_DEBUG("\n");
   46         return 0;
   47 }
   48 
   49 int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context)
   50 {
   51         unsigned int old, new;
   52 #ifdef __linux__
   53         unsigned int prev;
   54 #endif /* __linux__ */
   55 
   56 #ifdef __FreeBSD__
   57         char failed;
   58 #endif /* __FreeBSD__ */
   59 
   60         do {
   61                 old = *lock;
   62                 if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
   63                 else                      new = context | _DRM_LOCK_HELD;
   64 #ifdef __linux__
   65                 prev = cmpxchg(lock, old, new);
   66         } while (prev != old);
   67 #endif /* __linux__ */
   68 #ifdef __FreeBSD__
   69                 _DRM_CAS(lock, old, new, failed);
   70         } while (failed);
   71 #endif /* __FreeBSD__ */
   72         if (_DRM_LOCKING_CONTEXT(old) == context) {
   73                 if (old & _DRM_LOCK_HELD) {
   74                         if (context != DRM_KERNEL_CONTEXT) {
   75                                 DRM_ERROR("%d holds heavyweight lock\n",
   76                                           context);
   77                         }
   78                         return 0;
   79                 }
   80         }
   81         if (new == (context | _DRM_LOCK_HELD)) {
   82                                 /* Have lock */
   83                 return 1;
   84         }
   85         return 0;
   86 }
   87 
   88 /* This takes a lock forcibly and hands it to context.  Should ONLY be used
   89    inside *_unlock to give lock to kernel before calling *_dma_schedule. */
   90 int DRM(lock_transfer)(drm_device_t *dev,
   91                        __volatile__ unsigned int *lock, unsigned int context)
   92 {
   93         unsigned int old, new;
   94 #ifdef __linux__
   95         unsigned int prev;
   96 #endif /* __linux__ */
   97 #ifdef __FreeBSD__
   98         char failed;
   99 #endif /* __FreeBSD__ */
  100 
  101         dev->lock.pid = 0;
  102         do {
  103                 old  = *lock;
  104                 new  = context | _DRM_LOCK_HELD;
  105 #ifdef __linux__
  106                 prev = cmpxchg(lock, old, new);
  107         } while (prev != old);
  108 #endif /* __linux__ */
  109 #ifdef __FreeBSD__
  110                 _DRM_CAS(lock, old, new, failed);
  111         } while (failed);
  112 #endif /* __FreeBSD__ */
  113         return 1;
  114 }
  115 
  116 int DRM(lock_free)(drm_device_t *dev,
  117                    __volatile__ unsigned int *lock, unsigned int context)
  118 {
  119         unsigned int old, new;
  120 #ifdef __linux__
  121         unsigned int prev;
  122 #endif /* __linux__ */
  123         pid_t        pid = dev->lock.pid;
  124 #ifdef __FreeBSD__
  125         char failed;
  126 #endif /* __FreeBSD__ */
  127 
  128         dev->lock.pid = 0;
  129         do {
  130                 old  = *lock;
  131                 new  = 0;
  132 #ifdef __linux__
  133                 prev = cmpxchg(lock, old, new);
  134         } while (prev != old);
  135 #endif /* __linux__ */
  136 #ifdef __FreeBSD__
  137                 _DRM_CAS(lock, old, new, failed);
  138         } while (failed);
  139 #endif /* __FreeBSD__ */
  140         if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
  141                 DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
  142                           context,
  143                           _DRM_LOCKING_CONTEXT(old),
  144                           pid);
  145                 return 1;
  146         }
  147         DRM_OS_WAKEUP_INT(&dev->lock.lock_queue);
  148         return 0;
  149 }
  150 
  151 static int DRM(flush_queue)(drm_device_t *dev, int context)
  152 {
  153 #ifdef __linux__
  154         DECLARE_WAITQUEUE(entry, current);
  155 #endif /* __linux__ */
  156 #ifdef __FreeBSD__
  157         int               error;
  158 #endif /* __FreeBSD__ */
  159         int               ret   = 0;
  160         drm_queue_t       *q    = dev->queuelist[context];
  161 
  162         DRM_DEBUG("\n");
  163 
  164         atomic_inc(&q->use_count);
  165         if (atomic_read(&q->use_count) > 1) {
  166                 atomic_inc(&q->block_write);
  167 #ifdef __linux__
  168                 add_wait_queue(&q->flush_queue, &entry);
  169                 atomic_inc(&q->block_count);
  170                 for (;;) {
  171                         current->state = TASK_INTERRUPTIBLE;
  172                         if (!DRM_BUFCOUNT(&q->waitlist)) break;
  173                         schedule();
  174                         if (signal_pending(current)) {
  175                                 ret = -EINTR; /* Can't restart */
  176                                 break;
  177                         }
  178                 }
  179 #endif /* __linux__ */
  180 #ifdef __FreeBSD__
  181                 atomic_inc(&q->block_count);
  182                 error = tsleep(&q->flush_queue, PZERO|PCATCH, "drmfq", 0);
  183                 if (error)
  184                         return error;
  185 #endif /* __FreeBSD__ */
  186                 atomic_dec(&q->block_count);
  187 #ifdef __linux__
  188                 current->state = TASK_RUNNING;
  189                 remove_wait_queue(&q->flush_queue, &entry);
  190 #endif /* __linux__ */
  191         }
  192         atomic_dec(&q->use_count);
  193 
  194                                 /* NOTE: block_write is still incremented!
  195                                    Use drm_flush_unlock_queue to decrement. */
  196         return ret;
  197 }
  198 
  199 static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
  200 {
  201         drm_queue_t       *q    = dev->queuelist[context];
  202 
  203         DRM_DEBUG("\n");
  204 
  205         atomic_inc(&q->use_count);
  206         if (atomic_read(&q->use_count) > 1) {
  207                 if (atomic_read(&q->block_write)) {
  208                         atomic_dec(&q->block_write);
  209                         DRM_OS_WAKEUP_INT(&q->write_queue);
  210                 }
  211         }
  212         atomic_dec(&q->use_count);
  213         return 0;
  214 }
  215 
  216 int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
  217                                drm_lock_flags_t flags)
  218 {
  219         int ret = 0;
  220         int i;
  221 
  222         DRM_DEBUG("\n");
  223 
  224         if (flags & _DRM_LOCK_FLUSH) {
  225                 ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
  226                 if (!ret) ret = DRM(flush_queue)(dev, context);
  227         }
  228         if (flags & _DRM_LOCK_FLUSH_ALL) {
  229                 for (i = 0; !ret && i < dev->queue_count; i++) {
  230                         ret = DRM(flush_queue)(dev, i);
  231                 }
  232         }
  233         return ret;
  234 }
  235 
  236 int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
  237 {
  238         int ret = 0;
  239         int i;
  240 
  241         DRM_DEBUG("\n");
  242 
  243         if (flags & _DRM_LOCK_FLUSH) {
  244                 ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
  245                 if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
  246         }
  247         if (flags & _DRM_LOCK_FLUSH_ALL) {
  248                 for (i = 0; !ret && i < dev->queue_count; i++) {
  249                         ret = DRM(flush_unblock_queue)(dev, i);
  250                 }
  251         }
  252 
  253         return ret;
  254 }
  255 
  256 int DRM(finish)( DRM_OS_IOCTL )
  257 {
  258         DRM_OS_DEVICE;
  259         int               ret     = 0;
  260         drm_lock_t        lock;
  261 
  262         DRM_DEBUG("\n");
  263 
  264         DRM_OS_KRNFROMUSR( lock, (drm_lock_t *)data, sizeof(lock) );
  265 
  266         ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
  267         DRM(flush_unblock)(dev, lock.context, lock.flags);
  268         return ret;
  269 }
  270 
  271 /* If we get here, it means that the process has called DRM_IOCTL_LOCK
  272    without calling DRM_IOCTL_UNLOCK.
  273 
  274    If the lock is not held, then let the signal proceed as usual.
  275 
  276    If the lock is held, then set the contended flag and keep the signal
  277    blocked.
  278 
  279 
  280    Return 1 if the signal should be delivered normally.
  281    Return 0 if the signal should be blocked.  */
  282 
  283 int DRM(notifier)(void *priv)
  284 {
  285         drm_sigdata_t *s = (drm_sigdata_t *)priv;
  286         unsigned int  old, new;
  287 #ifdef __linux__
  288         unsigned int prev;
  289 #endif /* __linux__ */
  290 #ifdef __FreeBSD__
  291         char failed;
  292 #endif /* __FreeBSD__ */
  293 
  294 
  295                                 /* Allow signal delivery if lock isn't held */
  296         if (!_DRM_LOCK_IS_HELD(s->lock->lock)
  297             || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
  298 
  299                                 /* Otherwise, set flag to force call to
  300                                    drmUnlock */
  301         do {
  302                 old  = s->lock->lock;
  303                 new  = old | _DRM_LOCK_CONT;
  304 #ifdef __linux__
  305                 prev = cmpxchg(&s->lock->lock, old, new);
  306         } while (prev != old);
  307 #endif /* __linux__ */
  308 #ifdef __FreeBSD__
  309                 _DRM_CAS(&s->lock->lock, old, new, failed);
  310         } while (failed);
  311 #endif /* __FreeBSD__ */
  312         return 0;
  313 }
  314 

Cache object: 80799e465b735d376b1017555b7465c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.