linux/arch/x86/kernel/apic/probe_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Default generic APIC driver. This handles up to 8 CPUs.
   4 *
   5 * Copyright 2003 Andi Kleen, SuSE Labs.
   6 *
   7 * Generic x86 APIC driver probe layer.
   8 */
   9#include <linux/export.h>
  10#include <linux/errno.h>
  11#include <linux/smp.h>
  12
  13#include <asm/io_apic.h>
  14#include <asm/apic.h>
  15#include <asm/acpi.h>
  16
  17#include "local.h"
  18
  19static int default_x86_32_early_logical_apicid(int cpu)
  20{
  21        return 1 << cpu;
  22}
  23
  24static void setup_apic_flat_routing(void)
  25{
  26#ifdef CONFIG_X86_IO_APIC
  27        printk(KERN_INFO
  28                "Enabling APIC mode:  Flat.  Using %d I/O APICs\n",
  29                nr_ioapics);
  30#endif
  31}
  32
  33static int default_apic_id_registered(void)
  34{
  35        return physid_isset(read_apic_id(), phys_cpu_present_map);
  36}
  37
  38/*
  39 * Set up the logical destination ID.  Intel recommends to set DFR, LDR and
  40 * TPR before enabling an APIC.  See e.g. "AP-388 82489DX User's Manual"
  41 * (Intel document number 292116).
  42 */
  43static void default_init_apic_ldr(void)
  44{
  45        unsigned long val;
  46
  47        apic_write(APIC_DFR, APIC_DFR_VALUE);
  48        val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
  49        val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
  50        apic_write(APIC_LDR, val);
  51}
  52
  53static int default_phys_pkg_id(int cpuid_apic, int index_msb)
  54{
  55        return cpuid_apic >> index_msb;
  56}
  57
  58/* should be called last. */
  59static int probe_default(void)
  60{
  61        return 1;
  62}
  63
  64static struct apic apic_default __ro_after_init = {
  65
  66        .name                           = "default",
  67        .probe                          = probe_default,
  68        .acpi_madt_oem_check            = NULL,
  69        .apic_id_valid                  = default_apic_id_valid,
  70        .apic_id_registered             = default_apic_id_registered,
  71
  72        .delivery_mode                  = APIC_DELIVERY_MODE_FIXED,
  73        .dest_mode_logical              = true,
  74
  75        .disable_esr                    = 0,
  76
  77        .check_apicid_used              = default_check_apicid_used,
  78        .init_apic_ldr                  = default_init_apic_ldr,
  79        .ioapic_phys_id_map             = default_ioapic_phys_id_map,
  80        .setup_apic_routing             = setup_apic_flat_routing,
  81        .cpu_present_to_apicid          = default_cpu_present_to_apicid,
  82        .apicid_to_cpu_present          = physid_set_mask_of_physid,
  83        .check_phys_apicid_present      = default_check_phys_apicid_present,
  84        .phys_pkg_id                    = default_phys_pkg_id,
  85
  86        .get_apic_id                    = default_get_apic_id,
  87        .set_apic_id                    = NULL,
  88
  89        .calc_dest_apicid               = apic_flat_calc_apicid,
  90
  91        .send_IPI                       = default_send_IPI_single,
  92        .send_IPI_mask                  = default_send_IPI_mask_logical,
  93        .send_IPI_mask_allbutself       = default_send_IPI_mask_allbutself_logical,
  94        .send_IPI_allbutself            = default_send_IPI_allbutself,
  95        .send_IPI_all                   = default_send_IPI_all,
  96        .send_IPI_self                  = default_send_IPI_self,
  97
  98        .inquire_remote_apic            = default_inquire_remote_apic,
  99
 100        .read                           = native_apic_mem_read,
 101        .write                          = native_apic_mem_write,
 102        .eoi_write                      = native_apic_mem_write,
 103        .icr_read                       = native_apic_icr_read,
 104        .icr_write                      = native_apic_icr_write,
 105        .wait_icr_idle                  = native_apic_wait_icr_idle,
 106        .safe_wait_icr_idle             = native_safe_apic_wait_icr_idle,
 107
 108        .x86_32_early_logical_apicid    = default_x86_32_early_logical_apicid,
 109};
 110
 111apic_driver(apic_default);
 112
 113struct apic *apic __ro_after_init = &apic_default;
 114EXPORT_SYMBOL_GPL(apic);
 115
 116static int cmdline_apic __initdata;
 117static int __init parse_apic(char *arg)
 118{
 119        struct apic **drv;
 120
 121        if (!arg)
 122                return -EINVAL;
 123
 124        for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 125                if (!strcmp((*drv)->name, arg)) {
 126                        apic = *drv;
 127                        cmdline_apic = 1;
 128                        return 0;
 129                }
 130        }
 131
 132        /* Parsed again by __setup for debug/verbose */
 133        return 0;
 134}
 135early_param("apic", parse_apic);
 136
 137void __init default_setup_apic_routing(void)
 138{
 139        int version = boot_cpu_apic_version;
 140
 141        if (num_possible_cpus() > 8) {
 142                switch (boot_cpu_data.x86_vendor) {
 143                case X86_VENDOR_INTEL:
 144                        if (!APIC_XAPIC(version)) {
 145                                def_to_bigsmp = 0;
 146                                break;
 147                        }
 148                        /* P4 and above */
 149                        fallthrough;
 150                case X86_VENDOR_HYGON:
 151                case X86_VENDOR_AMD:
 152                        def_to_bigsmp = 1;
 153                }
 154        }
 155
 156#ifdef CONFIG_X86_BIGSMP
 157        /*
 158         * This is used to switch to bigsmp mode when
 159         * - There is no apic= option specified by the user
 160         * - generic_apic_probe() has chosen apic_default as the sub_arch
 161         * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
 162         */
 163
 164        if (!cmdline_apic && apic == &apic_default)
 165                generic_bigsmp_probe();
 166#endif
 167
 168        if (apic->setup_apic_routing)
 169                apic->setup_apic_routing();
 170}
 171
 172void __init generic_apic_probe(void)
 173{
 174        if (!cmdline_apic) {
 175                struct apic **drv;
 176
 177                for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 178                        if ((*drv)->probe()) {
 179                                apic = *drv;
 180                                break;
 181                        }
 182                }
 183                /* Not visible without early console */
 184                if (drv == __apicdrivers_end)
 185                        panic("Didn't find an APIC driver");
 186        }
 187        printk(KERN_INFO "Using APIC driver %s\n", apic->name);
 188}
 189
 190/* This function can switch the APIC even after the initial ->probe() */
 191int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 192{
 193        struct apic **drv;
 194
 195        for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
 196                if (!(*drv)->acpi_madt_oem_check)
 197                        continue;
 198                if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id))
 199                        continue;
 200
 201                if (!cmdline_apic) {
 202                        apic = *drv;
 203                        printk(KERN_INFO "Switched to APIC driver `%s'.\n",
 204                               apic->name);
 205                }
 206                return 1;
 207        }
 208        return 0;
 209}
 210