Merge branch 'x86-percpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
Linus Torvalds [Mon, 14 Sep 2009 15:01:28 +0000 (08:01 -0700)]
* 'x86-percpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, percpu: Collect hot percpu variables into one cacheline
  x86, percpu: Fix DECLARE/DEFINE_PER_CPU_PAGE_ALIGNED()
  x86, percpu: Add 'percpu_read_stable()' interface for cacheable accesses

1  2 
arch/x86/include/asm/thread_info.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
include/linux/percpu-defs.h

@@@ -95,7 -95,7 +95,7 @@@ struct thread_info 
  #define TIF_DEBUGCTLMSR               25      /* uses thread_struct.debugctlmsr */
  #define TIF_DS_AREA_MSR               26      /* uses thread_struct.ds_area_msr */
  #define TIF_LAZY_MMU_UPDATES  27      /* task is updating the mmu lazily */
 -#define TIF_SYSCALL_FTRACE    28      /* for ftrace syscall instrumentation */
 +#define TIF_SYSCALL_TRACEPOINT        28      /* syscall tracepoint instrumentation */
  
  #define _TIF_SYSCALL_TRACE    (1 << TIF_SYSCALL_TRACE)
  #define _TIF_NOTIFY_RESUME    (1 << TIF_NOTIFY_RESUME)
  #define _TIF_DEBUGCTLMSR      (1 << TIF_DEBUGCTLMSR)
  #define _TIF_DS_AREA_MSR      (1 << TIF_DS_AREA_MSR)
  #define _TIF_LAZY_MMU_UPDATES (1 << TIF_LAZY_MMU_UPDATES)
 -#define _TIF_SYSCALL_FTRACE   (1 << TIF_SYSCALL_FTRACE)
 +#define _TIF_SYSCALL_TRACEPOINT       (1 << TIF_SYSCALL_TRACEPOINT)
  
  /* work to do in syscall_trace_enter() */
  #define _TIF_WORK_SYSCALL_ENTRY       \
 -      (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_FTRACE |  \
 -       _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP)
 +      (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT |   \
 +       _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
  
  /* work to do in syscall_trace_leave() */
  #define _TIF_WORK_SYSCALL_EXIT        \
        (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP |    \
 -       _TIF_SYSCALL_FTRACE)
 +       _TIF_SYSCALL_TRACEPOINT)
  
  /* work to do on interrupt/exception return */
  #define _TIF_WORK_MASK                                                        \
           _TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU))
  
  /* work to do on any return to user space */
 -#define _TIF_ALLWORK_MASK ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE)
 +#define _TIF_ALLWORK_MASK                                             \
 +      ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT)
  
  /* Only used for 64 bit */
  #define _TIF_DO_NOTIFY_MASK                                           \
@@@ -214,7 -213,7 +214,7 @@@ DECLARE_PER_CPU(unsigned long, kernel_s
  static inline struct thread_info *current_thread_info(void)
  {
        struct thread_info *ti;
-       ti = (void *)(percpu_read(kernel_stack) +
+       ti = (void *)(percpu_read_stable(kernel_stack) +
                      KERNEL_STACK_OFFSET - THREAD_SIZE);
        return ti;
  }
@@@ -18,8 -18,8 +18,8 @@@
  #include <asm/hypervisor.h>
  #include <asm/processor.h>
  #include <asm/sections.h>
 -#include <asm/topology.h>
 -#include <asm/cpumask.h>
 +#include <linux/topology.h>
 +#include <linux/cpumask.h>
  #include <asm/pgtable.h>
  #include <asm/atomic.h>
  #include <asm/proto.h>
  #include <asm/desc.h>
  #include <asm/i387.h>
  #include <asm/mtrr.h>
 -#include <asm/numa.h>
 +#include <linux/numa.h>
  #include <asm/asm.h>
  #include <asm/cpu.h>
  #include <asm/mce.h>
  #include <asm/msr.h>
  #include <asm/pat.h>
 -#include <asm/smp.h>
 +#include <linux/smp.h>
  
  #ifdef CONFIG_X86_LOCAL_APIC
  #include <asm/uv/uv.h>
@@@ -59,30 -59,7 +59,30 @@@ void __init setup_cpu_local_masks(void
        alloc_bootmem_cpumask_var(&cpu_sibling_setup_mask);
  }
  
 -static const struct cpu_dev *this_cpu __cpuinitdata;
 +static void __cpuinit default_init(struct cpuinfo_x86 *c)
 +{
 +#ifdef CONFIG_X86_64
 +      display_cacheinfo(c);
 +#else
 +      /* Not much we can do here... */
 +      /* Check if at least it has cpuid */
 +      if (c->cpuid_level == -1) {
 +              /* No cpuid. It must be an ancient CPU */
 +              if (c->x86 == 4)
 +                      strcpy(c->x86_model_id, "486");
 +              else if (c->x86 == 3)
 +                      strcpy(c->x86_model_id, "386");
 +      }
 +#endif
 +}
 +
 +static const struct cpu_dev __cpuinitconst default_cpu = {
 +      .c_init         = default_init,
 +      .c_vendor       = "Unknown",
 +      .c_x86_vendor   = X86_VENDOR_UNKNOWN,
 +};
 +
 +static const struct cpu_dev *this_cpu __cpuinitdata = &default_cpu;
  
  DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = {
  #ifdef CONFIG_X86_64
         * TLS descriptors are currently at a different place compared to i386.
         * Hopefully nobody expects them at a fixed place (Wine?)
         */
 -      [GDT_ENTRY_KERNEL32_CS]         = { { { 0x0000ffff, 0x00cf9b00 } } },
 -      [GDT_ENTRY_KERNEL_CS]           = { { { 0x0000ffff, 0x00af9b00 } } },
 -      [GDT_ENTRY_KERNEL_DS]           = { { { 0x0000ffff, 0x00cf9300 } } },
 -      [GDT_ENTRY_DEFAULT_USER32_CS]   = { { { 0x0000ffff, 0x00cffb00 } } },
 -      [GDT_ENTRY_DEFAULT_USER_DS]     = { { { 0x0000ffff, 0x00cff300 } } },
 -      [GDT_ENTRY_DEFAULT_USER_CS]     = { { { 0x0000ffff, 0x00affb00 } } },
 +      [GDT_ENTRY_KERNEL32_CS]         = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff),
 +      [GDT_ENTRY_KERNEL_CS]           = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff),
 +      [GDT_ENTRY_KERNEL_DS]           = GDT_ENTRY_INIT(0xc093, 0, 0xfffff),
 +      [GDT_ENTRY_DEFAULT_USER32_CS]   = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff),
 +      [GDT_ENTRY_DEFAULT_USER_DS]     = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff),
 +      [GDT_ENTRY_DEFAULT_USER_CS]     = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff),
  #else
 -      [GDT_ENTRY_KERNEL_CS]           = { { { 0x0000ffff, 0x00cf9a00 } } },
 -      [GDT_ENTRY_KERNEL_DS]           = { { { 0x0000ffff, 0x00cf9200 } } },
 -      [GDT_ENTRY_DEFAULT_USER_CS]     = { { { 0x0000ffff, 0x00cffa00 } } },
 -      [GDT_ENTRY_DEFAULT_USER_DS]     = { { { 0x0000ffff, 0x00cff200 } } },
 +      [GDT_ENTRY_KERNEL_CS]           = GDT_ENTRY_INIT(0xc09a, 0, 0xfffff),
 +      [GDT_ENTRY_KERNEL_DS]           = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
 +      [GDT_ENTRY_DEFAULT_USER_CS]     = GDT_ENTRY_INIT(0xc0fa, 0, 0xfffff),
 +      [GDT_ENTRY_DEFAULT_USER_DS]     = GDT_ENTRY_INIT(0xc0f2, 0, 0xfffff),
        /*
         * Segments used for calling PnP BIOS have byte granularity.
         * They code segments and data segments have fixed 64k limits,
         * the transfer segment sizes are set at run time.
         */
        /* 32-bit code */
 -      [GDT_ENTRY_PNPBIOS_CS32]        = { { { 0x0000ffff, 0x00409a00 } } },
 +      [GDT_ENTRY_PNPBIOS_CS32]        = GDT_ENTRY_INIT(0x409a, 0, 0xffff),
        /* 16-bit code */
 -      [GDT_ENTRY_PNPBIOS_CS16]        = { { { 0x0000ffff, 0x00009a00 } } },
 +      [GDT_ENTRY_PNPBIOS_CS16]        = GDT_ENTRY_INIT(0x009a, 0, 0xffff),
        /* 16-bit data */
 -      [GDT_ENTRY_PNPBIOS_DS]          = { { { 0x0000ffff, 0x00009200 } } },
 +      [GDT_ENTRY_PNPBIOS_DS]          = GDT_ENTRY_INIT(0x0092, 0, 0xffff),
        /* 16-bit data */
 -      [GDT_ENTRY_PNPBIOS_TS1]         = { { { 0x00000000, 0x00009200 } } },
 +      [GDT_ENTRY_PNPBIOS_TS1]         = GDT_ENTRY_INIT(0x0092, 0, 0),
        /* 16-bit data */
 -      [GDT_ENTRY_PNPBIOS_TS2]         = { { { 0x00000000, 0x00009200 } } },
 +      [GDT_ENTRY_PNPBIOS_TS2]         = GDT_ENTRY_INIT(0x0092, 0, 0),
        /*
         * The APM segments have byte granularity and their bases
         * are set at run time.  All have 64k limits.
         */
        /* 32-bit code */
 -      [GDT_ENTRY_APMBIOS_BASE]        = { { { 0x0000ffff, 0x00409a00 } } },
 +      [GDT_ENTRY_APMBIOS_BASE]        = GDT_ENTRY_INIT(0x409a, 0, 0xffff),
        /* 16-bit code */
 -      [GDT_ENTRY_APMBIOS_BASE+1]      = { { { 0x0000ffff, 0x00009a00 } } },
 +      [GDT_ENTRY_APMBIOS_BASE+1]      = GDT_ENTRY_INIT(0x009a, 0, 0xffff),
        /* data */
 -      [GDT_ENTRY_APMBIOS_BASE+2]      = { { { 0x0000ffff, 0x00409200 } } },
 +      [GDT_ENTRY_APMBIOS_BASE+2]      = GDT_ENTRY_INIT(0x4092, 0, 0xffff),
  
 -      [GDT_ENTRY_ESPFIX_SS]           = { { { 0x0000ffff, 0x00cf9200 } } },
 -      [GDT_ENTRY_PERCPU]              = { { { 0x0000ffff, 0x00cf9200 } } },
 +      [GDT_ENTRY_ESPFIX_SS]           = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
 +      [GDT_ENTRY_PERCPU]              = GDT_ENTRY_INIT(0xc092, 0, 0xfffff),
        GDT_STACK_CANARY_INIT
  #endif
  } };
@@@ -355,6 -332,29 +355,6 @@@ void switch_to_new_gdt(int cpu
  
  static const struct cpu_dev *__cpuinitdata cpu_devs[X86_VENDOR_NUM] = {};
  
 -static void __cpuinit default_init(struct cpuinfo_x86 *c)
 -{
 -#ifdef CONFIG_X86_64
 -      display_cacheinfo(c);
 -#else
 -      /* Not much we can do here... */
 -      /* Check if at least it has cpuid */
 -      if (c->cpuid_level == -1) {
 -              /* No cpuid. It must be an ancient CPU */
 -              if (c->x86 == 4)
 -                      strcpy(c->x86_model_id, "486");
 -              else if (c->x86 == 3)
 -                      strcpy(c->x86_model_id, "386");
 -      }
 -#endif
 -}
 -
 -static const struct cpu_dev __cpuinitconst default_cpu = {
 -      .c_init = default_init,
 -      .c_vendor = "Unknown",
 -      .c_x86_vendor = X86_VENDOR_UNKNOWN,
 -};
 -
  static void __cpuinit get_model_name(struct cpuinfo_x86 *c)
  {
        unsigned int *v;
@@@ -982,18 -982,26 +982,26 @@@ static __init int setup_disablecpuid(ch
  __setup("clearcpuid=", setup_disablecpuid);
  
  #ifdef CONFIG_X86_64
 -struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table };
 +struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table };
  
  DEFINE_PER_CPU_FIRST(union irq_stack_union,
                     irq_stack_union) __aligned(PAGE_SIZE);
  
- DEFINE_PER_CPU(char *, irq_stack_ptr) =
-       init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
+ /*
+  * The following four percpu variables are hot.  Align current_task to
+  * cacheline size such that all four fall in the same cacheline.
+  */
+ DEFINE_PER_CPU(struct task_struct *, current_task) ____cacheline_aligned =
+       &init_task;
+ EXPORT_PER_CPU_SYMBOL(current_task);
  
  DEFINE_PER_CPU(unsigned long, kernel_stack) =
        (unsigned long)&init_thread_union - KERNEL_STACK_OFFSET + THREAD_SIZE;
  EXPORT_PER_CPU_SYMBOL(kernel_stack);
  
+ DEFINE_PER_CPU(char *, irq_stack_ptr) =
+       init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
  DEFINE_PER_CPU(unsigned int, irq_count) = -1;
  
  /*
@@@ -1008,8 -1016,7 +1016,7 @@@ static const unsigned int exception_sta
  };
  
  static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
-       [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ])
-       __aligned(PAGE_SIZE);
+       [(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
  
  /* May not be marked __init: used by software suspend */
  void syscall_init(void)
@@@ -1042,8 -1049,11 +1049,11 @@@ DEFINE_PER_CPU(struct orig_ist, orig_is
  
  #else /* CONFIG_X86_64 */
  
+ DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
+ EXPORT_PER_CPU_SYMBOL(current_task);
  #ifdef CONFIG_CC_STACKPROTECTOR
 -DEFINE_PER_CPU(unsigned long, stack_canary);
 +DEFINE_PER_CPU_ALIGNED(struct stack_canary, stack_canary);
  #endif
  
  /* Make sure %fs and %gs are initialized properly in idle threads */
@@@ -61,9 -61,6 +61,6 @@@
  
  asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  
- DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
- EXPORT_PER_CPU_SYMBOL(current_task);
  /*
   * Return saved PC of a blocked thread.
   */
@@@ -350,21 -347,14 +347,21 @@@ __switch_to(struct task_struct *prev_p
                                 *next = &next_p->thread;
        int cpu = smp_processor_id();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
 +      bool preload_fpu;
  
        /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
  
 -      __unlazy_fpu(prev_p);
 +      /*
 +       * If the task has used fpu the last 5 timeslices, just do a full
 +       * restore of the math state immediately to avoid the trap; the
 +       * chances of needing FPU soon are obviously high now
 +       */
 +      preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
  
 +      __unlazy_fpu(prev_p);
  
        /* we're going to use this soon, after a few expensive things */
 -      if (next_p->fpu_counter > 5)
 +      if (preload_fpu)
                prefetch(next->xstate);
  
        /*
                     task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT))
                __switch_to_xtra(prev_p, next_p, tss);
  
 +      /* If we're going to preload the fpu context, make sure clts
 +         is run while we're batching the cpu state updates. */
 +      if (preload_fpu)
 +              clts();
 +
        /*
         * Leave lazy mode, flushing any hypercalls made here.
         * This must be done before restoring TLS segments so
         */
        arch_end_context_switch(next_p);
  
 -      /* If the task has used fpu the last 5 timeslices, just do a full
 -       * restore of the math state immediately to avoid the trap; the
 -       * chances of needing FPU soon are obviously high now
 -       *
 -       * tsk_used_math() checks prevent calling math_state_restore(),
 -       * which can sleep in the case of !tsk_used_math()
 -       */
 -      if (tsk_used_math(next_p) && next_p->fpu_counter > 5)
 -              math_state_restore();
 +      if (preload_fpu)
 +              __math_state_restore();
  
        /*
         * Restore %gs if needed (which is common)
@@@ -55,9 -55,6 +55,6 @@@
  
  asmlinkage extern void ret_from_fork(void);
  
- DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
- EXPORT_PER_CPU_SYMBOL(current_task);
  DEFINE_PER_CPU(unsigned long, old_rsp);
  static DEFINE_PER_CPU(unsigned char, is_idle);
  
@@@ -386,17 -383,9 +383,17 @@@ __switch_to(struct task_struct *prev_p
        int cpu = smp_processor_id();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
        unsigned fsindex, gsindex;
 +      bool preload_fpu;
 +
 +      /*
 +       * If the task has used fpu the last 5 timeslices, just do a full
 +       * restore of the math state immediately to avoid the trap; the
 +       * chances of needing FPU soon are obviously high now
 +       */
 +      preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
  
        /* we're going to use this soon, after a few expensive things */
 -      if (next_p->fpu_counter > 5)
 +      if (preload_fpu)
                prefetch(next->xstate);
  
        /*
  
        load_TLS(next, cpu);
  
 +      /* Must be after DS reload */
 +      unlazy_fpu(prev_p);
 +
 +      /* Make sure cpu is ready for new context */
 +      if (preload_fpu)
 +              clts();
 +
        /*
         * Leave lazy mode, flushing any hypercalls made here.
         * This must be done before restoring TLS segments so
                wrmsrl(MSR_KERNEL_GS_BASE, next->gs);
        prev->gsindex = gsindex;
  
 -      /* Must be after DS reload */
 -      unlazy_fpu(prev_p);
 -
        /*
         * Switch the PDA and FPU contexts.
         */
                     task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV))
                __switch_to_xtra(prev_p, next_p, tss);
  
 -      /* If the task has used fpu the last 5 timeslices, just do a full
 -       * restore of the math state immediately to avoid the trap; the
 -       * chances of needing FPU soon are obviously high now
 -       *
 -       * tsk_used_math() checks prevent calling math_state_restore(),
 -       * which can sleep in the case of !tsk_used_math()
 +      /*
 +       * Preload the FPU context, now that we've determined that the
 +       * task is likely to be using it. 
         */
 -      if (tsk_used_math(next_p) && next_p->fpu_counter > 5)
 -              math_state_restore();
 +      if (preload_fpu)
 +              __math_state_restore();
        return prev_p;
  }
  
        DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \
        ____cacheline_aligned_in_smp
  
 +#define DECLARE_PER_CPU_ALIGNED(type, name)                           \
 +      DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION)    \
 +      ____cacheline_aligned
 +
 +#define DEFINE_PER_CPU_ALIGNED(type, name)                            \
 +      DEFINE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION)     \
 +      ____cacheline_aligned
 +
  /*
   * Declaration/definition used for per-CPU variables that must be page aligned.
   */
- #define DECLARE_PER_CPU_PAGE_ALIGNED(type, name)                              \
-       DECLARE_PER_CPU_SECTION(type, name, ".page_aligned")
+ #define DECLARE_PER_CPU_PAGE_ALIGNED(type, name)                      \
+       DECLARE_PER_CPU_SECTION(type, name, ".page_aligned")            \
+       __aligned(PAGE_SIZE)
  
  #define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)                               \
-       DEFINE_PER_CPU_SECTION(type, name, ".page_aligned")
+       DEFINE_PER_CPU_SECTION(type, name, ".page_aligned")             \
+       __aligned(PAGE_SIZE)
  
  /*
   * Intermodule exports for per-CPU variables.