Commit d63107fa authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Dave Hansen
Browse files

x86/apic: Register boot CPU APIC early



Register the boot CPU APIC right when the boot CPUs APIC is read from the
hardware. No point is doing this on random places and having wild
heuristics to save the boot CPU APIC ID slot and CPU number 0 reserved.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: default avatarMichael Kelley <mikelley@microsoft.com>
Tested-by: default avatarSohil Mehta <sohil.mehta@intel.com>
Tested-by: Juergen Gross <jgross@suse.com> # Xen PV (dom0 and unpriv. guest)
parent d10a9044
Loading
Loading
Loading
Loading
+50 −70
Original line number Diff line number Diff line
@@ -1734,6 +1734,8 @@ void apic_ap_setup(void)
	end_local_APIC_setup();
}

static __init void cpu_set_boot_apic(void);

static __init void apic_read_boot_cpu_id(bool x2apic)
{
	/*
@@ -1748,9 +1750,9 @@ static __init void apic_read_boot_cpu_id(bool x2apic)
		boot_cpu_physical_apicid = read_apic_id();
		boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
	}
	cpu_set_boot_apic();
}


#ifdef CONFIG_X86_X2APIC
int x2apic_mode;
EXPORT_SYMBOL_GPL(x2apic_mode);
@@ -2426,18 +2428,53 @@ static int allocate_logical_cpuid(int apicid)
	return nr_logical_cpuids++;
}

static void cpu_update_apic(int cpu, int apicid, int version)
{
	if (version == 0x0) {
		pr_warn("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n",
			cpu, apicid);
		version = 0x10;
	}

	if (version != boot_cpu_apic_version) {
		pr_warn("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n",
			boot_cpu_apic_version, cpu, version);
	}

#if defined(CONFIG_SMP) || defined(CONFIG_X86_64)
	early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
#endif
#ifdef CONFIG_X86_32
	early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
		apic->x86_32_early_logical_apicid(cpu);
#endif
	set_cpu_possible(cpu, true);
	physid_set(apicid, phys_cpu_present_map);
	set_cpu_present(cpu, true);
	num_processors++;

	if (system_state != SYSTEM_BOOTING)
		cpu_mark_primary_thread(cpu, apicid);
}

static __init void cpu_set_boot_apic(void)
{
	cpuid_to_apicid[0] = boot_cpu_physical_apicid;
	cpu_update_apic(0, boot_cpu_physical_apicid, boot_cpu_apic_version);
}

int generic_processor_info(int apicid, int version)
{
	int cpu, max = nr_cpu_ids;
	bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid,
				phys_cpu_present_map);

	/*
	 * boot_cpu_physical_apicid is guaranteed to contain the boot CPU
	 * APIC ID read from the local APIC when this function is invoked.
	 */
	if (disabled_cpu_apicid != boot_cpu_physical_apicid &&
	    disabled_cpu_apicid == apicid) {
	/* The boot CPU must be set before MADT/MPTABLE parsing happens */
	if (cpuid_to_apicid[0] == BAD_APICID)
		panic("Boot CPU APIC not registered yet\n");

	if (apicid == boot_cpu_physical_apicid)
		return 0;

	if (disabled_cpu_apicid == apicid) {
		int thiscpu = num_processors + disabled_cpus;

		pr_warn("APIC: Disabling requested cpu. Processor %d/0x%x ignored.\n",
@@ -2447,22 +2484,6 @@ int generic_processor_info(int apicid, int version)
		return -ENODEV;
	}

	/*
	 * If boot cpu has not been detected yet, then only allow upto
	 * nr_cpu_ids - 1 processors and keep one slot free for boot cpu
	 */
	if (!boot_cpu_detected && num_processors >= nr_cpu_ids - 1 &&
	    apicid != boot_cpu_physical_apicid) {
		int thiscpu = max + disabled_cpus - 1;

		pr_warn("APIC: NR_CPUS/possible_cpus limit of %i almost"
			" reached. Keeping one slot for boot cpu."
			"  Processor %d/0x%x ignored.\n", max, thiscpu, apicid);

		disabled_cpus++;
		return -ENODEV;
	}

	if (num_processors >= nr_cpu_ids) {
		int thiscpu = max + disabled_cpus;

@@ -2473,58 +2494,17 @@ int generic_processor_info(int apicid, int version)
		return -EINVAL;
	}

	if (apicid == boot_cpu_physical_apicid) {
		/*
		 * x86_cpu_to_apicid is required to have processors listed
		 * in same order as logical cpu numbers. Hence the first
		 * entry is BSP, and so on.
		 * boot_cpu_init() already hold bit 0 in cpu_present_mask
		 * for BSP.
		 */
		cpu = 0;

		/* Logical cpuid 0 is reserved for BSP. */
		cpuid_to_apicid[0] = apicid;
	} else {
	cpu = allocate_logical_cpuid(apicid);
	if (cpu < 0) {
		disabled_cpus++;
		return -EINVAL;
	}
	}

	/*
	 * Validate version
	 */
	if (version == 0x0) {
		pr_warn("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n",
			cpu, apicid);
		version = 0x10;
	}

	if (version != boot_cpu_apic_version) {
		pr_warn("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n",
			boot_cpu_apic_version, cpu, version);
	}

#if defined(CONFIG_SMP) || defined(CONFIG_X86_64)
	early_per_cpu(x86_cpu_to_apicid, cpu) = apicid;
#endif
#ifdef CONFIG_X86_32
	early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
		apic->x86_32_early_logical_apicid(cpu);
#endif
	set_cpu_possible(cpu, true);
	physid_set(apicid, phys_cpu_present_map);
	set_cpu_present(cpu, true);
	num_processors++;

	if (system_state != SYSTEM_BOOTING)
		cpu_mark_primary_thread(cpu, apicid);

	cpu_update_apic(cpu, apicid, version);
	return cpu;
}


void __irq_msi_compose_msg(struct irq_cfg *cfg, struct msi_msg *msg,
			   bool dmar)
{