]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - arch/x86/kernel/smpboot.c
Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / kernel / smpboot.c
index c3402fc30865cae73f19f828959629f6e91dbb96..ed556d50d7ed6d71f03d202ef84a6b6b54e95a02 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,15 +101,12 @@ 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;
 
 /* Maximum number of SMT threads on any online core */
-int __max_smt_threads __read_mostly;
+int __read_mostly __max_smt_threads = 1;
 
 /* Flag to indicate if a complete sched domain rebuild is required */
 bool x86_topology_update;
@@ -230,7 +228,7 @@ static void notrace start_secondary(void *unused)
        load_cr3(swapper_pg_dir);
        __flush_tlb_all();
 #endif
-
+       load_current_idt();
        cpu_init();
        x86_cpuinit.early_percpu_clock_init();
        preempt_disable();
@@ -241,19 +239,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();
@@ -270,6 +268,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
@@ -277,102 +294,23 @@ 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) {
-               pr_warn("Package %u of CPU %u exceeds BIOS package data %u.\n",
-                       logical_packages, cpu, __max_logical_packages);
-               return -ENOSPC;
-       }
-
        new = logical_packages++;
        if (new != pkg) {
                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
-        * might change in the future....
-        *
-        * While ideally we'd want '* smp_num_siblings' in the below @ncpus
-        * computation, this won't actually work since some Intel BIOSes
-        * report inconsistent HT data when they disable HT.
-        *
-        * In particular, they reduce the APIC-IDs to only include the cores,
-        * but leave the CPUID topology to say there are (2) siblings.
-        * This means we don't know how many threads there will be until
-        * after the APIC enumeration.
-        *
-        * By not including this we'll sometimes over-estimate the number of
-        * logical packages by the amount of !present siblings, but this is
-        * still better than MAX_LOCAL_APIC.
-        *
-        * We use total_cpus not nr_cpu_ids because nr_cpu_ids can be limited
-        * on the command line leading to a similar issue as the HT disable
-        * problem because the hyperthreads are usually enumerated after the
-        * primary cores.
-        */
-       ncpus = boot_cpu_data.x86_max_cores;
-       if (!ncpus) {
-               pr_warn("x86_max_cores == zero !?!?");
-               ncpus = 1;
-       }
-
-       __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);
-}
-
 void __init smp_store_boot_cpu_info(void)
 {
        int id = 0; /* CPU 0 */
@@ -380,7 +318,8 @@ void __init smp_store_boot_cpu_info(void)
 
        *c = boot_cpu_data;
        c->cpu_index = id;
-       smp_init_package_map(c, id);
+       topology_update_package_map(c->phys_proc_id, id);
+       c->initialized = true;
 }
 
 /*
@@ -391,13 +330,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
@@ -1081,7 +1023,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);
 
@@ -1177,17 +1119,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();
 
@@ -1224,16 +1159,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.
@@ -1244,29 +1169,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)
@@ -1281,9 +1183,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)
 {
@@ -1315,35 +1226,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();
@@ -1375,14 +1284,22 @@ void __init native_smp_prepare_boot_cpu(void)
 
 void __init native_smp_cpus_done(unsigned int max_cpus)
 {
+       int ncpus;
+
        pr_debug("Boot done\n");
+       /*
+        * Today neither Intel nor AMD support heterogenous systems so
+        * extrapolate the boot cpu's data to all packages.
+        */
+       ncpus = cpu_data(0).booted_cores * topology_max_smt_threads();
+       __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
+       pr_info("Max logical packages: %u\n", __max_logical_packages);
 
        if (x86_has_numa_in_package)
                set_sched_topology(x86_numa_in_package_topology);
 
        nmi_selftest();
        impress_friends();
-       setup_ioapic_dest();
        mtrr_aps_init();
 }
 
@@ -1541,13 +1458,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;