linux/arch/powerpc/include/asm/spinlock.h
<<
>>
Prefs
   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#include <asm/ppc-opcode.h>
  31
  32#define arch_spin_is_locked(x)          ((x)->slock != 0)
  33
  34#ifdef CONFIG_PPC64
  35/* use 0x800000yy when locked, where yy == CPU number */
  36#define LOCK_TOKEN      (*(u32 *)(&get_paca()->lock_token))
  37#else
  38#define LOCK_TOKEN      1
  39#endif
  40
  41#if defined(CONFIG_PPC64) && defined(CONFIG_SMP)
  42#define CLEAR_IO_SYNC   (get_paca()->io_sync = 0)
  43#define SYNC_IO         do {                                            \
  44                                if (unlikely(get_paca()->io_sync)) {    \
  45                                        mb();                           \
  46                                        get_paca()->io_sync = 0;        \
  47                                }                                       \
  48                        } while (0)
  49#else
  50#define CLEAR_IO_SYNC
  51#define SYNC_IO
  52#endif
  53
  54/*
  55 * This returns the old value in the lock, so we succeeded
  56 * in getting the lock if the return value is 0.
  57 */
  58static inline unsigned long __arch_spin_trylock(arch_spinlock_t *lock)
  59{
  60        unsigned long tmp, token;
  61
  62        token = LOCK_TOKEN;
  63        __asm__ __volatile__(
  64"1:     " PPC_LWARX(%0,0,%2,1) "\n\
  65        cmpwi           0,%0,0\n\
  66        bne-            2f\n\
  67        stwcx.          %1,0,%2\n\
  68        bne-            1b\n"
  69        PPC_ACQUIRE_BARRIER
  70"2:"
  71        : "=&r" (tmp)
  72        : "r" (token), "r" (&lock->slock)
  73        : "cr0", "memory");
  74
  75        return tmp;
  76}
  77
  78static inline int arch_spin_trylock(arch_spinlock_t *lock)
  79{
  80        CLEAR_IO_SYNC;
  81        return __arch_spin_trylock(lock) == 0;
  82}
  83
  84/*
  85 * On a system with shared processors (that is, where a physical
  86 * processor is multiplexed between several virtual processors),
  87 * there is no point spinning on a lock if the holder of the lock
  88 * isn't currently scheduled on a physical processor.  Instead
  89 * we detect this situation and ask the hypervisor to give the
  90 * rest of our timeslice to the lock holder.
  91 *
  92 * So that we can tell which virtual processor is holding a lock,
  93 * we put 0x80000000 | smp_processor_id() in the lock when it is
  94 * held.  Conveniently, we have a word in the paca that holds this
  95 * value.
  96 */
  97
  98#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
  99/* We only yield to the hypervisor if we are in shared processor mode */
 100#define SHARED_PROCESSOR (get_lppaca()->shared_proc)
 101extern void __spin_yield(arch_spinlock_t *lock);
 102extern void __rw_yield(arch_rwlock_t *lock);
 103#else /* SPLPAR || ISERIES */
 104#define __spin_yield(x) barrier()
 105#define __rw_yield(x)   barrier()
 106#define SHARED_PROCESSOR        0
 107#endif
 108
 109static inline void arch_spin_lock(arch_spinlock_t *lock)
 110{
 111        CLEAR_IO_SYNC;
 112        while (1) {
 113                if (likely(__arch_spin_trylock(lock) == 0))
 114                        break;
 115                do {
 116                        HMT_low();
 117                        if (SHARED_PROCESSOR)
 118                                __spin_yield(lock);
 119                } while (unlikely(lock->slock != 0));
 120                HMT_medium();
 121        }
 122}
 123
 124static inline
 125void arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags)
 126{
 127        unsigned long flags_dis;
 128
 129        CLEAR_IO_SYNC;
 130        while (1) {
 131                if (likely(__arch_spin_trylock(lock) == 0))
 132                        break;
 133                local_save_flags(flags_dis);
 134                local_irq_restore(flags);
 135                do {
 136                        HMT_low();
 137                        if (SHARED_PROCESSOR)
 138                                __spin_yield(lock);
 139                } while (unlikely(lock->slock != 0));
 140                HMT_medium();
 141                local_irq_restore(flags_dis);
 142        }
 143}
 144
 145static inline void arch_spin_unlock(arch_spinlock_t *lock)
 146{
 147        SYNC_IO;
 148        __asm__ __volatile__("# arch_spin_unlock\n\t"
 149                                PPC_RELEASE_BARRIER: : :"memory");
 150        lock->slock = 0;
 151}
 152
 153#ifdef CONFIG_PPC64
 154extern void arch_spin_unlock_wait(arch_spinlock_t *lock);
 155#else
 156#define arch_spin_unlock_wait(lock) \
 157        do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
 158#endif
 159
 160/*
 161 * Read-write spinlocks, allowing multiple readers
 162 * but only one writer.
 163 *
 164 * NOTE! it is quite common to have readers in interrupts
 165 * but no interrupt writers. For those circumstances we
 166 * can "mix" irq-safe locks - any writer needs to get a
 167 * irq-safe write-lock, but readers can get non-irqsafe
 168 * read-locks.
 169 */
 170
 171#define arch_read_can_lock(rw)          ((rw)->lock >= 0)
 172#define arch_write_can_lock(rw) (!(rw)->lock)
 173
 174#ifdef CONFIG_PPC64
 175#define __DO_SIGN_EXTEND        "extsw  %0,%0\n"
 176#define WRLOCK_TOKEN            LOCK_TOKEN      /* it's negative */
 177#else
 178#define __DO_SIGN_EXTEND
 179#define WRLOCK_TOKEN            (-1)
 180#endif
 181
 182/*
 183 * This returns the old value in the lock + 1,
 184 * so we got a read lock if the return value is > 0.
 185 */
 186static inline long __arch_read_trylock(arch_rwlock_t *rw)
 187{
 188        long tmp;
 189
 190        __asm__ __volatile__(
 191"1:     " PPC_LWARX(%0,0,%1,1) "\n"
 192        __DO_SIGN_EXTEND
 193"       addic.          %0,%0,1\n\
 194        ble-            2f\n"
 195        PPC405_ERR77(0,%1)
 196"       stwcx.          %0,0,%1\n\
 197        bne-            1b\n"
 198        PPC_ACQUIRE_BARRIER
 199"2:"    : "=&r" (tmp)
 200        : "r" (&rw->lock)
 201        : "cr0", "xer", "memory");
 202
 203        return tmp;
 204}
 205
 206/*
 207 * This returns the old value in the lock,
 208 * so we got the write lock if the return value is 0.
 209 */
 210static inline long __arch_write_trylock(arch_rwlock_t *rw)
 211{
 212        long tmp, token;
 213
 214        token = WRLOCK_TOKEN;
 215        __asm__ __volatile__(
 216"1:     " PPC_LWARX(%0,0,%2,1) "\n\
 217        cmpwi           0,%0,0\n\
 218        bne-            2f\n"
 219        PPC405_ERR77(0,%1)
 220"       stwcx.          %1,0,%2\n\
 221        bne-            1b\n"
 222        PPC_ACQUIRE_BARRIER
 223"2:"    : "=&r" (tmp)
 224        : "r" (token), "r" (&rw->lock)
 225        : "cr0", "memory");
 226
 227        return tmp;
 228}
 229
 230static inline void arch_read_lock(arch_rwlock_t *rw)
 231{
 232        while (1) {
 233                if (likely(__arch_read_trylock(rw) > 0))
 234                        break;
 235                do {
 236                        HMT_low();
 237                        if (SHARED_PROCESSOR)
 238                                __rw_yield(rw);
 239                } while (unlikely(rw->lock < 0));
 240                HMT_medium();
 241        }
 242}
 243
 244static inline void arch_write_lock(arch_rwlock_t *rw)
 245{
 246        while (1) {
 247                if (likely(__arch_write_trylock(rw) == 0))
 248                        break;
 249                do {
 250                        HMT_low();
 251                        if (SHARED_PROCESSOR)
 252                                __rw_yield(rw);
 253                } while (unlikely(rw->lock != 0));
 254                HMT_medium();
 255        }
 256}
 257
 258static inline int arch_read_trylock(arch_rwlock_t *rw)
 259{
 260        return __arch_read_trylock(rw) > 0;
 261}
 262
 263static inline int arch_write_trylock(arch_rwlock_t *rw)
 264{
 265        return __arch_write_trylock(rw) == 0;
 266}
 267
 268static inline void arch_read_unlock(arch_rwlock_t *rw)
 269{
 270        long tmp;
 271
 272        __asm__ __volatile__(
 273        "# read_unlock\n\t"
 274        PPC_RELEASE_BARRIER
 275"1:     lwarx           %0,0,%1\n\
 276        addic           %0,%0,-1\n"
 277        PPC405_ERR77(0,%1)
 278"       stwcx.          %0,0,%1\n\
 279        bne-            1b"
 280        : "=&r"(tmp)
 281        : "r"(&rw->lock)
 282        : "cr0", "xer", "memory");
 283}
 284
 285static inline void arch_write_unlock(arch_rwlock_t *rw)
 286{
 287        __asm__ __volatile__("# write_unlock\n\t"
 288                                PPC_RELEASE_BARRIER: : :"memory");
 289        rw->lock = 0;
 290}
 291
 292#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 293#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
 294
 295#define arch_spin_relax(lock)   __spin_yield(lock)
 296#define arch_read_relax(lock)   __rw_yield(lock)
 297#define arch_write_relax(lock)  __rw_yield(lock)
 298
 299#endif /* __KERNEL__ */
 300#endif /* __ASM_SPINLOCK_H */
 301
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.