linux/arch/x86/kernel/apic/apic_flat_64.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2004 James Cleverdon, IBM.
   4 *
   5 * Flat APIC subarch code.
   6 *
   7 * Hacked for x86-64 by James Cleverdon from i386 architecture code by
   8 * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
   9 * James Cleverdon.
  10 */
  11#include <linux/acpi.h>
  12#include <linux/errno.h>
  13#include <linux/threads.h>
  14#include <linux/cpumask.h>
  15#include <linux/string.h>
  16#include <linux/kernel.h>
  17#include <linux/ctype.h>
  18#include <linux/hardirq.h>
  19#include <linux/export.h>
  20
  21#include <asm/smp.h>
  22#include <asm/ipi.h>
  23#include <asm/apic.h>
  24#include <asm/apic_flat_64.h>
  25#include <asm/jailhouse_para.h>
  26
  27static struct apic apic_physflat;
  28static struct apic apic_flat;
  29
  30struct apic *apic __ro_after_init = &apic_flat;
  31EXPORT_SYMBOL_GPL(apic);
  32
  33static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  34{
  35        return 1;
  36}
  37
  38/*
  39 * Set up the logical destination ID.
  40 *
  41 * Intel recommends to set DFR, LDR and TPR before enabling
  42 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  43 * document number 292116).  So here it goes...
  44 */
  45void flat_init_apic_ldr(void)
  46{
  47        unsigned long val;
  48        unsigned long num, id;
  49
  50        num = smp_processor_id();
  51        id = 1UL << num;
  52        apic_write(APIC_DFR, APIC_DFR_FLAT);
  53        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  54        val |= SET_APIC_LOGICAL_ID(id);
  55        apic_write(APIC_LDR, val);
  56}
  57
  58static void _flat_send_IPI_mask(unsigned long mask, int vector)
  59{
  60        unsigned long flags;
  61
  62        local_irq_save(flags);
  63        __default_send_IPI_dest_field(mask, vector, apic->dest_logical);
  64        local_irq_restore(flags);
  65}
  66
  67static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
  68{
  69        unsigned long mask = cpumask_bits(cpumask)[0];
  70
  71        _flat_send_IPI_mask(mask, vector);
  72}
  73
  74static void
  75flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
  76{
  77        unsigned long mask = cpumask_bits(cpumask)[0];
  78        int cpu = smp_processor_id();
  79
  80        if (cpu < BITS_PER_LONG)
  81                clear_bit(cpu, &mask);
  82
  83        _flat_send_IPI_mask(mask, vector);
  84}
  85
  86static void flat_send_IPI_allbutself(int vector)
  87{
  88        int cpu = smp_processor_id();
  89
  90        if (IS_ENABLED(CONFIG_HOTPLUG_CPU) || vector == NMI_VECTOR) {
  91                if (!cpumask_equal(cpu_online_mask, cpumask_of(cpu))) {
  92                        unsigned long mask = cpumask_bits(cpu_online_mask)[0];
  93
  94                        if (cpu < BITS_PER_LONG)
  95                                clear_bit(cpu, &mask);
  96
  97                        _flat_send_IPI_mask(mask, vector);
  98                }
  99        } else if (num_online_cpus() > 1) {
 100                __default_send_IPI_shortcut(APIC_DEST_ALLBUT,
 101                                            vector, apic->dest_logical);
 102        }
 103}
 104
 105static void flat_send_IPI_all(int vector)
 106{
 107        if (vector == NMI_VECTOR) {
 108                flat_send_IPI_mask(cpu_online_mask, vector);
 109        } else {
 110                __default_send_IPI_shortcut(APIC_DEST_ALLINC,
 111                                            vector, apic->dest_logical);
 112        }
 113}
 114
 115static unsigned int flat_get_apic_id(unsigned long x)
 116{
 117        return (x >> 24) & 0xFF;
 118}
 119
 120static u32 set_apic_id(unsigned int id)
 121{
 122        return (id & 0xFF) << 24;
 123}
 124
 125static unsigned int read_xapic_id(void)
 126{
 127        return flat_get_apic_id(apic_read(APIC_ID));
 128}
 129
 130static int flat_apic_id_registered(void)
 131{
 132        return physid_isset(read_xapic_id(), phys_cpu_present_map);
 133}
 134
 135static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 136{
 137        return initial_apic_id >> index_msb;
 138}
 139
 140static int flat_probe(void)
 141{
 142        return 1;
 143}
 144
 145static struct apic apic_flat __ro_after_init = {
 146        .name                           = "flat",
 147        .probe                          = flat_probe,
 148        .acpi_madt_oem_check            = flat_acpi_madt_oem_check,
 149        .apic_id_valid                  = default_apic_id_valid,
 150        .apic_id_registered             = flat_apic_id_registered,
 151
 152        .irq_delivery_mode              = dest_Fixed,
 153        .irq_dest_mode                  = 1, /* logical */
 154
 155        .disable_esr                    = 0,
 156        .dest_logical                   = APIC_DEST_LOGICAL,
 157        .check_apicid_used              = NULL,
 158
 159        .init_apic_ldr                  = flat_init_apic_ldr,
 160
 161        .ioapic_phys_id_map             = NULL,
 162        .setup_apic_routing             = NULL,
 163        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 164        .apicid_to_cpu_present          = NULL,
 165        .check_phys_apicid_present      = default_check_phys_apicid_present,
 166        .phys_pkg_id                    = flat_phys_pkg_id,
 167
 168        .get_apic_id                    = flat_get_apic_id,
 169        .set_apic_id                    = set_apic_id,
 170
 171        .calc_dest_apicid               = apic_flat_calc_apicid,
 172
 173        .send_IPI                       = default_send_IPI_single,
 174        .send_IPI_mask                  = flat_send_IPI_mask,
 175        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
 176        .send_IPI_allbutself            = flat_send_IPI_allbutself,
 177        .send_IPI_all                   = flat_send_IPI_all,
 178        .send_IPI_self                  = apic_send_IPI_self,
 179
 180        .inquire_remote_apic            = default_inquire_remote_apic,
 181
 182        .read                           = native_apic_mem_read,
 183        .write                          = native_apic_mem_write,
 184        .eoi_write                      = native_apic_mem_write,
 185        .icr_read                       = native_apic_icr_read,
 186        .icr_write                      = native_apic_icr_write,
 187        .wait_icr_idle                  = native_apic_wait_icr_idle,
 188        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 189};
 190
 191/*
 192 * Physflat mode is used when there are more than 8 CPUs on a system.
 193 * We cannot use logical delivery in this case because the mask
 194 * overflows, so use physical mode.
 195 */
 196static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 197{
 198#ifdef CONFIG_ACPI
 199        /*
 200         * Quirk: some x86_64 machines can only use physical APIC mode
 201         * regardless of how many processors are present (x86_64 ES7000
 202         * is an example).
 203         */
 204        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
 205                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
 206                printk(KERN_DEBUG "system APIC only can use physical flat");
 207                return 1;
 208        }
 209
 210        if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
 211                printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
 212                return 1;
 213        }
 214#endif
 215
 216        return 0;
 217}
 218
 219static void physflat_init_apic_ldr(void)
 220{
 221        /*
 222         * LDR and DFR are not involved in physflat mode, rather:
 223         * "In physical destination mode, the destination processor is
 224         * specified by its local APIC ID [...]." (Intel SDM, 10.6.2.1)
 225         */
 226}
 227
 228static void physflat_send_IPI_allbutself(int vector)
 229{
 230        default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
 231}
 232
 233static void physflat_send_IPI_all(int vector)
 234{
 235        default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
 236}
 237
 238static int physflat_probe(void)
 239{
 240        if (apic == &apic_physflat || num_possible_cpus() > 8 ||
 241            jailhouse_paravirt())
 242                return 1;
 243
 244        return 0;
 245}
 246
 247static struct apic apic_physflat __ro_after_init = {
 248
 249        .name                           = "physical flat",
 250        .probe                          = physflat_probe,
 251        .acpi_madt_oem_check            = physflat_acpi_madt_oem_check,
 252        .apic_id_valid                  = default_apic_id_valid,
 253        .apic_id_registered             = flat_apic_id_registered,
 254
 255        .irq_delivery_mode              = dest_Fixed,
 256        .irq_dest_mode                  = 0, /* physical */
 257
 258        .disable_esr                    = 0,
 259        .dest_logical                   = 0,
 260        .check_apicid_used              = NULL,
 261
 262        .init_apic_ldr                  = physflat_init_apic_ldr,
 263
 264        .ioapic_phys_id_map             = NULL,
 265        .setup_apic_routing             = NULL,
 266        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 267        .apicid_to_cpu_present          = NULL,
 268        .check_phys_apicid_present      = default_check_phys_apicid_present,
 269        .phys_pkg_id                    = flat_phys_pkg_id,
 270
 271        .get_apic_id                    = flat_get_apic_id,
 272        .set_apic_id                    = set_apic_id,
 273
 274        .calc_dest_apicid               = apic_default_calc_apicid,
 275
 276        .send_IPI                       = default_send_IPI_single_phys,
 277        .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
 278        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_phys,
 279        .send_IPI_allbutself            = physflat_send_IPI_allbutself,
 280        .send_IPI_all                   = physflat_send_IPI_all,
 281        .send_IPI_self                  = apic_send_IPI_self,
 282
 283        .inquire_remote_apic            = default_inquire_remote_apic,
 284
 285        .read                           = native_apic_mem_read,
 286        .write                          = native_apic_mem_write,
 287        .eoi_write                      = native_apic_mem_write,
 288        .icr_read                       = native_apic_icr_read,
 289        .icr_write                      = native_apic_icr_write,
 290        .wait_icr_idle                  = native_apic_wait_icr_idle,
 291        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 292};
 293
 294/*
 295 * We need to check for physflat first, so this order is important.
 296 */
 297apic_drivers(apic_physflat, apic_flat);
 298