]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/x86/kernel/smpboot.c
x86/topology: Avoid wasting 128k for package id array
[linux.git] / arch / x86 / kernel / smpboot.c
index ad59edd84de70cfb978b8c0bc2ac38b892418b71..da5e162636fd636226f854e628e49bbf5d403dde 100644 (file)
@@ -77,6 +77,7 @@
 #include <asm/i8259.h>
 #include <asm/realmode.h>
 #include <asm/misc.h>
+#include <asm/qspinlock.h>
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
@@ -100,9 +101,6 @@ DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
 EXPORT_PER_CPU_SYMBOL(cpu_info);
 
 /* Logical package management. We might want to allocate that dynamically */
-static int *physical_to_logical_pkg __read_mostly;
-static unsigned long *physical_package_map __read_mostly;;
-static unsigned int max_physical_pkg_id __read_mostly;
 unsigned int __max_logical_packages __read_mostly;
 EXPORT_SYMBOL(__max_logical_packages);
 static unsigned int logical_packages __read_mostly;
@@ -193,6 +191,12 @@ static void smp_callin(void)
         */
        smp_store_cpu_info(cpuid);
 
+       /*
+        * The topology information must be up to date before
+        * calibrate_delay() and notify_cpu_starting().
+        */
+       set_cpu_sibling_map(raw_smp_processor_id());
+
        /*
         * Get our bogomips.
         * Update loops_per_jiffy in cpu_data. Previous call to
@@ -203,11 +207,6 @@ static void smp_callin(void)
        cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy;
        pr_debug("Stack at about %p\n", &cpuid);
 
-       /*
-        * This must be done before setting cpu_online_mask
-        * or calling notify_cpu_starting.
-        */
-       set_cpu_sibling_map(raw_smp_processor_id());
        wmb();
 
        notify_cpu_starting(cpuid);
@@ -249,19 +248,19 @@ static void notrace start_secondary(void *unused)
        /* otherwise gcc will move up smp_processor_id before the cpu_init */
        barrier();
        /*
-        * Check TSC synchronization with the BP:
+        * Check TSC synchronization with the boot CPU:
         */
        check_tsc_sync_target();
 
        /*
-        * Lock vector_lock and initialize the vectors on this cpu
-        * before setting the cpu online. We must set it online with
-        * vector_lock held to prevent a concurrent setup/teardown
-        * from seeing a half valid vector space.
+        * Lock vector_lock, set CPU online and bring the vector
+        * allocator online. Online must be set with vector_lock held
+        * to prevent a concurrent irq setup/teardown from seeing a
+        * half valid vector space.
         */
        lock_vector_lock();
-       setup_vector_irq(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
+       lapic_online();
        unlock_vector_lock();
        cpu_set_state_online(smp_processor_id());
        x86_platform.nmi_init();
@@ -278,6 +277,25 @@ static void notrace start_secondary(void *unused)
        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 }
 
+/**
+ * topology_phys_to_logical_pkg - Map a physical package id to a logical
+ *
+ * Returns logical package id or -1 if not found
+ */
+int topology_phys_to_logical_pkg(unsigned int phys_pkg)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+               if (c->initialized && c->phys_proc_id == phys_pkg)
+                       return c->logical_proc_id;
+       }
+       return -1;
+}
+EXPORT_SYMBOL(topology_phys_to_logical_pkg);
+
 /**
  * topology_update_package_map - Update the physical to logical package map
  * @pkg:       The physical package id as retrieved via CPUID
@@ -285,17 +303,11 @@ static void notrace start_secondary(void *unused)
  */
 int topology_update_package_map(unsigned int pkg, unsigned int cpu)
 {
-       unsigned int new;
+       int new;
 
-       /* Called from early boot ? */
-       if (!physical_package_map)
-               return 0;
-
-       if (pkg >= max_physical_pkg_id)
-               return -EINVAL;
-
-       /* Set the logical package id */
-       if (test_and_set_bit(pkg, physical_package_map))
+       /* Already available somewhere? */
+       new = topology_phys_to_logical_pkg(pkg);
+       if (new >= 0)
                goto found;
 
        if (logical_packages >= __max_logical_packages) {
@@ -309,30 +321,14 @@ int topology_update_package_map(unsigned int pkg, unsigned int cpu)
                pr_info("CPU %u Converting physical %u to logical package %u\n",
                        cpu, pkg, new);
        }
-       physical_to_logical_pkg[pkg] = new;
-
 found:
-       cpu_data(cpu).logical_proc_id = physical_to_logical_pkg[pkg];
+       cpu_data(cpu).logical_proc_id = new;
        return 0;
 }
 
-/**
- * topology_phys_to_logical_pkg - Map a physical package id to a logical
- *
- * Returns logical package id or -1 if not found
- */
-int topology_phys_to_logical_pkg(unsigned int phys_pkg)
-{
-       if (phys_pkg >= max_physical_pkg_id)
-               return -1;
-       return physical_to_logical_pkg[phys_pkg];
-}
-EXPORT_SYMBOL(topology_phys_to_logical_pkg);
-
 static void __init smp_init_package_map(struct cpuinfo_x86 *c, unsigned int cpu)
 {
        unsigned int ncpus;
-       size_t size;
 
        /*
         * Today neither Intel nor AMD support heterogenous systems. That
@@ -363,19 +359,6 @@ static void __init smp_init_package_map(struct cpuinfo_x86 *c, unsigned int cpu)
        }
 
        __max_logical_packages = DIV_ROUND_UP(total_cpus, ncpus);
-       logical_packages = 0;
-
-       /*
-        * Possibly larger than what we need as the number of apic ids per
-        * package can be smaller than the actual used apic ids.
-        */
-       max_physical_pkg_id = DIV_ROUND_UP(MAX_LOCAL_APIC, ncpus);
-       size = max_physical_pkg_id * sizeof(unsigned int);
-       physical_to_logical_pkg = kmalloc(size, GFP_KERNEL);
-       memset(physical_to_logical_pkg, 0xff, size);
-       size = BITS_TO_LONGS(max_physical_pkg_id) * sizeof(unsigned long);
-       physical_package_map = kzalloc(size, GFP_KERNEL);
-
        pr_info("Max logical packages: %u\n", __max_logical_packages);
 
        topology_update_package_map(c->phys_proc_id, cpu);
@@ -389,6 +372,7 @@ void __init smp_store_boot_cpu_info(void)
        *c = boot_cpu_data;
        c->cpu_index = id;
        smp_init_package_map(c, id);
+       c->initialized = true;
 }
 
 /*
@@ -399,13 +383,16 @@ void smp_store_cpu_info(int id)
 {
        struct cpuinfo_x86 *c = &cpu_data(id);
 
-       *c = boot_cpu_data;
+       /* Copy boot_cpu_data only on the first bringup */
+       if (!c->initialized)
+               *c = boot_cpu_data;
        c->cpu_index = id;
        /*
         * During boot time, CPU0 has this setup already. Save the info when
         * bringing up AP or offlined CPU0.
         */
        identify_secondary_cpu(c);
+       c->initialized = true;
 }
 
 static bool
@@ -961,8 +948,7 @@ void common_cpu_up(unsigned int cpu, struct task_struct *idle)
 #ifdef CONFIG_X86_32
        /* Stack for startup_32 can be just as for start_secondary onwards */
        irq_ctx_init(cpu);
-       per_cpu(cpu_current_top_of_stack, cpu) =
-               (unsigned long)task_stack_page(idle) + THREAD_SIZE;
+       per_cpu(cpu_current_top_of_stack, cpu) = task_top_of_stack(idle);
 #else
        initial_gs = per_cpu_offset(cpu);
 #endif
@@ -1094,7 +1080,7 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
        unsigned long flags;
        int err, ret = 0;
 
-       WARN_ON(irqs_disabled());
+       lockdep_assert_irqs_enabled();
 
        pr_debug("++++++++++++++++++++=_---CPU UP  %u\n", cpu);
 
@@ -1190,17 +1176,10 @@ static __init void disable_smp(void)
        cpumask_set_cpu(0, topology_core_cpumask(0));
 }
 
-enum {
-       SMP_OK,
-       SMP_NO_CONFIG,
-       SMP_NO_APIC,
-       SMP_FORCE_UP,
-};
-
 /*
  * Various sanity checks.
  */
-static int __init smp_sanity_check(unsigned max_cpus)
+static void __init smp_sanity_check(void)
 {
        preempt_disable();
 
@@ -1237,16 +1216,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
        }
 
-       /*
-        * If we couldn't find an SMP configuration at boot time,
-        * get out of here now!
-        */
-       if (!smp_found_config && !acpi_lapic) {
-               preempt_enable();
-               pr_notice("SMP motherboard not detected\n");
-               return SMP_NO_CONFIG;
-       }
-
        /*
         * Should not be necessary because the MP table should list the boot
         * CPU too, but we do it for the sake of robustness anyway.
@@ -1257,29 +1226,6 @@ static int __init smp_sanity_check(unsigned max_cpus)
                physid_set(hard_smp_processor_id(), phys_cpu_present_map);
        }
        preempt_enable();
-
-       /*
-        * If we couldn't find a local APIC, then get out of here now!
-        */
-       if (APIC_INTEGRATED(boot_cpu_apic_version) &&
-           !boot_cpu_has(X86_FEATURE_APIC)) {
-               if (!disable_apic) {
-                       pr_err("BIOS bug, local APIC #%d not detected!...\n",
-                               boot_cpu_physical_apicid);
-                       pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
-               }
-               return SMP_NO_APIC;
-       }
-
-       /*
-        * If SMP should be disabled, then really disable it!
-        */
-       if (!max_cpus) {
-               pr_info("SMP mode deactivated\n");
-               return SMP_FORCE_UP;
-       }
-
-       return SMP_OK;
 }
 
 static void __init smp_cpu_index_default(void)
@@ -1294,9 +1240,18 @@ static void __init smp_cpu_index_default(void)
        }
 }
 
+static void __init smp_get_logical_apicid(void)
+{
+       if (x2apic_mode)
+               cpu0_logical_apicid = apic_read(APIC_LDR);
+       else
+               cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
+}
+
 /*
- * Prepare for SMP bootup.  The MP table or ACPI has been read
- * earlier.  Just do some sanity checking here and enable APIC mode.
+ * Prepare for SMP bootup.
+ * @max_cpus: configured maximum number of CPUs, It is a legacy parameter
+ *            for common interface support.
  */
 void __init native_smp_prepare_cpus(unsigned int max_cpus)
 {
@@ -1328,35 +1283,33 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
 
        set_cpu_sibling_map(0);
 
-       switch (smp_sanity_check(max_cpus)) {
-       case SMP_NO_CONFIG:
-               disable_smp();
-               if (APIC_init_uniprocessor())
-                       pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
-               return;
-       case SMP_NO_APIC:
+       smp_sanity_check();
+
+       switch (apic_intr_mode) {
+       case APIC_PIC:
+       case APIC_VIRTUAL_WIRE_NO_CONFIG:
                disable_smp();
                return;
-       case SMP_FORCE_UP:
+       case APIC_SYMMETRIC_IO_NO_ROUTING:
                disable_smp();
-               apic_bsp_setup(false);
+               /* Setup local timer */
+               x86_init.timers.setup_percpu_clockev();
                return;
-       case SMP_OK:
+       case APIC_VIRTUAL_WIRE:
+       case APIC_SYMMETRIC_IO:
                break;
        }
 
-       if (read_apic_id() != boot_cpu_physical_apicid) {
-               panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
-                    read_apic_id(), boot_cpu_physical_apicid);
-               /* Or can we switch back to PIC here? */
-       }
+       /* Setup local timer */
+       x86_init.timers.setup_percpu_clockev();
 
-       default_setup_apic_routing();
-       cpu0_logical_apicid = apic_bsp_setup(false);
+       smp_get_logical_apicid();
 
        pr_info("CPU0: ");
        print_cpu_info(&cpu_data(0));
 
+       native_pv_lock_init();
+
        uv_system_init();
 
        set_mtrr_aps_delayed_init();
@@ -1395,7 +1348,6 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
 
        nmi_selftest();
        impress_friends();
-       setup_ioapic_dest();
        mtrr_aps_init();
 }
 
@@ -1554,13 +1506,14 @@ void cpu_disable_common(void)
        remove_cpu_from_maps(cpu);
        unlock_vector_lock();
        fixup_irqs();
+       lapic_offline();
 }
 
 int native_cpu_disable(void)
 {
        int ret;
 
-       ret = check_irq_vectors_for_cpu_disable();
+       ret = lapic_can_unplug_cpu();
        if (ret)
                return ret;