Merge branch 'for-2.6.39' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 15:22:41 +0000 (08:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Mar 2011 15:22:41 +0000 (08:22 -0700)
* 'for-2.6.39' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu:
  percpu, x86: Add arch-specific this_cpu_cmpxchg_double() support
  percpu: Generic support for this_cpu_cmpxchg_double()
  alpha: use L1_CACHE_BYTES for cacheline size in the linker script
  percpu: align percpu readmostly subsection to cacheline

Fix up trivial conflict in arch/x86/kernel/vmlinux.lds.S due to the
percpu alignment having changed ("x86: Reduce back the alignment of the
per-CPU data section")

1  2 
arch/arm/kernel/vmlinux.lds.S
arch/cris/kernel/vmlinux.lds.S
arch/x86/include/asm/percpu.h
arch/x86/kernel/vmlinux.lds.S
include/asm-generic/vmlinux.lds.h

  #define ARM_CPU_KEEP(x)
  #endif
  
 +#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
 +#define ARM_EXIT_KEEP(x)      x
 +#else
 +#define ARM_EXIT_KEEP(x)
 +#endif
 +
  OUTPUT_ARCH(arm)
  ENTRY(stext)
  
@@@ -49,7 -43,6 +49,7 @@@ SECTION
                _sinittext = .;
                        HEAD_TEXT
                        INIT_TEXT
 +                      ARM_EXIT_KEEP(EXIT_TEXT)
                _einittext = .;
                ARM_CPU_DISCARD(PROC_INFO)
                __arch_info_begin = .;
  #ifndef CONFIG_XIP_KERNEL
                __init_begin = _stext;
                INIT_DATA
 +              ARM_EXIT_KEEP(EXIT_DATA)
  #endif
        }
  
-       PERCPU(PAGE_SIZE)
+       PERCPU(32, PAGE_SIZE)
  
  #ifndef CONFIG_XIP_KERNEL
        . = ALIGN(PAGE_SIZE);
                . = ALIGN(PAGE_SIZE);
                __init_begin = .;
                INIT_DATA
 +              ARM_EXIT_KEEP(EXIT_DATA)
                . = ALIGN(PAGE_SIZE);
                __init_end = .;
  #endif
        }
  #endif
  
 +      NOTES
 +
        BSS_SECTION(0, 0, 0)
        _end = .;
  
@@@ -72,6 -72,11 +72,6 @@@ SECTION
        INIT_TEXT_SECTION(PAGE_SIZE)
        .init.data : { INIT_DATA }
        .init.setup : { INIT_SETUP(16) }
 -#ifdef CONFIG_ETRAX_ARCH_V32
 -      __start___param = .;
 -      __param : { *(__param) }
 -      __stop___param = .;
 -#endif
        .initcall.init : {
                INIT_CALLS
        }
  #endif
        __vmlinux_end = .;              /* Last address of the physical file. */
  #ifdef CONFIG_ETRAX_ARCH_V32
-       PERCPU(PAGE_SIZE)
+       PERCPU(32, PAGE_SIZE)
  
        .init.ramfs : {
                INIT_RAM_FS
@@@ -273,34 -273,34 +273,34 @@@ do {                                                                    
        typeof(var) pxo_new__ = (nval);                                 \
        switch (sizeof(var)) {                                          \
        case 1:                                                         \
 -              asm("\n1:mov "__percpu_arg(1)",%%al"                    \
 -                  "\n\tcmpxchgb %2, "__percpu_arg(1)                  \
 +              asm("\n\tmov "__percpu_arg(1)",%%al"                    \
 +                  "\n1:\tcmpxchgb %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
 -                          : "=a" (pxo_ret__), "+m" (var)              \
 +                          : "=&a" (pxo_ret__), "+m" (var)             \
                            : "q" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 2:                                                         \
 -              asm("\n1:mov "__percpu_arg(1)",%%ax"                    \
 -                  "\n\tcmpxchgw %2, "__percpu_arg(1)                  \
 +              asm("\n\tmov "__percpu_arg(1)",%%ax"                    \
 +                  "\n1:\tcmpxchgw %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
 -                          : "=a" (pxo_ret__), "+m" (var)              \
 +                          : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 4:                                                         \
 -              asm("\n1:mov "__percpu_arg(1)",%%eax"                   \
 -                  "\n\tcmpxchgl %2, "__percpu_arg(1)                  \
 +              asm("\n\tmov "__percpu_arg(1)",%%eax"                   \
 +                  "\n1:\tcmpxchgl %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
 -                          : "=a" (pxo_ret__), "+m" (var)              \
 +                          : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
        case 8:                                                         \
 -              asm("\n1:mov "__percpu_arg(1)",%%rax"                   \
 -                  "\n\tcmpxchgq %2, "__percpu_arg(1)                  \
 +              asm("\n\tmov "__percpu_arg(1)",%%rax"                   \
 +                  "\n1:\tcmpxchgq %2, "__percpu_arg(1)                \
                    "\n\tjnz 1b"                                        \
 -                          : "=a" (pxo_ret__), "+m" (var)              \
 +                          : "=&a" (pxo_ret__), "+m" (var)             \
                            : "r" (pxo_new__)                           \
                            : "memory");                                \
                break;                                                  \
  #define irqsafe_cpu_cmpxchg_4(pcp, oval, nval)        percpu_cmpxchg_op(pcp, oval, nval)
  #endif /* !CONFIG_M386 */
  
+ #ifdef CONFIG_X86_CMPXCHG64
+ #define percpu_cmpxchg8b_double(pcp1, o1, o2, n1, n2)                 \
+ ({                                                                    \
+       char __ret;                                                     \
+       typeof(o1) __o1 = o1;                                           \
+       typeof(o1) __n1 = n1;                                           \
+       typeof(o2) __o2 = o2;                                           \
+       typeof(o2) __n2 = n2;                                           \
+       typeof(o2) __dummy = n2;                                        \
+       asm volatile("cmpxchg8b "__percpu_arg(1)"\n\tsetz %0\n\t"       \
+                   : "=a"(__ret), "=m" (pcp1), "=d"(__dummy)           \
+                   :  "b"(__n1), "c"(__n2), "a"(__o1), "d"(__o2));     \
+       __ret;                                                          \
+ })
+ #define __this_cpu_cmpxchg_double_4(pcp1, pcp2, o1, o2, n1, n2)               percpu_cmpxchg8b_double(pcp1, o1, o2, n1, n2)
+ #define this_cpu_cmpxchg_double_4(pcp1, pcp2, o1, o2, n1, n2)         percpu_cmpxchg8b_double(pcp1, o1, o2, n1, n2)
+ #define irqsafe_cpu_cmpxchg_double_4(pcp1, pcp2, o1, o2, n1, n2)      percpu_cmpxchg8b_double(pcp1, o1, o2, n1, n2)
+ #endif /* CONFIG_X86_CMPXCHG64 */
  /*
   * Per cpu atomic 64 bit operations are only available under 64 bit.
   * 32 bit must fall back to generic operations.
  #define irqsafe_cpu_xor_8(pcp, val)   percpu_to_op("xor", (pcp), val)
  #define irqsafe_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
  #define irqsafe_cpu_cmpxchg_8(pcp, oval, nval)        percpu_cmpxchg_op(pcp, oval, nval)
+ /*
+  * Pretty complex macro to generate cmpxchg16 instruction.  The instruction
+  * is not supported on early AMD64 processors so we must be able to emulate
+  * it in software.  The address used in the cmpxchg16 instruction must be
+  * aligned to a 16 byte boundary.
+  */
+ #define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)                        \
+ ({                                                                    \
+       char __ret;                                                     \
+       typeof(o1) __o1 = o1;                                           \
+       typeof(o1) __n1 = n1;                                           \
+       typeof(o2) __o2 = o2;                                           \
+       typeof(o2) __n2 = n2;                                           \
+       typeof(o2) __dummy;                                             \
+       alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4,      \
+                      "cmpxchg16b %%gs:(%%rsi)\n\tsetz %0\n\t",        \
+                      X86_FEATURE_CX16,                                \
+                      ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)),         \
+                      "S" (&pcp1), "b"(__n1), "c"(__n2),               \
+                      "a"(__o1), "d"(__o2));                           \
+       __ret;                                                          \
+ })
+ #define __this_cpu_cmpxchg_double_8(pcp1, pcp2, o1, o2, n1, n2)               percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)
+ #define this_cpu_cmpxchg_double_8(pcp1, pcp2, o1, o2, n1, n2)         percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)
+ #define irqsafe_cpu_cmpxchg_double_8(pcp1, pcp2, o1, o2, n1, n2)      percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)
  #endif
  
  /* This is not atomic against other CPUs -- CPU preemption needs to be off */
@@@ -105,7 -105,6 +105,7 @@@ SECTION
                SCHED_TEXT
                LOCK_TEXT
                KPROBES_TEXT
 +              ENTRY_TEXT
                IRQENTRY_TEXT
                *(.fixup)
                *(.gnu.warning)
         * output PHDR, so the next output section - .init.text - should
         * start another segment - init.
         */
-       PERCPU_VADDR(0, :percpu)
+       PERCPU_VADDR(INTERNODE_CACHE_BYTES, 0, :percpu)
  #endif
  
        INIT_TEXT_SECTION(PAGE_SIZE)
        }
  
  #if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
-       PERCPU(PAGE_SIZE)
 -      PERCPU(INTERNODE_CACHE_BYTES, THREAD_SIZE)
++      PERCPU(INTERNODE_CACHE_BYTES, PAGE_SIZE)
  #endif
  
        . = ALIGN(PAGE_SIZE);
@@@ -15,7 -15,7 +15,7 @@@
   *    HEAD_TEXT_SECTION
   *    INIT_TEXT_SECTION(PAGE_SIZE)
   *    INIT_DATA_SECTION(...)
-  *    PERCPU(PAGE_SIZE)
+  *    PERCPU(CACHELINE_SIZE, PAGE_SIZE)
   *    __init_end = .;
   *
   *    _stext = .;
  #endif
  
  #ifdef CONFIG_EVENT_TRACING
 -#define FTRACE_EVENTS()       VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
 +#define FTRACE_EVENTS()       . = ALIGN(8);                                   \
 +                      VMLINUX_SYMBOL(__start_ftrace_events) = .;      \
                        *(_ftrace_events)                               \
                        VMLINUX_SYMBOL(__stop_ftrace_events) = .;
  #else
  #endif
  
  #ifdef CONFIG_FTRACE_SYSCALLS
 -#define TRACE_SYSCALLS() VMLINUX_SYMBOL(__start_syscalls_metadata) = .;       \
 +#define TRACE_SYSCALLS() . = ALIGN(8);                                        \
 +                       VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
                         *(__syscalls_metadata)                         \
                         VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
  #else
        CPU_KEEP(exit.data)                                             \
        MEM_KEEP(init.data)                                             \
        MEM_KEEP(exit.data)                                             \
 -      . = ALIGN(32);                                                  \
 -      VMLINUX_SYMBOL(__start___tracepoints) = .;                      \
 +      STRUCT_ALIGN();                                                 \
        *(__tracepoints)                                                \
 -      VMLINUX_SYMBOL(__stop___tracepoints) = .;                       \
        /* implement dynamic printk debug */                            \
        . = ALIGN(8);                                                   \
        VMLINUX_SYMBOL(__start___verbose) = .;                          \
        VMLINUX_SYMBOL(__stop___verbose) = .;                           \
        LIKELY_PROFILE()                                                \
        BRANCH_PROFILE()                                                \
 -      TRACE_PRINTKS()                                                 \
 -                                                                      \
 -      STRUCT_ALIGN();                                                 \
 -      FTRACE_EVENTS()                                                 \
 -                                                                      \
 -      STRUCT_ALIGN();                                                 \
 -      TRACE_SYSCALLS()
 +      TRACE_PRINTKS()
  
  /*
   * Data section helpers
                VMLINUX_SYMBOL(__start_rodata) = .;                     \
                *(.rodata) *(.rodata.*)                                 \
                *(__vermagic)           /* Kernel version magic */      \
 +              . = ALIGN(8);                                           \
 +              VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .;         \
 +              *(__tracepoints_ptrs)   /* Tracepoints: pointer array */\
 +              VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .;          \
                *(__markers_strings)    /* Markers: strings */          \
                *(__tracepoints_strings)/* Tracepoints: strings */      \
        }                                                               \
                *(.kprobes.text)                                        \
                VMLINUX_SYMBOL(__kprobes_text_end) = .;
  
 +#define ENTRY_TEXT                                                    \
 +              ALIGN_FUNCTION();                                       \
 +              VMLINUX_SYMBOL(__entry_text_start) = .;                 \
 +              *(.entry.text)                                          \
 +              VMLINUX_SYMBOL(__entry_text_end) = .;
 +
  #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  #define IRQENTRY_TEXT                                                 \
                ALIGN_FUNCTION();                                       \
        KERNEL_CTORS()                                                  \
        *(.init.rodata)                                                 \
        MCOUNT_REC()                                                    \
 +      FTRACE_EVENTS()                                                 \
 +      TRACE_SYSCALLS()                                                \
        DEV_DISCARD(init.rodata)                                        \
        CPU_DISCARD(init.rodata)                                        \
        MEM_DISCARD(init.rodata)                                        \
  
  /**
   * PERCPU_VADDR - define output section for percpu area
+  * @cacheline: cacheline size
   * @vaddr: explicit base address (optional)
   * @phdr: destination PHDR (optional)
   *
-  * Macro which expands to output section for percpu area.  If @vaddr
-  * is not blank, it specifies explicit base address and all percpu
-  * symbols will be offset from the given address.  If blank, @vaddr
-  * always equals @laddr + LOAD_OFFSET.
+  * Macro which expands to output section for percpu area.
+  *
+  * @cacheline is used to align subsections to avoid false cacheline
+  * sharing between subsections for different purposes.
+  *
+  * If @vaddr is not blank, it specifies explicit base address and all
+  * percpu symbols will be offset from the given address.  If blank,
+  * @vaddr always equals @laddr + LOAD_OFFSET.
   *
   * @phdr defines the output PHDR to use if not blank.  Be warned that
   * output PHDR is sticky.  If @phdr is specified, the next output
   * If there is no need to put the percpu section at a predetermined
   * address, use PERCPU().
   */
- #define PERCPU_VADDR(vaddr, phdr)                                     \
+ #define PERCPU_VADDR(cacheline, vaddr, phdr)                          \
        VMLINUX_SYMBOL(__per_cpu_load) = .;                             \
        .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load)         \
                                - LOAD_OFFSET) {                        \
                *(.data..percpu..first)                                 \
                . = ALIGN(PAGE_SIZE);                                   \
                *(.data..percpu..page_aligned)                          \
+               . = ALIGN(cacheline);                                   \
                *(.data..percpu..readmostly)                            \
+               . = ALIGN(cacheline);                                   \
                *(.data..percpu)                                        \
                *(.data..percpu..shared_aligned)                        \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
  
  /**
   * PERCPU - define output section for percpu area, simple version
+  * @cacheline: cacheline size
   * @align: required alignment
   *
-  * Align to @align and outputs output section for percpu area.  This
-  * macro doesn't maniuplate @vaddr or @phdr and __per_cpu_load and
+  * Align to @align and outputs output section for percpu area.  This macro
+  * doesn't manipulate @vaddr or @phdr and __per_cpu_load and
   * __per_cpu_start will be identical.
   *
-  * This macro is equivalent to ALIGN(align); PERCPU_VADDR( , ) except
-  * that __per_cpu_load is defined as a relative symbol against
-  * .data..percpu which is required for relocatable x86_32
-  * configuration.
+  * This macro is equivalent to ALIGN(@align); PERCPU_VADDR(@cacheline,,)
+  * except that __per_cpu_load is defined as a relative symbol against
+  * .data..percpu which is required for relocatable x86_32 configuration.
   */
- #define PERCPU(align)                                                 \
+ #define PERCPU(cacheline, align)                                      \
        . = ALIGN(align);                                               \
        .data..percpu   : AT(ADDR(.data..percpu) - LOAD_OFFSET) {       \
                VMLINUX_SYMBOL(__per_cpu_load) = .;                     \
                *(.data..percpu..first)                                 \
                . = ALIGN(PAGE_SIZE);                                   \
                *(.data..percpu..page_aligned)                          \
+               . = ALIGN(cacheline);                                   \
                *(.data..percpu..readmostly)                            \
+               . = ALIGN(cacheline);                                   \
                *(.data..percpu)                                        \
                *(.data..percpu..shared_aligned)                        \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \