From: jbeulich@novell.com
Subject: Go into polling mode early if lock owner is not running
Patch-mainline: n/a

This could be merged into the original ticket spinlock code once
validated, if there wasn't the dependency on smp-processor-id.h, which
only gets introduced in the 2.6.32 merge.

--- sle11sp3.orig/arch/x86/Kconfig	2013-02-05 16:50:47.000000000 +0100
+++ sle11sp3/arch/x86/Kconfig	2014-01-07 17:00:40.000000000 +0100
@@ -12,7 +12,7 @@ config X86_32
 
 config X86_64
 	def_bool 64BIT
-	select ARCH_USE_CMPXCHG_LOCKREF
+	select ARCH_USE_CMPXCHG_LOCKREF if !XEN
 
 ### Arch settings
 config X86
@@ -353,6 +353,8 @@ config X86_64_XEN
 	bool "Enable Xen compatible kernel"
 	depends on X86_64
 	select XEN
+	select ARCH_USE_CMPXCHG_LOCKREF if XEN_SPINLOCK_ACQUIRE_NESTING = ""
+#	select ARCH_USE_CMPXCHG_LOCKREF if (XEN_SPINLOCK_ACQUIRE_NESTING + 1) * NR_CPUS < 256
 	help
 	  This option will compile a kernel compatible with Xen hypervisor
 
--- sle11sp3.orig/arch/x86/include/mach-xen/asm/spinlock.h	2014-06-04 13:51:23.000000000 +0200
+++ sle11sp3/arch/x86/include/mach-xen/asm/spinlock.h	2012-10-19 14:45:43.000000000 +0200
@@ -45,6 +45,7 @@
 #ifdef TICKET_SHIFT
 
 #include <asm/irqflags.h>
+#include <asm/smp-processor-id.h>
 
 int xen_spinlock_init(unsigned int cpu);
 void xen_spinlock_cleanup(unsigned int cpu);
@@ -54,8 +55,8 @@ unsigned int xen_spin_adjust(const arch_
 #define xen_spin_adjust(lock, token) (token)
 #define xen_spin_wait(l, t, f) xen_spin_wait(l, t)
 #endif
-bool xen_spin_wait(arch_spinlock_t *, unsigned int *token,
-		   unsigned int flags);
+unsigned int xen_spin_wait(arch_spinlock_t *, unsigned int *token,
+			   unsigned int flags);
 void xen_spin_kick(const arch_spinlock_t *, unsigned int token);
 
 /*
@@ -87,15 +88,22 @@ void xen_spin_kick(const arch_spinlock_t
 	asm("1:\t" \
 	    "cmpb %h0, %b0\n\t" \
 	    "je 2f\n\t" \
+	    "cmpl %3, %4\n\t" \
+	    "jne 4f\n\t" \
 	    "decl %1\n\t" \
-	    "jz 2f\n\t" \
+	    "jz 2f\n" \
+	    "3:\t" \
 	    "rep ; nop\n\t" \
 	    "movb %2, %b0\n\t" \
 	    /* don't need lfence here, because loads are in-order */ \
 	    "jmp 1b\n" \
+	    "4:\t" \
+	    "shrl $1, %1\n\t" \
+	    "jnz 3b\n" \
 	    "2:" \
 	    : "+Q" (token), "+g" (count) \
-	    : "m" (lock->slock) \
+	    : "m" (lock->slock), "i" (RUNSTATE_running), \
+	      "m" (per_cpu(runstate.state, lock->owner)) \
 	    : "memory", "cc")
 #define __ticket_spin_unlock_body \
 	asm(UNLOCK_LOCK_PREFIX "incb %2\n\t" \
@@ -122,6 +130,9 @@ static __always_inline int __ticket_spin
 	    :
 	    : "memory", "cc");
 
+	if (tmp)
+		lock->owner = raw_smp_processor_id();
+
 	return tmp;
 }
 #elif TICKET_SHIFT == 16
@@ -144,15 +155,22 @@ static __always_inline int __ticket_spin
 		    "1:\t" \
 		    "cmpw %w2, %w0\n\t" \
 		    "je 2f\n\t" \
+		    "cmpl %4, %5\n\t" \
+		    "jne 4f\n\t" \
 		    "decl %1\n\t" \
-		    "jz 2f\n\t" \
+		    "jz 2f\n" \
+		    "3:\t" \
 		    "rep ; nop\n\t" \
 		    "movw %3, %w0\n\t" \
 		    /* don't need lfence here, because loads are in-order */ \
 		    "jmp 1b\n" \
+		    "4:\t" \
+		    "shrl $1, %1\n\t" \
+		    "jnz 3b\n" \
 		    "2:" \
 		    : "+r" (token), "+g" (count), "=&g" (tmp) \
-		    : "m" (lock->slock) \
+		    : "m" (lock->slock), "i" (RUNSTATE_running), \
+		      "m" (per_cpu(runstate.state, lock->owner)) \
 		    : "memory", "cc"); \
 	} while (0)
 #define __ticket_spin_unlock_body \
@@ -188,6 +206,9 @@ static __always_inline int __ticket_spin
 	    :
 	    : "memory", "cc");
 
+	if (tmp)
+		lock->owner = raw_smp_processor_id();
+
 	return tmp;
 }
 #endif
@@ -200,16 +221,18 @@ static __always_inline void __ticket_spi
 	bool free;
 
 	__ticket_spin_lock_preamble;
-	if (likely(free)) {
+	if (likely(free))
+		arch_local_irq_restore(flags);
+	else {
+		token = xen_spin_adjust(lock, token);
 		arch_local_irq_restore(flags);
-		return;
-	}
-	token = xen_spin_adjust(lock, token);
-	arch_local_irq_restore(flags);
-	do {
 		count = 1 << 12;
-		__ticket_spin_lock_body;
-	} while (unlikely(!count) && !xen_spin_wait(lock, &token, flags));
+		do {
+			__ticket_spin_lock_body;
+		} while (unlikely(!count)
+			 && (count = xen_spin_wait(lock, &token, flags)));
+	}
+	lock->owner = raw_smp_processor_id();
 }
 #else
 #define __ticket_spin_lock(lock) __ticket_spin_lock_flags(lock, -1)
@@ -222,13 +245,15 @@ static __always_inline void __ticket_spi
 	bool free;
 
 	__ticket_spin_lock_preamble;
-	if (likely(free))
-		return;
-	token = xen_spin_adjust(lock, token);
-	do {
+	if (unlikely(!free)) {
+		token = xen_spin_adjust(lock, token);
 		count = 1 << 12;
-		__ticket_spin_lock_body;
-	} while (unlikely(!count) && !xen_spin_wait(lock, &token, flags));
+		do {
+			__ticket_spin_lock_body;
+		} while (unlikely(!count)
+			 && (count = xen_spin_wait(lock, &token, flags)));
+	}
+	lock->owner = raw_smp_processor_id();
 }
 
 static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
--- sle11sp3.orig/arch/x86/include/mach-xen/asm/spinlock_types.h	2012-01-31 18:04:48.000000000 +0100
+++ sle11sp3/arch/x86/include/mach-xen/asm/spinlock_types.h	2012-10-19 14:45:38.000000000 +0200
@@ -25,6 +25,11 @@ typedef union {
 # define TICKET_SHIFT 16
 		u16 cur, seq;
 #endif
+#if CONFIG_NR_CPUS <= 256
+		u8 owner;
+#else
+		u16 owner;
+#endif
 #else /* ndef CONFIG_XEN_SPINLOCK_ACQUIRE_NESTING */
 /*
  * This differs from the pre-2.6.24 spinlock by always using xchgb
--- sle11sp3.orig/drivers/xen/core/spinlock.c	2012-06-21 13:49:49.000000000 +0200
+++ sle11sp3/drivers/xen/core/spinlock.c	2014-03-13 11:27:15.000000000 +0100
@@ -45,6 +45,8 @@ int __cpuinit xen_spinlock_init(unsigned
 	struct evtchn_bind_ipi bind_ipi;
 	int rc;
 
+	setup_runstate_area(cpu);
+
 	if (nopoll)
 		return 0;
 
@@ -154,6 +156,7 @@ static unsigned int ticket_drop(struct s
 
 	if (cmpxchg(&spinning->ticket, ticket, -1) != ticket)
 		return -1;
+	lock->owner = cpu;
 	__ticket_spin_unlock_body;
 	return kick ? (ticket + 1) & ((1 << TICKET_SHIFT) - 1) : -1;
 }
@@ -233,23 +236,26 @@ void xen_spin_irq_exit(void)
 		if (spinning->ticket + 1)
 			continue;
 		spinning->ticket = ticket_get(lock, spinning->prev);
-		if (lock->cur == spinning->ticket)
+		if (lock->cur == spinning->ticket) {
+			lock->owner = raw_smp_processor_id();
 			set_evtchn(percpu_read(poll_evtchn));
+		}
 	}
 }
 #endif
 
-bool xen_spin_wait(arch_spinlock_t *lock, unsigned int *ptok,
-		   unsigned int flags)
+unsigned int xen_spin_wait(arch_spinlock_t *lock, unsigned int *ptok,
+			   unsigned int flags)
 {
+	unsigned int cpu = raw_smp_processor_id();
 	typeof(vcpu_info(0)->evtchn_upcall_mask) upcall_mask
 		= arch_local_save_flags();
 	struct spinning spinning;
 
 	/* If kicker interrupt not initialized yet, just spin. */
-	if (unlikely(!cpu_online(raw_smp_processor_id()))
+	if (unlikely(!cpu_online(cpu))
 	    || unlikely(!percpu_read(poll_evtchn)))
-		return false;
+		return UINT_MAX;
 
 	/* announce we're spinning */
 	spinning.ticket = *ptok >> TICKET_SHIFT;
@@ -324,12 +330,14 @@ bool xen_spin_wait(arch_spinlock_t *lock
 	sequence();
 	arch_local_irq_restore(upcall_mask);
 	smp_rmb();
-	if (lock->cur == spinning.ticket)
-		return true;
+	if (lock->cur == spinning.ticket) {
+		lock->owner = cpu;
+		return 0;
+	}
 	BUG_ON(CONFIG_XEN_SPINLOCK_ACQUIRE_NESTING && !(spinning.ticket + 1));
 	*ptok = lock->cur | (spinning.ticket << TICKET_SHIFT);
 
-	return false;
+	return 1 << 10;
 }
 
 static inline unsigned int cpumask_cycle(int n, const struct cpumask *srcp)
