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 / powerpc / include / asm / spinlock.h < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  6.6 KB  |  296 lines

  1. #ifndef __ASM_SPINLOCK_H
  2. #define __ASM_SPINLOCK_H
  3. #ifdef __KERNEL__
  4.  
  5. /*
  6.  * Simple spin lock operations.  
  7.  *
  8.  * Copyright (C) 2001-2004 Paul Mackerras <paulus@au.ibm.com>, IBM
  9.  * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
  10.  * Copyright (C) 2002 Dave Engebretsen <engebret@us.ibm.com>, IBM
  11.  *    Rework to support virtual processors
  12.  *
  13.  * Type of int is used as a full 64b word is not necessary.
  14.  *
  15.  * This program is free software; you can redistribute it and/or
  16.  * modify it under the terms of the GNU General Public License
  17.  * as published by the Free Software Foundation; either version
  18.  * 2 of the License, or (at your option) any later version.
  19.  *
  20.  * (the type definitions are in asm/spinlock_types.h)
  21.  */
  22. #include <linux/irqflags.h>
  23. #ifdef CONFIG_PPC64
  24. #include <asm/paca.h>
  25. #include <asm/hvcall.h>
  26. #include <asm/iseries/hv_call.h>
  27. #endif
  28. #include <asm/asm-compat.h>
  29. #include <asm/synch.h>
  30.  
  31. #define __raw_spin_is_locked(x)        ((x)->slock != 0)
  32.  
  33. #ifdef CONFIG_PPC64
  34. /* use 0x800000yy when locked, where yy == CPU number */
  35. #define LOCK_TOKEN    (*(u32 *)(&get_paca()->lock_token))
  36. #else
  37. #define LOCK_TOKEN    1
  38. #endif
  39.  
  40. #if defined(CONFIG_PPC64) && defined(CONFIG_SMP)
  41. #define CLEAR_IO_SYNC    (get_paca()->io_sync = 0)
  42. #define SYNC_IO        do {                        \
  43.                 if (unlikely(get_paca()->io_sync)) {    \
  44.                     mb();                \
  45.                     get_paca()->io_sync = 0;    \
  46.                 }                    \
  47.             } while (0)
  48. #else
  49. #define CLEAR_IO_SYNC
  50. #define SYNC_IO
  51. #endif
  52.  
  53. /*
  54.  * This returns the old value in the lock, so we succeeded
  55.  * in getting the lock if the return value is 0.
  56.  */
  57. static inline unsigned long __spin_trylock(raw_spinlock_t *lock)
  58. {
  59.     unsigned long tmp, token;
  60.  
  61.     token = LOCK_TOKEN;
  62.     __asm__ __volatile__(
  63. "1:    lwarx        %0,0,%2\n\
  64.     cmpwi        0,%0,0\n\
  65.     bne-        2f\n\
  66.     stwcx.        %1,0,%2\n\
  67.     bne-        1b\n\
  68.     isync\n\
  69. 2:"    : "=&r" (tmp)
  70.     : "r" (token), "r" (&lock->slock)
  71.     : "cr0", "memory");
  72.  
  73.     return tmp;
  74. }
  75.  
  76. static inline int __raw_spin_trylock(raw_spinlock_t *lock)
  77. {
  78.     CLEAR_IO_SYNC;
  79.     return __spin_trylock(lock) == 0;
  80. }
  81.  
  82. /*
  83.  * On a system with shared processors (that is, where a physical
  84.  * processor is multiplexed between several virtual processors),
  85.  * there is no point spinning on a lock if the holder of the lock
  86.  * isn't currently scheduled on a physical processor.  Instead
  87.  * we detect this situation and ask the hypervisor to give the
  88.  * rest of our timeslice to the lock holder.
  89.  *
  90.  * So that we can tell which virtual processor is holding a lock,
  91.  * we put 0x80000000 | smp_processor_id() in the lock when it is
  92.  * held.  Conveniently, we have a word in the paca that holds this
  93.  * value.
  94.  */
  95.  
  96. #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
  97. /* We only yield to the hypervisor if we are in shared processor mode */
  98. #define SHARED_PROCESSOR (get_lppaca()->shared_proc)
  99. extern void __spin_yield(raw_spinlock_t *lock);
  100. extern void __rw_yield(raw_rwlock_t *lock);
  101. #else /* SPLPAR || ISERIES */
  102. #define __spin_yield(x)    barrier()
  103. #define __rw_yield(x)    barrier()
  104. #define SHARED_PROCESSOR    0
  105. #endif
  106.  
  107. static inline void __raw_spin_lock(raw_spinlock_t *lock)
  108. {
  109.     CLEAR_IO_SYNC;
  110.     while (1) {
  111.         if (likely(__spin_trylock(lock) == 0))
  112.             break;
  113.         do {
  114.             HMT_low();
  115.             if (SHARED_PROCESSOR)
  116.                 __spin_yield(lock);
  117.         } while (unlikely(lock->slock != 0));
  118.         HMT_medium();
  119.     }
  120. }
  121.  
  122. static inline
  123. void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
  124. {
  125.     unsigned long flags_dis;
  126.  
  127.     CLEAR_IO_SYNC;
  128.     while (1) {
  129.         if (likely(__spin_trylock(lock) == 0))
  130.             break;
  131.         local_save_flags(flags_dis);
  132.         local_irq_restore(flags);
  133.         do {
  134.             HMT_low();
  135.             if (SHARED_PROCESSOR)
  136.                 __spin_yield(lock);
  137.         } while (unlikely(lock->slock != 0));
  138.         HMT_medium();
  139.         local_irq_restore(flags_dis);
  140.     }
  141. }
  142.  
  143. static inline void __raw_spin_unlock(raw_spinlock_t *lock)
  144. {
  145.     SYNC_IO;
  146.     __asm__ __volatile__("# __raw_spin_unlock\n\t"
  147.                 LWSYNC_ON_SMP: : :"memory");
  148.     lock->slock = 0;
  149. }
  150.  
  151. #ifdef CONFIG_PPC64
  152. extern void __raw_spin_unlock_wait(raw_spinlock_t *lock);
  153. #else
  154. #define __raw_spin_unlock_wait(lock) \
  155.     do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
  156. #endif
  157.  
  158. /*
  159.  * Read-write spinlocks, allowing multiple readers
  160.  * but only one writer.
  161.  *
  162.  * NOTE! it is quite common to have readers in interrupts
  163.  * but no interrupt writers. For those circumstances we
  164.  * can "mix" irq-safe locks - any writer needs to get a
  165.  * irq-safe write-lock, but readers can get non-irqsafe
  166.  * read-locks.
  167.  */
  168.  
  169. #define __raw_read_can_lock(rw)        ((rw)->lock >= 0)
  170. #define __raw_write_can_lock(rw)    (!(rw)->lock)
  171.  
  172. #ifdef CONFIG_PPC64
  173. #define __DO_SIGN_EXTEND    "extsw    %0,%0\n"
  174. #define WRLOCK_TOKEN        LOCK_TOKEN    /* it's negative */
  175. #else
  176. #define __DO_SIGN_EXTEND
  177. #define WRLOCK_TOKEN        (-1)
  178. #endif
  179.  
  180. /*
  181.  * This returns the old value in the lock + 1,
  182.  * so we got a read lock if the return value is > 0.
  183.  */
  184. static inline long __read_trylock(raw_rwlock_t *rw)
  185. {
  186.     long tmp;
  187.  
  188.     __asm__ __volatile__(
  189. "1:    lwarx        %0,0,%1\n"
  190.     __DO_SIGN_EXTEND
  191. "    addic.        %0,%0,1\n\
  192.     ble-        2f\n"
  193.     PPC405_ERR77(0,%1)
  194. "    stwcx.        %0,0,%1\n\
  195.     bne-        1b\n\
  196.     isync\n\
  197. 2:"    : "=&r" (tmp)
  198.     : "r" (&rw->lock)
  199.     : "cr0", "xer", "memory");
  200.  
  201.     return tmp;
  202. }
  203.  
  204. /*
  205.  * This returns the old value in the lock,
  206.  * so we got the write lock if the return value is 0.
  207.  */
  208. static inline long __write_trylock(raw_rwlock_t *rw)
  209. {
  210.     long tmp, token;
  211.  
  212.     token = WRLOCK_TOKEN;
  213.     __asm__ __volatile__(
  214. "1:    lwarx        %0,0,%2\n\
  215.     cmpwi        0,%0,0\n\
  216.     bne-        2f\n"
  217.     PPC405_ERR77(0,%1)
  218. "    stwcx.        %1,0,%2\n\
  219.     bne-        1b\n\
  220.     isync\n\
  221. 2:"    : "=&r" (tmp)
  222.     : "r" (token), "r" (&rw->lock)
  223.     : "cr0", "memory");
  224.  
  225.     return tmp;
  226. }
  227.  
  228. static inline void __raw_read_lock(raw_rwlock_t *rw)
  229. {
  230.     while (1) {
  231.         if (likely(__read_trylock(rw) > 0))
  232.             break;
  233.         do {
  234.             HMT_low();
  235.             if (SHARED_PROCESSOR)
  236.                 __rw_yield(rw);
  237.         } while (unlikely(rw->lock < 0));
  238.         HMT_medium();
  239.     }
  240. }
  241.  
  242. static inline void __raw_write_lock(raw_rwlock_t *rw)
  243. {
  244.     while (1) {
  245.         if (likely(__write_trylock(rw) == 0))
  246.             break;
  247.         do {
  248.             HMT_low();
  249.             if (SHARED_PROCESSOR)
  250.                 __rw_yield(rw);
  251.         } while (unlikely(rw->lock != 0));
  252.         HMT_medium();
  253.     }
  254. }
  255.  
  256. static inline int __raw_read_trylock(raw_rwlock_t *rw)
  257. {
  258.     return __read_trylock(rw) > 0;
  259. }
  260.  
  261. static inline int __raw_write_trylock(raw_rwlock_t *rw)
  262. {
  263.     return __write_trylock(rw) == 0;
  264. }
  265.  
  266. static inline void __raw_read_unlock(raw_rwlock_t *rw)
  267. {
  268.     long tmp;
  269.  
  270.     __asm__ __volatile__(
  271.     "# read_unlock\n\t"
  272.     LWSYNC_ON_SMP
  273. "1:    lwarx        %0,0,%1\n\
  274.     addic        %0,%0,-1\n"
  275.     PPC405_ERR77(0,%1)
  276. "    stwcx.        %0,0,%1\n\
  277.     bne-        1b"
  278.     : "=&r"(tmp)
  279.     : "r"(&rw->lock)
  280.     : "cr0", "memory");
  281. }
  282.  
  283. static inline void __raw_write_unlock(raw_rwlock_t *rw)
  284. {
  285.     __asm__ __volatile__("# write_unlock\n\t"
  286.                 LWSYNC_ON_SMP: : :"memory");
  287.     rw->lock = 0;
  288. }
  289.  
  290. #define _raw_spin_relax(lock)    __spin_yield(lock)
  291. #define _raw_read_relax(lock)    __rw_yield(lock)
  292. #define _raw_write_relax(lock)    __rw_yield(lock)
  293.  
  294. #endif /* __KERNEL__ */
  295. #endif /* __ASM_SPINLOCK_H */
  296.