Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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 <linux/mutex.h>
  32. #include <drm/ttm/ttm_lock.h>
  33. #include <drm/ttm/ttm_module.h>
  34. //#include <linux/atomic.h>
  35. #include <linux/errno.h>
  36. #include <linux/wait.h>
  37. #include <linux/sched.h>
  38. #include <linux/module.h>
  39.  
  40. #define TTM_WRITE_LOCK_PENDING    (1 << 0)
  41. #define TTM_VT_LOCK_PENDING       (1 << 1)
  42. #define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
  43. #define TTM_VT_LOCK               (1 << 3)
  44. #define TTM_SUSPEND_LOCK          (1 << 4)
  45.  
  46. void ttm_lock_init(struct ttm_lock *lock)
  47. {
  48.         spin_lock_init(&lock->lock);
  49.         init_waitqueue_head(&lock->queue);
  50.         lock->rw = 0;
  51.         lock->flags = 0;
  52. }
  53. EXPORT_SYMBOL(ttm_lock_init);
  54.  
  55. void ttm_read_unlock(struct ttm_lock *lock)
  56. {
  57.         spin_lock(&lock->lock);
  58.         if (--lock->rw == 0)
  59.                 wake_up_all(&lock->queue);
  60.         spin_unlock(&lock->lock);
  61. }
  62. EXPORT_SYMBOL(ttm_read_unlock);
  63.  
  64. static bool __ttm_read_lock(struct ttm_lock *lock)
  65. {
  66.         bool locked = false;
  67.  
  68.         spin_lock(&lock->lock);
  69.         if (lock->rw >= 0 && lock->flags == 0) {
  70.                 ++lock->rw;
  71.                 locked = true;
  72.         }
  73.         spin_unlock(&lock->lock);
  74.         return locked;
  75. }
  76.  
  77. int ttm_read_lock(struct ttm_lock *lock, bool interruptible)
  78. {
  79.         int ret = 0;
  80.  
  81.         if (interruptible)
  82.                 ret = wait_event_interruptible(lock->queue,
  83.                                                __ttm_read_lock(lock));
  84.         else
  85.                 wait_event(lock->queue, __ttm_read_lock(lock));
  86.         return ret;
  87. }
  88. EXPORT_SYMBOL(ttm_read_lock);
  89.  
  90. static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
  91. {
  92.         bool block = true;
  93.  
  94.         *locked = false;
  95.  
  96.         spin_lock(&lock->lock);
  97.         if (lock->rw >= 0 && lock->flags == 0) {
  98.                 ++lock->rw;
  99.                 block = false;
  100.                 *locked = true;
  101.         } else if (lock->flags == 0) {
  102.                 block = false;
  103.         }
  104.         spin_unlock(&lock->lock);
  105.  
  106.         return !block;
  107. }
  108.  
  109. int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
  110. {
  111.         int ret = 0;
  112.         bool locked;
  113.  
  114.         if (interruptible)
  115.                 ret = wait_event_interruptible
  116.                         (lock->queue, __ttm_read_trylock(lock, &locked));
  117.         else
  118.                 wait_event(lock->queue, __ttm_read_trylock(lock, &locked));
  119.  
  120.         if (unlikely(ret != 0)) {
  121.                 BUG_ON(locked);
  122.                 return ret;
  123.         }
  124.  
  125.         return (locked) ? 0 : -EBUSY;
  126. }
  127.  
  128. void ttm_write_unlock(struct ttm_lock *lock)
  129. {
  130.         spin_lock(&lock->lock);
  131.         lock->rw = 0;
  132.         wake_up_all(&lock->queue);
  133.         spin_unlock(&lock->lock);
  134. }
  135. EXPORT_SYMBOL(ttm_write_unlock);
  136.  
  137. static bool __ttm_write_lock(struct ttm_lock *lock)
  138. {
  139.         bool locked = false;
  140.  
  141.         spin_lock(&lock->lock);
  142.         if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
  143.                 lock->rw = -1;
  144.                 lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  145.                 locked = true;
  146.         } else {
  147.                 lock->flags |= TTM_WRITE_LOCK_PENDING;
  148.         }
  149.         spin_unlock(&lock->lock);
  150.         return locked;
  151. }
  152.  
  153. int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
  154. {
  155.         int ret = 0;
  156.  
  157.         if (interruptible) {
  158.                 ret = wait_event_interruptible(lock->queue,
  159.                                                __ttm_write_lock(lock));
  160.                 if (unlikely(ret != 0)) {
  161.                         spin_lock(&lock->lock);
  162.                         lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  163.                         wake_up_all(&lock->queue);
  164.                         spin_unlock(&lock->lock);
  165.                 }
  166.         } else
  167.                 wait_event(lock->queue, __ttm_read_lock(lock));
  168.  
  169.         return ret;
  170. }
  171. EXPORT_SYMBOL(ttm_write_lock);
  172.  
  173. static int __ttm_vt_unlock(struct ttm_lock *lock)
  174. {
  175.         int ret = 0;
  176.  
  177.         spin_lock(&lock->lock);
  178.         if (unlikely(!(lock->flags & TTM_VT_LOCK)))
  179.                 ret = -EINVAL;
  180.         lock->flags &= ~TTM_VT_LOCK;
  181.         wake_up_all(&lock->queue);
  182.         spin_unlock(&lock->lock);
  183.  
  184.         return ret;
  185. }
  186.  
  187. static void ttm_vt_lock_remove(struct ttm_base_object **p_base)
  188. {
  189.         struct ttm_base_object *base = *p_base;
  190.         struct ttm_lock *lock = container_of(base, struct ttm_lock, base);
  191.         int ret;
  192.  
  193.         *p_base = NULL;
  194.         ret = __ttm_vt_unlock(lock);
  195.         BUG_ON(ret != 0);
  196. }
  197.  
  198. static bool __ttm_vt_lock(struct ttm_lock *lock)
  199. {
  200.         bool locked = false;
  201.  
  202.         spin_lock(&lock->lock);
  203.         if (lock->rw == 0) {
  204.                 lock->flags &= ~TTM_VT_LOCK_PENDING;
  205.                 lock->flags |= TTM_VT_LOCK;
  206.                 locked = true;
  207.         } else {
  208.                 lock->flags |= TTM_VT_LOCK_PENDING;
  209.         }
  210.         spin_unlock(&lock->lock);
  211.         return locked;
  212. }
  213.  
  214. int ttm_vt_lock(struct ttm_lock *lock,
  215.                 bool interruptible,
  216.                 struct ttm_object_file *tfile)
  217. {
  218.         int ret = 0;
  219.  
  220.         if (interruptible) {
  221.                 ret = wait_event_interruptible(lock->queue,
  222.                                                __ttm_vt_lock(lock));
  223.                 if (unlikely(ret != 0)) {
  224.                         spin_lock(&lock->lock);
  225.                         lock->flags &= ~TTM_VT_LOCK_PENDING;
  226.                         wake_up_all(&lock->queue);
  227.                         spin_unlock(&lock->lock);
  228.                         return ret;
  229.                 }
  230.         } else
  231.                 wait_event(lock->queue, __ttm_vt_lock(lock));
  232.  
  233.         /*
  234.          * Add a base-object, the destructor of which will
  235.          * make sure the lock is released if the client dies
  236.          * while holding it.
  237.          */
  238.  
  239.         ret = ttm_base_object_init(tfile, &lock->base, false,
  240.                                    ttm_lock_type, &ttm_vt_lock_remove, NULL);
  241.         if (ret)
  242.                 (void)__ttm_vt_unlock(lock);
  243.         else
  244.                 lock->vt_holder = tfile;
  245.  
  246.         return ret;
  247. }
  248. EXPORT_SYMBOL(ttm_vt_lock);
  249.  
  250. int ttm_vt_unlock(struct ttm_lock *lock)
  251. {
  252.         return ttm_ref_object_base_unref(lock->vt_holder,
  253.                                          lock->base.hash.key, TTM_REF_USAGE);
  254. }
  255. EXPORT_SYMBOL(ttm_vt_unlock);
  256.  
  257. void ttm_suspend_unlock(struct ttm_lock *lock)
  258. {
  259.         spin_lock(&lock->lock);
  260.         lock->flags &= ~TTM_SUSPEND_LOCK;
  261.         wake_up_all(&lock->queue);
  262.         spin_unlock(&lock->lock);
  263. }
  264. EXPORT_SYMBOL(ttm_suspend_unlock);
  265.  
  266. static bool __ttm_suspend_lock(struct ttm_lock *lock)
  267. {
  268.         bool locked = false;
  269.  
  270.         spin_lock(&lock->lock);
  271.         if (lock->rw == 0) {
  272.                 lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
  273.                 lock->flags |= TTM_SUSPEND_LOCK;
  274.                 locked = true;
  275.         } else {
  276.                 lock->flags |= TTM_SUSPEND_LOCK_PENDING;
  277.         }
  278.         spin_unlock(&lock->lock);
  279.         return locked;
  280. }
  281.  
  282. void ttm_suspend_lock(struct ttm_lock *lock)
  283. {
  284.         wait_event(lock->queue, __ttm_suspend_lock(lock));
  285. }
  286. EXPORT_SYMBOL(ttm_suspend_lock);
  287.