diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
commit | ace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch) | |
tree | b2d64bc10158fdd5497876388cd68142ca374ed3 /arch/x86/kernel/apic/apic_flat_64.c | |
parent | Initial commit. (diff) | |
download | linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip |
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'arch/x86/kernel/apic/apic_flat_64.c')
-rw-r--r-- | arch/x86/kernel/apic/apic_flat_64.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c new file mode 100644 index 0000000000..032a84e2c3 --- /dev/null +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2004 James Cleverdon, IBM. + * + * Flat APIC subarch code. + * + * Hacked for x86-64 by James Cleverdon from i386 architecture code by + * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and + * James Cleverdon. + */ +#include <linux/cpumask.h> +#include <linux/export.h> +#include <linux/acpi.h> + +#include <asm/jailhouse_para.h> +#include <asm/apic.h> + +#include "local.h" + +static struct apic apic_physflat; +static struct apic apic_flat; + +struct apic *apic __ro_after_init = &apic_flat; +EXPORT_SYMBOL_GPL(apic); + +static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + return 1; +} + +static void _flat_send_IPI_mask(unsigned long mask, int vector) +{ + unsigned long flags; + + local_irq_save(flags); + __default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL); + local_irq_restore(flags); +} + +static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector) +{ + unsigned long mask = cpumask_bits(cpumask)[0]; + + _flat_send_IPI_mask(mask, vector); +} + +static void +flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) +{ + unsigned long mask = cpumask_bits(cpumask)[0]; + int cpu = smp_processor_id(); + + if (cpu < BITS_PER_LONG) + __clear_bit(cpu, &mask); + + _flat_send_IPI_mask(mask, vector); +} + +static unsigned int flat_get_apic_id(unsigned long x) +{ + return (x >> 24) & 0xFF; +} + +static u32 set_apic_id(unsigned int id) +{ + return (id & 0xFF) << 24; +} + +static int flat_phys_pkg_id(int initial_apic_id, int index_msb) +{ + return initial_apic_id >> index_msb; +} + +static int flat_probe(void) +{ + return 1; +} + +static struct apic apic_flat __ro_after_init = { + .name = "flat", + .probe = flat_probe, + .acpi_madt_oem_check = flat_acpi_madt_oem_check, + .apic_id_registered = default_apic_id_registered, + + .delivery_mode = APIC_DELIVERY_MODE_FIXED, + .dest_mode_logical = true, + + .disable_esr = 0, + + .init_apic_ldr = default_init_apic_ldr, + .cpu_present_to_apicid = default_cpu_present_to_apicid, + .phys_pkg_id = flat_phys_pkg_id, + + .max_apic_id = 0xFE, + .get_apic_id = flat_get_apic_id, + .set_apic_id = set_apic_id, + + .calc_dest_apicid = apic_flat_calc_apicid, + + .send_IPI = default_send_IPI_single, + .send_IPI_mask = flat_send_IPI_mask, + .send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself, + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, + + .read = native_apic_mem_read, + .write = native_apic_mem_write, + .eoi = native_apic_mem_eoi, + .icr_read = native_apic_icr_read, + .icr_write = native_apic_icr_write, + .wait_icr_idle = apic_mem_wait_icr_idle, + .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout, +}; + +/* + * Physflat mode is used when there are more than 8 CPUs on a system. + * We cannot use logical delivery in this case because the mask + * overflows, so use physical mode. + */ +static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ +#ifdef CONFIG_ACPI + /* + * Quirk: some x86_64 machines can only use physical APIC mode + * regardless of how many processors are present (x86_64 ES7000 + * is an example). + */ + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) { + printk(KERN_DEBUG "system APIC only can use physical flat"); + return 1; + } + + if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) { + printk(KERN_DEBUG "IBM Summit detected, will use apic physical"); + return 1; + } +#endif + + return 0; +} + +static int physflat_probe(void) +{ + return apic == &apic_physflat || num_possible_cpus() > 8 || jailhouse_paravirt(); +} + +static struct apic apic_physflat __ro_after_init = { + + .name = "physical flat", + .probe = physflat_probe, + .acpi_madt_oem_check = physflat_acpi_madt_oem_check, + .apic_id_registered = default_apic_id_registered, + + .delivery_mode = APIC_DELIVERY_MODE_FIXED, + .dest_mode_logical = false, + + .disable_esr = 0, + + .check_apicid_used = NULL, + .ioapic_phys_id_map = NULL, + .cpu_present_to_apicid = default_cpu_present_to_apicid, + .phys_pkg_id = flat_phys_pkg_id, + + .max_apic_id = 0xFE, + .get_apic_id = flat_get_apic_id, + .set_apic_id = set_apic_id, + + .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 = default_send_IPI_mask_allbutself_phys, + .send_IPI_allbutself = default_send_IPI_allbutself, + .send_IPI_all = default_send_IPI_all, + .send_IPI_self = default_send_IPI_self, + + .read = native_apic_mem_read, + .write = native_apic_mem_write, + .eoi = native_apic_mem_eoi, + .icr_read = native_apic_icr_read, + .icr_write = native_apic_icr_write, + .wait_icr_idle = apic_mem_wait_icr_idle, + .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout, +}; + +/* + * We need to check for physflat first, so this order is important. + */ +apic_drivers(apic_physflat, apic_flat); |