Subversion Repositories Kolibri OS

Rev

Rev 5078 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20.  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21.  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24.  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27. /*
  28.  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  29.  */
  30.  
  31. #include <drm/ttm/ttm_lock.h>
  32. #include <drm/ttm/ttm_module.h>
  33. #include <linux/atomic.h>
  34. #include <linux/errno.h>
  35. #include <linux/wait.h>
  36. #include <linux/sched.h>
  37. #include <linux/module.h>
  38.  
  39. #define TTM_WRITE_LOCK_PENDING    (1 << 0)
  40. #define TTM_VT_LOCK_PENDING       (1 << 1)
  41. #define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
  42. #define TTM_VT_LOCK               (1 << 3)
  43. #define TTM_SUSPEND_LOCK          (1 << 4)
  44.  
  45. void ttm_lock_init(struct ttm_lock *lock)
  46. {
  47.         spin_lock_init(&lock->lock);
  48.         init_waitqueue_head(&lock->queue);
  49.         lock->rw = 0;
  50.         lock->flags = 0;
  51. }
  52. EXPORT_SYMBOL(ttm_lock_init);
  53.  
  54. void ttm_read_unlock(struct ttm_lock *lock)
  55. {
  56.         spin_lock(&lock->lock);
  57.         if (--lock->rw == 0)
  58.                 wake_up_all(&lock->queue);
  59.         spin_unlock(&lock->lock);
  60. }
  61. EXPORT_SYMBOL(ttm_read_unlock);
  62.  
  63. static bool __ttm_read_lock(struct ttm_lock *lock)
  64. {
  65.         bool locked = false;
  66.  
  67.         spin_lock(&lock->lock);
  68.         if (lock->rw >= 0 && lock->flags == 0) {
  69.                 ++lock->rw;
  70.                 locked = true;
  71.         }
  72.         spin_unlock(&lock->lock);
  73.         return locked;
  74. }
  75.  
  76. int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
  77. {
  78.         int ret = 0;
  79.  
  80.         if (interruptible)
  81.                 ret = wait_event_interruptible(lock->queue,
  82.                                                __ttm_read_lock(lock));
  83.         else
  84.                 wait_event(lock->queue, __ttm_read_lock(lock));
  85.         return ret;
  86. }
  87. EXPORT_SYMBOL(ttm_read_lock);
  88.  
  89. static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
  90. {
  91.         bool block = true;
  92.  
  93.         *locked = false;
  94.  
  95.         spin_lock(&lock->lock);
  96.         if (lock->rw >= 0 && lock->flags == 0) {
  97.                 ++lock->rw;
  98.                 block = false;
  99.                 *locked = true;
  100.         } else if (lock->flags == 0) {
  101.                 block = false;
  102.         }
  103.         spin_unlock(&lock->lock);
  104.  
  105.         return !block;
  106. }
  107.  
  108. int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
  109. {
  110.         int ret = 0;
  111.         bool locked;
  112.  
  113.         if (interruptible)
  114.                 ret = wait_event_interruptible
  115.                         (lock->queue, __ttm_read_trylock(lock, &locked));
  116.         else
  117.                 wait_event(lock->queue, __ttm_read_trylock(lock, &locked));
  118.  
  119.         if (unlikely(ret != 0)) {
  120.                 BUG_ON(locked);
  121.                 return ret;
  122.         }
  123.  
  124.         return (locked) ? 0 : -EBUSY;
  125. }
  126.  
  127. void ttm_write_unlock(struct ttm_lock *lock)
  128. {
  129.         spin_lock(&lock->lock);
  130.         lock->rw = 0;
  131.         wake_up_all(&lock->queue);
  132.         spin_unlock(&lock->lock);
  133. }
  134. EXPORT_SYMBOL(ttm_write_unlock);
  135.  
  136. static bool __ttm_write_lock(struct ttm_lock *lock)
  137. {
  138.         bool locked = false;
  139.  
  140.         spin_lock(&lock->lock);
  141.         if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
  142.                 lock->rw = -1;
  143.                 lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  144.                 locked = true;
  145.         } else {
  146.                 lock->flags |= TTM_WRITE_LOCK_PENDING;
  147.         }
  148.         spin_unlock(&lock->lock);
  149.         return locked;
  150. }
  151.  
  152. int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
  153. {
  154.         int ret = 0;
  155.  
  156.         if (interruptible) {
  157.                 ret = wait_event_interruptible(lock->queue,
  158.                                                __ttm_write_lock(lock));
  159.                 if (unlikely(ret != 0)) {
  160.                         spin_lock(&lock->lock);
  161.                         lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  162.                         wake_up_all(&lock->queue);
  163.                         spin_unlock(&lock->lock);
  164.                 }
  165.         } else
  166.                 wait_event(lock->queue, __ttm_write_lock(lock));
  167.  
  168.         return ret;
  169. }
  170. EXPORT_SYMBOL(ttm_write_lock);
  171.  
  172. static int __ttm_vt_unlock(struct ttm_lock *lock)
  173. {
  174.         int ret = 0;
  175.  
  176.         spin_lock(&lock->lock);
  177.         if (unlikely(!(lock->flags & TTM_VT_LOCK)))
  178.                 ret = -EINVAL;
  179.         lock->flags &= ~TTM_VT_LOCK;
  180.         wake_up_all(&lock->queue);
  181.         spin_unlock(&lock->lock);
  182.  
  183.         return ret;
  184. }
  185.  
  186. static void ttm_vt_lock_remove(struct ttm_base_object **p_base)
  187. {
  188.         struct ttm_base_object *base = *p_base;
  189.         struct ttm_lock *lock = container_of(base, struct ttm_lock, base);
  190.         int ret;
  191.  
  192.         *p_base = NULL;
  193.         ret = __ttm_vt_unlock(lock);
  194.         BUG_ON(ret != 0);
  195. }
  196.  
  197. static bool __ttm_vt_lock(struct ttm_lock *lock)
  198. {
  199.         bool locked = false;
  200.  
  201.         spin_lock(&lock->lock);
  202.         if (lock->rw == 0) {
  203.                 lock->flags &= ~TTM_VT_LOCK_PENDING;
  204.                 lock->flags |= TTM_VT_LOCK;
  205.                 locked = true;
  206.         } else {
  207.                 lock->flags |= TTM_VT_LOCK_PENDING;
  208.         }
  209.         spin_unlock(&lock->lock);
  210.         return locked;
  211. }
  212.  
  213. int ttm_vt_lock(struct ttm_lock *lock,
  214.                 bool interruptible,
  215.                 struct ttm_object_file *tfile)
  216. {
  217.         int ret = 0;
  218.  
  219.         if (interruptible) {
  220.                 ret = wait_event_interruptible(lock->queue,
  221.                                                __ttm_vt_lock(lock));
  222.                 if (unlikely(ret != 0)) {
  223.                         spin_lock(&lock->lock);
  224.                         lock->flags &= ~TTM_VT_LOCK_PENDING;
  225.                         wake_up_all(&lock->queue);
  226.                         spin_unlock(&lock->lock);
  227.                         return ret;
  228.                 }
  229.         } else
  230.                 wait_event(lock->queue, __ttm_vt_lock(lock));
  231.  
  232.         /*
  233.          * Add a base-object, the destructor of which will
  234.          * make sure the lock is released if the client dies
  235.          * while holding it.
  236.          */
  237.  
  238.         ret = ttm_base_object_init(tfile, &lock->base, false,
  239.                                    ttm_lock_type, &ttm_vt_lock_remove, NULL);
  240.         if (ret)
  241.                 (void)__ttm_vt_unlock(lock);
  242.         else
  243.                 lock->vt_holder = tfile;
  244.  
  245.         return ret;
  246. }
  247. EXPORT_SYMBOL(ttm_vt_lock);
  248.  
  249. int ttm_vt_unlock(struct ttm_lock *lock)
  250. {
  251.         return ttm_ref_object_base_unref(lock->vt_holder,
  252.                                          lock->base.hash.key, TTM_REF_USAGE);
  253. }
  254. EXPORT_SYMBOL(ttm_vt_unlock);
  255.  
  256. void ttm_suspend_unlock(struct ttm_lock *lock)
  257. {
  258.         spin_lock(&lock->lock);
  259.         lock->flags &= ~TTM_SUSPEND_LOCK;
  260.         wake_up_all(&lock->queue);
  261.         spin_unlock(&lock->lock);
  262. }
  263. EXPORT_SYMBOL(ttm_suspend_unlock);
  264.  
  265. static bool __ttm_suspend_lock(struct ttm_lock *lock)
  266. {
  267.         bool locked = false;
  268.  
  269.         spin_lock(&lock->lock);
  270.         if (lock->rw == 0) {
  271.                 lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
  272.                 lock->flags |= TTM_SUSPEND_LOCK;
  273.                 locked = true;
  274.         } else {
  275.                 lock->flags |= TTM_SUSPEND_LOCK_PENDING;
  276.         }
  277.         spin_unlock(&lock->lock);
  278.         return locked;
  279. }
  280.  
  281. void ttm_suspend_lock(struct ttm_lock *lock)
  282. {
  283.         wait_event(lock->queue, __ttm_suspend_lock(lock));
  284. }
  285. EXPORT_SYMBOL(ttm_suspend_lock);
  286.