mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
c5f12fdb8b
Pull x86 apic updates from Thomas Gleixner: - Cleanup the apic IPI implementation by removing duplicated code and consolidating the functions into the APIC core. - Implement a safe variant of the IPI broadcast mode. Contrary to earlier attempts this uses the core tracking of which CPUs have been brought online at least once so that a broadcast does not end up in some dead end in BIOS/SMM code when the CPU is still waiting for init. Once all CPUs have been brought up once, IPI broadcasting is enabled. Before that regular one by one IPIs are issued. - Drop the paravirt CR8 related functions as they have no user anymore - Initialize the APIC TPR to block interrupt 16-31 as they are reserved for CPU exceptions and should never be raised by any well behaving device. - Emit a warning when vector space exhaustion breaks the admin set affinity of an interrupt. - Make sure to use the NMI fallback when shutdown via reboot vector IPI fails. The original code had conditions which prevent the code path to be reached. - Annotate various APIC config variables as RO after init. [ The ipi broadcase change came in earlier through the cpu hotplug branch, but I left the explanation in the commit message since it was shared between the two different branches - Linus ] * 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (28 commits) x86/apic/vector: Warn when vector space exhaustion breaks affinity x86/apic: Annotate global config variables as "read-only after init" x86/apic/x2apic: Implement IPI shorthands support x86/apic/flat64: Remove the IPI shorthand decision logic x86/apic: Share common IPI helpers x86/apic: Remove the shorthand decision logic x86/smp: Enhance native_send_call_func_ipi() x86/smp: Move smp_function_call implementations into IPI code x86/apic: Provide and use helper for send_IPI_allbutself() x86/apic: Add static key to Control IPI shorthands x86/apic: Move no_ipi_broadcast() out of 32bit x86/apic: Add NMI_VECTOR wait to IPI shorthand x86/apic: Remove dest argument from __default_send_IPI_shortcut() x86/hotplug: Silence APIC and NMI when CPU is dead x86/cpu: Move arch_smt_update() to a neutral place x86/apic/uv: Make x2apic_extra_bits static x86/apic: Consolidate the apic local headers x86/apic: Move apic_flat_64 header into apic directory x86/apic: Move ipi header into apic directory x86/apic: Cleanup the include maze ...
215 lines
5.0 KiB
C
215 lines
5.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Default generic APIC driver. This handles up to 8 CPUs.
|
|
*
|
|
* Copyright 2003 Andi Kleen, SuSE Labs.
|
|
*
|
|
* Generic x86 APIC driver probe layer.
|
|
*/
|
|
#include <linux/export.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/smp.h>
|
|
|
|
#include <asm/apic.h>
|
|
#include <asm/acpi.h>
|
|
|
|
#include "local.h"
|
|
|
|
static int default_x86_32_early_logical_apicid(int cpu)
|
|
{
|
|
return 1 << cpu;
|
|
}
|
|
|
|
static void setup_apic_flat_routing(void)
|
|
{
|
|
#ifdef CONFIG_X86_IO_APIC
|
|
printk(KERN_INFO
|
|
"Enabling APIC mode: Flat. Using %d I/O APICs\n",
|
|
nr_ioapics);
|
|
#endif
|
|
}
|
|
|
|
static int default_apic_id_registered(void)
|
|
{
|
|
return physid_isset(read_apic_id(), phys_cpu_present_map);
|
|
}
|
|
|
|
/*
|
|
* Set up the logical destination ID. Intel recommends to set DFR, LDR and
|
|
* TPR before enabling an APIC. See e.g. "AP-388 82489DX User's Manual"
|
|
* (Intel document number 292116).
|
|
*/
|
|
static void default_init_apic_ldr(void)
|
|
{
|
|
unsigned long val;
|
|
|
|
apic_write(APIC_DFR, APIC_DFR_VALUE);
|
|
val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
|
|
val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
|
|
apic_write(APIC_LDR, val);
|
|
}
|
|
|
|
static int default_phys_pkg_id(int cpuid_apic, int index_msb)
|
|
{
|
|
return cpuid_apic >> index_msb;
|
|
}
|
|
|
|
/* should be called last. */
|
|
static int probe_default(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static struct apic apic_default __ro_after_init = {
|
|
|
|
.name = "default",
|
|
.probe = probe_default,
|
|
.acpi_madt_oem_check = NULL,
|
|
.apic_id_valid = default_apic_id_valid,
|
|
.apic_id_registered = default_apic_id_registered,
|
|
|
|
.irq_delivery_mode = dest_Fixed,
|
|
/* logical delivery broadcast to all CPUs: */
|
|
.irq_dest_mode = 1,
|
|
|
|
.disable_esr = 0,
|
|
.dest_logical = APIC_DEST_LOGICAL,
|
|
.check_apicid_used = default_check_apicid_used,
|
|
|
|
.init_apic_ldr = default_init_apic_ldr,
|
|
|
|
.ioapic_phys_id_map = default_ioapic_phys_id_map,
|
|
.setup_apic_routing = setup_apic_flat_routing,
|
|
.cpu_present_to_apicid = default_cpu_present_to_apicid,
|
|
.apicid_to_cpu_present = physid_set_mask_of_physid,
|
|
.check_phys_apicid_present = default_check_phys_apicid_present,
|
|
.phys_pkg_id = default_phys_pkg_id,
|
|
|
|
.get_apic_id = default_get_apic_id,
|
|
.set_apic_id = NULL,
|
|
|
|
.calc_dest_apicid = apic_flat_calc_apicid,
|
|
|
|
.send_IPI = default_send_IPI_single,
|
|
.send_IPI_mask = default_send_IPI_mask_logical,
|
|
.send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical,
|
|
.send_IPI_allbutself = default_send_IPI_allbutself,
|
|
.send_IPI_all = default_send_IPI_all,
|
|
.send_IPI_self = default_send_IPI_self,
|
|
|
|
.inquire_remote_apic = default_inquire_remote_apic,
|
|
|
|
.read = native_apic_mem_read,
|
|
.write = native_apic_mem_write,
|
|
.eoi_write = native_apic_mem_write,
|
|
.icr_read = native_apic_icr_read,
|
|
.icr_write = native_apic_icr_write,
|
|
.wait_icr_idle = native_apic_wait_icr_idle,
|
|
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
|
|
|
|
.x86_32_early_logical_apicid = default_x86_32_early_logical_apicid,
|
|
};
|
|
|
|
apic_driver(apic_default);
|
|
|
|
struct apic *apic __ro_after_init = &apic_default;
|
|
EXPORT_SYMBOL_GPL(apic);
|
|
|
|
static int cmdline_apic __initdata;
|
|
static int __init parse_apic(char *arg)
|
|
{
|
|
struct apic **drv;
|
|
|
|
if (!arg)
|
|
return -EINVAL;
|
|
|
|
for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
|
|
if (!strcmp((*drv)->name, arg)) {
|
|
apic = *drv;
|
|
cmdline_apic = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Parsed again by __setup for debug/verbose */
|
|
return 0;
|
|
}
|
|
early_param("apic", parse_apic);
|
|
|
|
void __init default_setup_apic_routing(void)
|
|
{
|
|
int version = boot_cpu_apic_version;
|
|
|
|
if (num_possible_cpus() > 8) {
|
|
switch (boot_cpu_data.x86_vendor) {
|
|
case X86_VENDOR_INTEL:
|
|
if (!APIC_XAPIC(version)) {
|
|
def_to_bigsmp = 0;
|
|
break;
|
|
}
|
|
/* P4 and above */
|
|
/* fall through */
|
|
case X86_VENDOR_HYGON:
|
|
case X86_VENDOR_AMD:
|
|
def_to_bigsmp = 1;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_X86_BIGSMP
|
|
/*
|
|
* This is used to switch to bigsmp mode when
|
|
* - There is no apic= option specified by the user
|
|
* - generic_apic_probe() has chosen apic_default as the sub_arch
|
|
* - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
|
|
*/
|
|
|
|
if (!cmdline_apic && apic == &apic_default)
|
|
generic_bigsmp_probe();
|
|
#endif
|
|
|
|
if (apic->setup_apic_routing)
|
|
apic->setup_apic_routing();
|
|
|
|
if (x86_platform.apic_post_init)
|
|
x86_platform.apic_post_init();
|
|
}
|
|
|
|
void __init generic_apic_probe(void)
|
|
{
|
|
if (!cmdline_apic) {
|
|
struct apic **drv;
|
|
|
|
for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
|
|
if ((*drv)->probe()) {
|
|
apic = *drv;
|
|
break;
|
|
}
|
|
}
|
|
/* Not visible without early console */
|
|
if (drv == __apicdrivers_end)
|
|
panic("Didn't find an APIC driver");
|
|
}
|
|
printk(KERN_INFO "Using APIC driver %s\n", apic->name);
|
|
}
|
|
|
|
/* This function can switch the APIC even after the initial ->probe() */
|
|
int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
|
|
{
|
|
struct apic **drv;
|
|
|
|
for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
|
|
if (!(*drv)->acpi_madt_oem_check)
|
|
continue;
|
|
if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id))
|
|
continue;
|
|
|
|
if (!cmdline_apic) {
|
|
apic = *drv;
|
|
printk(KERN_INFO "Switched to APIC driver `%s'.\n",
|
|
apic->name);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|