···19192020#define __raw_spin_lock_init(x) ((x)->lock = 0)21212222-#ifdef ASM_SUPPORTED2322/*2424- * Try to get the lock. If we fail to get the lock, make a non-standard call to2525- * ia64_spinlock_contention(). We do not use a normal call because that would force all2626- * callers of __raw_spin_lock() to be non-leaf routines. Instead, ia64_spinlock_contention() is2727- * carefully coded to touch only those registers that __raw_spin_lock() marks "clobbered".2323+ * Ticket locks are conceptually two parts, one indicating the current head of2424+ * the queue, and the other indicating the current tail. The lock is acquired2525+ * by atomically noting the tail and incrementing it by one (thus adding2626+ * ourself to the queue and noting our position), then waiting until the head2727+ * becomes equal to the the initial value of the tail.2828+ *2929+ * 63 32 31 03030+ * +----------------------------------------------------+3131+ * | next_ticket_number | now_serving |3232+ * +----------------------------------------------------+2833 */29343030-#define IA64_SPINLOCK_CLOBBERS "ar.ccv", "ar.pfs", "p14", "p15", "r27", "r28", "r29", "r30", "b6", "memory"3535+#define TICKET_SHIFT 3231363232-static inline void3333-__raw_spin_lock_flags (raw_spinlock_t *lock, unsigned long flags)3737+static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)3438{3535- register volatile unsigned int *ptr asm ("r31") = &lock->lock;3939+ int *p = (int *)&lock->lock, turn, now_serving;36403737-#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)3838-# ifdef CONFIG_ITANIUM3939- /* don't use brl on Itanium... */4040- asm volatile ("{\n\t"4141- " mov ar.ccv = r0\n\t"4242- " mov r28 = ip\n\t"4343- " mov r30 = 1;;\n\t"4444- "}\n\t"4545- "cmpxchg4.acq r30 = [%1], r30, ar.ccv\n\t"4646- "movl r29 = ia64_spinlock_contention_pre3_4;;\n\t"4747- "cmp4.ne p14, p0 = r30, r0\n\t"4848- "mov b6 = r29;;\n\t"4949- "mov r27=%2\n\t"5050- "(p14) br.cond.spnt.many b6"5151- : "=r"(ptr) : "r"(ptr), "r" (flags) : IA64_SPINLOCK_CLOBBERS);5252-# else5353- asm volatile ("{\n\t"5454- " mov ar.ccv = r0\n\t"5555- " mov r28 = ip\n\t"5656- " mov r30 = 1;;\n\t"5757- "}\n\t"5858- "cmpxchg4.acq r30 = [%1], r30, ar.ccv;;\n\t"5959- "cmp4.ne p14, p0 = r30, r0\n\t"6060- "mov r27=%2\n\t"6161- "(p14) brl.cond.spnt.many ia64_spinlock_contention_pre3_4;;"6262- : "=r"(ptr) : "r"(ptr), "r" (flags) : IA64_SPINLOCK_CLOBBERS);6363-# endif /* CONFIG_MCKINLEY */6464-#else6565-# ifdef CONFIG_ITANIUM6666- /* don't use brl on Itanium... */6767- /* mis-declare, so we get the entry-point, not it's function descriptor: */6868- asm volatile ("mov r30 = 1\n\t"6969- "mov r27=%2\n\t"7070- "mov ar.ccv = r0;;\n\t"7171- "cmpxchg4.acq r30 = [%0], r30, ar.ccv\n\t"7272- "movl r29 = ia64_spinlock_contention;;\n\t"7373- "cmp4.ne p14, p0 = r30, r0\n\t"7474- "mov b6 = r29;;\n\t"7575- "(p14) br.call.spnt.many b6 = b6"7676- : "=r"(ptr) : "r"(ptr), "r" (flags) : IA64_SPINLOCK_CLOBBERS);7777-# else7878- asm volatile ("mov r30 = 1\n\t"7979- "mov r27=%2\n\t"8080- "mov ar.ccv = r0;;\n\t"8181- "cmpxchg4.acq r30 = [%0], r30, ar.ccv;;\n\t"8282- "cmp4.ne p14, p0 = r30, r0\n\t"8383- "(p14) brl.call.spnt.many b6=ia64_spinlock_contention;;"8484- : "=r"(ptr) : "r"(ptr), "r" (flags) : IA64_SPINLOCK_CLOBBERS);8585-# endif /* CONFIG_MCKINLEY */8686-#endif4141+ now_serving = *p;4242+ turn = ia64_fetchadd(1, p+1, acq);4343+4444+ if (turn == now_serving)4545+ return;4646+4747+ do {4848+ cpu_relax();4949+ } while (ACCESS_ONCE(*p) != turn);8750}88518989-#define __raw_spin_lock(lock) __raw_spin_lock_flags(lock, 0)5252+static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)5353+{5454+ long tmp = ACCESS_ONCE(lock->lock), try;90559191-/* Unlock by doing an ordered store and releasing the cacheline with nta */9292-static inline void __raw_spin_unlock(raw_spinlock_t *x) {9393- barrier();9494- asm volatile ("st4.rel.nta [%0] = r0\n\t" :: "r"(x));5656+ if (!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1L << TICKET_SHIFT) - 1))) {5757+ try = tmp + (1L << TICKET_SHIFT);5858+5959+ return ia64_cmpxchg(acq, &lock->lock, tmp, try, sizeof (tmp)) == tmp;6060+ }6161+ return 0;9562}96639797-#else /* !ASM_SUPPORTED */9898-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)9999-# define __raw_spin_lock(x) \100100-do { \101101- __u32 *ia64_spinlock_ptr = (__u32 *) (x); \102102- __u64 ia64_spinlock_val; \103103- ia64_spinlock_val = ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0); \104104- if (unlikely(ia64_spinlock_val)) { \105105- do { \106106- while (*ia64_spinlock_ptr) \107107- ia64_barrier(); \108108- ia64_spinlock_val = ia64_cmpxchg4_acq(ia64_spinlock_ptr, 1, 0); \109109- } while (ia64_spinlock_val); \110110- } \111111-} while (0)112112-#define __raw_spin_unlock(x) do { barrier(); ((raw_spinlock_t *) x)->lock = 0; } while (0)113113-#endif /* !ASM_SUPPORTED */6464+static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)6565+{6666+ int *p = (int *)&lock->lock;11467115115-#define __raw_spin_is_locked(x) ((x)->lock != 0)116116-#define __raw_spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0)117117-#define __raw_spin_unlock_wait(lock) \118118- do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)6868+ (void)ia64_fetchadd(1, p, rel);6969+}7070+7171+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)7272+{7373+ long tmp = ACCESS_ONCE(lock->lock);7474+7575+ return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1L << TICKET_SHIFT) - 1));7676+}7777+7878+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)7979+{8080+ long tmp = ACCESS_ONCE(lock->lock);8181+8282+ return (((tmp >> TICKET_SHIFT) - tmp) & ((1L << TICKET_SHIFT) - 1)) > 1;8383+}8484+8585+static inline int __raw_spin_is_locked(raw_spinlock_t *lock)8686+{8787+ return __ticket_spin_is_locked(lock);8888+}8989+9090+static inline int __raw_spin_is_contended(raw_spinlock_t *lock)9191+{9292+ return __ticket_spin_is_contended(lock);9393+}9494+#define __raw_spin_is_contended __raw_spin_is_contended9595+9696+static __always_inline void __raw_spin_lock(raw_spinlock_t *lock)9797+{9898+ __ticket_spin_lock(lock);9999+}100100+101101+static __always_inline int __raw_spin_trylock(raw_spinlock_t *lock)102102+{103103+ return __ticket_spin_trylock(lock);104104+}105105+106106+static __always_inline void __raw_spin_unlock(raw_spinlock_t *lock)107107+{108108+ __ticket_spin_unlock(lock);109109+}110110+111111+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,112112+ unsigned long flags)113113+{114114+ __raw_spin_lock(lock);115115+}116116+117117+static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)118118+{119119+ while (__raw_spin_is_locked(lock))120120+ cpu_relax();121121+}119122120123#define __raw_read_can_lock(rw) (*(volatile int *)(rw) >= 0)121124#define __raw_write_can_lock(rw) (*(volatile int *)(rw) == 0)
+1-1
arch/ia64/include/asm/spinlock_types.h
···66#endif7788typedef struct {99- volatile unsigned int lock;99+ volatile unsigned long lock;1010} raw_spinlock_t;11111212#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
-89
arch/ia64/kernel/head.S
···11301130#endif /* CONFIG_IA64_BRL_EMU */1131113111321132#ifdef CONFIG_SMP11331133- /*11341134- * This routine handles spinlock contention. It uses a non-standard calling11351135- * convention to avoid converting leaf routines into interior routines. Because11361136- * of this special convention, there are several restrictions:11371137- *11381138- * - do not use gp relative variables, this code is called from the kernel11391139- * and from modules, r1 is undefined.11401140- * - do not use stacked registers, the caller owns them.11411141- * - do not use the scratch stack space, the caller owns it.11421142- * - do not use any registers other than the ones listed below11431143- *11441144- * Inputs:11451145- * ar.pfs - saved CFM of caller11461146- * ar.ccv - 0 (and available for use)11471147- * r27 - flags from spin_lock_irqsave or 0. Must be preserved.11481148- * r28 - available for use.11491149- * r29 - available for use.11501150- * r30 - available for use.11511151- * r31 - address of lock, available for use.11521152- * b6 - return address11531153- * p14 - available for use.11541154- * p15 - used to track flag status.11551155- *11561156- * If you patch this code to use more registers, do not forget to update11571157- * the clobber lists for spin_lock() in arch/ia64/include/asm/spinlock.h.11581158- */11591159-11601160-#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)11611161-11621162-GLOBAL_ENTRY(ia64_spinlock_contention_pre3_4)11631163- .prologue11641164- .save ar.pfs, r0 // this code effectively has a zero frame size11651165- .save rp, r2811661166- .body11671167- nop 011681168- tbit.nz p15,p0=r27,IA64_PSR_I_BIT11691169- .restore sp // pop existing prologue after next insn11701170- mov b6 = r2811711171- .prologue11721172- .save ar.pfs, r011731173- .altrp b611741174- .body11751175- ;;11761176-(p15) ssm psr.i // reenable interrupts if they were on11771177- // DavidM says that srlz.d is slow and is not required in this case11781178-.wait:11791179- // exponential backoff, kdb, lockmeter etc. go in here11801180- hint @pause11811181- ld4 r30=[r31] // don't use ld4.bias; if it's contended, we won't write the word11821182- nop 011831183- ;;11841184- cmp4.ne p14,p0=r30,r011851185-(p14) br.cond.sptk.few .wait11861186-(p15) rsm psr.i // disable interrupts if we reenabled them11871187- br.cond.sptk.few b6 // lock is now free, try to acquire11881188- .global ia64_spinlock_contention_pre3_4_end // for kernprof11891189-ia64_spinlock_contention_pre3_4_end:11901190-END(ia64_spinlock_contention_pre3_4)11911191-11921192-#else11931193-11941194-GLOBAL_ENTRY(ia64_spinlock_contention)11951195- .prologue11961196- .altrp b611971197- .body11981198- tbit.nz p15,p0=r27,IA64_PSR_I_BIT11991199- ;;12001200-.wait:12011201-(p15) ssm psr.i // reenable interrupts if they were on12021202- // DavidM says that srlz.d is slow and is not required in this case12031203-.wait2:12041204- // exponential backoff, kdb, lockmeter etc. go in here12051205- hint @pause12061206- ld4 r30=[r31] // don't use ld4.bias; if it's contended, we won't write the word12071207- ;;12081208- cmp4.ne p14,p0=r30,r012091209- mov r30 = 112101210-(p14) br.cond.sptk.few .wait212111211-(p15) rsm psr.i // disable interrupts if we reenabled them12121212- ;;12131213- cmpxchg4.acq r30=[r31], r30, ar.ccv12141214- ;;12151215- cmp4.ne p14,p0=r0,r3012161216-(p14) br.cond.sptk.few .wait12171217-12181218- br.ret.sptk.many b6 // lock is now taken12191219-END(ia64_spinlock_contention)12201220-12211221-#endif1222113312231134#ifdef CONFIG_HOTPLUG_CPU12241135GLOBAL_ENTRY(ia64_jump_to_sal)
-20
arch/ia64/kernel/ia64_ksyms.c
···8484#include <asm/unwind.h>8585EXPORT_SYMBOL(unw_init_running);86868787-#ifdef ASM_SUPPORTED8888-# ifdef CONFIG_SMP8989-# if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)9090-/*9191- * This is not a normal routine and we don't want a function descriptor for it, so we use9292- * a fake declaration here.9393- */9494-extern char ia64_spinlock_contention_pre3_4;9595-EXPORT_SYMBOL(ia64_spinlock_contention_pre3_4);9696-# else9797-/*9898- * This is not a normal routine and we don't want a function descriptor for it, so we use9999- * a fake declaration here.100100- */101101-extern char ia64_spinlock_contention;102102-EXPORT_SYMBOL(ia64_spinlock_contention);103103-# endif104104-# endif105105-#endif106106-10787#if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE)10888extern void esi_call_phys (void);10989EXPORT_SYMBOL_GPL(esi_call_phys);
+1-19
arch/ia64/oprofile/backtrace.c
···3232 u64 *prev_pfs_loc; /* state for WAR for old spinlock ool code */3333} ia64_backtrace_t;34343535-#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3)3636-/*3737- * Returns non-zero if the PC is in the spinlock contention out-of-line code3838- * with non-standard calling sequence (on older compilers).3939- */4040-static __inline__ int in_old_ool_spinlock_code(unsigned long pc)4141-{4242- extern const char ia64_spinlock_contention_pre3_4[] __attribute__ ((weak));4343- extern const char ia64_spinlock_contention_pre3_4_end[] __attribute__ ((weak));4444- unsigned long sc_start = (unsigned long)ia64_spinlock_contention_pre3_4;4545- unsigned long sc_end = (unsigned long)ia64_spinlock_contention_pre3_4_end;4646- return (sc_start && sc_end && pc >= sc_start && pc < sc_end);4747-}4848-#else4949-/* Newer spinlock code does a proper br.call and works fine with the unwinder */5050-#define in_old_ool_spinlock_code(pc) 05151-#endif5252-5335/* Returns non-zero if the PC is in the Interrupt Vector Table */5436static __inline__ int in_ivt_code(unsigned long pc)5537{···6280 */6381 if (bt->prev_pfs_loc && bt->regs && bt->frame.pfs_loc == bt->prev_pfs_loc)6482 bt->frame.pfs_loc = &bt->regs->ar_pfs;6565- bt->prev_pfs_loc = (in_old_ool_spinlock_code(bt->frame.ip) ? bt->frame.pfs_loc : NULL);8383+ bt->prev_pfs_loc = NULL;66846785 return unw_unwind(&bt->frame) == 0;6886}