Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Dec 2012 03:58:29 +0000 (19:58 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 12 Dec 2012 03:58:29 +0000 (19:58 -0800)
Pull x86 topology discovery improvements from Ingo Molnar:
 "These changes improve topology discovery on AMD CPUs.

  Right now this feeds information displayed in
  /sys/devices/system/cpu/cpuX/cache/indexY/* - but in the future we
  could use this to set up a better scheduling topology."

* 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86, cacheinfo: Base cache sharing info on CPUID 0x8000001d on AMD
  x86, cacheinfo: Make use of CPUID 0x8000001d for cache information on AMD
  x86, cacheinfo: Determine number of cache leafs using CPUID 0x8000001d on AMD
  x86: Add cpu_has_topoext

1  2 
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/smpboot.c

index 1b7d1656a042ff5e1886c6fff40bbde1ff3a472d,a8538e6d2ff243cf8c377bd519c410ff7c2dfdbe..ce71a25f4523091b87bbe82781fd557fbca873c5
@@@ -304,7 -304,7 +304,7 @@@ static void __cpuinit amd_get_topology(
        int cpu = smp_processor_id();
  
        /* get information required for multi-node processors */
-       if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+       if (cpu_has_topoext) {
                u32 eax, ebx, ecx, edx;
  
                cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
@@@ -631,20 -631,6 +631,20 @@@ static void __cpuinit init_amd(struct c
                }
        }
  
 +      /*
 +       * The way access filter has a performance penalty on some workloads.
 +       * Disable it on the affected CPUs.
 +       */
 +      if ((c->x86 == 0x15) &&
 +          (c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
 +              u64 val;
 +
 +              if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) {
 +                      val |= 0x1E;
 +                      wrmsrl_safe(0xc0011021, val);
 +              }
 +      }
 +
        cpu_detect_cache_sizes(c);
  
        /* Multi core CPU? */
        detect_ht(c);
  #endif
  
-       if (c->extended_cpuid_level >= 0x80000006) {
-               if (cpuid_edx(0x80000006) & 0xf000)
-                       num_cache_leaves = 4;
-               else
-                       num_cache_leaves = 3;
-       }
+       init_amd_cacheinfo(c);
  
        if (c->x86 >= 0xf)
                set_cpu_cap(c, X86_FEATURE_K8);
index c635663b20d9abb0a9557b6b9cc41c28d34c2200,732bf5cff6456e73f3df1a76f9621e97da9b0a16..ed0fe385289d1db348aaee1bae1e9f2aa63d1c5e
@@@ -68,8 -68,6 +68,8 @@@
  #include <asm/mwait.h>
  #include <asm/apic.h>
  #include <asm/io_apic.h>
 +#include <asm/i387.h>
 +#include <asm/fpu-internal.h>
  #include <asm/setup.h>
  #include <asm/uv/uv.h>
  #include <linux/mc146818rtc.h>
@@@ -127,8 -125,8 +127,8 @@@ EXPORT_PER_CPU_SYMBOL(cpu_info)
  atomic_t init_deasserted;
  
  /*
 - * Report back to the Boot Processor.
 - * Running on AP.
 + * Report back to the Boot Processor during boot time or to the caller processor
 + * during CPU online.
   */
  static void __cpuinit smp_callin(void)
  {
         * we may get here before an INIT-deassert IPI reaches
         * our local APIC.  We have to wait for the IPI or we'll
         * lock up on an APIC access.
 +       *
 +       * Since CPU0 is not wakened up by INIT, it doesn't wait for the IPI.
         */
 -      if (apic->wait_for_init_deassert)
 +      cpuid = smp_processor_id();
 +      if (apic->wait_for_init_deassert && cpuid != 0)
                apic->wait_for_init_deassert(&init_deasserted);
  
        /*
         * (This works even if the APIC is not enabled.)
         */
        phys_id = read_apic_id();
 -      cpuid = smp_processor_id();
        if (cpumask_test_cpu(cpuid, cpu_callin_mask)) {
                panic("%s: phys CPU#%d, CPU#%d already present??\n", __func__,
                                        phys_id, cpuid);
        cpumask_set_cpu(cpuid, cpu_callin_mask);
  }
  
 +static int cpu0_logical_apicid;
 +static int enable_start_cpu0;
  /*
   * Activate a secondary processor.
   */
@@@ -249,8 -243,6 +249,8 @@@ notrace static void __cpuinit start_sec
        preempt_disable();
        smp_callin();
  
 +      enable_start_cpu0 = 0;
 +
  #ifdef CONFIG_X86_32
        /* switch away from the initial page table */
        load_cr3(swapper_pg_dir);
        cpu_idle();
  }
  
 +void __init smp_store_boot_cpu_info(void)
 +{
 +      int id = 0; /* CPU 0 */
 +      struct cpuinfo_x86 *c = &cpu_data(id);
 +
 +      *c = boot_cpu_data;
 +      c->cpu_index = id;
 +}
 +
  /*
   * The bootstrap kernel entry code has set these up. Save them for
   * a given CPU
   */
 -
  void __cpuinit smp_store_cpu_info(int id)
  {
        struct cpuinfo_x86 *c = &cpu_data(id);
  
        *c = boot_cpu_data;
        c->cpu_index = id;
 -      if (id != 0)
 -              identify_secondary_cpu(c);
 +      /*
 +       * During boot time, CPU0 has this setup already. Save the info when
 +       * bringing up AP or offlined CPU0.
 +       */
 +      identify_secondary_cpu(c);
  }
  
  static bool __cpuinit
@@@ -332,7 -313,7 +332,7 @@@ do {                                                                       
  
  static bool __cpuinit match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
  {
-       if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+       if (cpu_has_topoext) {
                int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
  
                if (c->phys_proc_id == o->phys_proc_id &&
@@@ -500,7 -481,7 +500,7 @@@ void __inquire_remote_apic(int apicid
   * won't ... remember to clear down the APIC, etc later.
   */
  int __cpuinit
 -wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
 +wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
  {
        unsigned long send_status, accept_status = 0;
        int maxlvt;
        /* Target chip */
        /* Boot on the stack */
        /* Kick the second */
 -      apic_icr_write(APIC_DM_NMI | apic->dest_logical, logical_apicid);
 +      apic_icr_write(APIC_DM_NMI | apic->dest_logical, apicid);
  
        pr_debug("Waiting for send to finish...\n");
        send_status = safe_apic_wait_icr_idle();
@@@ -668,63 -649,6 +668,63 @@@ static void __cpuinit announce_cpu(int 
                        node, cpu, apicid);
  }
  
 +static int wakeup_cpu0_nmi(unsigned int cmd, struct pt_regs *regs)
 +{
 +      int cpu;
 +
 +      cpu = smp_processor_id();
 +      if (cpu == 0 && !cpu_online(cpu) && enable_start_cpu0)
 +              return NMI_HANDLED;
 +
 +      return NMI_DONE;
 +}
 +
 +/*
 + * Wake up AP by INIT, INIT, STARTUP sequence.
 + *
 + * Instead of waiting for STARTUP after INITs, BSP will execute the BIOS
 + * boot-strap code which is not a desired behavior for waking up BSP. To
 + * void the boot-strap code, wake up CPU0 by NMI instead.
 + *
 + * This works to wake up soft offlined CPU0 only. If CPU0 is hard offlined
 + * (i.e. physically hot removed and then hot added), NMI won't wake it up.
 + * We'll change this code in the future to wake up hard offlined CPU0 if
 + * real platform and request are available.
 + */
 +static int __cpuinit
 +wakeup_cpu_via_init_nmi(int cpu, unsigned long start_ip, int apicid,
 +             int *cpu0_nmi_registered)
 +{
 +      int id;
 +      int boot_error;
 +
 +      /*
 +       * Wake up AP by INIT, INIT, STARTUP sequence.
 +       */
 +      if (cpu)
 +              return wakeup_secondary_cpu_via_init(apicid, start_ip);
 +
 +      /*
 +       * Wake up BSP by nmi.
 +       *
 +       * Register a NMI handler to help wake up CPU0.
 +       */
 +      boot_error = register_nmi_handler(NMI_LOCAL,
 +                                        wakeup_cpu0_nmi, 0, "wake_cpu0");
 +
 +      if (!boot_error) {
 +              enable_start_cpu0 = 1;
 +              *cpu0_nmi_registered = 1;
 +              if (apic->dest_logical == APIC_DEST_LOGICAL)
 +                      id = cpu0_logical_apicid;
 +              else
 +                      id = apicid;
 +              boot_error = wakeup_secondary_cpu_via_nmi(id, start_ip);
 +      }
 +
 +      return boot_error;
 +}
 +
  /*
   * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
   * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@@ -740,7 -664,6 +740,7 @@@ static int __cpuinit do_boot_cpu(int ap
  
        unsigned long boot_error = 0;
        int timeout;
 +      int cpu0_nmi_registered = 0;
  
        /* Just in case we booted with a single CPU. */
        alternatives_enable_smp();
        }
  
        /*
 -       * Kick the secondary CPU. Use the method in the APIC driver
 -       * if it's defined - or use an INIT boot APIC message otherwise:
 +       * Wake up a CPU in difference cases:
 +       * - Use the method in the APIC driver if it's defined
 +       * Otherwise,
 +       * - Use an INIT boot APIC message for APs or NMI for BSP.
         */
        if (apic->wakeup_secondary_cpu)
                boot_error = apic->wakeup_secondary_cpu(apicid, start_ip);
        else
 -              boot_error = wakeup_secondary_cpu_via_init(apicid, start_ip);
 +              boot_error = wakeup_cpu_via_init_nmi(cpu, start_ip, apicid,
 +                                                   &cpu0_nmi_registered);
  
        if (!boot_error) {
                /*
                 */
                smpboot_restore_warm_reset_vector();
        }
 +      /*
 +       * Clean up the nmi handler. Do this after the callin and callout sync
 +       * to avoid impact of possible long unregister time.
 +       */
 +      if (cpu0_nmi_registered)
 +              unregister_nmi_handler(NMI_LOCAL, "wake_cpu0");
 +
        return boot_error;
  }
  
@@@ -882,7 -795,7 +882,7 @@@ int __cpuinit native_cpu_up(unsigned in
  
        pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
  
 -      if (apicid == BAD_APICID || apicid == boot_cpu_physical_apicid ||
 +      if (apicid == BAD_APICID ||
            !physid_isset(apicid, phys_cpu_present_map) ||
            !apic->apic_id_valid(apicid)) {
                pr_err("%s: bad cpu %d\n", __func__, cpu);
  
        per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
  
 +      /* the FPU context is blank, nobody can own it */
 +      __cpu_disable_lazy_restore(cpu);
 +
        err = do_boot_cpu(apicid, cpu, tidle);
        if (err) {
                pr_debug("do_boot_cpu failed %d\n", err);
@@@ -1080,7 -990,7 +1080,7 @@@ void __init native_smp_prepare_cpus(uns
        /*
         * Setup boot CPU information
         */
 -      smp_store_cpu_info(0); /* Final full version of the data */
 +      smp_store_boot_cpu_info(); /* Final full version of the data */
        cpumask_copy(cpu_callin_mask, cpumask_of(0));
        mb();
  
         */
        setup_local_APIC();
  
 +      if (x2apic_mode)
 +              cpu0_logical_apicid = apic_read(APIC_LDR);
 +      else
 +              cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
 +
        /*
         * Enable IO APIC before setting up error vector
         */
@@@ -1309,6 -1214,19 +1309,6 @@@ void cpu_disable_common(void
  
  int native_cpu_disable(void)
  {
 -      int cpu = smp_processor_id();
 -
 -      /*
 -       * Perhaps use cpufreq to drop frequency, but that could go
 -       * into generic code.
 -       *
 -       * We won't take down the boot processor on i386 due to some
 -       * interrupts only being able to be serviced by the BSP.
 -       * Especially so if we're not using an IOAPIC   -zwane
 -       */
 -      if (cpu == 0)
 -              return -EBUSY;
 -
        clear_local_APIC();
  
        cpu_disable_common();
@@@ -1348,14 -1266,6 +1348,14 @@@ void play_dead_common(void
        local_irq_disable();
  }
  
 +static bool wakeup_cpu0(void)
 +{
 +      if (smp_processor_id() == 0 && enable_start_cpu0)
 +              return true;
 +
 +      return false;
 +}
 +
  /*
   * We need to flush the caches before going to sleep, lest we have
   * dirty data in our caches when we come back up.
@@@ -1419,11 -1329,6 +1419,11 @@@ static inline void mwait_play_dead(void
                __monitor(mwait_ptr, 0, 0);
                mb();
                __mwait(eax, 0);
 +              /*
 +               * If NMI wants to wake up CPU0, start CPU0.
 +               */
 +              if (wakeup_cpu0())
 +                      start_cpu0();
        }
  }
  
@@@ -1434,11 -1339,6 +1434,11 @@@ static inline void hlt_play_dead(void
  
        while (1) {
                native_halt();
 +              /*
 +               * If NMI wants to wake up CPU0, start CPU0.
 +               */
 +              if (wakeup_cpu0())
 +                      start_cpu0();
        }
  }