home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / arch / x86 / include / asm / spinlock.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  8.8 KB  |  365 lines

  1. #ifndef _ASM_X86_SPINLOCK_H
  2. #define _ASM_X86_SPINLOCK_H
  3.  
  4. #include <asm/atomic.h>
  5. #include <asm/rwlock.h>
  6. #include <asm/page.h>
  7. #include <asm/processor.h>
  8. #include <linux/compiler.h>
  9. #include <asm/paravirt.h>
  10. /*
  11.  * Your basic SMP spinlocks, allowing only a single CPU anywhere
  12.  *
  13.  * Simple spin lock operations.  There are two variants, one clears IRQ's
  14.  * on the local processor, one does not.
  15.  *
  16.  * These are fair FIFO ticket locks, which are currently limited to 256
  17.  * CPUs.
  18.  *
  19.  * (the type definitions are in asm/spinlock_types.h)
  20.  */
  21.  
  22. #ifdef CONFIG_X86_32
  23. # define LOCK_PTR_REG "a"
  24. # define REG_PTR_MODE "k"
  25. #else
  26. # define LOCK_PTR_REG "D"
  27. # define REG_PTR_MODE "q"
  28. #endif
  29.  
  30. #if defined(CONFIG_X86_32) && \
  31.     (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
  32. /*
  33.  * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
  34.  * (PPro errata 66, 92)
  35.  */
  36. # define UNLOCK_LOCK_PREFIX LOCK_PREFIX
  37. #else
  38. # define UNLOCK_LOCK_PREFIX
  39. #endif
  40.  
  41. /*
  42.  * Ticket locks are conceptually two parts, one indicating the current head of
  43.  * the queue, and the other indicating the current tail. The lock is acquired
  44.  * by atomically noting the tail and incrementing it by one (thus adding
  45.  * ourself to the queue and noting our position), then waiting until the head
  46.  * becomes equal to the the initial value of the tail.
  47.  *
  48.  * We use an xadd covering *both* parts of the lock, to increment the tail and
  49.  * also load the position of the head, which takes care of memory ordering
  50.  * issues and should be optimal for the uncontended case. Note the tail must be
  51.  * in the high part, because a wide xadd increment of the low part would carry
  52.  * up and contaminate the high part.
  53.  *
  54.  * With fewer than 2^8 possible CPUs, we can use x86's partial registers to
  55.  * save some instructions and make the code more elegant. There really isn't
  56.  * much between them in performance though, especially as locks are out of line.
  57.  */
  58. #if (NR_CPUS < 256)
  59. #define TICKET_SHIFT 8
  60.  
  61. static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
  62. {
  63.     short inc = 0x0100;
  64.  
  65.     asm volatile (
  66.         LOCK_PREFIX "xaddw %w0, %1\n"
  67.         "1:\t"
  68.         "cmpb %h0, %b0\n\t"
  69.         "je 2f\n\t"
  70.         "rep ; nop\n\t"
  71.         "movb %1, %b0\n\t"
  72.         /* don't need lfence here, because loads are in-order */
  73.         "jmp 1b\n"
  74.         "2:"
  75.         : "+Q" (inc), "+m" (lock->slock)
  76.         :
  77.         : "memory", "cc");
  78. }
  79.  
  80. static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
  81. {
  82.     int tmp, new;
  83.  
  84.     asm volatile("movzwl %2, %0\n\t"
  85.              "cmpb %h0,%b0\n\t"
  86.              "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
  87.              "jne 1f\n\t"
  88.              LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
  89.              "1:"
  90.              "sete %b1\n\t"
  91.              "movzbl %b1,%0\n\t"
  92.              : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
  93.              :
  94.              : "memory", "cc");
  95.  
  96.     return tmp;
  97. }
  98.  
  99. static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
  100. {
  101.     asm volatile(UNLOCK_LOCK_PREFIX "incb %0"
  102.              : "+m" (lock->slock)
  103.              :
  104.              : "memory", "cc");
  105. }
  106. #else
  107. #define TICKET_SHIFT 16
  108.  
  109. static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
  110. {
  111.     int inc = 0x00010000;
  112.     int tmp;
  113.  
  114.     asm volatile(LOCK_PREFIX "xaddl %0, %1\n"
  115.              "movzwl %w0, %2\n\t"
  116.              "shrl $16, %0\n\t"
  117.              "1:\t"
  118.              "cmpl %0, %2\n\t"
  119.              "je 2f\n\t"
  120.              "rep ; nop\n\t"
  121.              "movzwl %1, %2\n\t"
  122.              /* don't need lfence here, because loads are in-order */
  123.              "jmp 1b\n"
  124.              "2:"
  125.              : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
  126.              :
  127.              : "memory", "cc");
  128. }
  129.  
  130. static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
  131. {
  132.     int tmp;
  133.     int new;
  134.  
  135.     asm volatile("movl %2,%0\n\t"
  136.              "movl %0,%1\n\t"
  137.              "roll $16, %0\n\t"
  138.              "cmpl %0,%1\n\t"
  139.              "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
  140.              "jne 1f\n\t"
  141.              LOCK_PREFIX "cmpxchgl %1,%2\n\t"
  142.              "1:"
  143.              "sete %b1\n\t"
  144.              "movzbl %b1,%0\n\t"
  145.              : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
  146.              :
  147.              : "memory", "cc");
  148.  
  149.     return tmp;
  150. }
  151.  
  152. static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
  153. {
  154.     asm volatile(UNLOCK_LOCK_PREFIX "incw %0"
  155.              : "+m" (lock->slock)
  156.              :
  157.              : "memory", "cc");
  158. }
  159. #endif
  160.  
  161. static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
  162. {
  163.     int tmp = ACCESS_ONCE(lock->slock);
  164.  
  165.     return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
  166. }
  167.  
  168. static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
  169. {
  170.     int tmp = ACCESS_ONCE(lock->slock);
  171.  
  172.     return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
  173. }
  174.  
  175. #ifdef CONFIG_PARAVIRT
  176. /*
  177.  * Define virtualization-friendly old-style lock byte lock, for use in
  178.  * pv_lock_ops if desired.
  179.  *
  180.  * This differs from the pre-2.6.24 spinlock by always using xchgb
  181.  * rather than decb to take the lock; this allows it to use a
  182.  * zero-initialized lock structure.  It also maintains a 1-byte
  183.  * contention counter, so that we can implement
  184.  * __byte_spin_is_contended.
  185.  */
  186. struct __byte_spinlock {
  187.     s8 lock;
  188.     s8 spinners;
  189. };
  190.  
  191. static inline int __byte_spin_is_locked(raw_spinlock_t *lock)
  192. {
  193.     struct __byte_spinlock *bl = (struct __byte_spinlock *)lock;
  194.     return bl->lock != 0;
  195. }
  196.  
  197. static inline int __byte_spin_is_contended(raw_spinlock_t *lock)
  198. {
  199.     struct __byte_spinlock *bl = (struct __byte_spinlock *)lock;
  200.     return bl->spinners != 0;
  201. }
  202.  
  203. static inline void __byte_spin_lock(raw_spinlock_t *lock)
  204. {
  205.     struct __byte_spinlock *bl = (struct __byte_spinlock *)lock;
  206.     s8 val = 1;
  207.  
  208.     asm("1: xchgb %1, %0\n"
  209.         "   test %1,%1\n"
  210.         "   jz 3f\n"
  211.         "   " LOCK_PREFIX "incb %2\n"
  212.         "2: rep;nop\n"
  213.         "   cmpb $1, %0\n"
  214.         "   je 2b\n"
  215.         "   " LOCK_PREFIX "decb %2\n"
  216.         "   jmp 1b\n"
  217.         "3:"
  218.         : "+m" (bl->lock), "+q" (val), "+m" (bl->spinners): : "memory");
  219. }
  220.  
  221. static inline int __byte_spin_trylock(raw_spinlock_t *lock)
  222. {
  223.     struct __byte_spinlock *bl = (struct __byte_spinlock *)lock;
  224.     u8 old = 1;
  225.  
  226.     asm("xchgb %1,%0"
  227.         : "+m" (bl->lock), "+q" (old) : : "memory");
  228.  
  229.     return old == 0;
  230. }
  231.  
  232. static inline void __byte_spin_unlock(raw_spinlock_t *lock)
  233. {
  234.     struct __byte_spinlock *bl = (struct __byte_spinlock *)lock;
  235.     smp_wmb();
  236.     bl->lock = 0;
  237. }
  238. #else  /* !CONFIG_PARAVIRT */
  239. static inline int __raw_spin_is_locked(raw_spinlock_t *lock)
  240. {
  241.     return __ticket_spin_is_locked(lock);
  242. }
  243.  
  244. static inline int __raw_spin_is_contended(raw_spinlock_t *lock)
  245. {
  246.     return __ticket_spin_is_contended(lock);
  247. }
  248.  
  249. static __always_inline void __raw_spin_lock(raw_spinlock_t *lock)
  250. {
  251.     __ticket_spin_lock(lock);
  252. }
  253.  
  254. static __always_inline int __raw_spin_trylock(raw_spinlock_t *lock)
  255. {
  256.     return __ticket_spin_trylock(lock);
  257. }
  258.  
  259. static __always_inline void __raw_spin_unlock(raw_spinlock_t *lock)
  260. {
  261.     __ticket_spin_unlock(lock);
  262. }
  263.  
  264. static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
  265.                           unsigned long flags)
  266. {
  267.     __raw_spin_lock(lock);
  268. }
  269.  
  270. #endif    /* CONFIG_PARAVIRT */
  271.  
  272. static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
  273. {
  274.     while (__raw_spin_is_locked(lock))
  275.         cpu_relax();
  276. }
  277.  
  278. /*
  279.  * Read-write spinlocks, allowing multiple readers
  280.  * but only one writer.
  281.  *
  282.  * NOTE! it is quite common to have readers in interrupts
  283.  * but no interrupt writers. For those circumstances we
  284.  * can "mix" irq-safe locks - any writer needs to get a
  285.  * irq-safe write-lock, but readers can get non-irqsafe
  286.  * read-locks.
  287.  *
  288.  * On x86, we implement read-write locks as a 32-bit counter
  289.  * with the high bit (sign) being the "contended" bit.
  290.  */
  291.  
  292. /**
  293.  * read_can_lock - would read_trylock() succeed?
  294.  * @lock: the rwlock in question.
  295.  */
  296. static inline int __raw_read_can_lock(raw_rwlock_t *lock)
  297. {
  298.     return (int)(lock)->lock > 0;
  299. }
  300.  
  301. /**
  302.  * write_can_lock - would write_trylock() succeed?
  303.  * @lock: the rwlock in question.
  304.  */
  305. static inline int __raw_write_can_lock(raw_rwlock_t *lock)
  306. {
  307.     return (lock)->lock == RW_LOCK_BIAS;
  308. }
  309.  
  310. static inline void __raw_read_lock(raw_rwlock_t *rw)
  311. {
  312.     asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t"
  313.              "jns 1f\n"
  314.              "call __read_lock_failed\n\t"
  315.              "1:\n"
  316.              ::LOCK_PTR_REG (rw) : "memory");
  317. }
  318.  
  319. static inline void __raw_write_lock(raw_rwlock_t *rw)
  320. {
  321.     asm volatile(LOCK_PREFIX " subl %1,(%0)\n\t"
  322.              "jz 1f\n"
  323.              "call __write_lock_failed\n\t"
  324.              "1:\n"
  325.              ::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory");
  326. }
  327.  
  328. static inline int __raw_read_trylock(raw_rwlock_t *lock)
  329. {
  330.     atomic_t *count = (atomic_t *)lock;
  331.  
  332.     atomic_dec(count);
  333.     if (atomic_read(count) >= 0)
  334.         return 1;
  335.     atomic_inc(count);
  336.     return 0;
  337. }
  338.  
  339. static inline int __raw_write_trylock(raw_rwlock_t *lock)
  340. {
  341.     atomic_t *count = (atomic_t *)lock;
  342.  
  343.     if (atomic_sub_and_test(RW_LOCK_BIAS, count))
  344.         return 1;
  345.     atomic_add(RW_LOCK_BIAS, count);
  346.     return 0;
  347. }
  348.  
  349. static inline void __raw_read_unlock(raw_rwlock_t *rw)
  350. {
  351.     asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory");
  352. }
  353.  
  354. static inline void __raw_write_unlock(raw_rwlock_t *rw)
  355. {
  356.     asm volatile(LOCK_PREFIX "addl %1, %0"
  357.              : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory");
  358. }
  359.  
  360. #define _raw_spin_relax(lock)    cpu_relax()
  361. #define _raw_read_relax(lock)    cpu_relax()
  362. #define _raw_write_relax(lock)    cpu_relax()
  363.  
  364. #endif /* _ASM_X86_SPINLOCK_H */
  365.