patch-2.4.25 linux-2.4.25/include/asm-ppc64/spinlock.h

Next file: linux-2.4.25/include/asm-ppc64/system.h
Previous file: linux-2.4.25/include/asm-ppc64/smp.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/include/asm-ppc64/spinlock.h linux-2.4.25/include/asm-ppc64/spinlock.h
@@ -6,16 +6,27 @@
  *
  * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
  * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
- *
- * Type of int is used as a full 64b word is not necessary.
+ * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>, IBM
+ *   Rework to support virtual processors
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+
+#include <asm/memory.h>
+#include <asm/hvcall.h>
+
+/*
+ * The following define is being used to select basic or shared processor
+ * locking when running on an RPA platform.  As we do more performance
+ * tuning, I would expect this selection mechanism to change.  Dave E.
+ */
+/* #define SPLPAR_LOCKS */
+
 typedef struct {
-	volatile unsigned int lock;
+	volatile unsigned long lock;
 } spinlock_t;
 
 #ifdef __KERNEL__
@@ -25,15 +36,15 @@
 
 static __inline__ int spin_trylock(spinlock_t *lock)
 {
-	unsigned int tmp;
+	unsigned long tmp;
 
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%1		# spin_trylock\n\
-	cmpwi		0,%0,0\n\
+"1:	ldarx		%0,0,%1		# spin_trylock\n\
+	cmpdi		0,%0,0\n\
 	li		%0,0\n\
 	bne-		2f\n\
 	li		%0,1\n\
-	stwcx.		%0,0,%1\n\
+	stdcx.		13,0,%1\n\
 	bne-		1b\n\
 	isync\n\
 2:"	: "=&r"(tmp)
@@ -43,27 +54,115 @@
 	return tmp;
 }
 
+/*
+ * Spin lock states:
+ *   0        : Unlocked
+ *   Negative : Locked.  Value is paca pointer (0xc...0) of holder
+ */
+#ifdef CONFIG_PPC_ISERIES
 static __inline__ void spin_lock(spinlock_t *lock)
 {
-	unsigned int tmp;
+	unsigned long tmp, tmp2;
 
 	__asm__ __volatile__(
 	"b		2f		# spin_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwzx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%2         # load the lock value\n\
+	cmpdi		0,%0,0          # if not locked, try to acquire\n\
+	beq-		2f\n\
+	lwz             5,0x280(%0)     # load yield counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	li              3,0x25          # yield hcall 0x8-12 \n\
+	rotrdi          3,3,1           #   put the bits in the right spot\n\
+	lhz             4,0x18(%0)      # processor number\n\
+	sldi            4,4,32          #   move into top half of word\n\
+	or              5,5,4           # r5 has yield cnt - or it in\n\
+	li              4,2             # yield to processor\n\
+	li              0,-1            # indicate an hcall\n\
+	sc                              # do the hcall \n\
+	b               1b\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bne-		1b\n\
+	stdcx.		13,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&lock->lock)
+	: "r0", "r3", "r4", "r5", "ctr", "cr0", "cr1", "cr2", "cr3", "cr4",
+	  "xer", "memory");
+}
+#else
+#ifdef SPLPAR_LOCKS
+static __inline__ void spin_lock(spinlock_t *lock)
+{
+	unsigned long tmp, tmp2;
+
+	__asm__ __volatile__(
+	"b		2f		# spin_lock\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%2         # load the lock value\n\
+	cmpdi		0,%0,0          # if not locked, try to acquire\n\
+	beq-		2f\n\
+	lwz             5,0x280(%0)     # load dispatch counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	li              3,0xE4          # give up the cycles H_CONFER\n\
+	lhz             4,0x18(%0)      # processor number\n\
+					# r5 has dispatch cnt already\n"
+	HVSC
+"        b               1b\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bne-		1b\n\
+	stdcx.		13,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&lock->lock)
+	: "r3", "r4", "r5", "cr0", "cr1", "ctr", "xer", "memory");
+}
+#else
+static __inline__ void spin_lock(spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+       "b		2f		# spin_lock\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%1         # load the lock value\n\
+	cmpdi		0,%0,0          # if not locked, try to acquire\n\
 	bne+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%1\n\
+	cmpdi		0,%0,0\n\
 	bne-		1b\n\
-	stwcx.		%2,0,%1\n\
+	stdcx.		13,0,%1\n\
 	bne-		2b\n\
 	isync"
 	: "=&r"(tmp)
-	: "r"(&lock->lock), "r"(1)
+	: "r"(&lock->lock)
 	: "cr0", "memory");
 }
+#endif
+#endif
 
 static __inline__ void spin_unlock(spinlock_t *lock)
 {
@@ -80,25 +179,33 @@
  * can "mix" irq-safe locks - any writer needs to get a
  * irq-safe write-lock, but readers can get non-irqsafe
  * read-locks.
+ *
+ * Write lock states:
+ *   0        : Unlocked
+ *   Positive : Reader count
+ *   Negative : Writer locked.  Value is paca pointer (0xc...0) of holder
+ *
+ * If lock is not held, try to acquire.
+ * If lock is held by a writer, yield cycles to the holder.
+ * If lock is help by reader(s), spin.
  */
 typedef struct {
-	volatile signed int lock;
+	volatile signed long lock;
 } rwlock_t;
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 
 static __inline__ int read_trylock(rwlock_t *rw)
 {
-	unsigned int tmp;
+	unsigned long tmp;
 	unsigned int ret;
 
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%2		# read_trylock\n\
+"1:	ldarx		%0,0,%2		# read_trylock\n\
 	li		%1,0\n\
-	extsw		%0,%0\n\
 	addic.		%0,%0,1\n\
 	ble-		2f\n\
-	stwcx.		%0,0,%2\n\
+	stdcx.		%0,0,%2\n\
 	bne-		1b\n\
 	li		%1,1\n\
 	isync\n\
@@ -109,38 +216,118 @@
 	return ret;
 }
 
+#ifdef CONFIG_PPC_ISERIES
+static __inline__ void read_lock(rwlock_t *rw)
+{
+	unsigned long tmp, tmp2;
+
+	__asm__ __volatile__(
+	"b		2f		# read_lock\n\
+1:"
+	HMT_LOW
+"	ldx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bge-		2f\n\
+	lwz             5,0x280(%0)     # load yield counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	li              3,0x25          # yield hcall 0x8-12 \n\
+	rotrdi          3,3,1           #   put the bits in the right spot\n\
+	lhz             4,0x18(%0)      # processor number\n\
+	sldi            4,4,32          #   move into top half of word\n\
+	or              5,5,4           # r5 has yield cnt - or it in\n\
+	li              4,2             # yield to processor\n\
+	li              0,-1            # indicate an hcall\n\
+	sc                              # do the hcall \n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	addic.		%0,%0,1\n\
+	ble-		1b\n\
+	stdcx.		%0,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&rw->lock)
+	: "r0", "r3", "r4", "r5", "ctr", "cr0", "cr1", "cr2", "cr3", "cr4",
+	  "xer", "memory");
+}
+#else
+#ifdef SPLPAR_LOCKS
+static __inline__ void read_lock(rwlock_t *rw)
+{
+	unsigned long tmp, tmp2;
+
+	__asm__ __volatile__(
+	"b		2f		# read_lock\n\
+1:"
+	HMT_LOW
+"	ldx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bge-		2f\n\
+	lwz             5,0x280(%0)     # load dispatch counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	li              3,0xE4          # give up the cycles H_CONFER\n\
+	lhz             4,0x18(%0)      # processor number\n\
+					# r5 has dispatch cnt already\n"
+	HVSC
+"2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	addic.		%0,%0,1\n\
+	ble-		1b\n\
+	stdcx.		%0,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&rw->lock)
+	: "r3", "r4", "r5", "cr0", "cr1", "ctr", "xer", "memory");
+}
+#else
 static __inline__ void read_lock(rwlock_t *rw)
 {
-	unsigned int tmp;
+	unsigned long tmp;
 
 	__asm__ __volatile__(
 	"b		2f		# read_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwax		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
+1:"
+	HMT_LOW
+"	ldx		%0,0,%1\n\
+	cmpdi		0,%0,0\n\
 	blt+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
-	extsw		%0,%0\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%1\n\
 	addic.		%0,%0,1\n\
 	ble-		1b\n\
-	stwcx.		%0,0,%1\n\
+	stdcx.		%0,0,%1\n\
 	bne-		2b\n\
 	isync"
 	: "=&r"(tmp)
 	: "r"(&rw->lock)
 	: "cr0", "memory");
 }
+#endif
+#endif
 
 static __inline__ void read_unlock(rwlock_t *rw)
 {
-	unsigned int tmp;
+	unsigned long tmp;
 
 	__asm__ __volatile__(
-	"lwsync				# read_unlock\n\
-1:	lwarx		%0,0,%1\n\
+	"eieio				# read_unlock\n\
+1:	ldarx		%0,0,%1\n\
 	addic		%0,%0,-1\n\
-	stwcx.		%0,0,%1\n\
+	stdcx.		%0,0,%1\n\
 	bne-		1b"
 	: "=&r"(tmp)
 	: "r"(&rw->lock)
@@ -149,46 +336,131 @@
 
 static __inline__ int write_trylock(rwlock_t *rw)
 {
-	unsigned int tmp;
-	unsigned int ret;
+	unsigned long tmp;
+	unsigned long ret;
 
 	__asm__ __volatile__(
-"1:	lwarx		%0,0,%2		# write_trylock\n\
-	cmpwi		0,%0,0\n\
+"1:	ldarx		%0,0,%2		# write_trylock\n\
+	cmpdi		0,%0,0\n\
 	li		%1,0\n\
 	bne-		2f\n\
-	stwcx.		%3,0,%2\n\
+	stdcx.		13,0,%2\n\
 	bne-		1b\n\
 	li		%1,1\n\
 	isync\n\
 2:"	: "=&r"(tmp), "=&r"(ret)
-	: "r"(&rw->lock), "r"(-1)
+	: "r"(&rw->lock)
 	: "cr0", "memory");
 
 	return ret;
 }
 
+#ifdef CONFIG_PPC_ISERIES
+static __inline__ void write_lock(rwlock_t *rw)
+{
+	unsigned long tmp, tmp2;
+
+	__asm__ __volatile__(
+	"b		2f		# spin_lock\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%2         # load the lock value\n\
+	cmpdi		0,%0,0          # if not locked(0), try to acquire\n\
+	beq-		2f\n\
+	bgt             1b              # negative(0xc..)->cycles to holder\n"
+"3:     lwz             5,0x280(%0)     # load yield counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	lhz             4,0x18(%0)      # processor number\n\
+	sldi            4,4,32          #   move into top half of word\n\
+	or              5,5,4           # r5 has yield cnt - or it in\n\
+	li              3,0x25          # yield hcall 0x8-12 \n\
+	rotrdi          3,3,1           #   put the bits in the right spot\n\
+	li              4,2             # yield to processor\n\
+	li              0,-1            # indicate an hcall\n\
+	sc                              # do the hcall \n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bne-		1b\n\
+	stdcx.		13,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&rw->lock)
+	: "r0", "r3", "r4", "r5", "ctr", "cr0", "cr1", "cr2", "cr3", "cr4",
+	  "xer", "memory");
+}
+#else
+#ifdef SPLPAR_LOCKS
+static __inline__ void write_lock(rwlock_t *rw)
+{
+	unsigned long tmp, tmp2;
+
+	__asm__ __volatile__(
+	"b		2f		# spin_lock\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%2         # load the lock value\n\
+	li              3,0xE4          # give up the cycles H_CONFER\n\
+	cmpdi		0,%0,0          # if not locked(0), try to acquire\n\
+	beq-		2f\n\
+	blt             3f              # negative(0xc..)->confer to holder\n\
+	b               1b\n"
+"3:      lwz             5,0x280(%0)     # load dispatch counter\n\
+	andi.           %1,5,1          # if even then spin\n\
+	beq             1b\n\
+	lwsync                          # if odd, give up cycles\n\
+	ldx             %1,0,%2         # reverify the lock holder\n\
+	cmpd            %0,%1\n\
+	bne             1b              # new holder so restart\n\
+	lhz             4,0x18(%0)      # processor number\n\
+					# r5 has dispatch cnt already\n"
+	HVSC
+"        b               1b\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%2\n\
+	cmpdi		0,%0,0\n\
+	bne-		1b\n\
+	stdcx.		13,0,%2\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp), "=&r"(tmp2)
+	: "r"(&rw->lock)
+	: "r3", "r4", "r5", "cr0", "cr1", "ctr", "xer", "memory");
+}
+#else
 static __inline__ void write_lock(rwlock_t *rw)
 {
-	unsigned int tmp;
+	unsigned long tmp;
 
 	__asm__ __volatile__(
-	"b		2f		# write_lock\n\
-1:	or		1,1,1		# spin at low priority\n\
-	lwax		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
+	"b		2f		# spin_lock\n\
+1:"
+	HMT_LOW
+"       ldx		%0,0,%1         # load the lock value\n\
+	cmpdi		0,%0,0          # if not locked(0), try to acquire\n\
 	bne+		1b\n\
-	or		2,2,2		# back to medium priority\n\
-2:	lwarx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
+2: \n"
+	HMT_MEDIUM
+" 	ldarx		%0,0,%1\n\
+	cmpdi		0,%0,0\n\
 	bne-		1b\n\
-	stwcx.		%2,0,%1\n\
+	stdcx.		13,0,%1\n\
 	bne-		2b\n\
 	isync"
 	: "=&r"(tmp)
-	: "r"(&rw->lock), "r"(-1)
+	: "r"(&rw->lock)
 	: "cr0", "memory");
 }
+#endif
+#endif
 
 static __inline__ void write_unlock(rwlock_t *rw)
 {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)