]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge commit 'v2.6.27-rc7' into x86/pebs
authorIngo Molnar <mingo@elte.hu>
Wed, 24 Sep 2008 07:56:20 +0000 (09:56 +0200)
committerIngo Molnar <mingo@elte.hu>
Wed, 24 Sep 2008 07:56:20 +0000 (09:56 +0200)
1  2 
arch/x86/Kconfig.cpu
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
include/asm-x86/processor.h

diff --combined arch/x86/Kconfig.cpu
index 468ffc2df0e00bd9de97fc8472666070e1a8efc6,b225219c448ca4cc44c7de2402b8c894e8b5da3e..60a85768cfcba7b78c15f183fe99017e35792880
@@@ -382,14 -382,17 +382,17 @@@ config X86_OOSTOR
  # P6_NOPs are a relatively minor optimization that require a family >=
  # 6 processor, except that it is broken on certain VIA chips.
  # Furthermore, AMD chips prefer a totally different sequence of NOPs
- # (which work on all CPUs).  As a result, disallow these if we're
- # compiling X86_GENERIC but not X86_64 (these NOPs do work on all
- # x86-64 capable chips); the list of processors in the right-hand clause
- # are the cores that benefit from this optimization.
+ # (which work on all CPUs).  In addition, it looks like Virtual PC
+ # does not understand them.
+ #
+ # As a result, disallow these if we're not compiling for X86_64 (these
+ # NOPs do work on all x86-64 capable chips); the list of processors in
+ # the right-hand clause are the cores that benefit from this optimization.
  #
  config X86_P6_NOP
        def_bool y
-       depends on (X86_64 || !X86_GENERIC) && (M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || MPENTIUM4 || MPSC)
+       depends on X86_64
+       depends on (MCORE2 || MPENTIUM4 || MPSC)
  
  config X86_TSC
        def_bool y
@@@ -415,21 -418,3 +418,21 @@@ config X86_MINIMUM_CPU_FAMIL
  config X86_DEBUGCTLMSR
        def_bool y
        depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
 +
 +config X86_DS
 +      bool "Debug Store support"
 +      default y
 +      help
 +        Add support for Debug Store.
 +        This allows the kernel to provide a memory buffer to the hardware
 +        to store various profiling and tracing events.
 +
 +config X86_PTRACE_BTS
 +      bool "ptrace interface to Branch Trace Store"
 +      default y
 +      depends on (X86_DS && X86_DEBUGCTLMSR)
 +      help
 +        Add a ptrace interface to allow collecting an execution trace
 +        of the traced task.
 +        This collects control flow changes in a (cyclic) buffer and allows
 +        debuggers to fill in the gaps and show an execution trace of the debuggee.
index 68f4ae2ac99a0664e2b0e2679f0b0172bae4011a,3b7a1ddcc0bce7eca8c989906fa377d4f0322f50..ae584f87d06aa66de16347e72c1a789c1ef63c4c
@@@ -95,7 -95,6 +95,6 @@@ static inline void play_dead(void
  {
        /* This must be done before dead CPU ack */
        cpu_exit_clear();
-       wbinvd();
        mb();
        /* Ack it */
        __get_cpu_var(cpu_state) = CPU_DEAD;
         * With physical CPU hotplug, we should halt the cpu
         */
        local_irq_disable();
-       while (1)
-               halt();
+       /* mask all interrupts, flush any and all caches, and halt */
+       wbinvd_halt();
  }
  #else
  static inline void play_dead(void)
@@@ -276,14 -275,6 +275,14 @@@ void exit_thread(void
                tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
                put_cpu();
        }
 +#ifdef CONFIG_X86_DS
 +      /* Free any DS contexts that have not been properly released. */
 +      if (unlikely(current->thread.ds_ctx)) {
 +              /* we clear debugctl to make sure DS is not used. */
 +              update_debugctlmsr(0);
 +              ds_free(current->thread.ds_ctx);
 +      }
 +#endif /* CONFIG_X86_DS */
  }
  
  void flush_thread(void)
@@@ -445,35 -436,6 +444,35 @@@ int set_tsc_mode(unsigned int val
        return 0;
  }
  
 +#ifdef CONFIG_X86_DS
 +static int update_debugctl(struct thread_struct *prev,
 +                      struct thread_struct *next, unsigned long debugctl)
 +{
 +      unsigned long ds_prev = 0;
 +      unsigned long ds_next = 0;
 +
 +      if (prev->ds_ctx)
 +              ds_prev = (unsigned long)prev->ds_ctx->ds;
 +      if (next->ds_ctx)
 +              ds_next = (unsigned long)next->ds_ctx->ds;
 +
 +      if (ds_next != ds_prev) {
 +              /* we clear debugctl to make sure DS
 +               * is not in use when we change it */
 +              debugctl = 0;
 +              update_debugctlmsr(0);
 +              wrmsr(MSR_IA32_DS_AREA, ds_next, 0);
 +      }
 +      return debugctl;
 +}
 +#else
 +static int update_debugctl(struct thread_struct *prev,
 +                      struct thread_struct *next, unsigned long debugctl)
 +{
 +      return debugctl;
 +}
 +#endif /* CONFIG_X86_DS */
 +
  static noinline void
  __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
                 struct tss_struct *tss)
        prev = &prev_p->thread;
        next = &next_p->thread;
  
 -      debugctl = prev->debugctlmsr;
 -      if (next->ds_area_msr != prev->ds_area_msr) {
 -              /* we clear debugctl to make sure DS
 -               * is not in use when we change it */
 -              debugctl = 0;
 -              update_debugctlmsr(0);
 -              wrmsr(MSR_IA32_DS_AREA, next->ds_area_msr, 0);
 -      }
 +      debugctl = update_debugctl(prev, next, prev->debugctlmsr);
  
        if (next->debugctlmsr != debugctl)
                update_debugctlmsr(next->debugctlmsr);
                        hard_enable_TSC();
        }
  
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
        if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
  
        if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
 -#endif
 +#endif /* CONFIG_X86_PTRACE_BTS */
  
  
        if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
index 91ffce47af8ec5401e8be094b39774f8dc843c57,71553b664e2af8601361a9af3413599b752a3e5c..30ce4734edaa0b672926649f20455ed8895a85a9
@@@ -93,14 -93,13 +93,13 @@@ DECLARE_PER_CPU(int, cpu_state)
  static inline void play_dead(void)
  {
        idle_task_exit();
-       wbinvd();
        mb();
        /* Ack it */
        __get_cpu_var(cpu_state) = CPU_DEAD;
  
        local_irq_disable();
-       while (1)
-               halt();
+       /* mask all interrupts, flush any and all caches, and halt */
+       wbinvd_halt();
  }
  #else
  static inline void play_dead(void)
@@@ -239,14 -238,6 +238,14 @@@ void exit_thread(void
                t->io_bitmap_max = 0;
                put_cpu();
        }
 +#ifdef CONFIG_X86_DS
 +      /* Free any DS contexts that have not been properly released. */
 +      if (unlikely(t->ds_ctx)) {
 +              /* we clear debugctl to make sure DS is not used. */
 +              update_debugctlmsr(0);
 +              ds_free(t->ds_ctx);
 +      }
 +#endif /* CONFIG_X86_DS */
  }
  
  void flush_thread(void)
@@@ -480,27 -471,13 +479,27 @@@ static inline void __switch_to_xtra(str
        next = &next_p->thread;
  
        debugctl = prev->debugctlmsr;
 -      if (next->ds_area_msr != prev->ds_area_msr) {
 -              /* we clear debugctl to make sure DS
 -               * is not in use when we change it */
 -              debugctl = 0;
 -              update_debugctlmsr(0);
 -              wrmsrl(MSR_IA32_DS_AREA, next->ds_area_msr);
 +
 +#ifdef CONFIG_X86_DS
 +      {
 +              unsigned long ds_prev = 0, ds_next = 0;
 +
 +              if (prev->ds_ctx)
 +                      ds_prev = (unsigned long)prev->ds_ctx->ds;
 +              if (next->ds_ctx)
 +                      ds_next = (unsigned long)next->ds_ctx->ds;
 +
 +              if (ds_next != ds_prev) {
 +                      /*
 +                       * We clear debugctl to make sure DS
 +                       * is not in use when we change it:
 +                       */
 +                      debugctl = 0;
 +                      update_debugctlmsr(0);
 +                      wrmsrl(MSR_IA32_DS_AREA, ds_next);
 +              }
        }
 +#endif /* CONFIG_X86_DS */
  
        if (next->debugctlmsr != debugctl)
                update_debugctlmsr(next->debugctlmsr);
                memset(tss->io_bitmap, 0xff, prev->io_bitmap_max);
        }
  
 -#ifdef X86_BTS
 +#ifdef CONFIG_X86_PTRACE_BTS
        if (test_tsk_thread_flag(prev_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(prev_p, BTS_TASK_DEPARTS);
  
        if (test_tsk_thread_flag(next_p, TIF_BTS_TRACE_TS))
                ptrace_bts_take_timestamp(next_p, BTS_TASK_ARRIVES);
 -#endif
 +#endif /* CONFIG_X86_PTRACE_BTS */
  }
  
  /*
index ec09649c01f356f7c37a27857b99a3dba7588bd4,4df3e2f6fb563f2039cbc90aa4016dce9cf9274c..b9d6e51a6fe46ff0c256ea1b7a4815afe23740ae
@@@ -20,7 -20,6 +20,7 @@@ struct mm_struct
  #include <asm/msr.h>
  #include <asm/desc_defs.h>
  #include <asm/nops.h>
 +#include <asm/ds.h>
  
  #include <linux/personality.h>
  #include <linux/cpumask.h>
@@@ -412,14 -411,9 +412,14 @@@ struct thread_struct 
        unsigned                io_bitmap_max;
  /* MSR_IA32_DEBUGCTLMSR value to switch in if TIF_DEBUGCTLMSR is set.  */
        unsigned long   debugctlmsr;
 -/* Debug Store - if not 0 points to a DS Save Area configuration;
 - *               goes into MSR_IA32_DS_AREA */
 -      unsigned long   ds_area_msr;
 +#ifdef CONFIG_X86_DS
 +/* Debug Store context; see include/asm-x86/ds.h; goes into MSR_IA32_DS_AREA */
 +      struct ds_context       *ds_ctx;
 +#endif /* CONFIG_X86_DS */
 +#ifdef CONFIG_X86_PTRACE_BTS
 +/* the signal to send on a bts buffer overflow */
 +      unsigned int    bts_ovfl_signal;
 +#endif /* CONFIG_X86_PTRACE_BTS */
  };
  
  static inline unsigned long native_get_debugreg(int regno)
@@@ -734,6 -728,29 +734,29 @@@ extern unsigned long             boot_option_idle_
  extern unsigned long          idle_halt;
  extern unsigned long          idle_nomwait;
  
+ /*
+  * on systems with caches, caches must be flashed as the absolute
+  * last instruction before going into a suspended halt.  Otherwise,
+  * dirty data can linger in the cache and become stale on resume,
+  * leading to strange errors.
+  *
+  * perform a variety of operations to guarantee that the compiler
+  * will not reorder instructions.  wbinvd itself is serializing
+  * so the processor will not reorder.
+  *
+  * Systems without cache can just go into halt.
+  */
+ static inline void wbinvd_halt(void)
+ {
+       mb();
+       /* check for clflush to determine if wbinvd is legal */
+       if (cpu_has_clflush)
+               asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory");
+       else
+               while (1)
+                       halt();
+ }
  extern void enable_sep_cpu(void);
  extern int sysenter_setup(void);