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/cpumask.h>
  12#include <linux/export.h>
  13#include <linux/acpi.h>
  14
  15#include <asm/jailhouse_para.h>
  16#include <asm/apic.h>
  17
  18#include "local.h"
  19
  20static struct apic apic_physflat;
  21static struct apic apic_flat;
  22
  23struct apic *apic __ro_after_init = &apic_flat;
  24EXPORT_SYMBOL_GPL(apic);
  25
  26static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  27{
  28        return 1;
  29}
  30
  31/*
  32 * Set up the logical destination ID.
  33 *
  34 * Intel recommends to set DFR, LDR and TPR before enabling
  35 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel
  36 * document number 292116).  So here it goes...
  37 */
  38void flat_init_apic_ldr(void)
  39{
  40        unsigned long val;
  41        unsigned long num, id;
  42
  43        num = smp_processor_id();
  44        id = 1UL << num;
  45        apic_write(APIC_DFR, APIC_DFR_FLAT);
  46        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  47        val |= SET_APIC_LOGICAL_ID(id);
  48        apic_write(APIC_LDR, val);
  49}
  50
  51static void _flat_send_IPI_mask(unsigned long mask, int vector)
  52{
  53        unsigned long flags;
  54
  55        local_irq_save(flags);
  56        __default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
  57        local_irq_restore(flags);
  58}
  59
  60static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
  61{
  62        unsigned long mask = cpumask_bits(cpumask)[0];
  63
  64        _flat_send_IPI_mask(mask, vector);
  65}
  66
  67static void
  68flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
  69{
  70        unsigned long mask = cpumask_bits(cpumask)[0];
  71        int cpu = smp_processor_id();
  72
  73        if (cpu < BITS_PER_LONG)
  74                __clear_bit(cpu, &mask);
  75
  76        _flat_send_IPI_mask(mask, vector);
  77}
  78
  79static unsigned int flat_get_apic_id(unsigned long x)
  80{
  81        return (x >> 24) & 0xFF;
  82}
  83
  84static u32 set_apic_id(unsigned int id)
  85{
  86        return (id & 0xFF) << 24;
  87}
  88
  89static unsigned int read_xapic_id(void)
  90{
  91        return flat_get_apic_id(apic_read(APIC_ID));
  92}
  93
  94static int flat_apic_id_registered(void)
  95{
  96        return physid_isset(read_xapic_id(), phys_cpu_present_map);
  97}
  98
  99static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
 100{
 101        return initial_apic_id >> index_msb;
 102}
 103
 104static int flat_probe(void)
 105{
 106        return 1;
 107}
 108
 109static struct apic apic_flat __ro_after_init = {
 110        .name                           = "flat",
 111        .probe                          = flat_probe,
 112        .acpi_madt_oem_check            = flat_acpi_madt_oem_check,
 113        .apic_id_valid                  = default_apic_id_valid,
 114        .apic_id_registered             = flat_apic_id_registered,
 115
 116        .delivery_mode                  = APIC_DELIVERY_MODE_FIXED,
 117        .dest_mode_logical              = true,
 118
 119        .disable_esr                    = 0,
 120
 121        .check_apicid_used              = NULL,
 122        .init_apic_ldr                  = flat_init_apic_ldr,
 123        .ioapic_phys_id_map             = NULL,
 124        .setup_apic_routing             = NULL,
 125        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 126        .apicid_to_cpu_present          = NULL,
 127        .check_phys_apicid_present      = default_check_phys_apicid_present,
 128        .phys_pkg_id                    = flat_phys_pkg_id,
 129
 130        .get_apic_id                    = flat_get_apic_id,
 131        .set_apic_id                    = set_apic_id,
 132
 133        .calc_dest_apicid               = apic_flat_calc_apicid,
 134
 135        .send_IPI                       = default_send_IPI_single,
 136        .send_IPI_mask                  = flat_send_IPI_mask,
 137        .send_IPI_mask_allbutself       = flat_send_IPI_mask_allbutself,
 138        .send_IPI_allbutself            = default_send_IPI_allbutself,
 139        .send_IPI_all                   = default_send_IPI_all,
 140        .send_IPI_self                  = default_send_IPI_self,
 141
 142        .inquire_remote_apic            = default_inquire_remote_apic,
 143
 144        .read                           = native_apic_mem_read,
 145        .write                          = native_apic_mem_write,
 146        .eoi_write                      = native_apic_mem_write,
 147        .icr_read                       = native_apic_icr_read,
 148        .icr_write                      = native_apic_icr_write,
 149        .wait_icr_idle                  = native_apic_wait_icr_idle,
 150        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 151};
 152
 153/*
 154 * Physflat mode is used when there are more than 8 CPUs on a system.
 155 * We cannot use logical delivery in this case because the mask
 156 * overflows, so use physical mode.
 157 */
 158static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 159{
 160#ifdef CONFIG_ACPI
 161        /*
 162         * Quirk: some x86_64 machines can only use physical APIC mode
 163         * regardless of how many processors are present (x86_64 ES7000
 164         * is an example).
 165         */
 166        if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
 167                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
 168                printk(KERN_DEBUG "system APIC only can use physical flat");
 169                return 1;
 170        }
 171
 172        if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
 173                printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
 174                return 1;
 175        }
 176#endif
 177
 178        return 0;
 179}
 180
 181static void physflat_init_apic_ldr(void)
 182{
 183        /*
 184         * LDR and DFR are not involved in physflat mode, rather:
 185         * "In physical destination mode, the destination processor is
 186         * specified by its local APIC ID [...]." (Intel SDM, 10.6.2.1)
 187         */
 188}
 189
 190static int physflat_probe(void)
 191{
 192        if (apic == &apic_physflat || num_possible_cpus() > 8 ||
 193            jailhouse_paravirt())
 194                return 1;
 195
 196        return 0;
 197}
 198
 199static struct apic apic_physflat __ro_after_init = {
 200
 201        .name                           = "physical flat",
 202        .probe                          = physflat_probe,
 203        .acpi_madt_oem_check            = physflat_acpi_madt_oem_check,
 204        .apic_id_valid                  = default_apic_id_valid,
 205        .apic_id_registered             = flat_apic_id_registered,
 206
 207        .delivery_mode                  = APIC_DELIVERY_MODE_FIXED,
 208        .dest_mode_logical              = false,
 209
 210        .disable_esr                    = 0,
 211
 212        .check_apicid_used              = NULL,
 213        .init_apic_ldr                  = physflat_init_apic_ldr,
 214        .ioapic_phys_id_map             = NULL,
 215        .setup_apic_routing             = NULL,
 216        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
 217        .apicid_to_cpu_present          = NULL,
 218        .check_phys_apicid_present      = default_check_phys_apicid_present,
 219        .phys_pkg_id                    = flat_phys_pkg_id,
 220
 221        .get_apic_id                    = flat_get_apic_id,
 222        .set_apic_id                    = set_apic_id,
 223
 224        .calc_dest_apicid               = apic_default_calc_apicid,
 225
 226        .send_IPI                       = default_send_IPI_single_phys,
 227        .send_IPI_mask                  = default_send_IPI_mask_sequence_phys,
 228        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_phys,
 229        .send_IPI_allbutself            = default_send_IPI_allbutself,
 230        .send_IPI_all                   = default_send_IPI_all,
 231        .send_IPI_self                  = default_send_IPI_self,
 232
 233        .inquire_remote_apic            = default_inquire_remote_apic,
 234
 235        .read                           = native_apic_mem_read,
 236        .write                          = native_apic_mem_write,
 237        .eoi_write                      = native_apic_mem_write,
 238        .icr_read                       = native_apic_icr_read,
 239        .icr_write                      = native_apic_icr_write,
 240        .wait_icr_idle                  = native_apic_wait_icr_idle,
 241        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 242};
 243
 244/*
 245 * We need to check for physflat first, so this order is important.
 246 */
 247apic_drivers(apic_physflat, apic_flat);
 248