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 ...
192 lines
4.3 KiB
C
192 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* APIC driver for "bigsmp" xAPIC machines with more than 8 virtual CPUs.
|
|
*
|
|
* Drives the local APIC in "clustered mode".
|
|
*/
|
|
#include <linux/cpumask.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/smp.h>
|
|
|
|
#include <asm/apic.h>
|
|
|
|
#include "local.h"
|
|
|
|
static unsigned bigsmp_get_apic_id(unsigned long x)
|
|
{
|
|
return (x >> 24) & 0xFF;
|
|
}
|
|
|
|
static int bigsmp_apic_id_registered(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static bool bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static int bigsmp_early_logical_apicid(int cpu)
|
|
{
|
|
/* on bigsmp, logical apicid is the same as physical */
|
|
return early_per_cpu(x86_cpu_to_apicid, cpu);
|
|
}
|
|
|
|
/*
|
|
* bigsmp enables physical destination mode
|
|
* and doesn't use LDR and DFR
|
|
*/
|
|
static void bigsmp_init_apic_ldr(void)
|
|
{
|
|
}
|
|
|
|
static void bigsmp_setup_apic_routing(void)
|
|
{
|
|
printk(KERN_INFO
|
|
"Enabling APIC mode: Physflat. Using %d I/O APICs\n",
|
|
nr_ioapics);
|
|
}
|
|
|
|
static int bigsmp_cpu_present_to_apicid(int mps_cpu)
|
|
{
|
|
if (mps_cpu < nr_cpu_ids)
|
|
return (int) per_cpu(x86_bios_cpu_apicid, mps_cpu);
|
|
|
|
return BAD_APICID;
|
|
}
|
|
|
|
static void bigsmp_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
|
|
{
|
|
/* For clustered we don't have a good way to do this yet - hack */
|
|
physids_promote(0xFFL, retmap);
|
|
}
|
|
|
|
static int bigsmp_check_phys_apicid_present(int phys_apicid)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
|
|
{
|
|
return cpuid_apic >> index_msb;
|
|
}
|
|
|
|
static void bigsmp_send_IPI_allbutself(int vector)
|
|
{
|
|
default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
|
|
}
|
|
|
|
static void bigsmp_send_IPI_all(int vector)
|
|
{
|
|
default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
|
|
}
|
|
|
|
static int dmi_bigsmp; /* can be set by dmi scanners */
|
|
|
|
static int hp_ht_bigsmp(const struct dmi_system_id *d)
|
|
{
|
|
printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident);
|
|
dmi_bigsmp = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static const struct dmi_system_id bigsmp_dmi_table[] = {
|
|
{ hp_ht_bigsmp, "HP ProLiant DL760 G2",
|
|
{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
|
|
DMI_MATCH(DMI_BIOS_VERSION, "P44-"),
|
|
}
|
|
},
|
|
|
|
{ hp_ht_bigsmp, "HP ProLiant DL740",
|
|
{ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
|
|
DMI_MATCH(DMI_BIOS_VERSION, "P47-"),
|
|
}
|
|
},
|
|
{ } /* NULL entry stops DMI scanning */
|
|
};
|
|
|
|
static int probe_bigsmp(void)
|
|
{
|
|
if (def_to_bigsmp)
|
|
dmi_bigsmp = 1;
|
|
else
|
|
dmi_check_system(bigsmp_dmi_table);
|
|
|
|
return dmi_bigsmp;
|
|
}
|
|
|
|
static struct apic apic_bigsmp __ro_after_init = {
|
|
|
|
.name = "bigsmp",
|
|
.probe = probe_bigsmp,
|
|
.acpi_madt_oem_check = NULL,
|
|
.apic_id_valid = default_apic_id_valid,
|
|
.apic_id_registered = bigsmp_apic_id_registered,
|
|
|
|
.irq_delivery_mode = dest_Fixed,
|
|
/* phys delivery to target CPU: */
|
|
.irq_dest_mode = 0,
|
|
|
|
.disable_esr = 1,
|
|
.dest_logical = 0,
|
|
.check_apicid_used = bigsmp_check_apicid_used,
|
|
|
|
.init_apic_ldr = bigsmp_init_apic_ldr,
|
|
|
|
.ioapic_phys_id_map = bigsmp_ioapic_phys_id_map,
|
|
.setup_apic_routing = bigsmp_setup_apic_routing,
|
|
.cpu_present_to_apicid = bigsmp_cpu_present_to_apicid,
|
|
.apicid_to_cpu_present = physid_set_mask_of_physid,
|
|
.check_phys_apicid_present = bigsmp_check_phys_apicid_present,
|
|
.phys_pkg_id = bigsmp_phys_pkg_id,
|
|
|
|
.get_apic_id = bigsmp_get_apic_id,
|
|
.set_apic_id = NULL,
|
|
|
|
.calc_dest_apicid = apic_default_calc_apicid,
|
|
|
|
.send_IPI = default_send_IPI_single_phys,
|
|
.send_IPI_mask = default_send_IPI_mask_sequence_phys,
|
|
.send_IPI_mask_allbutself = NULL,
|
|
.send_IPI_allbutself = bigsmp_send_IPI_allbutself,
|
|
.send_IPI_all = bigsmp_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 = bigsmp_early_logical_apicid,
|
|
};
|
|
|
|
void __init generic_bigsmp_probe(void)
|
|
{
|
|
unsigned int cpu;
|
|
|
|
if (!probe_bigsmp())
|
|
return;
|
|
|
|
apic = &apic_bigsmp;
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
if (early_per_cpu(x86_cpu_to_logical_apicid,
|
|
cpu) == BAD_APICID)
|
|
continue;
|
|
early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
|
|
bigsmp_early_logical_apicid(cpu);
|
|
}
|
|
|
|
pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name);
|
|
}
|
|
|
|
apic_driver(apic_bigsmp);
|