]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'x86-rwsem-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 18:41:35 +0000 (10:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 18:41:35 +0000 (10:41 -0800)
* 'x86-rwsem-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86-64, rwsem: Avoid store forwarding hazard in __downgrade_write
  x86-64, rwsem: 64-bit xadd rwsem implementation
  x86: Fix breakage of UML from the changes in the rwsem system
  x86-64: support native xadd rwsem implementation
  x86: clean up rwsem type system

arch/um/sys-x86_64/Makefile
arch/x86/Kconfig.cpu
arch/x86/include/asm/rwsem.h
arch/x86/lib/Makefile
arch/x86/lib/rwsem_64.S [new file with mode: 0644]

index 2201e9c20e4a85ec4673939f27e15a3ef3431f94..c1ea9eb04466b00a35c8a895d09887546e78abfc 100644 (file)
@@ -8,7 +8,8 @@ obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \
        setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \
        sysrq.o ksyms.o tls.o
 
-subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o
+subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \
+               lib/rwsem_64.o
 subarch-obj-$(CONFIG_MODULES) += kernel/module.o
 
 ldt-y = ../sys-i386/ldt.o
index f20ddf84a89397c322d4f35657400d5590891832..a19829374e6a006b80a5db969a19c4f7dbae3449 100644 (file)
@@ -319,7 +319,7 @@ config X86_L1_CACHE_SHIFT
 
 config X86_XADD
        def_bool y
-       depends on X86_32 && !M386
+       depends on X86_64 || !M386
 
 config X86_PPRO_FENCE
        bool "PentiumPro memory ordering errata workaround"
index 413620024768a15b18a5ed77a3327a21d6e217cb..606ede126972e568b992268da3df6f64b7e98480 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/lockdep.h>
+#include <asm/asm.h>
 
 struct rwsem_waiter;
 
@@ -55,17 +56,28 @@ extern asmregparm struct rw_semaphore *
 
 /*
  * the semaphore definition
+ *
+ * The bias values and the counter type limits the number of
+ * potential readers/writers to 32767 for 32 bits and 2147483647
+ * for 64 bits.
  */
 
-#define RWSEM_UNLOCKED_VALUE           0x00000000
-#define RWSEM_ACTIVE_BIAS              0x00000001
-#define RWSEM_ACTIVE_MASK              0x0000ffff
-#define RWSEM_WAITING_BIAS             (-0x00010000)
+#ifdef CONFIG_X86_64
+# define RWSEM_ACTIVE_MASK             0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK             0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE           0x00000000L
+#define RWSEM_ACTIVE_BIAS              0x00000001L
+#define RWSEM_WAITING_BIAS             (-RWSEM_ACTIVE_MASK-1)
 #define RWSEM_ACTIVE_READ_BIAS         RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS                (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
+typedef signed long rwsem_count_t;
+
 struct rw_semaphore {
-       signed long             count;
+       rwsem_count_t           count;
        spinlock_t              wait_lock;
        struct list_head        wait_list;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -105,7 +117,7 @@ do {                                                                \
 static inline void __down_read(struct rw_semaphore *sem)
 {
        asm volatile("# beginning down_read\n\t"
-                    LOCK_PREFIX "  inc%z0      (%1)\n\t"
+                    LOCK_PREFIX _ASM_INC "(%1)\n\t"
                     /* adds 0x00000001, returns the old value */
                     "  jns        1f\n"
                     "  call call_rwsem_down_read_failed\n"
@@ -121,7 +133,7 @@ static inline void __down_read(struct rw_semaphore *sem)
  */
 static inline int __down_read_trylock(struct rw_semaphore *sem)
 {
-       __s32 result, tmp;
+       rwsem_count_t result, tmp;
        asm volatile("# beginning __down_read_trylock\n\t"
                     "  mov          %0,%1\n\t"
                     "1:\n\t"
@@ -143,7 +155,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
  */
 static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
 {
-       int tmp;
+       rwsem_count_t tmp;
 
        tmp = RWSEM_ACTIVE_WRITE_BIAS;
        asm volatile("# beginning down_write\n\t"
@@ -170,9 +182,9 @@ static inline void __down_write(struct rw_semaphore *sem)
  */
 static inline int __down_write_trylock(struct rw_semaphore *sem)
 {
-       signed long ret = cmpxchg(&sem->count,
-                                 RWSEM_UNLOCKED_VALUE,
-                                 RWSEM_ACTIVE_WRITE_BIAS);
+       rwsem_count_t ret = cmpxchg(&sem->count,
+                                   RWSEM_UNLOCKED_VALUE,
+                                   RWSEM_ACTIVE_WRITE_BIAS);
        if (ret == RWSEM_UNLOCKED_VALUE)
                return 1;
        return 0;
@@ -183,7 +195,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
  */
 static inline void __up_read(struct rw_semaphore *sem)
 {
-       __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
+       rwsem_count_t tmp = -RWSEM_ACTIVE_READ_BIAS;
        asm volatile("# beginning __up_read\n\t"
                     LOCK_PREFIX "  xadd      %1,(%2)\n\t"
                     /* subtracts 1, returns the old value */
@@ -201,7 +213,7 @@ static inline void __up_read(struct rw_semaphore *sem)
  */
 static inline void __up_write(struct rw_semaphore *sem)
 {
-       unsigned long tmp;
+       rwsem_count_t tmp;
        asm volatile("# beginning __up_write\n\t"
                     LOCK_PREFIX "  xadd      %1,(%2)\n\t"
                     /* tries to transition
@@ -221,33 +233,38 @@ static inline void __up_write(struct rw_semaphore *sem)
 static inline void __downgrade_write(struct rw_semaphore *sem)
 {
        asm volatile("# beginning __downgrade_write\n\t"
-                    LOCK_PREFIX "  add%z0    %2,(%1)\n\t"
-                    /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
+                    LOCK_PREFIX _ASM_ADD "%2,(%1)\n\t"
+                    /*
+                     * transitions 0xZZZZ0001 -> 0xYYYY0001 (i386)
+                     *     0xZZZZZZZZ00000001 -> 0xYYYYYYYY00000001 (x86_64)
+                     */
                     "  jns       1f\n\t"
                     "  call call_rwsem_downgrade_wake\n"
                     "1:\n\t"
                     "# ending __downgrade_write\n"
                     : "+m" (sem->count)
-                    : "a" (sem), "i" (-RWSEM_WAITING_BIAS)
+                    : "a" (sem), "er" (-RWSEM_WAITING_BIAS)
                     : "memory", "cc");
 }
 
 /*
  * implement atomic add functionality
  */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+static inline void rwsem_atomic_add(rwsem_count_t delta,
+                                   struct rw_semaphore *sem)
 {
-       asm volatile(LOCK_PREFIX "add%z0 %1,%0"
+       asm volatile(LOCK_PREFIX _ASM_ADD "%1,%0"
                     : "+m" (sem->count)
-                    : "ir" (delta));
+                    : "er" (delta));
 }
 
 /*
  * implement exchange and add functionality
  */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+static inline rwsem_count_t rwsem_atomic_update(rwsem_count_t delta,
+                                               struct rw_semaphore *sem)
 {
-       int tmp = delta;
+       rwsem_count_t tmp = delta;
 
        asm volatile(LOCK_PREFIX "xadd %0,%1"
                     : "+r" (tmp), "+m" (sem->count)
index 710cc1405866e60d236c0b105135eeb49f84a764..419386c24b8205c3a22c993b3da48f448bf96283 100644 (file)
@@ -39,4 +39,5 @@ else
         lib-y += thunk_64.o clear_page_64.o copy_page_64.o
         lib-y += memmove_64.o memset_64.o
         lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o
+       lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem_64.o
 endif
diff --git a/arch/x86/lib/rwsem_64.S b/arch/x86/lib/rwsem_64.S
new file mode 100644 (file)
index 0000000..15acecf
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * x86-64 rwsem wrappers
+ *
+ * This interfaces the inline asm code to the slow-path
+ * C routines. We need to save the call-clobbered regs
+ * that the asm does not mark as clobbered, and move the
+ * argument from %rax to %rdi.
+ *
+ * NOTE! We don't need to save %rax, because the functions
+ * will always return the semaphore pointer in %rax (which
+ * is also the input argument to these helpers)
+ *
+ * The following can clobber %rdx because the asm clobbers it:
+ *   call_rwsem_down_write_failed
+ *   call_rwsem_wake
+ * but %rdi, %rsi, %rcx, %r8-r11 always need saving.
+ */
+
+#include <linux/linkage.h>
+#include <asm/rwlock.h>
+#include <asm/alternative-asm.h>
+#include <asm/frame.h>
+#include <asm/dwarf2.h>
+
+#define save_common_regs \
+       pushq %rdi; \
+       pushq %rsi; \
+       pushq %rcx; \
+       pushq %r8; \
+       pushq %r9; \
+       pushq %r10; \
+       pushq %r11
+
+#define restore_common_regs \
+       popq %r11; \
+       popq %r10; \
+       popq %r9; \
+       popq %r8; \
+       popq %rcx; \
+       popq %rsi; \
+       popq %rdi
+
+/* Fix up special calling conventions */
+ENTRY(call_rwsem_down_read_failed)
+       save_common_regs
+       pushq %rdx
+       movq %rax,%rdi
+       call rwsem_down_read_failed
+       popq %rdx
+       restore_common_regs
+       ret
+       ENDPROC(call_rwsem_down_read_failed)
+
+ENTRY(call_rwsem_down_write_failed)
+       save_common_regs
+       movq %rax,%rdi
+       call rwsem_down_write_failed
+       restore_common_regs
+       ret
+       ENDPROC(call_rwsem_down_write_failed)
+
+ENTRY(call_rwsem_wake)
+       decw %dx    /* do nothing if still outstanding active readers */
+       jnz 1f
+       save_common_regs
+       movq %rax,%rdi
+       call rwsem_wake
+       restore_common_regs
+1:     ret
+       ENDPROC(call_rwsem_wake)
+
+/* Fix up special calling conventions */
+ENTRY(call_rwsem_downgrade_wake)
+       save_common_regs
+       pushq %rdx
+       movq %rax,%rdi
+       call rwsem_downgrade_wake
+       popq %rdx
+       restore_common_regs
+       ret
+       ENDPROC(call_rwsem_downgrade_wake)